From 04ee85dc927aeccd07e04db7c3315897dd8a8242 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Thu, 8 Dec 2011 15:28:29 -0200 Subject: [PATCH] experiment shaders in outfit --- modules/outfit.frag | 49 ++++++++++ modules/shadertest.frag | 37 ++++++- .../graphics/paintershaderprogram.cpp | 19 ++-- src/framework/graphics/paintershaderprogram.h | 1 + src/framework/graphics/shaderprogram.cpp | 2 +- src/framework/graphics/shaderprogram.h | 4 +- src/otclient/const.h | 8 -- src/otclient/core/creature.cpp | 96 +++++++++++++------ src/otclient/core/spritemanager.cpp | 39 +------- src/otclient/core/spritemanager.h | 10 +- src/otclient/core/thing.cpp | 4 +- src/otclient/core/thing.h | 2 +- 12 files changed, 179 insertions(+), 92 deletions(-) create mode 100644 modules/outfit.frag diff --git a/modules/outfit.frag b/modules/outfit.frag new file mode 100644 index 00000000..e1df99fa --- /dev/null +++ b/modules/outfit.frag @@ -0,0 +1,49 @@ +uniform float opacity; +uniform vec4 color; +uniform float ticks; + +uniform sampler2D texture; // outfit texture +varying vec2 textureCoords; // outfit texture coords +uniform sampler2D maskTexture; // outfit color mask + +uniform vec4 headColor; +uniform vec4 bodyColor; +uniform vec4 legsColor; +uniform vec4 feetColor; + +vec4 calcPixel(vec2 texCoord) +{ + vec4 pixel = texture2D(texture, texCoord); + vec4 maskColor = texture2D(maskTexture, texCoord); + + vec4 outColor = vec4(0); + if(maskColor.r == 1.0 && maskColor.g == 1.0) { + outColor = headColor; + } else if(maskColor.r == 1.0) { + outColor = bodyColor; + } else if(maskColor.g == 1.0) { + outColor = legsColor; + } else if(maskColor.b == 1.0) { + outColor = feetColor; + } + + if(outColor.a != 0.0) + pixel = pixel * outColor; + return pixel; +} +void main() +{ + vec4 pixel = calcPixel(textureCoords); + int num = 16; + + vec4 sum = vec4(0); + int i, j; + for(i=-num/2;igetId()); + setUniformValue(location, index); +} + void PainterShaderProgram::setTexture(const TexturePtr& texture) { if(!texture) @@ -78,9 +83,7 @@ void PainterShaderProgram::setTexture(const TexturePtr& texture) }; bind(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture->getId()); - setUniformValue(TEXTURE_UNIFORM, 0); + setUniformTexture(TEXTURE_UNIFORM, texture, 0); setUniformValue(TEXTURE_TRANSFORM_MATRIX_UNIFORM, textureTransformMatrix, true); } diff --git a/src/framework/graphics/paintershaderprogram.h b/src/framework/graphics/paintershaderprogram.h index 9abdeb4d..80f1e19f 100644 --- a/src/framework/graphics/paintershaderprogram.h +++ b/src/framework/graphics/paintershaderprogram.h @@ -50,6 +50,7 @@ public: void setColor(const Color& color); void setOpacity(GLfloat opacity); void setTexture(const TexturePtr& texture); + void setUniformTexture(int location, const TexturePtr& texture, int index); void draw(const CoordsBuffer& coordsBuffer, DrawMode drawMode = Triangles); private: diff --git a/src/framework/graphics/shaderprogram.cpp b/src/framework/graphics/shaderprogram.cpp index 8899f07a..ace96f81 100644 --- a/src/framework/graphics/shaderprogram.cpp +++ b/src/framework/graphics/shaderprogram.cpp @@ -139,6 +139,6 @@ void ShaderProgram::bindAttributeLocation(int location, const char* name) void ShaderProgram::bindUniformLocation(int location, const char* name) { assert(m_linked); - assert(location >= 0 && location < 10); + assert(location >= 0 && location < MAX_UNIFORM_LOCATIONS); m_uniformLocations[location] = glGetUniformLocation(m_programId, name); } diff --git a/src/framework/graphics/shaderprogram.h b/src/framework/graphics/shaderprogram.h index c09c0894..f05cd226 100644 --- a/src/framework/graphics/shaderprogram.h +++ b/src/framework/graphics/shaderprogram.h @@ -28,7 +28,7 @@ class ShaderProgram { enum { - MAX_UNIFORM_LOCATIONS = 10 + MAX_UNIFORM_LOCATIONS = 30 }; public: ShaderProgram(); @@ -62,6 +62,7 @@ public: void setAttributeValue(const char *name, GLfloat x, GLfloat y) { glVertexAttrib2f(getAttributeLocation(name), x, y); } void setAttributeValue(const char *name, GLfloat x, GLfloat y, GLfloat z) { glVertexAttrib3f(getAttributeLocation(name), x, y, z); } + void setUniformValue(int location, const Color& color) { glUniform4f(m_uniformLocations[location], color.r() / 255.0f, color.g() / 255.0f, color.b() / 255.0f, color.a() / 255.0f); } void setUniformValue(int location, GLint value) { glUniform1i(m_uniformLocations[location], value); } void setUniformValue(int location, GLfloat value) { glUniform1f(m_uniformLocations[location], value); } void setUniformValue(int location, GLfloat x, GLfloat y) { glUniform2f(m_uniformLocations[location], x, y); } @@ -69,6 +70,7 @@ public: void setUniformValue(int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { glUniform4f(m_uniformLocations[location], x, y, z, w); } void setUniformValue(int location, GLfloat mat2[2][2], bool transpose) { glUniformMatrix2fv(m_uniformLocations[location], 1, transpose ? GL_TRUE : GL_FALSE, (GLfloat *)mat2); } void setUniformValue(int location, GLfloat mat3[3][3], bool transpose) { glUniformMatrix3fv(m_uniformLocations[location], 1, transpose ? GL_TRUE : GL_FALSE, (GLfloat *)mat3); } + void setUniformValue(const char *name, const Color& color) { glUniform4f(glGetUniformLocation(m_programId, name), color.r() / 255.0f, color.g() / 255.0f, color.b() / 255.0f, color.a() / 255.0f); } void setUniformValue(const char *name, GLint value) { glUniform1i(glGetUniformLocation(m_programId, name), value); } void setUniformValue(const char *name, GLfloat value) { glUniform1f(glGetUniformLocation(m_programId, name), value); } void setUniformValue(const char *name, GLfloat x, GLfloat y) { glUniform2f(glGetUniformLocation(m_programId, name), x, y); } diff --git a/src/otclient/const.h b/src/otclient/const.h index 554f65a2..150d209e 100644 --- a/src/otclient/const.h +++ b/src/otclient/const.h @@ -250,14 +250,6 @@ namespace Otc ClientGetObjectInfo = 243 }; - enum SpriteMask { - SpriteRedMask = 0, - SpriteGreenMask, - SpriteBlueMask, - SpriteYellowMask, - SpriteNoMask = 255 - }; - enum InventorySlots { InventorySlotHead = 1, InventorySlotNecklace, diff --git a/src/otclient/core/creature.cpp b/src/otclient/core/creature.cpp index b8ece933..08bf079e 100644 --- a/src/otclient/core/creature.cpp +++ b/src/otclient/core/creature.cpp @@ -31,6 +31,10 @@ #include #include +#include +#include +#include "spritemanager.h" + Creature::Creature() : Thing() { m_healthPercent = 0; @@ -43,6 +47,13 @@ Creature::Creature() : Thing() m_informationFont = g_fonts.getFont("verdana-11px-rounded"); } +PainterShaderProgramPtr outfitProgram; +int HEAD_COLOR_UNIFORM = 10; +int BODY_COLOR_UNIFORM = 11; +int LEGS_COLOR_UNIFORM = 12; +int FEET_COLOR_UNIFORM = 13; +int MASK_TEXTURE_UNIFORM = 14; + void Creature::draw(const Point& p) { // TODO: activate on attack, follow, discover how 'attacked' works @@ -51,6 +62,18 @@ void Creature::draw(const Point& p) g_painter.drawBoundingRect(Rect(p + m_walkOffset - 8, Size(32, 32)), 2); } + if(!outfitProgram) { + outfitProgram = PainterShaderProgramPtr(new PainterShaderProgram); + outfitProgram->addShaderFromSourceCode(Shader::Vertex, glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader); + outfitProgram->addShaderFromSourceFile(Shader::Fragment, "/outfit.frag"); + assert(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"); + outfitProgram->bindUniformLocation(MASK_TEXTURE_UNIFORM, "maskTexture"); + } + // Render creature for(m_yPattern = 0; m_yPattern < m_type->dimensions[ThingType::PatternY]; m_yPattern++) { @@ -58,35 +81,52 @@ void Creature::draw(const Point& p) if(m_yPattern > 0 && !(m_outfit.getAddons() & (1 << (m_yPattern-1)))) continue; - // draw white item - g_painter.setColor(Fw::white); - internalDraw(p + m_walkOffset, 0); - - // draw mask if exists - if(m_type->dimensions[ThingType::Layers] > 1) { - // switch to blend color mode - g_painter.setCompositionMode(Painter::CompositionMode_ColorizeDest); - - // head - g_painter.setColor(m_outfit.getHeadColor()); - internalDraw(p + m_walkOffset, 1, Otc::SpriteYellowMask); - - // body - g_painter.setColor(m_outfit.getBodyColor()); - internalDraw(p + m_walkOffset, 1, Otc::SpriteRedMask); - - // legs - g_painter.setColor(m_outfit.getLegsColor()); - internalDraw(p + m_walkOffset, 1, Otc::SpriteGreenMask); - - // feet - g_painter.setColor(m_outfit.getFeetColor()); - internalDraw(p + m_walkOffset, 1, Otc::SpriteBlueMask); - - // restore default blend func - g_painter.setCompositionMode(Painter::CompositionMode_SourceOver); - g_painter.setColor(Fw::white); + g_painter.setCustomProgram(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()); + + for(int yi = 0; yi < m_type->dimensions[ThingType::Height]; yi++) { + for(int xi = 0; xi < m_type->dimensions[ThingType::Width]; xi++) { + int sprIndex = ((((((m_animation % m_type->dimensions[ThingType::AnimationPhases]) + * m_type->dimensions[ThingType::PatternZ] + m_zPattern) + * m_type->dimensions[ThingType::PatternY] + m_yPattern) + * m_type->dimensions[ThingType::PatternX] + m_xPattern) + * m_type->dimensions[ThingType::Layers] + 0) + * m_type->dimensions[ThingType::Height] + yi) + * m_type->dimensions[ThingType::Width] + xi; + if(m_type->dimensions[ThingType::Layers] > 1) { + int maskIndex = ((((((m_animation % m_type->dimensions[ThingType::AnimationPhases]) + * m_type->dimensions[ThingType::PatternZ] + m_zPattern) + * m_type->dimensions[ThingType::PatternY] + m_yPattern) + * m_type->dimensions[ThingType::PatternX] + m_xPattern) + * m_type->dimensions[ThingType::Layers] + 1) + * m_type->dimensions[ThingType::Height] + yi) + * m_type->dimensions[ThingType::Width] + xi; + int spriteId = m_type->sprites[maskIndex]; + if(!spriteId) + continue; + TexturePtr maskTex = g_sprites.getSpriteTexture(spriteId); + outfitProgram->setUniformTexture(MASK_TEXTURE_UNIFORM, maskTex, 1); + } + + int spriteId = m_type->sprites[sprIndex]; + if(!spriteId) + continue; + + TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId); + + Rect drawRect(((p + m_walkOffset).x - xi*32) - m_type->parameters[ThingType::DisplacementX], + ((p + m_walkOffset).y - yi*32) - m_type->parameters[ThingType::DisplacementY], + 32, 32); + g_painter.drawTexturedRect(drawRect, spriteTex); + } } + + g_painter.releaseCustomProgram(); } } diff --git a/src/otclient/core/spritemanager.cpp b/src/otclient/core/spritemanager.cpp index f1d5d0c5..731e66c1 100644 --- a/src/otclient/core/spritemanager.cpp +++ b/src/otclient/core/spritemanager.cpp @@ -118,30 +118,7 @@ TexturePtr SpriteManager::loadSpriteTexture(int id) return TexturePtr(new Texture(32, 32, 4, pixels)); } -TexturePtr SpriteManager::loadSpriteMask(TexturePtr spriteTex, Otc::SpriteMask mask) -{ - auto pixels = spriteTex->getPixels(); - - static uint32 maskColors[4] = { Fw::red, Fw::green, Fw::blue, Fw::yellow }; - uint32 maskColor = maskColors[mask]; - uint32 whiteColor = Fw::white; - uint32 alphaColor = Fw::alpha; - - // convert pixels - // masked color -> white color - // any other color -> alpha color - for(int i=0;i<4096;i+=4) { - uint32& currentColor = *(uint32*)&pixels[i]; - if(currentColor == maskColor) - currentColor = whiteColor; - else - currentColor = alphaColor; - } - - return TexturePtr(new Texture(32, 32, 4, &pixels[0])); -} - -TexturePtr SpriteManager::getSpriteTexture(int id, Otc::SpriteMask mask) +TexturePtr SpriteManager::getSpriteTexture(int id) { if(id == 0) return g_graphics.getEmptyTexture(); @@ -149,17 +126,11 @@ TexturePtr SpriteManager::getSpriteTexture(int id, Otc::SpriteMask mask) assert(id > 0 && id <= m_spritesCount); // load sprites on demand - Sprite& sprite = m_sprites[id-1]; - if(!sprite.texture) - sprite.texture = loadSpriteTexture(id); + TexturePtr& sprite = m_sprites[id-1]; + if(!sprite) + sprite = loadSpriteTexture(id); //TODO: release unused sprites textures after X seconds // to avoid massive texture allocations - - if(mask != Otc::SpriteNoMask) { - if(!sprite.masks[mask]) - sprite.masks[mask] = loadSpriteMask(sprite.texture, mask); - return sprite.masks[mask]; - } else - return sprite.texture; + return sprite; } diff --git a/src/otclient/core/spritemanager.h b/src/otclient/core/spritemanager.h index 0c97f8a2..7b1dfb2c 100644 --- a/src/otclient/core/spritemanager.h +++ b/src/otclient/core/spritemanager.h @@ -26,11 +26,6 @@ #include "declarations.h" #include -struct Sprite { - TexturePtr texture; - TexturePtr masks[4]; -}; - class SpriteManager { public: @@ -42,16 +37,15 @@ public: uint32 getSignature() { return m_signature; } int getSpritesCount() { return m_spritesCount; } - TexturePtr getSpriteTexture(int id, Otc::SpriteMask mask = Otc::SpriteNoMask); + TexturePtr getSpriteTexture(int id); private: TexturePtr loadSpriteTexture(int id); - TexturePtr loadSpriteMask(TexturePtr spriteTex, Otc::SpriteMask mask); uint32 m_signature; uint16 m_spritesCount; std::stringstream m_fin; - std::vector m_sprites; + std::vector m_sprites; TexturePtr m_transparentSprite; }; diff --git a/src/otclient/core/thing.cpp b/src/otclient/core/thing.cpp index 972d4ee1..109a0d0a 100644 --- a/src/otclient/core/thing.cpp +++ b/src/otclient/core/thing.cpp @@ -34,7 +34,7 @@ Thing::Thing() : m_id(0) m_type = g_thingsType.getEmptyThingType(); } -void Thing::internalDraw(const Point& p, int layers, Otc::SpriteMask mask) +void Thing::internalDraw(const Point& p, int layers) { for(int yi = 0; yi < m_type->dimensions[ThingType::Height]; yi++) { for(int xi = 0; xi < m_type->dimensions[ThingType::Width]; xi++) { @@ -50,7 +50,7 @@ void Thing::internalDraw(const Point& p, int layers, Otc::SpriteMask mask) if(!spriteId) continue; - TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId, mask); + TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId); Rect drawRect((p.x - xi*32) - m_type->parameters[ThingType::DisplacementX], (p.y - yi*32) - m_type->parameters[ThingType::DisplacementY], diff --git a/src/otclient/core/thing.h b/src/otclient/core/thing.h index 3614d512..29328d47 100644 --- a/src/otclient/core/thing.h +++ b/src/otclient/core/thing.h @@ -63,7 +63,7 @@ public: virtual LocalPlayerPtr asLocalPlayer() { return nullptr; } protected: - void internalDraw(const Point& p, int layers, Otc::SpriteMask mask = Otc::SpriteNoMask); + void internalDraw(const Point& p, int layers); uint32 m_id; Position m_position;