TWP: Debug lighting shader

This commit is contained in:
scemino 2024-01-28 21:07:09 +01:00 committed by Eugene Sandulenko
parent ef2d87e1d7
commit 0d87082d11
15 changed files with 425 additions and 150 deletions

View File

@ -140,7 +140,7 @@ Shader::~Shader() {
}
void Shader::init(const char *name, const char *vertex, const char *fragment) {
const char* attributes[]={"a_position", "a_color", "a_texCoords", nullptr};
const char *attributes[] = {"a_position", "a_color", "a_texCoords", nullptr};
_shader.loadFromStrings(name, vertex, fragment, attributes);
uint32 vbo = g_engine->getGfx()._vbo;
@ -153,19 +153,28 @@ int Shader::getUniformLocation(const char *name) const {
return _shader.getUniformLocation(name);
}
void Shader::setUniform(const char * name, int value) {
void Shader::setUniform(const char *name, int value) {
_shader.setUniform(name, value);
}
void Shader::setUniform(const char * name, float value) {
void Shader::setUniform(const char *name, float value) {
_shader.setUniform1f(name, value);
}
void Shader::setUniform(const char * name, float* value, size_t count) {
void Shader::setUniform(const char *name, float *value, size_t count) {
GLint loc = _shader.getUniformLocation(name);
GL_CALL(glUniform1fv(loc, count, value));
}
void Shader::setUniform2(const char *name, float *value, size_t count) {
GLint loc = _shader.getUniformLocation(name);
GL_CALL(glUniform2fv(loc, count, value));
}
void Shader::setUniform3(const char *name, float *value, size_t count) {
GLint loc = _shader.getUniformLocation(name);
GL_CALL(glUniform3fv(loc, count, value));
}
void Shader::setUniform(const char *name, Math::Vector2d value) {
_shader.setUniform(name, value);

View File

@ -137,6 +137,8 @@ public:
void setUniform(const char * name, int value);
void setUniform(const char * name, float value);
void setUniform(const char * name, float* value, size_t count);
void setUniform2(const char * name, float* value, size_t count);
void setUniform3(const char * name, float* value, size_t count);
void setUniform(const char *name, Math::Matrix4 value);
void setUniform(const char * name, Math::Vector2d value);

View File

@ -1,116 +1,223 @@
#include "twp/lighting.h"
#include "twp/room.h"
#include "graphics/opengl/debug.h"
#include "graphics/opengl/system_headers.h"
#include "common/math.h"
namespace Twp {
// Lighting::Lighting() {
// const char *vshader = R"(#version 110
// uniform mat4 u_transform;
// attribute vec2 a_position;
// attribute vec4 a_color;
// attribute vec2 a_texCoords;
// varying vec4 v_color;
// varying vec2 v_texCoords;
// void main() {
// gl_Position = u_transform * vec4(a_position, 0.0, 1.0);
// v_color = a_color;
// v_texCoords = a_texCoords;
// })";
Lighting::Lighting() {
const char *vshader = R"(#version 110
uniform mat4 u_transform;
attribute vec2 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoords;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
gl_Position = u_transform * vec4(a_position, 0.0, 1.0);
v_color = a_color;
v_texCoords = a_texCoords;
})";
const char *fshader = R"(#version 110
varying vec2 v_texCoords;
varying vec4 v_color;
uniform sampler2D u_texture;
uniform vec2 u_contentSize;
uniform vec3 u_ambientColor;
uniform vec2 u_spritePosInSheet;
uniform vec2 u_spriteSizeRelToSheet;
uniform vec2 u_spriteOffset;
uniform int u_numberLights;
uniform vec3 u_lightPos[50];
uniform vec3 u_lightColor[50];
uniform float u_brightness[50];
uniform float u_cutoffRadius[50];
uniform float u_halfRadius[50];
uniform float u_coneCosineHalfConeAngle[50];
uniform float u_coneFalloff[50];
uniform vec2 u_coneDirection[50];
void main(void) {
vec4 texColor = texture2D(u_texture, v_texCoords);
vec2 spriteTexCoord = (v_texCoords - u_spritePosInSheet) / u_spriteSizeRelToSheet; // [0..1]
vec2 pixelPos = spriteTexCoord * u_contentSize + u_spriteOffset; // [0..origSize]
vec2 curPixelPosInLocalSpace = vec2(pixelPos.x, -pixelPos.y);
vec3 diffuse = vec3(0, 0, 0);
for (int i = 0; i < u_numberLights; i++) {
vec2 lightVec = curPixelPosInLocalSpace.xy - u_lightPos[i].xy;
float coneValue = dot(normalize(-lightVec), u_coneDirection[i]);
if (coneValue >= u_coneCosineHalfConeAngle[i]) {
float intercept = u_cutoffRadius[i] * u_halfRadius[i];
float dx_1 = 0.5 / intercept;
float dx_2 = 0.5 / (u_cutoffRadius[i] - intercept);
float offset = 0.5 + intercept * dx_2;
float lightDist = length(lightVec);
float falloffTermNear = clamp((1.0 - lightDist * dx_1), 0.0, 1.0);
float falloffTermFar = clamp((offset - lightDist * dx_2), 0.0, 1.0);
float falloffSelect = step(intercept, lightDist);
float falloffTerm = (1.0 - falloffSelect) * falloffTermNear + falloffSelect * falloffTermFar;
float spotLight = u_brightness[i] * falloffTerm;
vec3 ltdiffuse = vec3(u_brightness[i] * falloffTerm) * u_lightColor[i];
float coneRange = 1.0 - u_coneCosineHalfConeAngle[i];
float halfConeRange = coneRange * u_coneFalloff[i];
float conePos = 1.0 - coneValue;
float coneFalloff = 1.0;
if (conePos > halfConeRange) {
coneFalloff = 1.0 - ((conePos - halfConeRange) / (coneRange - halfConeRange));
}
diffuse += ltdiffuse * coneFalloff;
;
}
}
vec3 finalLight = (diffuse);
vec4 finalCol = texColor * v_color;
finalCol.rgb = finalCol.rgb * u_ambientColor;
gl_FragColor = vec4(finalCol.rgb + diffuse, finalCol.a);
})";
// const char *fshader = R"(#version 110
// varying vec2 v_texCoords;
// varying vec4 v_color;
// #ifdef GL_ES
// precision highp float;
// #endif
// uniform sampler2D u_texture;
// varying vec2 v_texCoords;
// varying vec4 v_color;
// uniform vec2 u_contentSize;
// uniform vec3 u_ambientColor;
// uniform vec2 u_spritePosInSheet;
// uniform vec2 u_spriteSizeRelToSheet;
// uniform vec2 u_spriteOffset;
// uniform sampler2D u_texture;
// uniform int u_numberLights;
// uniform vec3 u_lightPos[50];
// uniform vec3 u_lightColor[50];
// uniform float u_brightness[50];
// uniform float u_cutoffRadius[50];
// uniform float u_halfRadius[50];
// uniform float u_coneCosineHalfConeAngle[50];
// uniform float u_coneFalloff[50];
// uniform vec2 u_coneDirection[50];
// uniform vec2 u_contentSize;
// uniform vec3 u_ambientColor;
// uniform vec2 u_spritePosInSheet;
// uniform vec2 u_spriteSizeRelToSheet;
// uniform vec2 u_spriteOffset;
// void main(void) {
// vec4 texColor = texture2D(u_texture, v_texCoords);
// uniform int u_numberLights;
// uniform vec3 u_lightPos[50];
// uniform vec3 u_lightColor[50];
// uniform float u_brightness[50];
// uniform float u_cutoffRadius[50];
// uniform float u_halfRadius[50];
// uniform float u_coneCosineHalfConeAngle[50];
// uniform float u_coneFalloff[50];
// uniform vec2 u_coneDirection[50];
// vec2 spriteTexCoord = (v_texCoords - u_spritePosInSheet) / u_spriteSizeRelToSheet; // [0..1]
// vec2 pixelPos = spriteTexCoord * u_contentSize + u_spriteOffset; // [0..origSize]
// vec2 curPixelPosInLocalSpace = vec2(pixelPos.x, -pixelPos.y);
// void main(void)
// {
// vec4 texColor = texture2D(u_texture, v_texCoords);
// vec3 diffuse = vec3(0, 0, 0);
// for (int i = 0; i < u_numberLights; i++) {
// vec2 lightVec = curPixelPosInLocalSpace.xy - u_lightPos[i].xy;
// float coneValue = dot(normalize(-lightVec), u_coneDirection[i]);
// if (coneValue >= u_coneCosineHalfConeAngle[i]) {
// float intercept = u_cutoffRadius[i] * u_halfRadius[i];
// float dx_1 = 0.5 / intercept;
// float dx_2 = 0.5 / (u_cutoffRadius[i] - intercept);
// float offset = 0.5 + intercept * dx_2;
// vec2 spriteTexCoord = (v_texCoords - u_spritePosInSheet) / u_spriteSizeRelToSheet; // [0..1]
// vec2 pixelPos = spriteTexCoord * u_contentSize + u_spriteOffset; // [0..origSize]
// vec2 curPixelPosInLocalSpace = vec2(pixelPos.x, -pixelPos.y);
// float lightDist = length(lightVec);
// float falloffTermNear = clamp((1.0 - lightDist * dx_1), 0.0, 1.0);
// float falloffTermFar = clamp((offset - lightDist * dx_2), 0.0, 1.0);
// float falloffSelect = step(intercept, lightDist);
// float falloffTerm = (1.0 - falloffSelect) * falloffTermNear + falloffSelect * falloffTermFar;
// float spotLight = u_brightness[i] * falloffTerm;
// vec3 diffuse = vec3(0,0,0);
// for ( int i = 0; i < u_numberLights; i ++)
// {
// vec2 lightVec = curPixelPosInLocalSpace.xy - u_lightPos[i].xy;
// float coneValue = dot( normalize(-lightVec), u_coneDirection[i] );
// if ( coneValue >= u_coneCosineHalfConeAngle[i] )
// {
// float intercept = u_cutoffRadius[i] * u_halfRadius[i];
// float dx_1 = 0.5 / intercept;
// float dx_2 = 0.5 / (u_cutoffRadius[i] - intercept);
// float offset = 0.5 + intercept * dx_2;
// vec3 ltdiffuse = vec3(u_brightness[i] * falloffTerm) * u_lightColor[i];
// float lightDist = length(lightVec);
// float falloffTermNear = clamp((1.0 - lightDist * dx_1), 0.0, 1.0);
// float falloffTermFar = clamp((offset - lightDist * dx_2), 0.0, 1.0);
// float falloffSelect = step(intercept, lightDist);
// float falloffTerm = (1.0 - falloffSelect) * falloffTermNear + falloffSelect * falloffTermFar;
// float spotLight = u_brightness[i] * falloffTerm;
// float coneRange = 1.0 - u_coneCosineHalfConeAngle[i];
// float halfConeRange = coneRange * u_coneFalloff[i];
// float conePos = 1.0 - coneValue;
// float coneFalloff = 1.0;
// if (conePos > halfConeRange) {
// coneFalloff = 1.0 - ((conePos - halfConeRange) / (coneRange - halfConeRange));
// }
// vec3 ltdiffuse = vec3(u_brightness[i] * falloffTerm) * u_lightColor[i];
// diffuse += ltdiffuse * coneFalloff;
// ;
// }
// }
// vec3 finalLight = (diffuse);
// vec4 finalCol = texColor * v_color;
// finalCol.rgb = finalCol.rgb * u_ambientColor;
// gl_FragColor = vec4(finalCol.rgb + diffuse, finalCol.a);
// })";
// init(vshader, fshader);
// float coneRange = 1.0-u_coneCosineHalfConeAngle[i];
// float halfConeRange = coneRange * u_coneFalloff[i];
// float conePos = 1.0-coneValue;
// float coneFalloff = 1.0;
// if ( conePos > halfConeRange )
// {
// coneFalloff = 1.0-((conePos-halfConeRange)/(coneRange-halfConeRange));
// }
// GL_CALL(_contentSizeLoc = glGetUniformLocation(program, "u_contentSize"));
// GL_CALL(_spriteOffsetLoc = glGetUniformLocation(program, "u_spriteOffset"));
// GL_CALL(_spritePosInSheetLoc = glGetUniformLocation(program, "u_spritePosInSheet"));
// GL_CALL(_spriteSizeRelToSheetLoc = glGetUniformLocation(program, "u_spriteSizeRelToSheet"));
// GL_CALL(_numberLightsLoc = glGetUniformLocation(program, "u_numberLights"));
// GL_CALL(_ambientColorLoc = glGetUniformLocation(program, "u_ambientColor"));
// }
// diffuse += ltdiffuse*coneFalloff;;
// }
// }
// vec4 finalCol = texColor * v_color;
// vec3 finalLight = (diffuse+u_ambientColor);
// finalLight = min( finalLight, vec3(1,1,1) );
// gl_FragColor = vec4(finalCol.rgb*finalLight, finalCol.a);
// })";
// Lighting::~Lighting() {}
init("lighting", vshader, fshader);
}
// void Lighting::setSpriteSheetFrame(const SpriteSheetFrame& frame, const Texture& texture) {
// _contentSize = frame.sourceSize;
// //_spriteOffset = {-frame.frame.width() / 2.f, -frame.frame.height() / 2.f};
// _spriteOffset = {0, (float)frame.frame.height()};
// _spritePosInSheet = {(float)(frame.frame.left) / texture.width, (float)(frame.frame.top) / texture.height};
// _spriteSizeRelToSheet = {(float)(frame.sourceSize.getX()) / texture.width, (float)(frame.sourceSize.getY()) / texture.height};
// }
Lighting::~Lighting() {}
// void Lighting::applyUniforms() {
// GL_CALL(glUniform1i(_numberLightsLoc, 0));
// float ambientColor[] = {1,1,1};
// GL_CALL(glUniform3fv(_ambientColorLoc, 1, ambientColor));
// GL_CALL(glUniform2fv(_contentSizeLoc, 1, _contentSize.getData()));
// GL_CALL(glUniform2fv(_spriteOffsetLoc, 1, _spriteOffset.getData()));
// GL_CALL(glUniform2fv(_spritePosInSheetLoc, 1, _spritePosInSheet.getData()));
// GL_CALL(glUniform2fv(_spriteSizeRelToSheetLoc, 1, _spriteSizeRelToSheet.getData()));
// }
void Lighting::setSpriteOffset(const Math::Vector2d &offset) {
_spriteOffset = offset;
}
void Lighting::setSpriteSheetFrame(const SpriteSheetFrame &frame, const Texture &texture) {
_contentSize = frame.sourceSize;
_spritePosInSheet = {(float)(frame.frame.left) / texture.width, (float)(frame.frame.top) / texture.height};
_spriteSizeRelToSheet = {(float)(frame.frame.width()) / texture.width, (float)(frame.frame.height()) / texture.height};
}
void Lighting::update(const Lights &lights) {
_ambientLight = lights._ambientLight;
u_numberLights = 0;
for (int i = 0; i < MIN(MAX_LIGHTS, lights._numLights); ++i) {
const Light &light = lights._lights[i];
if (!light.on)
continue;
const float direction = light.coneDirection - 90.f;
u_lightPos[u_numberLights * 3 + 0] = light.pos.getX();
u_lightPos[u_numberLights * 3 + 1] = light.pos.getY();
u_lightPos[u_numberLights * 3 + 2] = 1.f;
u_coneDirection[u_numberLights * 2 + 0] = cos(Common::deg2rad(direction));
u_coneDirection[u_numberLights * 2 + 1] = sin(Common::deg2rad(direction));
u_coneCosineHalfConeAngle[u_numberLights] = cos(Common::deg2rad(light.coneAngle / 2.f));
u_coneFalloff[u_numberLights] = light.coneFalloff;
u_lightColor[u_numberLights * 3 + 0] = light.color.rgba.r;
u_lightColor[u_numberLights * 3 + 1] = light.color.rgba.g;
u_lightColor[u_numberLights * 3 + 2] = light.color.rgba.b;
u_brightness[u_numberLights] = light.brightness;
u_cutoffRadius[u_numberLights] = MAX(1.0f, light.cutOffRadius);
u_halfRadius[u_numberLights] = MAX(0.01f, MIN(0.99f, light.halfRadius));
u_numberLights++;
}
}
void Lighting::applyUniforms() {
setUniform3("u_ambientColor", _ambientLight);
setUniform("u_numberLights", u_numberLights);
if (u_numberLights > 0) {
setUniform3("u_lightPos", u_lightPos, MAX_LIGHTS);
setUniform2("u_coneDirection", u_coneDirection, MAX_LIGHTS);
setUniform("u_coneCosineHalfConeAngle", u_coneCosineHalfConeAngle, MAX_LIGHTS);
setUniform("u_coneFalloff", u_coneFalloff, MAX_LIGHTS);
setUniform3("u_lightColor", u_lightColor, MAX_LIGHTS);
setUniform("u_brightness", u_brightness, MAX_LIGHTS);
setUniform("u_cutoffRadius", u_cutoffRadius, MAX_LIGHTS);
setUniform("u_halfRadius", u_halfRadius, MAX_LIGHTS);
}
setUniform("u_contentSize", _contentSize);
setUniform("u_spriteOffset", _spriteOffset);
setUniform("u_spritePosInSheet", _spritePosInSheet);
setUniform("u_spriteSizeRelToSheet", _spriteSizeRelToSheet);
}
} // namespace Twp

View File

@ -25,31 +25,42 @@
#include "twp/gfx.h"
#include "twp/spritesheet.h"
#define MAX_LIGHTS 50
namespace Twp {
// class Lighting {
// public:
// Lighting();
// virtual ~Lighting();
struct Lights;
// void setSpriteSheetFrame(const SpriteSheetFrame &frame, const Texture &texture);
class Lighting : public Shader {
public:
Lighting();
virtual ~Lighting();
// private:
// virtual void applyUniforms() final;
void setSpriteOffset(const Math::Vector2d& offset);
void setSpriteSheetFrame(const SpriteSheetFrame &frame, const Texture &getNumTextures);
// private:
// int32 _contentSizeLoc;
// int32 _spriteOffsetLoc;
// int32 _spritePosInSheetLoc;
// int32 _spriteSizeRelToSheetLoc;
// int32 _numberLightsLoc;
// int32 _ambientColorLoc;
void update(const Lights& lights);
// Math::Vector2d _contentSize;
// Math::Vector2d _spriteOffset;
// Math::Vector2d _spritePosInSheet;
// Math::Vector2d _spriteSizeRelToSheet;
// };
private:
virtual void applyUniforms() final;
public:
Math::Vector2d _contentSize;
Math::Vector2d _spriteOffset;
Math::Vector2d _spritePosInSheet;
Math::Vector2d _spriteSizeRelToSheet;
Color _ambientLight; // Ambient light color
int u_numberLights = 0;
float u_lightPos[3 * MAX_LIGHTS];
float u_coneDirection[2 * MAX_LIGHTS];
float u_coneCosineHalfConeAngle[MAX_LIGHTS];
float u_coneFalloff[MAX_LIGHTS];
float u_lightColor[3 * MAX_LIGHTS];
float u_brightness[MAX_LIGHTS];
float u_cutoffRadius[MAX_LIGHTS];
float u_halfRadius[MAX_LIGHTS];
};
} // namespace Twp

View File

@ -77,18 +77,18 @@ struct Scaling {
struct Light {
Color color;
Math::Vector2d pos;
float brightness; // light brightness 1.0f...100.f
float coneDirection; // cone direction 0...360.f
float coneAngle; // cone angle 0...360.f
float coneFalloff; // cone falloff 0.f...1.0f
float cutOffRadius; // cutoff radius
float halfRadius; // cone half radius 0.0f...1.0f
bool on;
int id;
float brightness = 0.f; // light brightness 1.0f...100.f
float coneDirection = 0.f; // cone direction 0...360.f
float coneAngle = 0.f; // cone angle 0...360.f
float coneFalloff = 0.f; // cone falloff 0.f...1.0f
float cutOffRadius = 0.f; // cutoff radius
float halfRadius = 0.f; // cone half radius 0.0f...1.0f
bool on = false;
int id = 0;
};
struct Lights {
int _numLights; // Number of lights
int _numLights = 0; // Number of lights
Light _lights[50];
Color _ambientLight; // Ambient light color
};

View File

@ -133,42 +133,93 @@ static SQInteger enterRoomFromDoor(HSQUIRRELVM v) {
}
static SQInteger lightBrightness(HSQUIRRELVM v) {
warning("TODO: lightBrightness not implemented");
Light *light = sqlight(v, 2);
if (light) {
float brightness;
if (SQ_FAILED(sqget(v, 3, brightness)))
return sq_throwerror(v, "failed to get brightness");
light->brightness = brightness;
}
return 0;
}
static SQInteger lightConeDirection(HSQUIRRELVM v) {
warning("TODO: lightConeDirection not implemented");
Light *light = sqlight(v, 2);
if (light) {
float direction;
if (SQ_FAILED(sqget(v, 3, direction)))
return sq_throwerror(v, "failed to get direction");
light->coneDirection = direction;
}
return 0;
}
static SQInteger lightConeAngle(HSQUIRRELVM v) {
warning("TODO: lightConeAngle not implemented");
Light *light = sqlight(v, 2);
if (light) {
float angle;
if (SQ_FAILED(sqget(v, 3, angle)))
return sq_throwerror(v, "failed to get angle");
light->coneAngle = angle;
}
return 0;
}
static SQInteger lightConeFalloff(HSQUIRRELVM v) {
warning("TODO: lightConeFalloff not implemented");
Light *light = sqlight(v, 2);
if (light) {
float falloff;
if (SQ_FAILED(sqget(v, 3, falloff)))
return sq_throwerror(v, "failed to get falloff");
light->coneFalloff = falloff;
}
return 0;
}
static SQInteger lightCutOffRadius(HSQUIRRELVM v) {
warning("TODO: lightCutOffRadius not implemented");
Light *light = sqlight(v, 2);
if (light) {
float cutOffRadius;
if (SQ_FAILED(sqget(v, 3, cutOffRadius)))
return sq_throwerror(v, "failed to get cutOffRadius");
light->cutOffRadius = cutOffRadius;
}
return 0;
}
static SQInteger lightHalfRadius(HSQUIRRELVM v) {
warning("TODO: lightHalfRadius not implemented");
Light *light = sqlight(v, 2);
if (light) {
float halfRadius;
if (SQ_FAILED(sqget(v, 3, halfRadius)))
return sq_throwerror(v, "failed to get halfRadius");
light->halfRadius = halfRadius;
}
return 0;
}
static SQInteger lightTurnOn(HSQUIRRELVM v) {
warning("TODO: lightTurnOn not implemented");
Light *light = sqlight(v, 2);
if (light) {
bool on;
if (SQ_FAILED(sqget(v, 3, on)))
return sq_throwerror(v, "failed to get on");
light->on = on;
}
return 0;
}
static SQInteger lightZRange(HSQUIRRELVM v) {
warning("TODO: lightZRange not implemented");
Light *light = sqlight(v, 2);
if (light) {
int nearY, farY;
if (SQ_FAILED(sqget(v, 3, nearY)))
return sq_throwerror(v, "failed to get nearY");
if (SQ_FAILED(sqget(v, 4, farY)))
return sq_throwerror(v, "failed to get farY");
warning("lightZRange not implemented");
}
return 0;
}
@ -459,6 +510,14 @@ static SQInteger roomSize(HSQUIRRELVM v) {
return 1;
}
static SQInteger setAmbientLight(HSQUIRRELVM v) {
int c = 0;
if (SQ_FAILED(sqget(v, 2, c)))
return sq_throwerror(v, "failed to get color");
g_engine->_room->_lights._ambientLight = Color::rgb(c);
return 0;
}
// Sets walkbox to be hidden (YES) or not (NO).
// If the walkbox is hidden, the actors cannot walk to any point within that area anymore, nor to any walkbox that's connected to it on the other side from the actor.
// Often used on small walkboxes below a gate or door to keep the actor from crossing that boundary if the gate/door is closed.
@ -499,6 +558,7 @@ void sqgame_register_roomlib(HSQUIRRELVM v) {
regFunc(v, roomRotateTo, "roomRotateTo");
regFunc(v, roomSize, "roomSize");
regFunc(v, roomOverlayColor, "roomOverlayColor");
regFunc(v, setAmbientLight, _SC("setAmbientLight"));
regFunc(v, walkboxHidden, "walkboxHidden");
}
} // namespace Twp

View File

@ -28,6 +28,7 @@
#include "twp/gfx.h"
#include "twp/object.h"
#include "twp/util.h"
#include "twp/lighting.h"
namespace Twp {
@ -179,18 +180,22 @@ static int cmpNodes(const Node *x, const Node *y) {
return y->getZSort() < x->getZSort();
}
void Node::onDrawChildren(Math::Matrix4 trsf) {
Common::Array<Node *> children(_children);
Common::sort(children.begin(), children.end(), cmpNodes);
for (size_t i = 0; i < children.size(); i++) {
Node *child = children[i];
child->draw(trsf);
}
}
void Node::draw(Math::Matrix4 parent) {
if (_visible) {
Math::Matrix4 trsf = getTrsf(parent);
Math::Matrix4 myTrsf(trsf);
myTrsf.translate(Math::Vector3d(-_anchor.getX(), _anchor.getY(), 0.f));
Common::Array<Node *> children(_children);
Common::sort(children.begin(), children.end(), cmpNodes);
drawCore(myTrsf);
for (size_t i = 0; i < children.size(); i++) {
Node *child = children[i];
child->draw(trsf);
}
onDrawChildren(trsf);
}
}
@ -239,20 +244,37 @@ Math::Matrix4 ParallaxNode::getTrsf(Math::Matrix4 parentTrsf) {
return trsf;
}
void ParallaxNode::onDrawChildren(Math::Matrix4 trsf) {
Node::onDrawChildren(trsf);
}
void ParallaxNode::drawCore(Math::Matrix4 trsf) {
Gfx &gfx = g_engine->getGfx();
SpriteSheet *sheet = g_engine->_resManager.spriteSheet(_sheet);
Texture *texture = g_engine->_resManager.texture(sheet->meta.image);
// enable debug lighting
if (_zOrder == 0) {
g_engine->getGfx().use(g_engine->_lighting);
} else {
g_engine->getGfx().use(nullptr);
}
Math::Matrix4 t = trsf;
float x = 0.f;
for (size_t i = 0; i < _frames.size(); i++) {
const SpriteSheetFrame &frame = sheet->frameTable[_frames[i]];
g_engine->_lighting->setSpriteOffset({0.f, static_cast<float>(-frame.frame.height())});
g_engine->_lighting->setSpriteSheetFrame(frame, *texture);
Math::Matrix4 myTrsf = t;
myTrsf.translate(Math::Vector3d(x + frame.spriteSourceSize.left, frame.sourceSize.getY() - frame.spriteSourceSize.height() - frame.spriteSourceSize.top, 0.0f));
gfx.drawSprite(frame.frame, *texture, getColor(), myTrsf);
t = trsf;
x += frame.frame.width();
}
g_engine->getGfx().use(nullptr);
}
Anim::Anim(Object *obj)
@ -360,7 +382,16 @@ void Anim::drawCore(Math::Matrix4 trsf) {
float y = 0.5f * (sf.sourceSize.getY()) - sf.spriteSourceSize.height() - sf.spriteSourceSize.top;
Math::Vector3d pos(int(-x), int(y), 0.f);
trsf.translate(pos);
if (_obj->_lit) {
g_engine->getGfx().use(g_engine->_lighting);
Math::Vector2d p = getAbsPos();
g_engine->_lighting->setSpriteOffset({(flipX ? 0.f : -sf.frame.width()) + p.getX(), -sf.frame.height() - p.getY()});
g_engine->_lighting->setSpriteSheetFrame(sf, *texture);
} else {
g_engine->getGfx().use(nullptr);
}
g_engine->getGfx().drawSprite(sf.frame, *texture, getComputedColor(), trsf, flipX);
g_engine->getGfx().use(nullptr);
}
}
}

View File

@ -111,6 +111,7 @@ public:
void draw(Math::Matrix4 parent = Math::Matrix4());
protected:
virtual void onDrawChildren(Math::Matrix4 trsf);
virtual void onColorUpdated(Color c) {}
virtual void drawCore(Math::Matrix4 trsf) {}
@ -143,6 +144,7 @@ public:
Math::Matrix4 getTrsf(Math::Matrix4 parentTrsf) override final;
protected:
void onDrawChildren(Math::Matrix4 trsf) override;
void drawCore(Math::Matrix4 trsf) override final;
private:

View File

@ -19,6 +19,7 @@
*
*/
#include "twp/lighting.h"
#include "twp/squtil.h"
#include "twp/room.h"
#include "twp/object.h"
@ -421,6 +422,26 @@ ThreadBase *sqthread(int id) {
return nullptr;
}
Light *sqlight(int id) {
if(!g_engine->_room)
return nullptr;
for (size_t i = 0; i < MAX_LIGHTS; i++) {
Light *light = &g_engine->_room->_lights._lights[i];
if (light->id == id) {
return light;
}
}
return nullptr;
}
Light *sqlight(HSQUIRRELVM v, int i) {
int id;
if (SQ_SUCCEEDED(sqget(v, i, id)))
return sqlight(id);
return nullptr;
}
struct GetThread {
GetThread(HSQUIRRELVM v) : _v(v) {}
bool operator()(ThreadBase *t) {

View File

@ -172,6 +172,8 @@ SoundDefinition *sqsounddef(int id);
ThreadBase *sqthread(HSQUIRRELVM v);
ThreadBase *sqthread(HSQUIRRELVM v, int id);
ThreadBase *sqthread(int id);
Light *sqlight(int id);
Light *sqlight(HSQUIRRELVM v, int i);
template<typename... T>
void sqcall(HSQUIRRELVM v, HSQOBJECT o, const char *name, T... args) {

View File

@ -733,11 +733,6 @@ static SQInteger removeCallback(HSQUIRRELVM v) {
return 0;
}
static SQInteger setAmbientLight(HSQUIRRELVM v) {
warning("TODO: setAmbientLight: not implemented");
return 0;
}
static SQInteger startthread(HSQUIRRELVM v) {
return _startthread(v, false);
}
@ -847,7 +842,6 @@ void sqgame_register_syslib(HSQUIRRELVM v) {
regFunc(v, microTime, _SC("microTime"));
regFunc(v, moveCursorTo, _SC("moveCursorTo"));
regFunc(v, removeCallback, _SC("removeCallback"));
regFunc(v, setAmbientLight, _SC("setAmbientLight"));
regFunc(v, startglobalthread, _SC("startglobalthread"));
regFunc(v, startthread, _SC("startthread"));
regFunc(v, stopthread, _SC("stopthread"));

View File

@ -70,6 +70,7 @@ TwpEngine::TwpEngine(OSystem *syst, const ADGameDescription *gameDesc)
_screenScene.setName("Screen");
_scene.addChild(&_walkboxNode);
_screenScene.addChild(&_pathNode);
_screenScene.addChild(&_lightingNode);
_screenScene.addChild(&_hotspotMarker);
_screenScene.addChild(&_inputState);
_screenScene.addChild(&_sentence);
@ -605,6 +606,7 @@ void TwpEngine::draw(RenderTexture *outTexture) {
_gfx.setRenderTarget(&renderTexture2);
if (_room) {
setShaderEffect(_room->_effect);
_lighting->update(_room->_lights);
}
_shaderParams.randomValue[0] = g_engine->getRandom();
_shaderParams.timeLapse = fmodf(_time, 1000.f);
@ -714,7 +716,7 @@ Common::Error TwpEngine::run() {
_sepiaShader.init("sepia", vsrc, sepiaShader);
_fadeShader.reset(new FadeShader());
// _lighting = new Lighting();
_lighting = new Lighting();
_pack.init();
@ -861,6 +863,11 @@ Common::Error TwpEngine::run() {
_pathNode.setMode(mode);
}
break;
case Common::KEYCODE_l:
if (control) {
_lightingNode.setVisible(!_lightingNode.isVisible());
}
break;
default:
break;
}

View File

@ -231,6 +231,7 @@ private:
SentenceNode _sentence;
WalkboxNode _walkboxNode;
PathNode _pathNode;
LightingNode _lightingNode;
Shader _bwShader;
Shader _ghostShader;
Shader _sepiaShader;

View File

@ -21,6 +21,7 @@
#include "twp/twp.h"
#include "twp/walkboxnode.h"
#include "twp/lighting.h"
namespace Twp {
@ -47,7 +48,7 @@ void WalkboxNode::drawCore(Math::Matrix4 trsf) {
const Walkbox &wb = walkboxes[i];
const Color color = wb.isVisible() ? green : red;
Common::Array<Vertex> vertices;
const Common::Array<Vector2i>& points = wb.getPoints();
const Common::Array<Vector2i> &points = wb.getPoints();
for (uint j = 0; j < points.size(); j++) {
Vector2i pInt = points[j];
Math::Vector2d p = (Math::Vector2d)pInt;
@ -69,7 +70,7 @@ void WalkboxNode::drawCore(Math::Matrix4 trsf) {
const Walkbox &wb = walkboxes[i];
const Color color = i == 0 ? green : red;
Common::Array<Vertex> vertices;
const Common::Array<Vector2i>& points = wb.getPoints();
const Common::Array<Vector2i> &points = wb.getPoints();
for (uint j = 0; j < points.size(); j++) {
Vector2i pInt = points[j];
Math::Vector2d p = (Math::Vector2d)pInt;
@ -138,7 +139,7 @@ void PathNode::drawCore(Math::Matrix4 trsf) {
}
// draw graph nodes
const Twp::Graph& graph = g_engine->_room->_pathFinder.getGraph();
const Twp::Graph &graph = g_engine->_room->_pathFinder.getGraph();
if (((_mode == PathMode::GraphMode) || (_mode == PathMode::All))) {
for (uint i = 0; i < graph._concaveVertices.size(); i++) {
const Math::Vector2d p = g_engine->roomToScreen((Math::Vector2d)graph._concaveVertices[i]) - Math::Vector2d(2.f, 2.f);
@ -195,7 +196,7 @@ void PathNode::drawCore(Math::Matrix4 trsf) {
// draw a green square if inside walkbox, red if not
Common::Array<Walkbox> walkboxes = g_engine->_room ? g_engine->_room->_pathFinder.getWalkboxes() : Common::Array<Walkbox>();
if(walkboxes.empty())
if (walkboxes.empty())
return;
const bool inside = (walkboxes.size() > 0) && walkboxes[0].contains((Vector2i)roomPos);
@ -207,9 +208,28 @@ void PathNode::drawCore(Math::Matrix4 trsf) {
// draw a blue square on the closest point
pos = g_engine->roomToScreen((Math::Vector2d)walkboxes[0].getClosestPointOnEdge((Vector2i)roomPos));
t = Math::Matrix4();
t.translate(Math::Vector3d(pos.getX()-2.f, pos.getY()-2.f, 0.f));
t.translate(Math::Vector3d(pos.getX() - 2.f, pos.getY() - 2.f, 0.f));
g_engine->getGfx().drawQuad(Math::Vector2d(4.f, 4.f), blue, t);
}
}
LightingNode::LightingNode() : Node("Lighting") {
setVisible(false);
}
void LightingNode::drawCore(Math::Matrix4 trsf) {
if (!g_engine->_room)
return;
const float size = 6.0f;
for (int i = 0; i < MAX_LIGHTS; i++) {
float *pos = &g_engine->_lighting->u_lightPos[i * 3];
float *color = &g_engine->_lighting->u_lightColor[i * 3];
Math::Vector2d p = g_engine->roomToScreen(Math::Vector2d(pos[0], pos[1]));
Math::Matrix4 t;
t.translate(Math::Vector3d(p.getX() - size / 2.f, p.getY() - size / 2.f, 0.f));
g_engine->getGfx().drawQuad(Math::Vector2d(size, size), Color(color[0], color[1], color[2]), t);
}
}
} // namespace Twp

View File

@ -67,6 +67,14 @@ private:
PathMode _mode = PathMode::None;
};
class LightingNode : public Node {
public:
LightingNode();
private:
virtual void drawCore(Math::Matrix4 trsf) override;
};
} // namespace Twp
#endif