graphics optimizations/fixes/features

* cache text vertex for StaticText, AnimatedText and Creature names
* improved outfit rendering
* fully compatible with OpenGL 1.1
* enable mipmaping for game sprites again
* Ctrl+W hotkey clean game texts
This commit is contained in:
Eduardo Bart 2012-06-08 21:40:22 -03:00
parent 1a7f2a44fc
commit 95cf7eb788
21 changed files with 180 additions and 155 deletions

View File

@ -53,6 +53,7 @@ function GameInterface.init()
Keyboard.bindKeyPress('Ctrl+-', function() gameMapPanel:zoomOut() end, gameRootPanel, 250) Keyboard.bindKeyPress('Ctrl+-', function() gameMapPanel:zoomOut() end, gameRootPanel, 250)
Keyboard.bindKeyDown('Ctrl+Q', GameInterface.tryLogout, gameRootPanel) Keyboard.bindKeyDown('Ctrl+Q', GameInterface.tryLogout, gameRootPanel)
Keyboard.bindKeyDown('Ctrl+L', GameInterface.tryLogout, gameRootPanel) Keyboard.bindKeyDown('Ctrl+L', GameInterface.tryLogout, gameRootPanel)
Keyboard.bindKeyDown('Ctrl+W', function() g_map.cleanTexts() TextMessage.clearMessages() end, gameRootPanel)
if g_game.isOnline() then if g_game.isOnline() then
GameInterface.show() GameInterface.show()

View File

@ -197,6 +197,7 @@ SET(framework_SOURCES ${framework_SOURCES}
# framework graphics # framework graphics
${CMAKE_CURRENT_LIST_DIR}/graphics/font.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/font.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/cachedtext.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/fontmanager.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/fontmanager.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/graphics.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/graphics.cpp
${CMAKE_CURRENT_LIST_DIR}/graphics/painter.cpp ${CMAKE_CURRENT_LIST_DIR}/graphics/painter.cpp

View File

@ -167,7 +167,6 @@ void Application::run()
if(!m_initialized) if(!m_initialized)
return; return;
bool cacheForeground = true;
m_stopping = false; m_stopping = false;
m_running = true; m_running = true;
@ -190,14 +189,7 @@ void Application::run()
bool redraw = false; bool redraw = false;
bool updateForeground = false; bool updateForeground = false;
bool canCacheForeground = g_graphics.canCacheBackbuffer() && m_foregroundFrameCounter.getMaxFps() != 0; bool cacheForeground = g_graphics.canCacheBackbuffer() && m_foregroundFrameCounter.getMaxFps() != 0;
if(cacheForeground != canCacheForeground) {
cacheForeground = canCacheForeground;
if(cacheForeground)
glColorMask(1,1,1,1);
else
glColorMask(1,1,1,0);
}
if(m_backgroundFrameCounter.shouldProcessNextFrame()) { if(m_backgroundFrameCounter.shouldProcessNextFrame()) {
redraw = true; redraw = true;
@ -219,11 +211,15 @@ void Application::run()
m_foregroundFrameCounter.processNextFrame(); m_foregroundFrameCounter.processNextFrame();
// draw foreground // draw foreground
g_painter->clear(Color::black); g_painter->setAlphaWriting(true);
g_painter->clear(Color::alpha);
g_ui.render(Fw::ForegroundPane); g_ui.render(Fw::ForegroundPane);
// copy the foreground to a texture // copy the foreground to a texture
m_foreground->copyFromScreen(viewportRect); m_foreground->copyFromScreen(viewportRect);
g_painter->clear(Color::black);
g_painter->setAlphaWriting(false);
} }
// draw background (animated stuff) // draw background (animated stuff)

View File

@ -30,6 +30,7 @@ class Texture;
class Image; class Image;
class AnimatedTexture; class AnimatedTexture;
class Font; class Font;
class CachedText;
class FrameBuffer; class FrameBuffer;
class Shader; class Shader;
class ShaderProgram; class ShaderProgram;
@ -46,6 +47,7 @@ typedef std::shared_ptr<Image> ImagePtr;
typedef std::shared_ptr<Texture> TexturePtr; typedef std::shared_ptr<Texture> TexturePtr;
typedef std::shared_ptr<AnimatedTexture> AnimatedTexturePtr; typedef std::shared_ptr<AnimatedTexture> AnimatedTexturePtr;
typedef std::shared_ptr<Font> FontPtr; typedef std::shared_ptr<Font> FontPtr;
typedef std::shared_ptr<CachedText> CachedTextPtr;
typedef std::shared_ptr<FrameBuffer> FrameBufferPtr; typedef std::shared_ptr<FrameBuffer> FrameBufferPtr;
typedef std::shared_ptr<Shader> ShaderPtr; typedef std::shared_ptr<Shader> ShaderPtr;
typedef std::shared_ptr<ShaderProgram> ShaderProgramPtr; typedef std::shared_ptr<ShaderProgram> ShaderProgramPtr;

View File

@ -131,13 +131,57 @@ bool Image::nextMipmap()
assert(m_bpp == 4); assert(m_bpp == 4);
assert(stdext::is_power_of_two(m_size.width()) && stdext::is_power_of_two(m_size.height())); assert(stdext::is_power_of_two(m_size.width()) && stdext::is_power_of_two(m_size.height()));
if(m_size.width() == 1 || m_size.height() == 1) int iw = m_size.width();
int ih = m_size.height();
if(iw == 1 && ih == 1)
return false; return false;
Size size = m_size / 2; int ow = iw > 1 ? iw/2 : 1;
std::vector<uint8> pixels(size.area()*4, 0xFF); int oh = ih > 1 ? ih/2 : 1;
std::vector<uint8> pixels(ow*oh*4, 0xFF);
//FIXME: calculate mipmaps for 8x1, 4x1, 2x1 ...
if(iw != 1 && ih != 1) {
for(int x=0;x<ow;++x) {
for(int y=0;y<oh;++y) {
uint8 *inPixel[4];
inPixel[0] = &m_pixels[((y*2)*iw + (x*2))*4];
inPixel[1] = &m_pixels[((y*2)*iw + (x*2)+1)*4];
inPixel[2] = &m_pixels[((y*2+1)*iw + (x*2))*4];
inPixel[3] = &m_pixels[((y*2+1)*iw + (x*2)+1)*4];
uint8 *outPixel = &pixels[(y*ow + x)*4];
int pixelsSum[4];
for(int i=0;i<4;++i)
pixelsSum[i] = 0;
int usedPixels = 0;
for(int j=0;j<4;++j) {
// ignore colors of complete alpha pixels
if(inPixel[j][3] < 16)
continue;
for(int i=0;i<4;++i)
pixelsSum[i] += inPixel[j][i];
usedPixels++;
}
// try to guess the alpha pixel more accurately
for(int i=0;i<4;++i) {
if(usedPixels > 0)
outPixel[i] = pixelsSum[i] / usedPixels;
else
outPixel[i] = 0;
}
outPixel[3] = pixelsSum[3]/4;
}
}
}
m_pixels = pixels; m_pixels = pixels;
m_size = size; m_size = Size(ow, oh);
return true; return true;
} }

View File

@ -34,6 +34,7 @@ Painter::Painter()
m_compositionMode = CompositionMode_Normal; m_compositionMode = CompositionMode_Normal;
m_shaderProgram = nullptr; m_shaderProgram = nullptr;
m_texture = nullptr; m_texture = nullptr;
m_alphaWriting = false;
} }
void Painter::resetState() void Painter::resetState()
@ -44,6 +45,7 @@ void Painter::resetState()
resetClipRect(); resetClipRect();
resetShaderProgram(); resetShaderProgram();
resetTexture(); resetTexture();
resetAlphaWriting();
} }
void Painter::refreshState() void Painter::refreshState()
@ -51,6 +53,7 @@ void Painter::refreshState()
updateGlCompositionMode(); updateGlCompositionMode();
updateGlClipRect(); updateGlClipRect();
updateGlTexture(); updateGlTexture();
updateGlAlphaWriting();
} }
void Painter::saveState() void Painter::saveState()
@ -64,6 +67,7 @@ void Painter::saveState()
m_olderStates[m_oldStateIndex].clipRect = m_clipRect; m_olderStates[m_oldStateIndex].clipRect = m_clipRect;
m_olderStates[m_oldStateIndex].shaderProgram = m_shaderProgram; m_olderStates[m_oldStateIndex].shaderProgram = m_shaderProgram;
m_olderStates[m_oldStateIndex].texture = m_texture; m_olderStates[m_oldStateIndex].texture = m_texture;
m_olderStates[m_oldStateIndex].alphaWriting = m_alphaWriting;
m_oldStateIndex++; m_oldStateIndex++;
} }
@ -137,6 +141,15 @@ void Painter::setTexture(Texture* texture)
} }
} }
void Painter::setAlphaWriting(bool enable)
{
if(m_alphaWriting == enable)
return;
m_alphaWriting = enable;
updateGlAlphaWriting();
}
void Painter::updateGlTexture() void Painter::updateGlTexture()
{ {
if(m_glTextureId != 0) if(m_glTextureId != 0)
@ -177,3 +190,11 @@ void Painter::updateGlClipRect()
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
} }
} }
void Painter::updateGlAlphaWriting()
{
if(m_alphaWriting)
glColorMask(1,1,1,1);
else
glColorMask(1,1,1,0);
}

View File

@ -52,6 +52,7 @@ public:
Rect clipRect; Rect clipRect;
Texture *texture; Texture *texture;
PainterShaderProgram *shaderProgram; PainterShaderProgram *shaderProgram;
bool alphaWriting;
}; };
Painter(); Painter();
@ -85,6 +86,7 @@ public:
virtual void setClipRect(const Rect& clipRect); virtual void setClipRect(const Rect& clipRect);
virtual void setShaderProgram(PainterShaderProgram *shaderProgram) { m_shaderProgram = shaderProgram; } virtual void setShaderProgram(PainterShaderProgram *shaderProgram) { m_shaderProgram = shaderProgram; }
virtual void setTexture(Texture *texture); virtual void setTexture(Texture *texture);
void setAlphaWriting(bool enable);
void setShaderProgram(const PainterShaderProgramPtr& shaderProgram) { setShaderProgram(shaderProgram.get()); } void setShaderProgram(const PainterShaderProgramPtr& shaderProgram) { setShaderProgram(shaderProgram.get()); }
void setTexture(const TexturePtr& texture) { setTexture(texture.get()); } void setTexture(const TexturePtr& texture) { setTexture(texture.get()); }
@ -96,6 +98,7 @@ public:
CompositionMode getCompositionMode() { return m_compositionMode; } CompositionMode getCompositionMode() { return m_compositionMode; }
Rect getClipRect() { return m_clipRect; } Rect getClipRect() { return m_clipRect; }
PainterShaderProgram *getShaderProgram() { return m_shaderProgram; } PainterShaderProgram *getShaderProgram() { return m_shaderProgram; }
bool getAlphaWriting() { return m_alphaWriting; }
void resetColor() { setColor(Color::white); } void resetColor() { setColor(Color::white); }
void resetOpacity() { setOpacity(1.0f); } void resetOpacity() { setOpacity(1.0f); }
@ -103,11 +106,13 @@ public:
void resetCompositionMode() { setCompositionMode(CompositionMode_Normal); } void resetCompositionMode() { setCompositionMode(CompositionMode_Normal); }
void resetShaderProgram() { setShaderProgram(nullptr); } void resetShaderProgram() { setShaderProgram(nullptr); }
void resetTexture() { setTexture(nullptr); } void resetTexture() { setTexture(nullptr); }
void resetAlphaWriting() { setAlphaWriting(false); }
protected: protected:
void updateGlTexture(); void updateGlTexture();
void updateGlCompositionMode(); void updateGlCompositionMode();
void updateGlClipRect(); void updateGlClipRect();
void updateGlAlphaWriting();
CoordsBuffer m_coordsBuffer; CoordsBuffer m_coordsBuffer;
@ -119,6 +124,7 @@ protected:
Rect m_clipRect; Rect m_clipRect;
Texture *m_texture; Texture *m_texture;
PainterShaderProgram *m_shaderProgram; PainterShaderProgram *m_shaderProgram;
bool m_alphaWriting;
PainterState m_olderStates[10]; PainterState m_olderStates[10];
int m_oldStateIndex; int m_oldStateIndex;

View File

@ -62,7 +62,6 @@ Texture::Texture(const ImagePtr& image, bool buildMipmaps)
bind(); bind();
/*
if(buildMipmaps) { if(buildMipmaps) {
int level = 0; int level = 0;
do { do {
@ -70,7 +69,6 @@ Texture::Texture(const ImagePtr& image, bool buildMipmaps)
} while(glImage->nextMipmap()); } while(glImage->nextMipmap());
m_hasMipmaps = true; m_hasMipmaps = true;
} else } else
*/
setupPixels(0, glImage->getSize(), glImage->getPixelData(), glImage->getBpp()); setupPixels(0, glImage->getSize(), glImage->getPixelData(), glImage->getBpp());
setupWrap(); setupWrap();

View File

@ -370,10 +370,10 @@ void X11Window::internalChooseGLVisual()
#else #else
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
#endif #endif
EGL_RED_SIZE, 5, EGL_RED_SIZE, 4,
EGL_GREEN_SIZE, 6, EGL_GREEN_SIZE, 4,
EGL_BLUE_SIZE, 5, EGL_BLUE_SIZE, 4,
EGL_ALPHA_SIZE, 0, EGL_ALPHA_SIZE, 4,
EGL_NONE EGL_NONE
}; };

View File

@ -28,20 +28,22 @@
AnimatedText::AnimatedText() AnimatedText::AnimatedText()
{ {
m_font = g_fonts.getFont("verdana-11px-rounded"); m_cachedText.setFont(g_fonts.getFont("verdana-11px-rounded"));
m_cachedText.setAlign(Fw::AlignLeft);
} }
void AnimatedText::draw(const Point& dest, const Rect& visibleRect) void AnimatedText::draw(const Point& dest, const Rect& visibleRect)
{ {
Point p = dest; Point p = dest;
p.x += 20 - m_textSize.width() / 2; Size textSize = m_cachedText.getTextSize();
p.x += 20 - textSize.width() / 2;
p.y += (-20 * m_animationTimer.ticksElapsed()) / Otc::ANIMATED_TEXT_DURATION; p.y += (-20 * m_animationTimer.ticksElapsed()) / Otc::ANIMATED_TEXT_DURATION;
Rect rect(p, m_textSize); Rect rect(p, textSize);
if(visibleRect.contains(rect)) { if(visibleRect.contains(rect)) {
//TODO: cache into a framebuffer //TODO: cache into a framebuffer
g_painter->setColor(m_color); g_painter->setColor(m_color);
m_font->drawText(m_text, rect, Fw::AlignLeft); m_cachedText.draw(rect);
} }
} }
@ -61,6 +63,5 @@ void AnimatedText::setColor(int color)
void AnimatedText::setText(const std::string& text) void AnimatedText::setText(const std::string& text)
{ {
m_textSize = m_font->calculateTextRectSize(text); m_cachedText.setText(text);
m_text = text;
} }

View File

@ -26,6 +26,7 @@
#include "thing.h" #include "thing.h"
#include <framework/graphics/fontmanager.h> #include <framework/graphics/fontmanager.h>
#include <framework/core/timer.h> #include <framework/core/timer.h>
#include <framework/graphics/cachedtext.h>
class AnimatedText : public Thing class AnimatedText : public Thing
{ {
@ -42,11 +43,9 @@ public:
bool isAnimatedText() { return true; } bool isAnimatedText() { return true; }
private: private:
FontPtr m_font;
Size m_textSize;
std::string m_text;
Color m_color; Color m_color;
Timer m_animationTimer; Timer m_animationTimer;
CachedText m_cachedText;
}; };
#endif #endif

View File

@ -52,7 +52,8 @@ Creature::Creature() : Thing()
m_skull = Otc::SkullNone; m_skull = Otc::SkullNone;
m_shield = Otc::ShieldNone; m_shield = Otc::ShieldNone;
m_emblem = Otc::EmblemNone; m_emblem = Otc::EmblemNone;
m_informationFont = g_fonts.getFont("verdana-11px-rounded"); m_nameCache.setFont(g_fonts.getFont("verdana-11px-rounded"));
m_nameCache.setAlign(Fw::AlignTopCenter);
} }
/* /*
@ -85,21 +86,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)
{ {
/*
if(!outfitProgram) {
outfitProgram = PainterShaderProgramPtr(new PainterShaderProgram);
outfitProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader);
outfitProgram->addShaderFromSourceFile(Shader::Fragment, "/game_shaders/outfit.frag");
outfitProgram->link();
outfitProgram->bindUniformLocation(HEAD_COLOR_UNIFORM, "headColor");
outfitProgram->bindUniformLocation(BODY_COLOR_UNIFORM, "bodyColor");
outfitProgram->bindUniformLocation(LEGS_COLOR_UNIFORM, "legsColor");
outfitProgram->bindUniformLocation(FEET_COLOR_UNIFORM, "feetColor");
}
*/
int xPattern = 0, yPattern = 0, zPattern = 0;
// outfit is a real creature // outfit is a real creature
if(m_outfit.getCategory() == ThingsType::Creature) { if(m_outfit.getCategory() == ThingsType::Creature) {
int animationPhase = animateWalk ? m_walkAnimationPhase : 0; int animationPhase = animateWalk ? m_walkAnimationPhase : 0;
@ -110,6 +96,7 @@ void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool ani
} }
// xPattern => creature direction // xPattern => creature direction
int xPattern;
if(direction == Otc::NorthEast || direction == Otc::SouthEast) if(direction == Otc::NorthEast || direction == Otc::SouthEast)
xPattern = Otc::East; xPattern = Otc::East;
else if(direction == Otc::NorthWest || direction == Otc::SouthWest) else if(direction == Otc::NorthWest || direction == Otc::SouthWest)
@ -118,56 +105,30 @@ void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool ani
xPattern = direction; xPattern = direction;
// yPattern => creature addon // yPattern => creature addon
for(yPattern = 0; yPattern < getNumPatternsY(); yPattern++) { for(int yPattern = 0; yPattern < getNumPatternsY(); yPattern++) {
// continue if we dont have this addon. // continue if we dont have this addon
if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1)))) if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
continue; continue;
/* m_type->draw(dest, scaleFactor, 0, xPattern, yPattern, 0, animationPhase);
g_painter->setShaderProgram(outfitProgram);
outfitProgram->bind();
outfitProgram->setUniformValue(HEAD_COLOR_UNIFORM, m_outfit.getHeadColor());
outfitProgram->setUniformValue(BODY_COLOR_UNIFORM, m_outfit.getBodyColor());
outfitProgram->setUniformValue(LEGS_COLOR_UNIFORM, m_outfit.getLegsColor());
outfitProgram->setUniformValue(FEET_COLOR_UNIFORM, m_outfit.getFeetColor());
*/
m_type->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase);
for(int h = 0; h < getDimensionHeight(); h++) {
for(int w = 0; w < getDimensionWidth(); w++) {
// setup texture outfit mask
/*
TexturePtr maskTex;
if(getLayers() > 1)
maskTex = m_type->getSprite(w, h, 1, xPattern, yPattern, zPattern, animationPhase);
outfitProgram->setTexture(maskTex, 1);
*/
Point p = dest + (-Point(w,h)*Otc::TILE_PIXELS)*scaleFactor;
if(getLayers() > 1) { if(getLayers() > 1) {
g_painter->saveState(); Color oldColor = g_painter->getColor();
Painter::CompositionMode oldComposition = g_painter->getCompositionMode();
g_painter->setCompositionMode(Painter::CompositionMode_Multiply); g_painter->setCompositionMode(Painter::CompositionMode_Multiply);
g_painter->setColor(m_outfit.getHeadColor()); g_painter->setColor(m_outfit.getHeadColor());
m_type->drawMask(p, scaleFactor, w, h, xPattern, yPattern, zPattern, 1, animationPhase, ThingType::YellowMask); m_type->draw(dest, scaleFactor, ThingType::YellowMask, xPattern, yPattern, 0, animationPhase);
g_painter->setColor(m_outfit.getBodyColor()); g_painter->setColor(m_outfit.getBodyColor());
m_type->drawMask(p, scaleFactor, w, h, xPattern, yPattern, zPattern, 1, animationPhase, ThingType::RedMask); m_type->draw(dest, scaleFactor, ThingType::RedMask, xPattern, yPattern, 0, animationPhase);
g_painter->setColor(m_outfit.getLegsColor()); g_painter->setColor(m_outfit.getLegsColor());
m_type->drawMask(p, scaleFactor, w, h, xPattern, yPattern, zPattern, 1, animationPhase, ThingType::GreenMask); m_type->draw(dest, scaleFactor, ThingType::GreenMask, xPattern, yPattern, 0, animationPhase);
g_painter->setColor(m_outfit.getFeetColor()); g_painter->setColor(m_outfit.getFeetColor());
m_type->drawMask(p, scaleFactor, w, h, xPattern, yPattern, zPattern, 1, animationPhase, ThingType::BlueMask); m_type->draw(dest, scaleFactor, ThingType::BlueMask, xPattern, yPattern, 0, animationPhase);
g_painter->setColor(oldColor);
g_painter->restoreSavedState(); g_painter->setCompositionMode(oldComposition);
} }
} }
}
//g_painter->resetShaderProgram();
}
// outfit is a creature imitating an item or the invisible effect // outfit is a creature imitating an item or the invisible effect
} else { } else {
int animationPhase = 0; int animationPhase = 0;
@ -203,6 +164,7 @@ void Creature::drawOutfit(const Rect& destRect, bool resize)
outfitBuffer = FrameBufferPtr(new FrameBuffer(Size(2*Otc::TILE_PIXELS, 2*Otc::TILE_PIXELS))); outfitBuffer = FrameBufferPtr(new FrameBuffer(Size(2*Otc::TILE_PIXELS, 2*Otc::TILE_PIXELS)));
outfitBuffer->bind(); outfitBuffer->bind();
g_painter->setAlphaWriting(true);
g_painter->clear(Color::alpha); g_painter->clear(Color::alpha);
internalDrawOutfit(Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) + getDisplacement(), 1, false, true, Otc::South); internalDrawOutfit(Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) + getDisplacement(), 1, false, true, Otc::South);
outfitBuffer->release(); outfitBuffer->release();
@ -236,7 +198,8 @@ void Creature::drawInformation(const Point& point, bool useGray, const Rect& par
Rect backgroundRect = Rect(point.x-(13.5), point.y, 27, 4); Rect backgroundRect = Rect(point.x-(13.5), point.y, 27, 4);
backgroundRect.bind(parentRect); backgroundRect.bind(parentRect);
Rect textRect = Rect(point.x - m_nameSize.width() / 2.0, point.y-12, m_nameSize); Size nameSize = m_nameCache.getTextSize();
Rect textRect = Rect(point.x - nameSize.width() / 2.0, point.y-12, nameSize);
textRect.bind(parentRect); textRect.bind(parentRect);
// distance them // distance them
@ -256,8 +219,7 @@ void Creature::drawInformation(const Point& point, bool useGray, const Rect& par
g_painter->setColor(fillColor); g_painter->setColor(fillColor);
g_painter->drawFilledRect(healthRect); g_painter->drawFilledRect(healthRect);
if(m_informationFont) m_nameCache.draw(textRect);
m_informationFont->drawText(m_name, textRect, Fw::AlignTopCenter);
if(m_skull != Otc::SkullNone && m_skullTexture) { if(m_skull != Otc::SkullNone && m_skullTexture) {
g_painter->setColor(Color::white); g_painter->setColor(Color::white);
@ -447,8 +409,7 @@ void Creature::terminateWalk()
void Creature::setName(const std::string& name) void Creature::setName(const std::string& name)
{ {
if(m_informationFont) m_nameCache.setText(name);
m_nameSize = m_informationFont->calculateTextRectSize(name);
m_name = name; m_name = name;
} }

View File

@ -28,6 +28,7 @@
#include <framework/core/declarations.h> #include <framework/core/declarations.h>
#include <framework/core/timer.h> #include <framework/core/timer.h>
#include <framework/graphics/fontmanager.h> #include <framework/graphics/fontmanager.h>
#include <framework/graphics/cachedtext.h>
class Creature : public Thing class Creature : public Thing
{ {
@ -104,7 +105,6 @@ protected:
uint32 m_id; uint32 m_id;
std::string m_name; std::string m_name;
Size m_nameSize;
uint8 m_healthPercent; uint8 m_healthPercent;
Otc::Direction m_direction; Otc::Direction m_direction;
Outfit m_outfit; Outfit m_outfit;
@ -124,8 +124,7 @@ protected:
Boolean<false> m_showTimedSquare; Boolean<false> m_showTimedSquare;
Boolean<false> m_showStaticSquare; Boolean<false> m_showStaticSquare;
Boolean<false> m_removed; Boolean<false> m_removed;
CachedText m_nameCache;
FontPtr m_informationFont;
Color m_informationColor; Color m_informationColor;
// walk related // walk related

View File

@ -124,6 +124,12 @@ void Map::cleanDynamicThings()
for(int i=0;i<=Otc::MAX_Z;++i) for(int i=0;i<=Otc::MAX_Z;++i)
m_floorMissiles[i].clear(); m_floorMissiles[i].clear();
cleanTexts();
}
void Map::cleanTexts()
{
m_animatedTexts.clear(); m_animatedTexts.clear();
m_staticTexts.clear(); m_staticTexts.clear();
} }

View File

@ -38,6 +38,7 @@ public:
void save(); void save();
void clean(); void clean();
void cleanDynamicThings(); void cleanDynamicThings();
void cleanTexts();
// thing related // thing related
void addThing(const ThingPtr& thing, const Position& pos, int stackPos = -1); void addThing(const ThingPtr& thing, const Position& pos, int stackPos = -1);

View File

@ -28,20 +28,21 @@
StaticText::StaticText() StaticText::StaticText()
{ {
m_font = g_fonts.getFont("verdana-11px-rounded"); m_cachedText.setFont(g_fonts.getFont("verdana-11px-rounded"));
m_cachedText.setAlign(Fw::AlignCenter);
} }
void StaticText::draw(const Point& dest, const Rect& parentRect) void StaticText::draw(const Point& dest, const Rect& parentRect)
{ {
Rect rect = Rect(dest - Point(m_textSize.width() / 2, m_textSize.height()) + Point(20, 5), m_textSize); Size textSize = m_cachedText.getTextSize();
Rect rect = Rect(dest - Point(textSize.width() / 2, textSize.height()) + Point(20, 5), textSize);
Rect boundRect = rect; Rect boundRect = rect;
boundRect.bind(parentRect); boundRect.bind(parentRect);
// draw only if the real center is not too far from the parent center, or its a yell // draw only if the real center is not too far from the parent center, or its a yell
if((boundRect.center() - rect.center()).length() < parentRect.width() / 15 || isYell()) { if((boundRect.center() - rect.center()).length() < parentRect.width() / 15 || isYell()) {
//TODO: cache into a framebuffer
g_painter->setColor(m_color); g_painter->setColor(m_color);
m_font->drawText(m_text, boundRect, Fw::AlignCenter); m_cachedText.draw(boundRect);
} }
} }
@ -116,6 +117,6 @@ void StaticText::compose()
text += "\n"; text += "\n";
} }
m_text = m_font->wrapText(text, Otc::MAX_STATIC_TEXT_WIDTH); m_cachedText.setText(text);
m_textSize = m_font->calculateTextRectSize(m_text); m_cachedText.wrapText(Otc::MAX_STATIC_TEXT_WIDTH);
} }

View File

@ -24,6 +24,7 @@
#define STATICTEXT_H #define STATICTEXT_H
#include "thing.h" #include "thing.h"
#include <framework/graphics/cachedtext.h>
#include <framework/graphics/fontmanager.h> #include <framework/graphics/fontmanager.h>
class StaticText : public Thing class StaticText : public Thing
@ -48,13 +49,12 @@ public:
private: private:
void compose(); void compose();
FontPtr m_font;
Size m_textSize;
Boolean<false> m_yell; Boolean<false> m_yell;
std::vector<std::string> m_messages; std::vector<std::string> m_messages;
std::string m_name, m_text; std::string m_name;
Otc::SpeakType m_messageType; Otc::SpeakType m_messageType;
Color m_color; Color m_color;
CachedText m_cachedText;
}; };
#endif #endif

View File

@ -146,6 +146,7 @@ bool ThingsType::parseThingType(const FileStreamPtr& fin, ThingType& thingType)
thingType.m_textures.resize(thingType.m_dimensions[ThingType::AnimationPhases]); thingType.m_textures.resize(thingType.m_dimensions[ThingType::AnimationPhases]);
thingType.m_texturesFramesRects.resize(thingType.m_dimensions[ThingType::AnimationPhases]); thingType.m_texturesFramesRects.resize(thingType.m_dimensions[ThingType::AnimationPhases]);
thingType.m_texturesFramesOriginRects.resize(thingType.m_dimensions[ThingType::AnimationPhases]);
thingType.m_texturesFramesOffsets.resize(thingType.m_dimensions[ThingType::AnimationPhases]); thingType.m_texturesFramesOffsets.resize(thingType.m_dimensions[ThingType::AnimationPhases]);
return true; return true;

View File

@ -41,8 +41,15 @@ void ThingType::draw(const Point& dest, float scaleFactor, int layer, int xPatte
const TexturePtr& texture = getTexture(animationPhase); // texture might not exists, neither its rects. const TexturePtr& texture = getTexture(animationPhase); // texture might not exists, neither its rects.
int frameIndex = getTextureIndex(layer, xPattern, yPattern, zPattern); int frameIndex = getTextureIndex(layer, xPattern, yPattern, zPattern);
Point textureOffset = m_texturesFramesOffsets[animationPhase][frameIndex]; Point textureOffset;
Rect textureRect = m_texturesFramesRects[animationPhase][frameIndex]; Rect textureRect;
if(scaleFactor != 1.0f) {
textureRect = m_texturesFramesOriginRects[animationPhase][frameIndex];
} else {
textureOffset = m_texturesFramesOffsets[animationPhase][frameIndex];
textureRect = m_texturesFramesRects[animationPhase][frameIndex];
}
Point displacement(m_parameters[DisplacementX], m_parameters[DisplacementY]); Point displacement(m_parameters[DisplacementX], m_parameters[DisplacementY]);
Rect screenRect(dest + (-displacement + textureOffset - Point(m_dimensions[Width] - 1, m_dimensions[Height] - 1) * Otc::TILE_PIXELS) * scaleFactor, Rect screenRect(dest + (-displacement + textureOffset - Point(m_dimensions[Width] - 1, m_dimensions[Height] - 1) * Otc::TILE_PIXELS) * scaleFactor,
@ -51,68 +58,45 @@ void ThingType::draw(const Point& dest, float scaleFactor, int layer, int xPatte
g_painter->drawTexturedRect(screenRect, texture, textureRect); g_painter->drawTexturedRect(screenRect, texture, textureRect);
} }
void ThingType::drawMask(const Point& dest, float scaleFactor, int w, int h, int xPattern, int yPattern, int zPattern, int layer, int animationPhase, ThingType::SpriteMask mask)
{
int scaledSize = Otc::TILE_PIXELS * scaleFactor;
Point displacement(m_parameters[DisplacementX], m_parameters[DisplacementY]);
Rect drawRect(dest - displacement*scaleFactor, Size(scaledSize, scaledSize));
g_painter->drawTexturedRect(drawRect, getSpriteMask(w, h, layer, xPattern, yPattern, zPattern, animationPhase, mask));
}
TexturePtr& ThingType::getSpriteMask(int w, int h, int l, int x, int y, int z, int a, ThingType::SpriteMask mask)
{
if(m_spritesMask.size() == 0)
m_spritesMask.resize(m_spritesIndex.size());
uint index = getSpriteIndex(w,h,l,x,y,z,a);
TexturePtr& maskTexture = m_spritesMask[index][mask];
if(!maskTexture) {
ImagePtr maskImage = g_sprites.getSpriteImage(m_spritesIndex[index]);
if(!maskImage)
maskTexture = g_graphics.getEmptyTexture();
else {
static Color maskColors[LastMask] = { Color::yellow, Color::red, Color::green, Color::blue };
maskImage->overwriteMask(maskColors[mask]);
maskTexture = TexturePtr(new Texture(maskImage, true));
}
}
return maskTexture;
}
TexturePtr& ThingType::getTexture(int animationPhase) TexturePtr& ThingType::getTexture(int animationPhase)
{ {
TexturePtr& animationPhaseTexture = m_textures[animationPhase]; TexturePtr& animationPhaseTexture = m_textures[animationPhase];
if(!animationPhaseTexture) { if(!animationPhaseTexture) {
// we don't need layers in common items, they will be pre-drawn
int textureLayers = m_dimensions[Layers]; int textureLayers = 1;
if(m_category != ThingsType::Creature) // we dont need layers in texture. they can be 'rendered' now. int numLayers = m_dimensions[Layers];
textureLayers = 1; if(m_category == ThingsType::Creature && m_dimensions[Layers] >= 2) {
// 5 layers: outfit base, red mask, green mask, blue mask, yellow mask
textureLayers = 5;
numLayers = 5;
}
int indexSize = textureLayers * m_dimensions[PatternX] * m_dimensions[PatternY] * m_dimensions[PatternZ]; int indexSize = textureLayers * m_dimensions[PatternX] * m_dimensions[PatternY] * m_dimensions[PatternZ];
Size textureSize = getBestDimension(m_dimensions[Width], m_dimensions[Height], indexSize); Size textureSize = getBestDimension(m_dimensions[Width], m_dimensions[Height], indexSize);
ImagePtr fullImage = ImagePtr(new Image(textureSize * Otc::TILE_PIXELS)); ImagePtr fullImage = ImagePtr(new Image(textureSize * Otc::TILE_PIXELS));
m_texturesFramesRects[animationPhase].resize(indexSize); m_texturesFramesRects[animationPhase].resize(indexSize);
m_texturesFramesOriginRects[animationPhase].resize(indexSize);
m_texturesFramesOffsets[animationPhase].resize(indexSize); m_texturesFramesOffsets[animationPhase].resize(indexSize);
for(int z = 0; z < m_dimensions[PatternZ]; ++z) { for(int z = 0; z < m_dimensions[PatternZ]; ++z) {
for(int y = 0; y < m_dimensions[PatternY]; ++y) { for(int y = 0; y < m_dimensions[PatternY]; ++y) {
for(int x = 0; x < m_dimensions[PatternX]; ++x) { for(int x = 0; x < m_dimensions[PatternX]; ++x) {
for(int l = 0; l < m_dimensions[Layers]; ++l) { for(int l = 0; l < numLayers; ++l) {
bool spriteMask = (m_category == ThingsType::Creature && l > 0);
int frameIndex = getTextureIndex(l % textureLayers, x, y, z); int frameIndex = getTextureIndex(l % textureLayers, x, y, z);
Point framePos = Point(frameIndex % (textureSize.width() / m_dimensions[Width]) * m_dimensions[Width], Point framePos = Point(frameIndex % (textureSize.width() / m_dimensions[Width]) * m_dimensions[Width],
frameIndex / (textureSize.width() / m_dimensions[Width]) * m_dimensions[Height]) * Otc::TILE_PIXELS; frameIndex / (textureSize.width() / m_dimensions[Width]) * m_dimensions[Height]) * Otc::TILE_PIXELS;
for(int h = 0; h < m_dimensions[Height]; ++h) { for(int h = 0; h < m_dimensions[Height]; ++h) {
for(int w = 0; w < m_dimensions[Width]; ++w) { for(int w = 0; w < m_dimensions[Width]; ++w) {
uint spriteIndex = getSpriteIndex(w, h, l, x, y, z, animationPhase); uint spriteIndex = getSpriteIndex(w, h, spriteMask ? 1 : l, x, y, z, animationPhase);
ImagePtr spriteImage = g_sprites.getSpriteImage(m_spritesIndex[spriteIndex]); ImagePtr spriteImage = g_sprites.getSpriteImage(m_spritesIndex[spriteIndex]);
if(spriteImage) { if(spriteImage) {
if(spriteMask) {
static Color maskColors[] = { Color::red, Color::green, Color::blue, Color::yellow };
spriteImage->overwriteMask(maskColors[l - 1]);
}
Point spritePos = Point(m_dimensions[Width] - w - 1, Point spritePos = Point(m_dimensions[Width] - w - 1,
m_dimensions[Height] - h - 1) * Otc::TILE_PIXELS; m_dimensions[Height] - h - 1) * Otc::TILE_PIXELS;
@ -121,7 +105,7 @@ TexturePtr& ThingType::getTexture(int animationPhase)
} }
} }
Rect drawRect(framePos + Point(m_dimensions[Width], m_dimensions[Height]) * Otc::TILE_PIXELS, framePos); Rect drawRect(framePos + Point(m_dimensions[Width], m_dimensions[Height]) * Otc::TILE_PIXELS - Point(1,1), framePos);
for(int x = framePos.x; x < framePos.x + m_dimensions[Width] * Otc::TILE_PIXELS; ++x) { for(int x = framePos.x; x < framePos.x + m_dimensions[Width] * Otc::TILE_PIXELS; ++x) {
for(int y = framePos.y; y < framePos.y + m_dimensions[Height] * Otc::TILE_PIXELS; ++y) { for(int y = framePos.y; y < framePos.y + m_dimensions[Height] * Otc::TILE_PIXELS; ++y) {
uint8 *p = fullImage->getPixel(x,y); uint8 *p = fullImage->getPixel(x,y);
@ -135,19 +119,21 @@ TexturePtr& ThingType::getTexture(int animationPhase)
} }
m_texturesFramesRects[animationPhase][frameIndex] = drawRect; m_texturesFramesRects[animationPhase][frameIndex] = drawRect;
m_texturesFramesOffsets[animationPhase][frameIndex] = drawRect.topLeft() - framePos + Point(1,1); m_texturesFramesOriginRects[animationPhase][frameIndex] = Rect(framePos, Size(m_dimensions[Width], m_dimensions[Height]) * Otc::TILE_PIXELS);
m_texturesFramesOffsets[animationPhase][frameIndex] = drawRect.topLeft() - framePos;
} }
} }
} }
} }
animationPhaseTexture = TexturePtr(new Texture(fullImage, true)); animationPhaseTexture = TexturePtr(new Texture(fullImage, true));
animationPhaseTexture->setSmooth(true);
} }
return animationPhaseTexture; return animationPhaseTexture;
} }
Size ThingType::getBestDimension(int w, int h, int count) Size ThingType::getBestDimension(int w, int h, int count)
{ {
const int MAX = 16; const int MAX = 32;
int k = 1; int k = 1;
while(k < w) while(k < w)

View File

@ -99,10 +99,10 @@ struct ThingType
}; };
enum SpriteMask { enum SpriteMask {
YellowMask = 0, RedMask = 1,
RedMask,
GreenMask, GreenMask,
BlueMask, BlueMask,
YellowMask,
LastMask LastMask
}; };
@ -146,10 +146,10 @@ private:
std::array<int, LastParameter> m_parameters; std::array<int, LastParameter> m_parameters;
std::array<bool, LastProperty> m_properties; std::array<bool, LastProperty> m_properties;
std::vector<int> m_spritesIndex; std::vector<int> m_spritesIndex;
std::vector<std::array<TexturePtr, LastMask>> m_spritesMask;
std::vector<TexturePtr> m_textures; std::vector<TexturePtr> m_textures;
std::vector<std::vector<Rect> > m_texturesFramesRects; std::vector<std::vector<Rect> > m_texturesFramesRects;
std::vector<std::vector<Rect> > m_texturesFramesOriginRects;
std::vector<std::vector<Point> > m_texturesFramesOffsets; std::vector<std::vector<Point> > m_texturesFramesOffsets;
friend class ThingsType; friend class ThingsType;

View File

@ -68,6 +68,7 @@ void OTClient::registerLuaFunctions()
g_lua.bindClassStaticFunction("g_map", "removeThingByPos", std::bind(&Map::removeThingByPos, &g_map, std::placeholders::_1, std::placeholders::_2)); g_lua.bindClassStaticFunction("g_map", "removeThingByPos", std::bind(&Map::removeThingByPos, &g_map, std::placeholders::_1, std::placeholders::_2));
g_lua.bindClassStaticFunction("g_map", "removeThing", std::bind(&Map::removeThing, &g_map, std::placeholders::_1)); g_lua.bindClassStaticFunction("g_map", "removeThing", std::bind(&Map::removeThing, &g_map, std::placeholders::_1));
g_lua.bindClassStaticFunction("g_map", "cleanTile", std::bind(&Map::cleanTile, &g_map, std::placeholders::_1)); g_lua.bindClassStaticFunction("g_map", "cleanTile", std::bind(&Map::cleanTile, &g_map, std::placeholders::_1));
g_lua.bindClassStaticFunction("g_map", "cleanTexts", std::bind(&Map::cleanTexts, &g_map));
g_lua.bindClassStaticFunction("g_map", "getTile", std::bind(&Map::getTile, &g_map, std::placeholders::_1)); g_lua.bindClassStaticFunction("g_map", "getTile", std::bind(&Map::getTile, &g_map, std::placeholders::_1));
g_lua.bindClassStaticFunction("g_map", "setCentralPosition", std::bind(&Map::setCentralPosition, &g_map, std::placeholders::_1)); g_lua.bindClassStaticFunction("g_map", "setCentralPosition", std::bind(&Map::setCentralPosition, &g_map, std::placeholders::_1));
g_lua.bindClassStaticFunction("g_map", "getCentralPosition", std::bind(&Map::getCentralPosition, &g_map)); g_lua.bindClassStaticFunction("g_map", "getCentralPosition", std::bind(&Map::getCentralPosition, &g_map));