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:
parent
1a7f2a44fc
commit
95cf7eb788
|
@ -53,6 +53,7 @@ function GameInterface.init()
|
|||
Keyboard.bindKeyPress('Ctrl+-', function() gameMapPanel:zoomOut() end, gameRootPanel, 250)
|
||||
Keyboard.bindKeyDown('Ctrl+Q', 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
|
||||
GameInterface.show()
|
||||
|
|
|
@ -197,6 +197,7 @@ SET(framework_SOURCES ${framework_SOURCES}
|
|||
|
||||
# framework graphics
|
||||
${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/graphics.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/graphics/painter.cpp
|
||||
|
|
|
@ -167,7 +167,6 @@ void Application::run()
|
|||
if(!m_initialized)
|
||||
return;
|
||||
|
||||
bool cacheForeground = true;
|
||||
m_stopping = false;
|
||||
m_running = true;
|
||||
|
||||
|
@ -190,14 +189,7 @@ void Application::run()
|
|||
bool redraw = false;
|
||||
bool updateForeground = false;
|
||||
|
||||
bool canCacheForeground = 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);
|
||||
}
|
||||
bool cacheForeground = g_graphics.canCacheBackbuffer() && m_foregroundFrameCounter.getMaxFps() != 0;
|
||||
|
||||
if(m_backgroundFrameCounter.shouldProcessNextFrame()) {
|
||||
redraw = true;
|
||||
|
@ -219,11 +211,15 @@ void Application::run()
|
|||
m_foregroundFrameCounter.processNextFrame();
|
||||
|
||||
// draw foreground
|
||||
g_painter->clear(Color::black);
|
||||
g_painter->setAlphaWriting(true);
|
||||
g_painter->clear(Color::alpha);
|
||||
g_ui.render(Fw::ForegroundPane);
|
||||
|
||||
// copy the foreground to a texture
|
||||
m_foreground->copyFromScreen(viewportRect);
|
||||
|
||||
g_painter->clear(Color::black);
|
||||
g_painter->setAlphaWriting(false);
|
||||
}
|
||||
|
||||
// draw background (animated stuff)
|
||||
|
|
|
@ -30,6 +30,7 @@ class Texture;
|
|||
class Image;
|
||||
class AnimatedTexture;
|
||||
class Font;
|
||||
class CachedText;
|
||||
class FrameBuffer;
|
||||
class Shader;
|
||||
class ShaderProgram;
|
||||
|
@ -46,6 +47,7 @@ typedef std::shared_ptr<Image> ImagePtr;
|
|||
typedef std::shared_ptr<Texture> TexturePtr;
|
||||
typedef std::shared_ptr<AnimatedTexture> AnimatedTexturePtr;
|
||||
typedef std::shared_ptr<Font> FontPtr;
|
||||
typedef std::shared_ptr<CachedText> CachedTextPtr;
|
||||
typedef std::shared_ptr<FrameBuffer> FrameBufferPtr;
|
||||
typedef std::shared_ptr<Shader> ShaderPtr;
|
||||
typedef std::shared_ptr<ShaderProgram> ShaderProgramPtr;
|
||||
|
|
|
@ -131,13 +131,57 @@ bool Image::nextMipmap()
|
|||
assert(m_bpp == 4);
|
||||
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;
|
||||
|
||||
Size size = m_size / 2;
|
||||
std::vector<uint8> pixels(size.area()*4, 0xFF);
|
||||
int ow = iw > 1 ? iw/2 : 1;
|
||||
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_size = size;
|
||||
m_size = Size(ow, oh);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ Painter::Painter()
|
|||
m_compositionMode = CompositionMode_Normal;
|
||||
m_shaderProgram = nullptr;
|
||||
m_texture = nullptr;
|
||||
m_alphaWriting = false;
|
||||
}
|
||||
|
||||
void Painter::resetState()
|
||||
|
@ -44,6 +45,7 @@ void Painter::resetState()
|
|||
resetClipRect();
|
||||
resetShaderProgram();
|
||||
resetTexture();
|
||||
resetAlphaWriting();
|
||||
}
|
||||
|
||||
void Painter::refreshState()
|
||||
|
@ -51,6 +53,7 @@ void Painter::refreshState()
|
|||
updateGlCompositionMode();
|
||||
updateGlClipRect();
|
||||
updateGlTexture();
|
||||
updateGlAlphaWriting();
|
||||
}
|
||||
|
||||
void Painter::saveState()
|
||||
|
@ -64,6 +67,7 @@ void Painter::saveState()
|
|||
m_olderStates[m_oldStateIndex].clipRect = m_clipRect;
|
||||
m_olderStates[m_oldStateIndex].shaderProgram = m_shaderProgram;
|
||||
m_olderStates[m_oldStateIndex].texture = m_texture;
|
||||
m_olderStates[m_oldStateIndex].alphaWriting = m_alphaWriting;
|
||||
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()
|
||||
{
|
||||
if(m_glTextureId != 0)
|
||||
|
@ -177,3 +190,11 @@ void Painter::updateGlClipRect()
|
|||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
void Painter::updateGlAlphaWriting()
|
||||
{
|
||||
if(m_alphaWriting)
|
||||
glColorMask(1,1,1,1);
|
||||
else
|
||||
glColorMask(1,1,1,0);
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
Rect clipRect;
|
||||
Texture *texture;
|
||||
PainterShaderProgram *shaderProgram;
|
||||
bool alphaWriting;
|
||||
};
|
||||
|
||||
Painter();
|
||||
|
@ -85,6 +86,7 @@ public:
|
|||
virtual void setClipRect(const Rect& clipRect);
|
||||
virtual void setShaderProgram(PainterShaderProgram *shaderProgram) { m_shaderProgram = shaderProgram; }
|
||||
virtual void setTexture(Texture *texture);
|
||||
void setAlphaWriting(bool enable);
|
||||
|
||||
void setShaderProgram(const PainterShaderProgramPtr& shaderProgram) { setShaderProgram(shaderProgram.get()); }
|
||||
void setTexture(const TexturePtr& texture) { setTexture(texture.get()); }
|
||||
|
@ -96,6 +98,7 @@ public:
|
|||
CompositionMode getCompositionMode() { return m_compositionMode; }
|
||||
Rect getClipRect() { return m_clipRect; }
|
||||
PainterShaderProgram *getShaderProgram() { return m_shaderProgram; }
|
||||
bool getAlphaWriting() { return m_alphaWriting; }
|
||||
|
||||
void resetColor() { setColor(Color::white); }
|
||||
void resetOpacity() { setOpacity(1.0f); }
|
||||
|
@ -103,11 +106,13 @@ public:
|
|||
void resetCompositionMode() { setCompositionMode(CompositionMode_Normal); }
|
||||
void resetShaderProgram() { setShaderProgram(nullptr); }
|
||||
void resetTexture() { setTexture(nullptr); }
|
||||
void resetAlphaWriting() { setAlphaWriting(false); }
|
||||
|
||||
protected:
|
||||
void updateGlTexture();
|
||||
void updateGlCompositionMode();
|
||||
void updateGlClipRect();
|
||||
void updateGlAlphaWriting();
|
||||
|
||||
CoordsBuffer m_coordsBuffer;
|
||||
|
||||
|
@ -119,6 +124,7 @@ protected:
|
|||
Rect m_clipRect;
|
||||
Texture *m_texture;
|
||||
PainterShaderProgram *m_shaderProgram;
|
||||
bool m_alphaWriting;
|
||||
|
||||
PainterState m_olderStates[10];
|
||||
int m_oldStateIndex;
|
||||
|
|
|
@ -62,7 +62,6 @@ Texture::Texture(const ImagePtr& image, bool buildMipmaps)
|
|||
|
||||
bind();
|
||||
|
||||
/*
|
||||
if(buildMipmaps) {
|
||||
int level = 0;
|
||||
do {
|
||||
|
@ -70,7 +69,6 @@ Texture::Texture(const ImagePtr& image, bool buildMipmaps)
|
|||
} while(glImage->nextMipmap());
|
||||
m_hasMipmaps = true;
|
||||
} else
|
||||
*/
|
||||
setupPixels(0, glImage->getSize(), glImage->getPixelData(), glImage->getBpp());
|
||||
|
||||
setupWrap();
|
||||
|
|
|
@ -370,10 +370,10 @@ void X11Window::internalChooseGLVisual()
|
|||
#else
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
|
||||
#endif
|
||||
EGL_RED_SIZE, 5,
|
||||
EGL_GREEN_SIZE, 6,
|
||||
EGL_BLUE_SIZE, 5,
|
||||
EGL_ALPHA_SIZE, 0,
|
||||
EGL_RED_SIZE, 4,
|
||||
EGL_GREEN_SIZE, 4,
|
||||
EGL_BLUE_SIZE, 4,
|
||||
EGL_ALPHA_SIZE, 4,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
|
|
|
@ -28,20 +28,22 @@
|
|||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
Rect rect(p, m_textSize);
|
||||
Rect rect(p, textSize);
|
||||
|
||||
if(visibleRect.contains(rect)) {
|
||||
//TODO: cache into a framebuffer
|
||||
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)
|
||||
{
|
||||
m_textSize = m_font->calculateTextRectSize(text);
|
||||
m_text = text;
|
||||
m_cachedText.setText(text);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "thing.h"
|
||||
#include <framework/graphics/fontmanager.h>
|
||||
#include <framework/core/timer.h>
|
||||
#include <framework/graphics/cachedtext.h>
|
||||
|
||||
class AnimatedText : public Thing
|
||||
{
|
||||
|
@ -42,11 +43,9 @@ public:
|
|||
bool isAnimatedText() { return true; }
|
||||
|
||||
private:
|
||||
FontPtr m_font;
|
||||
Size m_textSize;
|
||||
std::string m_text;
|
||||
Color m_color;
|
||||
Timer m_animationTimer;
|
||||
CachedText m_cachedText;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -52,7 +52,8 @@ Creature::Creature() : Thing()
|
|||
m_skull = Otc::SkullNone;
|
||||
m_shield = Otc::ShieldNone;
|
||||
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)
|
||||
{
|
||||
/*
|
||||
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
|
||||
if(m_outfit.getCategory() == ThingsType::Creature) {
|
||||
int animationPhase = animateWalk ? m_walkAnimationPhase : 0;
|
||||
|
@ -110,6 +96,7 @@ void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool ani
|
|||
}
|
||||
|
||||
// xPattern => creature direction
|
||||
int xPattern;
|
||||
if(direction == Otc::NorthEast || direction == Otc::SouthEast)
|
||||
xPattern = Otc::East;
|
||||
else if(direction == Otc::NorthWest || direction == Otc::SouthWest)
|
||||
|
@ -118,56 +105,30 @@ void Creature::internalDrawOutfit(const Point& dest, float scaleFactor, bool ani
|
|||
xPattern = direction;
|
||||
|
||||
// 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))))
|
||||
continue;
|
||||
|
||||
/*
|
||||
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;
|
||||
m_type->draw(dest, scaleFactor, 0, xPattern, yPattern, 0, animationPhase);
|
||||
|
||||
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->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());
|
||||
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());
|
||||
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());
|
||||
m_type->drawMask(p, scaleFactor, w, h, xPattern, yPattern, zPattern, 1, animationPhase, ThingType::BlueMask);
|
||||
|
||||
g_painter->restoreSavedState();
|
||||
m_type->draw(dest, scaleFactor, ThingType::BlueMask, xPattern, yPattern, 0, animationPhase);
|
||||
g_painter->setColor(oldColor);
|
||||
g_painter->setCompositionMode(oldComposition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//g_painter->resetShaderProgram();
|
||||
}
|
||||
// outfit is a creature imitating an item or the invisible effect
|
||||
} else {
|
||||
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->bind();
|
||||
g_painter->setAlphaWriting(true);
|
||||
g_painter->clear(Color::alpha);
|
||||
internalDrawOutfit(Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) + getDisplacement(), 1, false, true, Otc::South);
|
||||
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);
|
||||
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);
|
||||
|
||||
// distance them
|
||||
|
@ -256,8 +219,7 @@ void Creature::drawInformation(const Point& point, bool useGray, const Rect& par
|
|||
g_painter->setColor(fillColor);
|
||||
g_painter->drawFilledRect(healthRect);
|
||||
|
||||
if(m_informationFont)
|
||||
m_informationFont->drawText(m_name, textRect, Fw::AlignTopCenter);
|
||||
m_nameCache.draw(textRect);
|
||||
|
||||
if(m_skull != Otc::SkullNone && m_skullTexture) {
|
||||
g_painter->setColor(Color::white);
|
||||
|
@ -447,8 +409,7 @@ void Creature::terminateWalk()
|
|||
|
||||
void Creature::setName(const std::string& name)
|
||||
{
|
||||
if(m_informationFont)
|
||||
m_nameSize = m_informationFont->calculateTextRectSize(name);
|
||||
m_nameCache.setText(name);
|
||||
m_name = name;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <framework/core/declarations.h>
|
||||
#include <framework/core/timer.h>
|
||||
#include <framework/graphics/fontmanager.h>
|
||||
#include <framework/graphics/cachedtext.h>
|
||||
|
||||
class Creature : public Thing
|
||||
{
|
||||
|
@ -104,7 +105,6 @@ protected:
|
|||
|
||||
uint32 m_id;
|
||||
std::string m_name;
|
||||
Size m_nameSize;
|
||||
uint8 m_healthPercent;
|
||||
Otc::Direction m_direction;
|
||||
Outfit m_outfit;
|
||||
|
@ -124,8 +124,7 @@ protected:
|
|||
Boolean<false> m_showTimedSquare;
|
||||
Boolean<false> m_showStaticSquare;
|
||||
Boolean<false> m_removed;
|
||||
|
||||
FontPtr m_informationFont;
|
||||
CachedText m_nameCache;
|
||||
Color m_informationColor;
|
||||
|
||||
// walk related
|
||||
|
|
|
@ -124,6 +124,12 @@ void Map::cleanDynamicThings()
|
|||
|
||||
for(int i=0;i<=Otc::MAX_Z;++i)
|
||||
m_floorMissiles[i].clear();
|
||||
|
||||
cleanTexts();
|
||||
}
|
||||
|
||||
void Map::cleanTexts()
|
||||
{
|
||||
m_animatedTexts.clear();
|
||||
m_staticTexts.clear();
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
void save();
|
||||
void clean();
|
||||
void cleanDynamicThings();
|
||||
void cleanTexts();
|
||||
|
||||
// thing related
|
||||
void addThing(const ThingPtr& thing, const Position& pos, int stackPos = -1);
|
||||
|
|
|
@ -28,20 +28,21 @@
|
|||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
boundRect.bind(parentRect);
|
||||
|
||||
// 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()) {
|
||||
//TODO: cache into a framebuffer
|
||||
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";
|
||||
}
|
||||
|
||||
m_text = m_font->wrapText(text, Otc::MAX_STATIC_TEXT_WIDTH);
|
||||
m_textSize = m_font->calculateTextRectSize(m_text);
|
||||
m_cachedText.setText(text);
|
||||
m_cachedText.wrapText(Otc::MAX_STATIC_TEXT_WIDTH);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#define STATICTEXT_H
|
||||
|
||||
#include "thing.h"
|
||||
#include <framework/graphics/cachedtext.h>
|
||||
#include <framework/graphics/fontmanager.h>
|
||||
|
||||
class StaticText : public Thing
|
||||
|
@ -48,13 +49,12 @@ public:
|
|||
private:
|
||||
void compose();
|
||||
|
||||
FontPtr m_font;
|
||||
Size m_textSize;
|
||||
Boolean<false> m_yell;
|
||||
std::vector<std::string> m_messages;
|
||||
std::string m_name, m_text;
|
||||
std::string m_name;
|
||||
Otc::SpeakType m_messageType;
|
||||
Color m_color;
|
||||
CachedText m_cachedText;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -146,6 +146,7 @@ bool ThingsType::parseThingType(const FileStreamPtr& fin, ThingType& thingType)
|
|||
|
||||
thingType.m_textures.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]);
|
||||
|
||||
return true;
|
||||
|
|
|
@ -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.
|
||||
|
||||
int frameIndex = getTextureIndex(layer, xPattern, yPattern, zPattern);
|
||||
Point textureOffset = m_texturesFramesOffsets[animationPhase][frameIndex];
|
||||
Rect textureRect = m_texturesFramesRects[animationPhase][frameIndex];
|
||||
Point textureOffset;
|
||||
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]);
|
||||
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);
|
||||
}
|
||||
|
||||
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& animationPhaseTexture = m_textures[animationPhase];
|
||||
if(!animationPhaseTexture) {
|
||||
|
||||
int textureLayers = m_dimensions[Layers];
|
||||
if(m_category != ThingsType::Creature) // we dont need layers in texture. they can be 'rendered' now.
|
||||
textureLayers = 1;
|
||||
// we don't need layers in common items, they will be pre-drawn
|
||||
int textureLayers = 1;
|
||||
int numLayers = m_dimensions[Layers];
|
||||
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];
|
||||
Size textureSize = getBestDimension(m_dimensions[Width], m_dimensions[Height], indexSize);
|
||||
ImagePtr fullImage = ImagePtr(new Image(textureSize * Otc::TILE_PIXELS));
|
||||
|
||||
m_texturesFramesRects[animationPhase].resize(indexSize);
|
||||
m_texturesFramesOriginRects[animationPhase].resize(indexSize);
|
||||
m_texturesFramesOffsets[animationPhase].resize(indexSize);
|
||||
|
||||
for(int z = 0; z < m_dimensions[PatternZ]; ++z) {
|
||||
for(int y = 0; y < m_dimensions[PatternY]; ++y) {
|
||||
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);
|
||||
Point framePos = Point(frameIndex % (textureSize.width() / m_dimensions[Width]) * m_dimensions[Width],
|
||||
frameIndex / (textureSize.width() / m_dimensions[Width]) * m_dimensions[Height]) * Otc::TILE_PIXELS;
|
||||
|
||||
for(int h = 0; h < m_dimensions[Height]; ++h) {
|
||||
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]);
|
||||
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,
|
||||
m_dimensions[Height] - h - 1) * Otc::TILE_PIXELS;
|
||||
|
||||
|
@ -121,33 +105,35 @@ 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 y = framePos.y; y < framePos.y + m_dimensions[Height] * Otc::TILE_PIXELS; ++y) {
|
||||
uint8 *p = fullImage->getPixel(x,y);
|
||||
if(p[3] != 0x00) {
|
||||
drawRect.setTop(std::min(y, (int)drawRect.top()));
|
||||
drawRect.setLeft(std::min(x, (int)drawRect.left()));
|
||||
drawRect.setTop (std::min(y, (int)drawRect.top()));
|
||||
drawRect.setLeft (std::min(x, (int)drawRect.left()));
|
||||
drawRect.setBottom(std::max(y, (int)drawRect.bottom()));
|
||||
drawRect.setRight(std::max(x, (int)drawRect.right()));
|
||||
drawRect.setRight (std::max(x, (int)drawRect.right()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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->setSmooth(true);
|
||||
}
|
||||
return animationPhaseTexture;
|
||||
}
|
||||
|
||||
Size ThingType::getBestDimension(int w, int h, int count)
|
||||
{
|
||||
const int MAX = 16;
|
||||
const int MAX = 32;
|
||||
|
||||
int k = 1;
|
||||
while(k < w)
|
||||
|
|
|
@ -99,10 +99,10 @@ struct ThingType
|
|||
};
|
||||
|
||||
enum SpriteMask {
|
||||
YellowMask = 0,
|
||||
RedMask,
|
||||
RedMask = 1,
|
||||
GreenMask,
|
||||
BlueMask,
|
||||
YellowMask,
|
||||
LastMask
|
||||
};
|
||||
|
||||
|
@ -146,10 +146,10 @@ private:
|
|||
std::array<int, LastParameter> m_parameters;
|
||||
std::array<bool, LastProperty> m_properties;
|
||||
std::vector<int> m_spritesIndex;
|
||||
std::vector<std::array<TexturePtr, LastMask>> m_spritesMask;
|
||||
|
||||
std::vector<TexturePtr> m_textures;
|
||||
std::vector<std::vector<Rect> > m_texturesFramesRects;
|
||||
std::vector<std::vector<Rect> > m_texturesFramesOriginRects;
|
||||
std::vector<std::vector<Point> > m_texturesFramesOffsets;
|
||||
|
||||
friend class ThingsType;
|
||||
|
|
|
@ -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", "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", "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", "setCentralPosition", std::bind(&Map::setCentralPosition, &g_map, std::placeholders::_1));
|
||||
g_lua.bindClassStaticFunction("g_map", "getCentralPosition", std::bind(&Map::getCentralPosition, &g_map));
|
||||
|
|
Loading…
Reference in New Issue