restore outfit colors

* rework sprite manager and ThingType
* render colored outfits again compatible with OpenGL 1
This commit is contained in:
Eduardo Bart 2012-05-09 17:26:34 -03:00
parent fea34a41ea
commit 6495d74edd
19 changed files with 193 additions and 268 deletions

1
TODO
View File

@ -2,7 +2,6 @@
game_shaders (with shader manager) game_shaders (with shader manager)
game_map (with save/load/options) game_map (with save/load/options)
game_minimap (with all tibia functionality) game_minimap (with all tibia functionality)
game_playertrade
== NOTABLE FEATURES == NOTABLE FEATURES
make left panel optional make left panel optional

View File

@ -1,9 +1,5 @@
PlayerTrade = {} PlayerTrade = {}
-- g_game.inspectTrade(counterOffer, index)
-- g_game.acceptTrade()
-- g_game.rejectTrade()
local tradeWindow local tradeWindow
local function createTrade() local function createTrade()

View File

@ -31,7 +31,8 @@ Image::Image(const Size& size, int bpp, uint8 *pixels)
m_size = size; m_size = size;
m_bpp = bpp; m_bpp = bpp;
m_pixels.resize(size.area() * bpp); m_pixels.resize(size.area() * bpp);
memcpy(&m_pixels[0], pixels, m_pixels.size()); if(pixels)
memcpy(&m_pixels[0], pixels, m_pixels.size());
} }
ImagePtr Image::load(const std::string& file) ImagePtr Image::load(const std::string& file)
@ -62,3 +63,23 @@ ImagePtr Image::loadPNG(const std::string& file)
} }
return image; return image;
} }
void Image::overwriteMask(const Color& maskedColor, const Color& insideColor, const Color& outsideColor)
{
assert(m_bpp == 4);
for(int p=0;p<getPixelCount();p++) {
uint8& r = m_pixels[p*4 + 0];
uint8& g = m_pixels[p*4 + 1];
uint8& b = m_pixels[p*4 + 2];
uint8& a = m_pixels[p*4 + 3];
Color pixelColor(r,g,b,a);
Color writeColor = (pixelColor == maskedColor) ? insideColor : outsideColor;
r = writeColor.r();
g = writeColor.g();
b = writeColor.b();
a = writeColor.a();
}
}

View File

@ -29,13 +29,19 @@
class Image class Image
{ {
public: public:
Image(const Size& size, int bpp, uint8 *pixels); Image(const Size& size, int bpp = 4, uint8 *pixels = nullptr);
static ImagePtr load(const std::string& file); static ImagePtr load(const std::string& file);
static ImagePtr loadPNG(const std::string& file); static ImagePtr loadPNG(const std::string& file);
const std::vector<uint8>& getPixels() { return m_pixels; } void overwriteMask(const Color& maskedColor, const Color& insideColor = Color::white, const Color& outsideColor = Color::alpha);
std::vector<uint8>& getPixels() { return m_pixels; }
uint8* getPixelData() { return &m_pixels[0]; }
int getPixelCount() { return m_size.area(); }
const Size& getSize() { return m_size; } const Size& getSize() { return m_size; }
int getWidth() { return m_size.width(); }
int getHeight() { return m_size.height(); }
int getBpp() { return m_bpp; } int getBpp() { return m_bpp; }
private: private:

View File

@ -23,12 +23,18 @@
#include "texture.h" #include "texture.h"
#include "graphics.h" #include "graphics.h"
#include "framebuffer.h" #include "framebuffer.h"
#include "image.h"
Texture::Texture() Texture::Texture()
{ {
m_textureId = 0; m_textureId = 0;
} }
Texture::Texture(const ImagePtr& image)
{
internalLoadGLTexture(image->getPixelData(), image->getBpp(), image->getWidth(), image->getHeight());
}
Texture::Texture(int width, int height, int channels, uchar *pixels) Texture::Texture(int width, int height, int channels, uchar *pixels)
{ {
// generate opengl texture // generate opengl texture

View File

@ -29,6 +29,7 @@ class Texture : public std::enable_shared_from_this<Texture>
{ {
public: public:
Texture(); Texture();
Texture(const ImagePtr& image);
Texture(int width, int height, int channels, uchar* pixels = NULL); Texture(int width, int height, int channels, uchar* pixels = NULL);
virtual ~Texture(); virtual ~Texture();

View File

@ -28,6 +28,7 @@ SET(otclient_SOURCES ${otclient_SOURCES}
${CMAKE_CURRENT_LIST_DIR}/core/game.cpp ${CMAKE_CURRENT_LIST_DIR}/core/game.cpp
${CMAKE_CURRENT_LIST_DIR}/core/map.cpp ${CMAKE_CURRENT_LIST_DIR}/core/map.cpp
${CMAKE_CURRENT_LIST_DIR}/core/mapview.cpp ${CMAKE_CURRENT_LIST_DIR}/core/mapview.cpp
${CMAKE_CURRENT_LIST_DIR}/core/thingtype.cpp
${CMAKE_CURRENT_LIST_DIR}/core/thingstype.cpp ${CMAKE_CURRENT_LIST_DIR}/core/thingstype.cpp
${CMAKE_CURRENT_LIST_DIR}/core/spritemanager.cpp ${CMAKE_CURRENT_LIST_DIR}/core/spritemanager.cpp
${CMAKE_CURRENT_LIST_DIR}/core/item.cpp ${CMAKE_CURRENT_LIST_DIR}/core/item.cpp

View File

@ -88,7 +88,6 @@ void Creature::draw(const Point& dest, float scaleFactor, bool animate)
void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool animateWalk, bool animateIdle, Otc::Direction direction) void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool animateWalk, bool animateIdle, Otc::Direction direction)
{ {
g_painter->setColor(Color::white);
/* /*
if(!outfitProgram) { if(!outfitProgram) {
outfitProgram = PainterShaderProgramPtr(new PainterShaderProgram); outfitProgram = PainterShaderProgramPtr(new PainterShaderProgram);
@ -141,15 +140,32 @@ void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool ani
for(int h = 0; h < getDimensionHeight(); h++) { for(int h = 0; h < getDimensionHeight(); h++) {
for(int w = 0; w < getDimensionWidth(); w++) { for(int w = 0; w < getDimensionWidth(); w++) {
// setup texture outfit mask // setup texture outfit mask
/*
TexturePtr maskTex; TexturePtr maskTex;
if(getLayers() > 1) { if(getLayers() > 1)
int maskId = getSpriteId(w, h, 1, xPattern, yPattern, zPattern, animationPhase); maskTex = m_type->getSprite(w, h, 1, xPattern, yPattern, zPattern, animationPhase);
maskTex = g_sprites.getSpriteTexture(maskId);
}
//outfitProgram->setTexture(maskTex, 1);
internalDraw(dest + (-Point(w,h)*Otc::TILE_PIXELS)*scaleFactor, outfitProgram->setTexture(maskTex, 1);
scaleFactor, w, h, xPattern, yPattern, zPattern, 0, animationPhase); */
Point p = dest + (-Point(w,h)*Otc::TILE_PIXELS)*scaleFactor;
m_type->draw(p, scaleFactor, w, h, xPattern, yPattern, zPattern, 0, animationPhase);
if(getLayers() > 1) {
g_painter->setCompositionMode(Painter::CompositionMode_Multiply);
g_painter->setColor(m_outfit.getHeadColor());
m_type->drawMask(p, scaleFactor, w, h, xPattern, yPattern, zPattern, 1, animationPhase, ThingType::YellowMask);
g_painter->setColor(m_outfit.getBodyColor());
m_type->drawMask(p, scaleFactor, w, h, xPattern, yPattern, zPattern, 1, animationPhase, ThingType::RedMask);
g_painter->setColor(m_outfit.getLegsColor());
m_type->drawMask(p, scaleFactor, w, h, xPattern, yPattern, zPattern, 1, animationPhase, ThingType::GreenMask);
g_painter->setColor(m_outfit.getFeetColor());
m_type->drawMask(p, scaleFactor, w, h, xPattern, yPattern, zPattern, 1, animationPhase, ThingType::BlueMask);
g_painter->resetColor();
g_painter->resetCompositionMode();
}
} }
} }
@ -178,7 +194,7 @@ void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool ani
if(m_outfit.getCategory() == ThingsType::Effect) if(m_outfit.getCategory() == ThingsType::Effect)
animationPhase = std::min(animationPhase+1, getAnimationPhases()); animationPhase = std::min(animationPhase+1, getAnimationPhases());
internalDraw(dest, scaleFactor, 0, 0, 0, animationPhase); m_type->draw(dest, scaleFactor, 0, 0, 0, animationPhase);
} }
} }

View File

@ -41,6 +41,8 @@ class Effect;
class Missile; class Missile;
class AnimatedText; class AnimatedText;
class StaticText; class StaticText;
class ThingType;
class ThingsType;
typedef std::shared_ptr<MapView> MapViewPtr; typedef std::shared_ptr<MapView> MapViewPtr;
typedef std::shared_ptr<Tile> TilePtr; typedef std::shared_ptr<Tile> TilePtr;

View File

@ -32,7 +32,7 @@ void Effect::draw(const Point& dest, float scaleFactor, bool animate)
int animationPhase = 0; int animationPhase = 0;
if(animate) if(animate)
animationPhase = std::min((int)(m_animationTimer.ticksElapsed() / Otc::EFFECT_TICKS_PER_FRAME), getAnimationPhases() - 1); animationPhase = std::min((int)(m_animationTimer.ticksElapsed() / Otc::EFFECT_TICKS_PER_FRAME), getAnimationPhases() - 1);
internalDraw(dest, scaleFactor, 0, 0, 0, animationPhase); m_type->draw(dest, scaleFactor, 0, 0, 0, animationPhase);
} }
void Effect::startAnimation() void Effect::startAnimation()

View File

@ -181,7 +181,7 @@ void Item::draw(const Point& dest, float scaleFactor, bool animate)
*/ */
// now we can draw the item // now we can draw the item
internalDraw(dest, scaleFactor, xPattern, yPattern, zPattern, animationPhase); m_type->draw(dest, scaleFactor, xPattern, yPattern, zPattern, animationPhase);
// release draw shader // release draw shader
g_painter->resetShaderProgram(); g_painter->resetShaderProgram();

View File

@ -63,7 +63,7 @@ void Missile::draw(const Point& dest, float scaleFactor, bool animate)
} }
float fraction = m_animationTimer.ticksElapsed() / m_duration; float fraction = m_animationTimer.ticksElapsed() / m_duration;
internalDraw(dest + m_delta * fraction * scaleFactor, scaleFactor, xPattern, yPattern, 0, 0); m_type->draw(dest + m_delta * fraction * scaleFactor, scaleFactor, xPattern, yPattern, 0, 0);
} }
void Missile::setPath(const Position& fromPosition, const Position& toPosition) void Missile::setPath(const Position& fromPosition, const Position& toPosition)

View File

@ -22,10 +22,8 @@
#include "spritemanager.h" #include "spritemanager.h"
#include <framework/core/resourcemanager.h> #include <framework/core/resourcemanager.h>
#include <framework/core/eventdispatcher.h>
#include <framework/core/filestream.h> #include <framework/core/filestream.h>
#include <framework/graphics/graphics.h> #include <framework/graphics/image.h>
#include <framework/thirdparty/apngloader.h>
SpriteManager g_sprites; SpriteManager g_sprites;
@ -47,7 +45,6 @@ bool SpriteManager::load(const std::string& file)
m_signature = m_spritesFile->getU32(); m_signature = m_spritesFile->getU32();
m_spritesCount = m_spritesFile->getU16(); m_spritesCount = m_spritesFile->getU16();
m_sprites.resize(m_spritesCount);
m_loaded = true; m_loaded = true;
return true; return true;
} catch(Exception& e) { } catch(Exception& e) {
@ -58,35 +55,22 @@ bool SpriteManager::load(const std::string& file)
void SpriteManager::unload() void SpriteManager::unload()
{ {
m_sprites.clear();
m_spritesCount = 0; m_spritesCount = 0;
m_signature = 0; m_signature = 0;
} }
void SpriteManager::preloadSprites() ImagePtr SpriteManager::getSpriteImage(int id)
{ {
// preload every 50 sprites, periodically if(id == 0)
const int burst = 50; return nullptr;
const int interval = 10;
auto preload = [this](int start) {
for(int i=start;i<start+burst && i<=m_spritesCount;++i) {
loadSpriteTexture(i);
}
};
for(int i=1;i<=m_spritesCount;i+=burst)
g_eventDispatcher.scheduleEvent(std::bind(preload, i), (i/burst) * interval);
}
TexturePtr SpriteManager::loadSpriteTexture(int id)
{
m_spritesFile->seek(((id-1) * 4) + 6); m_spritesFile->seek(((id-1) * 4) + 6);
uint32 spriteAddress = m_spritesFile->getU32(); uint32 spriteAddress = m_spritesFile->getU32();
// no sprite? return an empty texture // no sprite? return an empty texture
if(spriteAddress == 0) if(spriteAddress == 0)
return g_graphics.getEmptyTexture(); return nullptr;
m_spritesFile->seek(spriteAddress); m_spritesFile->seek(spriteAddress);
@ -97,7 +81,14 @@ TexturePtr SpriteManager::loadSpriteTexture(int id)
uint16 pixelDataSize = m_spritesFile->getU16(); uint16 pixelDataSize = m_spritesFile->getU16();
static std::vector<uint8> pixels(SPRITE_SIZE); enum {
SPRITE_SIZE = 32,
SPRITE_DATA_SIZE = SPRITE_SIZE*SPRITE_SIZE*4
};
ImagePtr image(new Image(Size(SPRITE_SIZE, SPRITE_SIZE)));
uint8 *pixels = image->getPixelData();
int writePos = 0; int writePos = 0;
int read = 0; int read = 0;
@ -106,8 +97,10 @@ TexturePtr SpriteManager::loadSpriteTexture(int id)
uint16 transparentPixels = m_spritesFile->getU16(); uint16 transparentPixels = m_spritesFile->getU16();
uint16 coloredPixels = m_spritesFile->getU16(); uint16 coloredPixels = m_spritesFile->getU16();
if(writePos + transparentPixels*4 + coloredPixels*3 >= SPRITE_SIZE) if(writePos + transparentPixels*4 + coloredPixels*3 >= SPRITE_DATA_SIZE) {
return g_graphics.getEmptyTexture(); logWarning("corrupt sprite id ", id);
return nullptr;
}
for(int i = 0; i < transparentPixels; i++) { for(int i = 0; i < transparentPixels; i++) {
pixels[writePos + 0] = 0x00; pixels[writePos + 0] = 0x00;
@ -130,7 +123,7 @@ TexturePtr SpriteManager::loadSpriteTexture(int id)
} }
// fill remaining pixels with alpha // fill remaining pixels with alpha
while(writePos < SPRITE_SIZE) { while(writePos < SPRITE_DATA_SIZE) {
pixels[writePos + 0] = 0x00; pixels[writePos + 0] = 0x00;
pixels[writePos + 1] = 0x00; pixels[writePos + 1] = 0x00;
pixels[writePos + 2] = 0x00; pixels[writePos + 2] = 0x00;
@ -138,100 +131,6 @@ TexturePtr SpriteManager::loadSpriteTexture(int id)
writePos += 4; writePos += 4;
} }
TexturePtr spriteTex(new Texture(32, 32, 4, &pixels[0])); return image;
spriteTex->setSmooth(true);
if(g_graphics.canUseMipmaps())
spriteTex->generateSoftwareMipmaps(pixels);
return spriteTex;
} }
TexturePtr& SpriteManager::getSpriteTexture(int id)
{
if(id == 0)
return g_graphics.getEmptyTexture();
assert(id > 0 && id <= m_spritesCount);
// load sprites on demand
TexturePtr& sprite = m_sprites[id-1];
if(!sprite)
sprite = loadSpriteTexture(id);
//TODO: release unused sprites textures after X seconds
// to avoid massive texture allocations
return sprite;
}
bool SpriteManager::exportSprites()
{
g_resources.makeDir("sprites");
std::stringstream ss;
for(volatile int i = 1; i <= m_spritesCount; i++) {
m_spritesFile->seek(((i-1) * 4) + 6);
uint32 spriteAddress = m_spritesFile->getU32();
if(spriteAddress == 0)
continue;
m_spritesFile->seek(spriteAddress);
// skip color key
m_spritesFile->getU8();
m_spritesFile->getU8();
m_spritesFile->getU8();
uint16 pixelDataSize = m_spritesFile->getU16();
uchar pixels[SPRITE_SIZE];
int writePos = 0;
int read = 0;
// decompress pixels
while(read < pixelDataSize) {
uint16 transparentPixels = m_spritesFile->getU16();
uint16 coloredPixels = m_spritesFile->getU16();
if(writePos + transparentPixels*4 + coloredPixels*3 >= SPRITE_SIZE)
return false; // skip the whole process or just ignore this sprite?
for(int i = 0; i < transparentPixels; i++) {
pixels[writePos + 0] = 0x00;
pixels[writePos + 1] = 0x00;
pixels[writePos + 2] = 0x00;
pixels[writePos + 3] = 0x00;
writePos += 4;
}
for(int i = 0; i < coloredPixels; i++) {
pixels[writePos + 0] = m_spritesFile->getU8();
pixels[writePos + 1] = m_spritesFile->getU8();
pixels[writePos + 2] = m_spritesFile->getU8();
pixels[writePos + 3] = 0xFF;
writePos += 4;
}
read += 4 + (3 * coloredPixels);
}
// fill remaining pixels with alpha
while(writePos < SPRITE_SIZE) {
pixels[writePos + 0] = 0x00;
pixels[writePos + 1] = 0x00;
pixels[writePos + 2] = 0x00;
pixels[writePos + 3] = 0x00;
writePos += 4;
}
// We should get the OTClient and export to that folder...
std::string fileName = Fw::formatString("sprites/%d.png", i);
ss.str("");
save_png(ss, SPRITE_WIDTH, SPRITE_HEIGHT, SPRITE_CHANNELS, pixels);
g_resources.saveFile(fileName, ss);
}
return true;
}

View File

@ -24,40 +24,26 @@
#define SPRITEMANAGER_H #define SPRITEMANAGER_H
#include <framework/core/declarations.h> #include <framework/core/declarations.h>
#include <framework/graphics/texture.h> #include <framework/graphics/declarations.h>
class SpriteManager class SpriteManager
{ {
enum {
SPRITE_WIDTH=32,
SPRITE_HEIGHT=32,
SPRITE_CHANNELS=4,
SPRITE_SIZE=SPRITE_WIDTH*SPRITE_HEIGHT*SPRITE_CHANNELS
};
public: public:
SpriteManager(); SpriteManager();
bool load(const std::string& file); bool load(const std::string& file);
void unload(); void unload();
void preloadSprites();
uint32 getSignature() { return m_signature; } uint32 getSignature() { return m_signature; }
int getSpritesCount() { return m_spritesCount; } int getSpritesCount() { return m_spritesCount; }
bool exportSprites(); ImagePtr getSpriteImage(int id);
TexturePtr& getSpriteTexture(int id);
bool isLoaded() { return m_loaded; } bool isLoaded() { return m_loaded; }
private: private:
TexturePtr loadSpriteTexture(int id);
Boolean<false> m_loaded; Boolean<false> m_loaded;
uint32 m_signature; uint32 m_signature;
int m_spritesCount; int m_spritesCount;
std::vector<TexturePtr> m_sprites;
TexturePtr m_transparentSprite;
FileStreamPtr m_spritesFile; FileStreamPtr m_spritesFile;
}; };

View File

@ -74,23 +74,3 @@ int Thing::getStackpos()
return -1; return -1;
} }
} }
void Thing::internalDraw(const Point& dest, float scaleFactor, int w, int h, int xPattern, int yPattern, int zPattern, int layer, int animationPhase)
{
int scaledSize = Otc::TILE_PIXELS * scaleFactor;
int spriteId = getSpriteId(w, h, layer, xPattern, yPattern, zPattern, animationPhase);
if(spriteId) {
Rect drawRect(dest - getDisplacement()*scaleFactor, Size(scaledSize, scaledSize));
g_painter->setColor(Color::white);
g_painter->drawTexturedRect(drawRect, g_sprites.getSpriteTexture(spriteId));
}
}
void Thing::internalDraw(const Point& dest, float scaleFactor, int xPattern, int yPattern, int zPattern, int animationPhase)
{
for(int l = 0; l < getLayers(); ++l)
for(int w = 0; w < getDimensionWidth(); ++w)
for(int h = 0; h < getDimensionHeight(); ++h)
internalDraw(dest - Point(w,h)*Otc::TILE_PIXELS*scaleFactor, scaleFactor, w, h, xPattern, yPattern, zPattern, l, animationPhase);
}

View File

@ -65,55 +65,48 @@ public:
virtual StaticTextPtr asStaticText() { return nullptr; } virtual StaticTextPtr asStaticText() { return nullptr; }
// type related // type related
bool isGround() { return m_type->properties[ThingType::IsGround]; } bool isGround() { return m_type->getProperty(ThingType::IsGround); }
bool isFullGround() { return m_type->properties[ThingType::IsFullGround]; } bool isFullGround() { return m_type->getProperty(ThingType::IsFullGround); }
bool isTranslucent() { return m_type->properties[ThingType::IsTranslucent]; } bool isTranslucent() { return m_type->getProperty(ThingType::IsTranslucent); }
bool isGroundBorder() { return m_type->properties[ThingType::IsGroundBorder]; } bool isGroundBorder() { return m_type->getProperty(ThingType::IsGroundBorder); }
bool isOnBottom() { return m_type->properties[ThingType::IsOnBottom]; } bool isOnBottom() { return m_type->getProperty(ThingType::IsOnBottom); }
bool isOnTop() { return m_type->properties[ThingType::IsOnTop]; } bool isOnTop() { return m_type->getProperty(ThingType::IsOnTop); }
bool isDontHide() { return m_type->properties[ThingType::DontHide]; } bool isDontHide() { return m_type->getProperty(ThingType::DontHide); }
bool isContainer() { return m_type->properties[ThingType::IsContainer]; } bool isContainer() { return m_type->getProperty(ThingType::IsContainer); }
bool isForceUse() { return m_type->properties[ThingType::IsForceUse]; } bool isForceUse() { return m_type->getProperty(ThingType::IsForceUse); }
bool isMultiUse() { return m_type->properties[ThingType::IsMultiUse]; } bool isMultiUse() { return m_type->getProperty(ThingType::IsMultiUse); }
bool isRotateable() { return m_type->properties[ThingType::IsRotateable]; } bool isRotateable() { return m_type->getProperty(ThingType::IsRotateable); }
bool isNotMoveable() { return m_type->properties[ThingType::IsNotMovable]; } bool isNotMoveable() { return m_type->getProperty(ThingType::IsNotMovable); }
bool isNotWalkable() { return m_type->properties[ThingType::NotWalkable]; } bool isNotWalkable() { return m_type->getProperty(ThingType::NotWalkable); }
bool isPickupable() { return m_type->properties[ThingType::IsPickupable]; } bool isPickupable() { return m_type->getProperty(ThingType::IsPickupable); }
bool isNotPathable() { return m_type->properties[ThingType::NotPathable]; } bool isNotPathable() { return m_type->getProperty(ThingType::NotPathable); }
bool isIgnoreLook() { return m_type->properties[ThingType::IgnoreLook]; } bool isIgnoreLook() { return m_type->getProperty(ThingType::IgnoreLook); }
bool isHangable() { return m_type->properties[ThingType::IsHangable]; } bool isHangable() { return m_type->getProperty(ThingType::IsHangable); }
bool isHookSouth() { return m_type->properties[ThingType::HookSouth]; } bool isHookSouth() { return m_type->getProperty(ThingType::HookSouth); }
bool isHookEast() { return m_type->properties[ThingType::HookEast]; } bool isHookEast() { return m_type->getProperty(ThingType::HookEast); }
bool isStackable() { return m_type->properties[ThingType::IsStackable]; } bool isStackable() { return m_type->getProperty(ThingType::IsStackable); }
bool isAnimateAlways() { return m_type->properties[ThingType::AnimateAlways]; } bool isAnimateAlways() { return m_type->getProperty(ThingType::AnimateAlways); }
bool isLyingCorpse() { return m_type->properties[ThingType::IsLyingCorpse]; } bool isLyingCorpse() { return m_type->getProperty(ThingType::IsLyingCorpse); }
bool blocksProjectile() { return m_type->properties[ThingType::BlockProjectile]; } bool blocksProjectile() { return m_type->getProperty(ThingType::BlockProjectile); }
bool isFluid() { return m_type->properties[ThingType::IsFluid]; } bool isFluid() { return m_type->getProperty(ThingType::IsFluid); }
bool isFluidContainer() { return m_type->properties[ThingType::IsFluidContainer]; } bool isFluidContainer() { return m_type->getProperty(ThingType::IsFluidContainer); }
Size getDimension() { return Size(m_type->dimensions[ThingType::Width], m_type->dimensions[ThingType::Height]); } Size getDimension() { return Size(m_type->getDimension(ThingType::Width), m_type->getDimension(ThingType::Height)); }
int getDimensionWidth() { return m_type->dimensions[ThingType::Width]; } int getDimensionWidth() { return m_type->getDimension(ThingType::Width); }
int getDimensionHeight() { return m_type->dimensions[ThingType::Height]; } int getDimensionHeight() { return m_type->getDimension(ThingType::Height); }
int getExactSize() { return m_type->dimensions[ThingType::ExactSize]; } int getExactSize() { return m_type->getDimension(ThingType::ExactSize); }
Point getDisplacement() { return Point(m_type->parameters[ThingType::DisplacementX], m_type->parameters[ThingType::DisplacementY]); } Point getDisplacement() { return Point(m_type->getParameter(ThingType::DisplacementX), m_type->getParameter(ThingType::DisplacementY)); }
int getNumPatternsX() { return m_type->dimensions[ThingType::PatternX]; } int getNumPatternsX() { return m_type->getDimension(ThingType::PatternX); }
int getNumPatternsY() { return m_type->dimensions[ThingType::PatternY]; } int getNumPatternsY() { return m_type->getDimension(ThingType::PatternY); }
int getNumPatternsZ() { return m_type->dimensions[ThingType::PatternZ]; } int getNumPatternsZ() { return m_type->getDimension(ThingType::PatternZ); }
int getDisplacementX() { return m_type->parameters[ThingType::DisplacementX]; } int getDisplacementX() { return m_type->getParameter(ThingType::DisplacementX); }
int getDisplacementY() { return m_type->parameters[ThingType::DisplacementY]; } int getDisplacementY() { return m_type->getParameter(ThingType::DisplacementY); }
int getLayers() { return m_type->dimensions[ThingType::Layers]; } int getLayers() { return m_type->getDimension(ThingType::Layers); }
int getAnimationPhases() { return m_type->dimensions[ThingType::AnimationPhases]; } int getAnimationPhases() { return m_type->getDimension(ThingType::AnimationPhases); }
int getGroundSpeed() { return m_type->parameters[ThingType::GroundSpeed]; } int getGroundSpeed() { return m_type->getParameter(ThingType::GroundSpeed); }
int getElevation() { return m_type->parameters[ThingType::Elevation]; } int getElevation() { return m_type->getParameter(ThingType::Elevation); }
int getMinimapColor() { return m_type->parameters[ThingType::MiniMapColor]; } int getMinimapColor() { return m_type->getParameter(ThingType::MiniMapColor); }
int getSpriteId(int w = 0, int h = 0, int layer = 0,
int xPattern = 0, int yPattern = 0, int zPattern = 0,
int animation = 0) { return m_type->getSpriteId(w, h, layer, xPattern, yPattern, zPattern, animation); }
protected: protected:
void internalDraw(const Point& dest, float scaleFactor, int w, int h, int xPattern, int yPattern, int zPattern, int layer, int animationPhase);
void internalDraw(const Point& dest, float scaleFactor, int xPattern, int yPattern, int zPattern, int animationPhase);
Position m_position; Position m_position;
ThingType *m_type; ThingType *m_type;
}; };

View File

@ -71,46 +71,47 @@ void ThingsType::parseThingType(std::stringstream& fin, ThingType& thingType)
if(property == ThingType::LastPropertyValue) if(property == ThingType::LastPropertyValue)
break; break;
thingType.properties[property] = true; thingType.m_properties[property] = true;
if(property == ThingType::IsGround) if(property == ThingType::IsGround)
thingType.parameters[ThingType::GroundSpeed] = Fw::getU16(fin); thingType.m_parameters[ThingType::GroundSpeed] = Fw::getU16(fin);
else if(property == ThingType::IsWritable || property == ThingType::IsWritableOnce) else if(property == ThingType::IsWritable || property == ThingType::IsWritableOnce)
thingType.parameters[ThingType::MaxTextLenght] = Fw::getU16(fin); thingType.m_parameters[ThingType::MaxTextLenght] = Fw::getU16(fin);
else if(property == ThingType::HasLight) { else if(property == ThingType::HasLight) {
thingType.parameters[ThingType::LightLevel] = Fw::getU16(fin); thingType.m_parameters[ThingType::LightLevel] = Fw::getU16(fin);
thingType.parameters[ThingType::LightColor] = Fw::getU16(fin); thingType.m_parameters[ThingType::LightColor] = Fw::getU16(fin);
} }
else if(property == ThingType::HasDisplacement) { else if(property == ThingType::HasDisplacement) {
thingType.parameters[ThingType::DisplacementX] = Fw::getU16(fin); thingType.m_parameters[ThingType::DisplacementX] = Fw::getU16(fin);
thingType.parameters[ThingType::DisplacementY] = Fw::getU16(fin); thingType.m_parameters[ThingType::DisplacementY] = Fw::getU16(fin);
} }
else if(property == ThingType::HasElevation) else if(property == ThingType::HasElevation)
thingType.parameters[ThingType::Elevation] = Fw::getU16(fin); thingType.m_parameters[ThingType::Elevation] = Fw::getU16(fin);
else if(property == ThingType::MiniMap) else if(property == ThingType::MiniMap)
thingType.parameters[ThingType::MiniMapColor] = Fw::getU16(fin); thingType.m_parameters[ThingType::MiniMapColor] = Fw::getU16(fin);
else if(property == ThingType::LensHelp) else if(property == ThingType::LensHelp)
thingType.parameters[ThingType::LensHelpParameter] = Fw::getU16(fin); thingType.m_parameters[ThingType::LensHelpParameter] = Fw::getU16(fin);
else if(property == ThingType::Cloth) else if(property == ThingType::Cloth)
thingType.parameters[ThingType::ClothSlot] = Fw::getU16(fin); thingType.m_parameters[ThingType::ClothSlot] = Fw::getU16(fin);
} }
int totalSprites = 1; int totalSprites = 1;
for(int i = 0; i < ThingType::LastDimension; ++i) { for(int i = 0; i < ThingType::LastDimension; ++i) {
if(i == ThingType::ExactSize && thingType.dimensions[ThingType::Width] <= 1 && thingType.dimensions[ThingType::Height] <= 1) { if(i == ThingType::ExactSize && thingType.m_dimensions[ThingType::Width] <= 1 && thingType.m_dimensions[ThingType::Height] <= 1) {
thingType.dimensions[i] = 32; thingType.m_dimensions[i] = 32;
continue; continue;
} }
thingType.dimensions[i] = Fw::getU8(fin); thingType.m_dimensions[i] = Fw::getU8(fin);
if(i != ThingType::ExactSize) if(i != ThingType::ExactSize)
totalSprites *= thingType.dimensions[i]; totalSprites *= thingType.m_dimensions[i];
} }
thingType.sprites.resize(totalSprites); thingType.m_spritesIndex.resize(totalSprites);
thingType.m_sprites.resize(totalSprites);
for(int i = 0; i < totalSprites; i++) for(int i = 0; i < totalSprites; i++)
thingType.sprites[i] = Fw::getU16(fin); thingType.m_spritesIndex[i] = Fw::getU16(fin);
} }
ThingType *ThingsType::getThingType(uint16 id, Categories category) ThingType *ThingsType::getThingType(uint16 id, Categories category)

View File

@ -25,16 +25,11 @@
#include "declarations.h" #include "declarations.h"
#include <framework/graphics/declarations.h>
struct ThingType struct ThingType
{ {
ThingType() { enum Dimension {
// fill default values
dimensions.fill(0);
properties.fill(false);
parameters.fill(0);
}
enum Dimensions {
Width = 0, Width = 0,
Height, Height,
ExactSize, ExactSize,
@ -45,10 +40,8 @@ struct ThingType
AnimationPhases, AnimationPhases,
LastDimension LastDimension
}; };
std::array<int, LastDimension> dimensions;
std::vector<int> sprites;
enum Properties { enum Property {
IsGround = 0, IsGround = 0,
IsGroundBorder, IsGroundBorder,
IsOnBottom, IsOnBottom,
@ -86,9 +79,8 @@ struct ThingType
LastProperty, LastProperty,
LastPropertyValue = 255 LastPropertyValue = 255
}; };
std::array<bool, LastProperty> properties;
enum Parameters { enum Parameter {
GroundSpeed = 0, GroundSpeed = 0,
Fluid, Fluid,
MaxTextLenght, MaxTextLenght,
@ -102,23 +94,49 @@ struct ThingType
Elevation, Elevation,
LastParameter LastParameter
}; };
std::array<int, LastParameter> parameters;
int getSpriteId(int w, int h, int l, int x, int y, int z, int a) enum SpriteMask {
{ YellowMask = 0,
int sprIndex = ((((((a % dimensions[ThingType::AnimationPhases]) RedMask,
* dimensions[ThingType::PatternZ] + z) GreenMask,
* dimensions[ThingType::PatternY] + y) BlueMask,
* dimensions[ThingType::PatternX] + x) LastMask
* dimensions[ThingType::Layers] + l) };
* dimensions[ThingType::Height] + h)
* dimensions[ThingType::Width] + w;
if(sprIndex >= 0 && sprIndex < (int)sprites.size()) ThingType();
return sprites[sprIndex];
return 0; void draw(const Point& dest, float scaleFactor, int w, int h, int xPattern, int yPattern, int zPattern, int layer, int animationPhase);
void draw(const Point& dest, float scaleFactor, int xPattern, int yPattern, int zPattern, int animationPhase);
void drawMask(const Point& dest, float scaleFactor, int w, int h, int xPattern, int yPattern, int zPattern, int layer, int animationPhase, SpriteMask mask);
TexturePtr& getSprite(int w, int h, int l, int x, int y, int z, int a);
TexturePtr& getSpriteMask(int w, int h, int l, int x, int y, int z, int a, SpriteMask mask);
bool getProperty(Property property) { return m_properties[property]; }
int getParameter(Parameter param) { return m_parameters[param]; }
int getDimension(Dimension dimension) { return m_dimensions[dimension]; }
private:
uint getSpriteIndex(int w, int h, int l, int x, int y, int z, int a) {
uint index = ((((((a % m_dimensions[ThingType::AnimationPhases])
* m_dimensions[ThingType::PatternZ] + z)
* m_dimensions[ThingType::PatternY] + y)
* m_dimensions[ThingType::PatternX] + x)
* m_dimensions[ThingType::Layers] + l)
* m_dimensions[ThingType::Height] + h)
* m_dimensions[ThingType::Width] + w;
assert(index < m_sprites.size());
return index;
} }
std::array<int, LastDimension> m_dimensions;
std::array<int, LastParameter> m_parameters;
std::array<bool, LastProperty> m_properties;
std::vector<int> m_spritesIndex;
std::vector<TexturePtr> m_sprites;
std::vector<std::array<TexturePtr, LastMask>> m_spritesMask;
friend class ThingsType;
}; };
typedef std::vector<ThingType> ThingTypeList; typedef std::vector<ThingType> ThingTypeList;

View File

@ -55,10 +55,10 @@ void OTClient::registerLuaFunctions()
g_lua.registerStaticClass("g_sprites"); g_lua.registerStaticClass("g_sprites");
g_lua.bindClassStaticFunction("g_sprites", "load", std::bind(&SpriteManager::load, &g_sprites, std::placeholders::_1)); g_lua.bindClassStaticFunction("g_sprites", "load", std::bind(&SpriteManager::load, &g_sprites, std::placeholders::_1));
g_lua.bindClassStaticFunction("g_sprites", "unload", std::bind(&SpriteManager::unload, &g_sprites));
g_lua.bindClassStaticFunction("g_sprites", "isLoaded", std::bind(&SpriteManager::isLoaded, &g_sprites)); g_lua.bindClassStaticFunction("g_sprites", "isLoaded", std::bind(&SpriteManager::isLoaded, &g_sprites));
g_lua.bindClassStaticFunction("g_sprites", "getSignature", std::bind(&SpriteManager::getSignature, &g_sprites)); g_lua.bindClassStaticFunction("g_sprites", "getSignature", std::bind(&SpriteManager::getSignature, &g_sprites));
g_lua.bindClassStaticFunction("g_sprites", "preloadSprites", std::bind(&SpriteManager::preloadSprites, &g_sprites)); g_lua.bindClassStaticFunction("g_sprites", "getSpritesCount", std::bind(&SpriteManager::getSpritesCount, &g_sprites));
g_lua.bindClassStaticFunction("g_sprites", "export", std::bind(&SpriteManager::exportSprites, &g_sprites));
g_lua.registerStaticClass("g_map"); g_lua.registerStaticClass("g_map");
g_lua.bindClassStaticFunction("g_map", "isLookPossible", std::bind(&Map::isLookPossible, &g_map, std::placeholders::_1)); g_lua.bindClassStaticFunction("g_map", "isLookPossible", std::bind(&Map::isLookPossible, &g_map, std::placeholders::_1));