experiment shaders in outfit

This commit is contained in:
Eduardo Bart 2011-12-08 15:28:29 -02:00
parent 5ec386b35f
commit 04ee85dc92
12 changed files with 174 additions and 87 deletions

49
modules/outfit.frag Normal file
View File

@ -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;i<num/2;++i) {
for(j=-num/2;j<num/2;++j) {
sum += calcPixel(textureCoords + vec2(i+1, j+1)*0.005) * 1.0/(num*num);
}
}
sum = sin(ticks/500.0)*sum;
gl_FragColor = pixel * color * opacity + sum;
}

View File

@ -1,3 +1,38 @@
varying vec2 textureCoords;
uniform float opacity;
uniform vec4 color;
uniform float ticks;
uniform sampler2D texture;
void main()
{
gl_FragColor = texture2D(texture, textureCoords) * color * opacity;
}
/*
varying vec2 textureCoords;
uniform vec4 color;
uniform float ticks;
uniform sampler2D texture;
void main()
{
int num = 4;
vec4 sum = vec4(0);
int i, j;
for(i=-num/2;i<num/2;++i) {
for(j=-num/2;j<num/2;++j) {
sum += texture2D(texture, textureCoords + vec2(i+1, j+1)*0.001) * 1.0/(num*num);
}
}
float period = ticks/1000.0;
float a = (sin(period)+1.0)/2.0;
sum.a = 0;
gl_FragColor = vec4(1,1,1,2) - texture2D(texture, textureCoords);
}
*/
/*
uniform sampler2D texture;
varying vec2 textureCoords;
@ -31,7 +66,7 @@ void main()
}
}
}
*/
/*
uniform sampler2D texture;
varying vec2 textureCoords;

View File

@ -51,11 +51,7 @@ void PainterShaderProgram::setProjectionMatrix(float projectionMatrix[3][3])
void PainterShaderProgram::setColor(const Color& color)
{
bind();
setUniformValue(COLOR_UNIFORM,
color.r() / 255.0f,
color.g() / 255.0f,
color.b() / 255.0f,
color.a() / 255.0f);
setUniformValue(COLOR_UNIFORM, color);
}
void PainterShaderProgram::setOpacity(GLfloat opacity)
@ -64,6 +60,15 @@ void PainterShaderProgram::setOpacity(GLfloat opacity)
setUniformValue(OPACITY_UNIFORM, opacity);
}
void PainterShaderProgram::setUniformTexture(int location, const TexturePtr& texture, int index)
{
if(!texture)
return;
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, texture->getId());
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);
}

View File

@ -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:

View File

@ -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);
}

View File

@ -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); }

View File

@ -250,14 +250,6 @@ namespace Otc
ClientGetObjectInfo = 243
};
enum SpriteMask {
SpriteRedMask = 0,
SpriteGreenMask,
SpriteBlueMask,
SpriteYellowMask,
SpriteNoMask = 255
};
enum InventorySlots {
InventorySlotHead = 1,
InventorySlotNecklace,

View File

@ -31,6 +31,10 @@
#include <framework/core/eventdispatcher.h>
#include <framework/core/clock.h>
#include <framework/graphics/paintershaderprogram.h>
#include <framework/graphics/paintershadersources.h>
#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);
g_painter.setCustomProgram(outfitProgram);
// draw mask if exists
if(m_type->dimensions[ThingType::Layers] > 1) {
// switch to blend color mode
g_painter.setCompositionMode(Painter::CompositionMode_ColorizeDest);
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());
// head
g_painter.setColor(m_outfit.getHeadColor());
internalDraw(p + m_walkOffset, 1, Otc::SpriteYellowMask);
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);
}
// body
g_painter.setColor(m_outfit.getBodyColor());
internalDraw(p + m_walkOffset, 1, Otc::SpriteRedMask);
int spriteId = m_type->sprites[sprIndex];
if(!spriteId)
continue;
// legs
g_painter.setColor(m_outfit.getLegsColor());
internalDraw(p + m_walkOffset, 1, Otc::SpriteGreenMask);
TexturePtr spriteTex = g_sprites.getSpriteTexture(spriteId);
// 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);
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();
}
}

View File

@ -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;
}

View File

@ -26,11 +26,6 @@
#include "declarations.h"
#include <framework/graphics/texture.h>
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<Sprite> m_sprites;
std::vector<TexturePtr> m_sprites;
TexturePtr m_transparentSprite;
};

View File

@ -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],

View File

@ -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;