mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-06 13:16:52 +02:00
#23 improve shadows quality; shader and lighting refactoring; fix muzzle flash alpha; increase light radius by 2; #15 WebGL version on Safari/Edge fix audio and shadows support
This commit is contained in:
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
31
src/core.h
31
src/core.h
@@ -67,6 +67,7 @@
|
|||||||
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
|
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
|
||||||
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
|
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
|
||||||
PFNGLUNIFORM1IVPROC glUniform1iv;
|
PFNGLUNIFORM1IVPROC glUniform1iv;
|
||||||
|
PFNGLUNIFORM1FVPROC glUniform1fv;
|
||||||
PFNGLUNIFORM2FVPROC glUniform2fv;
|
PFNGLUNIFORM2FVPROC glUniform2fv;
|
||||||
PFNGLUNIFORM3FVPROC glUniform3fv;
|
PFNGLUNIFORM3FVPROC glUniform3fv;
|
||||||
PFNGLUNIFORM4FVPROC glUniform4fv;
|
PFNGLUNIFORM4FVPROC glUniform4fv;
|
||||||
@@ -86,9 +87,9 @@
|
|||||||
// Render to texture
|
// Render to texture
|
||||||
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
|
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
|
||||||
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
|
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
|
||||||
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
|
|
||||||
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
|
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
|
||||||
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
|
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
|
||||||
|
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
|
||||||
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
|
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
|
||||||
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
|
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
|
||||||
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
|
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
|
||||||
@@ -190,6 +191,7 @@ namespace Core {
|
|||||||
GetProcOGL(glGetShaderInfoLog);
|
GetProcOGL(glGetShaderInfoLog);
|
||||||
GetProcOGL(glGetUniformLocation);
|
GetProcOGL(glGetUniformLocation);
|
||||||
GetProcOGL(glUniform1iv);
|
GetProcOGL(glUniform1iv);
|
||||||
|
GetProcOGL(glUniform1fv);
|
||||||
GetProcOGL(glUniform2fv);
|
GetProcOGL(glUniform2fv);
|
||||||
GetProcOGL(glUniform3fv);
|
GetProcOGL(glUniform3fv);
|
||||||
GetProcOGL(glUniform4fv);
|
GetProcOGL(glUniform4fv);
|
||||||
@@ -209,9 +211,9 @@ namespace Core {
|
|||||||
|
|
||||||
GetProcOGL(glGenFramebuffers);
|
GetProcOGL(glGenFramebuffers);
|
||||||
GetProcOGL(glBindFramebuffer);
|
GetProcOGL(glBindFramebuffer);
|
||||||
GetProcOGL(glFramebufferTexture2D);
|
|
||||||
GetProcOGL(glGenRenderbuffers);
|
GetProcOGL(glGenRenderbuffers);
|
||||||
GetProcOGL(glBindRenderbuffer);
|
GetProcOGL(glBindRenderbuffer);
|
||||||
|
GetProcOGL(glFramebufferTexture2D);
|
||||||
GetProcOGL(glFramebufferRenderbuffer);
|
GetProcOGL(glFramebufferRenderbuffer);
|
||||||
GetProcOGL(glRenderbufferStorage);
|
GetProcOGL(glRenderbufferStorage);
|
||||||
GetProcOGL(glCheckFramebufferStatus);
|
GetProcOGL(glCheckFramebufferStatus);
|
||||||
@@ -227,18 +229,22 @@ namespace Core {
|
|||||||
//LOG("%s\n", ext);
|
//LOG("%s\n", ext);
|
||||||
support.depthTexture = extSupport(ext, "_depth_texture");
|
support.depthTexture = extSupport(ext, "_depth_texture");
|
||||||
support.shadowSampler = extSupport(ext, "EXT_shadow_samplers") || extSupport(ext, "GL_ARB_shadow");
|
support.shadowSampler = extSupport(ext, "EXT_shadow_samplers") || extSupport(ext, "GL_ARB_shadow");
|
||||||
support.VAO = (void*)glBindVertexArray != NULL;
|
support.VAO = extSupport(ext, "_vertex_array_object");
|
||||||
|
|
||||||
LOG("Vendor : %s\n", glGetString(GL_VENDOR));
|
char *vendor = (char*)glGetString(GL_VENDOR);
|
||||||
|
LOG("Vendor : %s\n", vendor);
|
||||||
LOG("Renderer : %s\n", glGetString(GL_RENDERER));
|
LOG("Renderer : %s\n", glGetString(GL_RENDERER));
|
||||||
LOG("Version : %s\n", glGetString(GL_VERSION));
|
LOG("Version : %s\n", glGetString(GL_VERSION));
|
||||||
|
|
||||||
LOG("supports:\n");
|
LOG("supports:\n");
|
||||||
LOG(" depth texture : %s\n", support.depthTexture ? "true" : "false");
|
LOG(" depth texture : %s\n", support.depthTexture ? "true" : "false");
|
||||||
LOG(" shadow sampler : %s\n", support.shadowSampler ? "true" : "false");
|
LOG(" shadow sampler : %s\n", support.shadowSampler ? "true" : "false");
|
||||||
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false");
|
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false");
|
||||||
LOG("\n");
|
LOG("\n");
|
||||||
|
|
||||||
|
// if (strcmp(vendor, "WebKit") == 0) // TODO: check for safari
|
||||||
|
// support.depthTexture = support.shadowSampler = false; // depth textures is not supported in Safari browser in fact :(
|
||||||
|
|
||||||
glGenFramebuffers(1, &RT);
|
glGenFramebuffers(1, &RT);
|
||||||
|
|
||||||
Sound::init();
|
Sound::init();
|
||||||
@@ -254,7 +260,7 @@ namespace Core {
|
|||||||
|
|
||||||
void clear(const vec4 &color) {
|
void clear(const vec4 &color) {
|
||||||
glClearColor(color.x, color.y, color.z, color.w);
|
glClearColor(color.x, color.y, color.z, color.w);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setViewport(int x, int y, int width, int height) {
|
void setViewport(int x, int y, int width, int height) {
|
||||||
@@ -303,15 +309,18 @@ namespace Core {
|
|||||||
void setTarget(Texture *target) {
|
void setTarget(Texture *target) {
|
||||||
if (!target) {
|
if (!target) {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glColorMask(true, true, true, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, RT);
|
glBindFramebuffer(GL_FRAMEBUFFER, RT);
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target->ID, 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target->ID, 0);
|
||||||
glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
|
glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, target->dummy ? target->dummy->ID : 0, 0);
|
||||||
|
|
||||||
GLenum buffers[] = { GL_COLOR_ATTACHMENT0 };
|
bool mask = !target->depth;
|
||||||
glDrawBuffers(target->depth ? 0 : 1, buffers);
|
glColorMask(mask, mask, mask, mask);
|
||||||
|
// GLenum buffers[] = { GL_COLOR_ATTACHMENT0 };
|
||||||
|
// glDrawBuffers(target->depth ? 0 : 1, buffers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -350,7 +350,7 @@ namespace Debug {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lights(const TR::Level &level) {
|
void lights(const TR::Level &level, int room) {
|
||||||
// int roomIndex = level.entities[lara->entity].room;
|
// int roomIndex = level.entities[lara->entity].room;
|
||||||
// int lightIndex = getLightIndex(lara->pos, roomIndex);
|
// int lightIndex = getLightIndex(lara->pos, roomIndex);
|
||||||
|
|
||||||
@@ -361,10 +361,12 @@ namespace Debug {
|
|||||||
float a = l.intensity / 8191.0f;
|
float a = l.intensity / 8191.0f;
|
||||||
vec3 p = vec3(l.x, l.y, l.z);
|
vec3 p = vec3(l.x, l.y, l.z);
|
||||||
vec4 color = vec4(a, a, a, 1);
|
vec4 color = vec4(a, a, a, 1);
|
||||||
|
if (i == room) color.x = color.z = 0;
|
||||||
Debug::Draw::point(p, color);
|
Debug::Draw::point(p, color);
|
||||||
//if (i == roomIndex && j == lightIndex)
|
//if (i == roomIndex && j == lightIndex)
|
||||||
// color = vec4(0, 1, 0, 1);
|
// color = vec4(0, 1, 0, 1);
|
||||||
Debug::Draw::sphere(p, l.attenuation, color);
|
Debug::Draw::sphere(p, l.radius, color);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -271,7 +271,7 @@ namespace TR {
|
|||||||
int32 x, y, z;
|
int32 x, y, z;
|
||||||
uint16 align; // ! not exists in file !
|
uint16 align; // ! not exists in file !
|
||||||
uint16 intensity;
|
uint16 intensity;
|
||||||
uint32 attenuation;
|
uint32 radius;
|
||||||
} *lights;
|
} *lights;
|
||||||
|
|
||||||
struct Mesh {
|
struct Mesh {
|
||||||
@@ -924,7 +924,9 @@ namespace TR {
|
|||||||
light.intensity = stream.read(intensity);
|
light.intensity = stream.read(intensity);
|
||||||
} else
|
} else
|
||||||
stream.read(light.intensity);
|
stream.read(light.intensity);
|
||||||
stream.read(light.attenuation);
|
stream.read(light.radius);
|
||||||
|
|
||||||
|
light.radius *= 2;
|
||||||
}
|
}
|
||||||
// meshes
|
// meshes
|
||||||
r.meshes = new Room::Mesh[stream.read(r.meshesCount)];
|
r.meshes = new Room::Mesh[stream.read(r.meshesCount)];
|
||||||
@@ -1107,7 +1109,6 @@ namespace TR {
|
|||||||
stream.read(c.x);
|
stream.read(c.x);
|
||||||
stream.read(c.y);
|
stream.read(c.y);
|
||||||
stream.read(c.z);
|
stream.read(c.z);
|
||||||
c.w = 0;
|
|
||||||
}
|
}
|
||||||
int16 nCount;
|
int16 nCount;
|
||||||
stream.read(nCount);
|
stream.read(nCount);
|
||||||
@@ -1120,6 +1121,7 @@ namespace TR {
|
|||||||
stream.read(n.y);
|
stream.read(n.y);
|
||||||
stream.read(n.z);
|
stream.read(n.z);
|
||||||
n.w = 1;
|
n.w = 1;
|
||||||
|
c.w = 0x1FFF;
|
||||||
} else { // intensity
|
} else { // intensity
|
||||||
stream.read(c.w);
|
stream.read(c.w);
|
||||||
n = { 0, 0, 0, 0 };
|
n = { 0, 0, 0, 0 };
|
||||||
@@ -1173,6 +1175,7 @@ namespace TR {
|
|||||||
if (nCount > 0) { // normal
|
if (nCount > 0) { // normal
|
||||||
stream.read(n);
|
stream.read(n);
|
||||||
n.w = 1;
|
n.w = 1;
|
||||||
|
c.w = 0x1FFF;
|
||||||
} else { // intensity
|
} else { // intensity
|
||||||
stream.read(c.w);
|
stream.read(c.w);
|
||||||
n = { 0, 0, 0, 0 };
|
n = { 0, 0, 0, 0 };
|
||||||
|
@@ -1733,6 +1733,7 @@ struct Lara : Character {
|
|||||||
mat4 m(matrix);
|
mat4 m(matrix);
|
||||||
m.rotateX(-PI * 0.5f);
|
m.rotateX(-PI * 0.5f);
|
||||||
m.translate(offset);
|
m.translate(offset);
|
||||||
|
|
||||||
Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha));
|
Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha));
|
||||||
renderMesh(m, mesh, level->extra.muzzleFlash->mStart);
|
renderMesh(m, mesh, level->extra.muzzleFlash->mStart);
|
||||||
}
|
}
|
||||||
@@ -1741,10 +1742,12 @@ struct Lara : Character {
|
|||||||
Controller::render(frustum, mesh);
|
Controller::render(frustum, mesh);
|
||||||
chestOffset = animation.getJoints(getMatrix(), 7).getPos(); // TODO: move to update func
|
chestOffset = animation.getJoints(getMatrix(), 7).getPos(); // TODO: move to update func
|
||||||
|
|
||||||
if (wpnCurrent != Weapon::SHOTGUN && Core::pass != Core::passShadow) {
|
if (wpnCurrent != Weapon::SHOTGUN && Core::pass != Core::passShadow && (arms[0].shotTimer < MUZZLE_FLASH_TIME || arms[1].shotTimer < MUZZLE_FLASH_TIME)) {
|
||||||
mat4 matrix = getMatrix();
|
mat4 matrix = getMatrix();
|
||||||
|
Core::active.shader->setParam(uType, Shader::FLASH);
|
||||||
renderMuzzleFlash(mesh, animation.getJoints(matrix, 10, true), vec3(-10, -50, 150), arms[0].shotTimer);
|
renderMuzzleFlash(mesh, animation.getJoints(matrix, 10, true), vec3(-10, -50, 150), arms[0].shotTimer);
|
||||||
renderMuzzleFlash(mesh, animation.getJoints(matrix, 13, true), vec3( 10, -50, 150), arms[1].shotTimer);
|
renderMuzzleFlash(mesh, animation.getJoints(matrix, 13, true), vec3( 10, -50, 150), arms[1].shotTimer);
|
||||||
|
Core::active.shader->setParam(uType, Shader::ENTITY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
174
src/level.h
174
src/level.h
@@ -22,7 +22,7 @@ const char GUI[] =
|
|||||||
;
|
;
|
||||||
|
|
||||||
struct Level {
|
struct Level {
|
||||||
enum { shStatic, shCaustics, shSprite, shShadowOpaque, shShadowSprite, shGUI, shMAX };
|
enum { shDefault, shShadow, shGUI, shMAX };
|
||||||
|
|
||||||
TR::Level level;
|
TR::Level level;
|
||||||
Shader *shaders[shMAX];
|
Shader *shaders[shMAX];
|
||||||
@@ -34,9 +34,8 @@ struct Level {
|
|||||||
Texture *shadow;
|
Texture *shadow;
|
||||||
|
|
||||||
float time;
|
float time;
|
||||||
bool perspShadows;
|
|
||||||
|
|
||||||
Level(const char *name, bool demo, bool home) : level(name, demo), lara(NULL), time(0.0f), perspShadows(false) {
|
Level(const char *name, bool demo, bool home) : level(name, demo), lara(NULL), time(0.0f) {
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
Debug::init();
|
Debug::init();
|
||||||
#endif
|
#endif
|
||||||
@@ -215,17 +214,10 @@ struct Level {
|
|||||||
else
|
else
|
||||||
strcat(ext, "#define SHADOW_COLOR\n");
|
strcat(ext, "#define SHADOW_COLOR\n");
|
||||||
|
|
||||||
sprintf(def, "%s#define PASS_SHADOW\n", ext);
|
|
||||||
shaders[shShadowOpaque] = new Shader(SHADER, def);
|
|
||||||
strcat(def, "#define SPRITE\n");
|
|
||||||
shaders[shShadowSprite] = new Shader(SHADER, def);
|
|
||||||
|
|
||||||
sprintf(def, "%s#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define MAX_SHADOW_DIST %d.0\n", ext, MAX_LIGHTS, mesh->animTexRangesCount, mesh->animTexOffsetsCount, MAX_SHADOW_DIST);
|
sprintf(def, "%s#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define MAX_SHADOW_DIST %d.0\n", ext, MAX_LIGHTS, mesh->animTexRangesCount, mesh->animTexOffsetsCount, MAX_SHADOW_DIST);
|
||||||
shaders[shStatic] = new Shader(SHADER, def);
|
shaders[shDefault] = new Shader(SHADER, def);
|
||||||
sprintf(ext, "%s#define CAUSTICS\n", def);
|
sprintf(def, "%s#define PASS_SHADOW\n", ext);
|
||||||
shaders[shCaustics] = new Shader(SHADER, ext);
|
shaders[shShadow] = new Shader(SHADER, def);
|
||||||
sprintf(ext, "%s#define SPRITE\n", def);
|
|
||||||
shaders[shSprite] = new Shader(SHADER, ext);
|
|
||||||
sprintf(ext, "%s#define SPRITE\n", def);
|
sprintf(ext, "%s#define SPRITE\n", def);
|
||||||
shaders[shGUI] = new Shader(GUI, "");
|
shaders[shGUI] = new Shader(GUI, "");
|
||||||
}
|
}
|
||||||
@@ -331,17 +323,21 @@ struct Level {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Shader *setRoomShader(const TR::Room &room, float intensity) {
|
void setRoomShader(const TR::Room &room, float intensity) {
|
||||||
if (Core::pass == Core::passShadow)
|
if (Core::pass == Core::passShadow) {
|
||||||
return shaders[shShadowOpaque];
|
shaders[shShadow]->bind();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shaders[shDefault]->bind();
|
||||||
if (room.flags.water) {
|
if (room.flags.water) {
|
||||||
Core::color = vec4(0.6f, 0.9f, 0.9f, intensity);
|
Core::color = vec4(0.6f, 0.9f, 0.9f, intensity);
|
||||||
return shaders[shCaustics];
|
Core::active.shader->setParam(uCaustics, 1);
|
||||||
} else {
|
} else {
|
||||||
Core::color = vec4(1.0f, 1.0f, 1.0f, intensity);
|
Core::color = vec4(1.0f, 1.0f, 1.0f, intensity);
|
||||||
return shaders[shStatic];
|
Core::active.shader->setParam(uCaustics, 0);
|
||||||
}
|
}
|
||||||
|
Core::active.shader->setParam(uColor, Core::color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderRoom(int roomIndex, int from = -1) {
|
void renderRoom(int roomIndex, int from = -1) {
|
||||||
@@ -351,14 +347,13 @@ struct Level {
|
|||||||
TR::Room &room = level.rooms[roomIndex];
|
TR::Room &room = level.rooms[roomIndex];
|
||||||
vec3 offset = vec3(float(room.info.x), 0.0f, float(room.info.z));
|
vec3 offset = vec3(float(room.info.x), 0.0f, float(room.info.z));
|
||||||
|
|
||||||
Shader *sh = setRoomShader(room, 1.0f);
|
setRoomShader(room, intensityf(room.ambient));
|
||||||
|
Shader *sh = Core::active.shader;
|
||||||
|
|
||||||
Core::lightColor[0] = vec4(0, 0, 0, 1);
|
Core::lightColor[0] = vec4(0, 0, 0, 1);
|
||||||
// glDisable(GL_CULL_FACE);
|
sh->setParam(uType, Shader::ROOM);
|
||||||
sh->bind();
|
|
||||||
sh->setParam(uColor, Core::color);
|
|
||||||
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
||||||
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
||||||
|
|
||||||
// room static meshes
|
// room static meshes
|
||||||
if (Core::pass != Core::passShadow)
|
if (Core::pass != Core::passShadow)
|
||||||
@@ -379,8 +374,8 @@ struct Level {
|
|||||||
continue;
|
continue;
|
||||||
rMesh.flags.rendered = true;
|
rMesh.flags.rendered = true;
|
||||||
|
|
||||||
Core::color.w = intensityf(rMesh.intensity == -1 ? room.ambient : rMesh.intensity);
|
//Core::color.w = intensityf(rMesh.intensity);//intensityf(rMesh.intensity == -1 ? room.ambient : rMesh.intensity);
|
||||||
sh->setParam(uColor, Core::color);
|
//sh->setParam(uColor, Core::color);
|
||||||
|
|
||||||
// render static mesh
|
// render static mesh
|
||||||
mat4 mTemp = Core::mModel;
|
mat4 mTemp = Core::mModel;
|
||||||
@@ -396,29 +391,20 @@ struct Level {
|
|||||||
mat4 mTemp = Core::mModel;
|
mat4 mTemp = Core::mModel;
|
||||||
room.flags.rendered = true;
|
room.flags.rendered = true;
|
||||||
|
|
||||||
Core::lightColor[0] = vec4(0, 0, 0, 1);
|
|
||||||
|
|
||||||
Core::mModel.translate(offset);
|
Core::mModel.translate(offset);
|
||||||
|
|
||||||
// render room geometry
|
|
||||||
sh->setParam(uModel, Core::mModel);
|
sh->setParam(uModel, Core::mModel);
|
||||||
|
|
||||||
|
// render room geometry
|
||||||
if (Core::pass == Core::passOpaque) {
|
if (Core::pass == Core::passOpaque) {
|
||||||
Core::color.w = intensityf(room.ambient);
|
|
||||||
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
|
||||||
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
|
||||||
sh->setParam(uColor, Core::color);
|
|
||||||
mesh->renderRoomGeometry(roomIndex);
|
mesh->renderRoomGeometry(roomIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// render room sprites
|
// render room sprites
|
||||||
if (mesh->hasRoomSprites(roomIndex) && Core::pass != Core::passShadow) {
|
if (mesh->hasRoomSprites(roomIndex) && Core::pass != Core::passShadow) {
|
||||||
sh = shaders[Core::pass == Core::passShadow ? shShadowSprite : shSprite];
|
Core::color.w = 1.0;
|
||||||
sh->bind();
|
sh->setParam(uType, Shader::SPRITE);
|
||||||
Core::color.w = 1.0f;
|
sh->setParam(uColor, Core::color);
|
||||||
sh->setParam(uModel, Core::mModel);
|
|
||||||
sh->setParam(uColor, Core::color);
|
|
||||||
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
|
||||||
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
|
||||||
mesh->renderRoomSprites(roomIndex);
|
mesh->renderRoomSprites(roomIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,32 +439,14 @@ struct Level {
|
|||||||
camera->frustum = camFrustum; // pop camera frustum
|
camera->frustum = camFrustum; // pop camera frustum
|
||||||
}
|
}
|
||||||
|
|
||||||
int getLightIndex(const vec3 &pos, int &room) {
|
int getLightIndex(const vec3 &pos, int &room, float maxAtt = -1.0f, int depth = 0) {
|
||||||
int idx = -1;
|
|
||||||
float dist;
|
|
||||||
// for (int j = 0; j < level.roomsCount; j++)
|
|
||||||
int j = room;
|
|
||||||
for (int i = 0; i < level.rooms[j].lightsCount; i++) {
|
|
||||||
TR::Room::Light &light = level.rooms[j].lights[i];
|
|
||||||
float d = (pos - vec3(float(light.x), float(light.y), float(light.z))).length2();
|
|
||||||
if (idx == -1 || d < dist) {
|
|
||||||
idx = i;
|
|
||||||
dist = d;
|
|
||||||
// room = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int getLightIndex2(const vec3 &pos, int &room, float maxAtt = -1.0f, int depth = 3) {
|
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
|
|
||||||
TR::Room &r = level.rooms[room];
|
TR::Room &r = level.rooms[room];
|
||||||
|
|
||||||
for (int i = 0; i < r.lightsCount; i++) {
|
for (int i = 0; i < r.lightsCount; i++) {
|
||||||
TR::Room::Light &light = r.lights[i];
|
TR::Room::Light &light = r.lights[i];
|
||||||
float att = max(0.0f, 1.0f - (pos - vec3(float(light.x), float(light.y), float(light.z))).length2() / ((float)light.attenuation * (float)light.attenuation));
|
float att = max(0.0f, 1.0f - (pos - vec3(float(light.x), float(light.y), float(light.z))).length2() / ((float)light.radius * (float)light.radius));
|
||||||
if (att > maxAtt) {
|
if (att > maxAtt) {
|
||||||
maxAtt = att;
|
maxAtt = att;
|
||||||
idx = i;
|
idx = i;
|
||||||
@@ -488,7 +456,7 @@ struct Level {
|
|||||||
if (depth > 0)
|
if (depth > 0)
|
||||||
for (int i = 0; i < r.portalsCount; i++) {
|
for (int i = 0; i < r.portalsCount; i++) {
|
||||||
int nextRoom = r.portals[i].roomIndex;
|
int nextRoom = r.portals[i].roomIndex;
|
||||||
int nextLight = getLightIndex2(pos, nextRoom, maxAtt, depth - 1);
|
int nextLight = getLightIndex(pos, nextRoom, maxAtt, depth - 1);
|
||||||
if (nextLight > -1) {
|
if (nextLight > -1) {
|
||||||
room = nextRoom;
|
room = nextRoom;
|
||||||
idx = nextLight;
|
idx = nextLight;
|
||||||
@@ -506,7 +474,7 @@ struct Level {
|
|||||||
TR::Room::Light &light = level.rooms[room].lights[idx];
|
TR::Room::Light &light = level.rooms[room].lights[idx];
|
||||||
float c = 1.0f - intensityf(level.rooms[room].lights[idx].intensity);
|
float c = 1.0f - intensityf(level.rooms[room].lights[idx].intensity);
|
||||||
Core::lightPos[0] = vec3(float(light.x), float(light.y), float(light.z));
|
Core::lightPos[0] = vec3(float(light.x), float(light.y), float(light.z));
|
||||||
Core::lightColor[0] = vec4(c, c, c, (float)light.attenuation * (float)light.attenuation);
|
Core::lightColor[0] = vec4(c, c, c, (float)light.radius * (float)light.radius);
|
||||||
} else {
|
} else {
|
||||||
Core::lightPos[0] = vec3(0);
|
Core::lightPos[0] = vec3(0);
|
||||||
Core::lightColor[0] = vec4(0, 0, 0, 1);
|
Core::lightColor[0] = vec4(0, 0, 0, 1);
|
||||||
@@ -525,19 +493,20 @@ struct Level {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
int16 lum = entity.intensity == -1 ? room.ambient : entity.intensity;
|
int16 lum = entity.intensity == -1 ? room.ambient : entity.intensity;
|
||||||
setRoomShader(room, sqrtf(intensityf(lum)))->bind();
|
setRoomShader(room, intensityf(lum));
|
||||||
|
|
||||||
if (entity.modelIndex > 0) // model
|
if (entity.modelIndex > 0) { // model
|
||||||
getLight(((Controller*)entity.controller)->pos, entity.room);
|
getLight(((Controller*)entity.controller)->pos, entity.room);
|
||||||
|
Core::active.shader->setParam(uType, Shader::ENTITY);
|
||||||
|
}
|
||||||
|
|
||||||
if (entity.modelIndex < 0) { // sprite
|
if (entity.modelIndex < 0) { // sprite
|
||||||
shaders[Core::pass == Core::passShadow ? shShadowSprite : shSprite]->bind();
|
Core::active.shader->setParam(uType, Shader::SPRITE);
|
||||||
Core::lightPos[0] = vec3(0);
|
Core::lightPos[0] = vec3(0);
|
||||||
Core::lightColor[0] = vec4(0, 0, 0, 1);
|
Core::lightColor[0] = vec4(0, 0, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::active.shader->setParam(uColor, Core::color);
|
Core::active.shader->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
||||||
Core::active.shader->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
|
||||||
Core::active.shader->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
Core::active.shader->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
||||||
|
|
||||||
((Controller*)entity.controller)->render(camera->frustum, mesh);
|
((Controller*)entity.controller)->render(camera->frustum, mesh);
|
||||||
@@ -555,16 +524,6 @@ struct Level {
|
|||||||
}
|
}
|
||||||
|
|
||||||
camera->update();
|
camera->update();
|
||||||
|
|
||||||
static bool tmpFlag = false;
|
|
||||||
|
|
||||||
if (Input::down[ikEnter]) {
|
|
||||||
if (!tmpFlag) {
|
|
||||||
perspShadows = !perspShadows;
|
|
||||||
tmpFlag = true;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
tmpFlag = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
@@ -581,25 +540,23 @@ struct Level {
|
|||||||
Core::active.shader = NULL;
|
Core::active.shader = NULL;
|
||||||
for (int i = 0; i < shMAX; i++) {
|
for (int i = 0; i < shMAX; i++) {
|
||||||
shaders[i]->bind();
|
shaders[i]->bind();
|
||||||
shaders[i]->setParam(uViewProj, Core::mViewProj);
|
shaders[i]->setParam(uViewProj, Core::mViewProj);
|
||||||
shaders[i]->setParam(uLightProj, Core::mLightProj);
|
shaders[i]->setParam(uLightProj, Core::mLightProj);
|
||||||
shaders[i]->setParam(uViewInv, Core::mViewInv);
|
shaders[i]->setParam(uViewInv, Core::mViewInv);
|
||||||
shaders[i]->setParam(uViewPos, Core::viewPos);
|
shaders[i]->setParam(uViewPos, Core::viewPos);
|
||||||
shaders[i]->setParam(uParam, vec4(time, 0, 0, 0));
|
shaders[i]->setParam(uTime, time);
|
||||||
shaders[i]->setParam(uLightTarget, lara->pos);
|
shaders[i]->setParam(uLightTarget, lara->pos);
|
||||||
shaders[i]->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
|
shaders[i]->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
|
||||||
shaders[i]->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
|
shaders[i]->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
|
||||||
}
|
}
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
Core::setCulling(cfFront);
|
|
||||||
|
|
||||||
Core::mModel.identity();
|
Core::mModel.identity();
|
||||||
|
|
||||||
// clear visible flags for rooms & static meshes
|
// clear visible flags for rooms & static meshes
|
||||||
for (int i = 0; i < level.roomsCount; i++) {
|
for (int i = 0; i < level.roomsCount; i++) {
|
||||||
TR::Room &room = level.rooms[i];
|
TR::Room &room = level.rooms[i];
|
||||||
room.flags.rendered = false; // clear visible flag for room geometry & sprites
|
room.flags.rendered = false; // clear visible flag for room geometry & sprites
|
||||||
|
|
||||||
for (int j = 0; j < room.meshesCount; j++)
|
for (int j = 0; j < room.meshesCount; j++)
|
||||||
room.meshes[j].flags.rendered = false; // clear visible flag for room static meshes
|
room.meshes[j].flags.rendered = false; // clear visible flag for room static meshes
|
||||||
@@ -621,7 +578,7 @@ struct Level {
|
|||||||
|
|
||||||
void renderEntities() {
|
void renderEntities() {
|
||||||
PROFILE_MARKER("ENTITIES");
|
PROFILE_MARKER("ENTITIES");
|
||||||
shaders[Core::pass == Core::passShadow ? shShadowOpaque : shStatic]->bind();
|
shaders[Core::pass == Core::passShadow ? shShadow : shDefault]->bind();
|
||||||
for (int i = 0; i < level.entitiesCount; i++)
|
for (int i = 0; i < level.entitiesCount; i++)
|
||||||
renderEntity(level.entities[i]);
|
renderEntity(level.entities[i]);
|
||||||
}
|
}
|
||||||
@@ -638,27 +595,13 @@ struct Level {
|
|||||||
|
|
||||||
// omni-spot light shadows
|
// omni-spot light shadows
|
||||||
int room = lara->getRoomIndex();
|
int room = lara->getRoomIndex();
|
||||||
int idx = getLightIndex2(lara->pos, room);
|
int idx = getLightIndex(lara->pos, room);
|
||||||
if (idx < 0) return false;
|
if (idx < 0) return false;
|
||||||
|
|
||||||
if (perspShadows) {
|
TR::Room::Light &light = level.rooms[room].lights[idx];
|
||||||
TR::Room::Light &light = level.rooms[room].lights[idx];
|
vec3 shadowLightPos = vec3(float(light.x), float(light.y), float(light.z));
|
||||||
vec3 lightPos = vec3(float(light.x), float(light.y), float(light.z));
|
Core::mView = mat4(shadowLightPos, pos - vec3(0, 256, 0), vec3(0, -1, 0)).inverse();
|
||||||
Core::mView = mat4(lightPos, pos - vec3(0, 256, 0), vec3(0, -1, 0)).inverse();
|
Core::mProj = mat4(120, 1.0f, camera->znear, camera->zfar);
|
||||||
Core::mProj = mat4(120, 1.0f, camera->znear, camera->zfar);
|
|
||||||
//Core::mProj.e22 /= camera->zfar;
|
|
||||||
//Core::mProj.e32 /= camera->zfar;
|
|
||||||
} else {
|
|
||||||
// fixed direct light shadows
|
|
||||||
float size = MAX_SHADOW_DIST;
|
|
||||||
float zfar = 8192.0f;
|
|
||||||
Core::mView = mat4(pos - vec3(1536, 4096, 1024), pos, vec3(1, 0, 0)).inverse();
|
|
||||||
Core::mProj = mat4(-size, size, -size, size, 0, zfar);
|
|
||||||
|
|
||||||
// Core::mProj.e22 /= zfar;
|
|
||||||
// Core::mProj.e23 /= zfar;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Core::mViewProj = Core::mProj * Core::mView;
|
Core::mViewProj = Core::mProj * Core::mView;
|
||||||
|
|
||||||
@@ -667,12 +610,7 @@ struct Level {
|
|||||||
bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f;
|
bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f;
|
||||||
Core::mLightProj = bias * Core::mProj * Core::mView; // * ( * ) ?
|
Core::mLightProj = bias * Core::mProj * Core::mView; // * ( * ) ?
|
||||||
|
|
||||||
Shader *sh = shaders[shShadowOpaque];
|
Shader *sh = shaders[shShadow];
|
||||||
sh->bind();
|
|
||||||
sh->setParam(uViewProj, Core::mViewProj);
|
|
||||||
sh->setParam(uLightProj, Core::mLightProj);
|
|
||||||
|
|
||||||
sh = shaders[shShadowSprite];
|
|
||||||
sh->bind();
|
sh->bind();
|
||||||
sh->setParam(uViewProj, Core::mViewProj);
|
sh->setParam(uViewProj, Core::mViewProj);
|
||||||
sh->setParam(uLightProj, Core::mLightProj);
|
sh->setParam(uLightProj, Core::mLightProj);
|
||||||
@@ -688,15 +626,17 @@ struct Level {
|
|||||||
Core::setBlending(bmNone);
|
Core::setBlending(bmNone);
|
||||||
Core::setTarget(shadow);
|
Core::setTarget(shadow);
|
||||||
Core::setViewport(0, 0, shadow->width, shadow->height);
|
Core::setViewport(0, 0, shadow->width, shadow->height);
|
||||||
Core::clear(vec4(1.0));
|
Core::clear(vec4(1.0));
|
||||||
|
Core::setCulling(cfBack);
|
||||||
renderScene();
|
renderScene();
|
||||||
|
Core::setCulling(cfFront);
|
||||||
Core::setTarget(NULL);
|
Core::setTarget(NULL);
|
||||||
shadow->bind(sShadow);
|
shadow->bind(sShadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void render() {
|
void render() {
|
||||||
renderShadows();
|
renderShadows();
|
||||||
|
|
||||||
Core::pass = Core::passOpaque;
|
Core::pass = Core::passOpaque;
|
||||||
Core::setBlending(bmAlpha);
|
Core::setBlending(bmAlpha);
|
||||||
Core::clear(vec4(0.0f));
|
Core::clear(vec4(0.0f));
|
||||||
@@ -733,7 +673,7 @@ struct Level {
|
|||||||
|
|
||||||
Debug::begin();
|
Debug::begin();
|
||||||
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||||
Debug::Level::lights(level);
|
Debug::Level::lights(level, lara->getRoomIndex());
|
||||||
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
|
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
|
||||||
// Debug::Level::portals(level);
|
// Debug::Level::portals(level);
|
||||||
// Debug::Level::meshes(level);
|
// Debug::Level::meshes(level);
|
||||||
|
@@ -9,7 +9,8 @@
|
|||||||
<script type='text/javascript'>
|
<script type='text/javascript'>
|
||||||
var statusElement = document.getElementById('status');
|
var statusElement = document.getElementById('status');
|
||||||
var canvasElement = document.getElementById('canvas');
|
var canvasElement = document.getElementById('canvas');
|
||||||
|
var proc;
|
||||||
|
|
||||||
var Module = {
|
var Module = {
|
||||||
TOTAL_MEMORY: 64*1024*1024,
|
TOTAL_MEMORY: 64*1024*1024,
|
||||||
preRun: [],
|
preRun: [],
|
||||||
@@ -52,7 +53,7 @@
|
|||||||
var rate = 44100 / ctx.sampleRate;
|
var rate = 44100 / ctx.sampleRate;
|
||||||
var framesCount = Math.ceil(count * rate);
|
var framesCount = Math.ceil(count * rate);
|
||||||
var frames = Module._malloc(framesCount * 4); // interleaved short L, R
|
var frames = Module._malloc(framesCount * 4); // interleaved short L, R
|
||||||
var proc = ctx.createScriptProcessor(count, 2, 2);
|
proc = ctx.createScriptProcessor(count, 2, 2);
|
||||||
proc.onaudioprocess = function(e) {
|
proc.onaudioprocess = function(e) {
|
||||||
var L = e.outputBuffer.getChannelData(0),
|
var L = e.outputBuffer.getChannelData(0),
|
||||||
R = e.outputBuffer.getChannelData(1);
|
R = e.outputBuffer.getChannelData(1);
|
||||||
|
138
src/shader.glsl
138
src/shader.glsl
@@ -2,14 +2,23 @@ R"====(
|
|||||||
varying vec2 vTexCoord;
|
varying vec2 vTexCoord;
|
||||||
|
|
||||||
#ifndef PASS_SHADOW
|
#ifndef PASS_SHADOW
|
||||||
varying vec4 vLightProj;
|
varying vec3 vCoord;
|
||||||
varying vec3 vCoord;
|
varying vec4 vNormal;
|
||||||
varying vec4 vNormal;
|
varying vec3 vViewVec;
|
||||||
varying vec3 vViewVec;
|
varying vec4 vColor;
|
||||||
varying vec4 vColor;
|
varying vec4 vLightProj;
|
||||||
varying float vLightTargetDist;
|
varying float vLightTargetDist;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define TYPE_SPRITE 0
|
||||||
|
#define TYPE_ROOM 1
|
||||||
|
#define TYPE_ENTITY 2
|
||||||
|
#define TYPE_FLASH 3
|
||||||
|
|
||||||
|
uniform int uType;
|
||||||
|
uniform int uCaustics;
|
||||||
|
uniform float uTime;
|
||||||
|
|
||||||
#ifdef VERTEX
|
#ifdef VERTEX
|
||||||
uniform mat4 uViewProj;
|
uniform mat4 uViewProj;
|
||||||
uniform mat4 uModel;
|
uniform mat4 uModel;
|
||||||
@@ -19,20 +28,16 @@ varying vec2 vTexCoord;
|
|||||||
|
|
||||||
#ifndef PASS_SHADOW
|
#ifndef PASS_SHADOW
|
||||||
uniform vec3 uViewPos;
|
uniform vec3 uViewPos;
|
||||||
|
uniform vec2 uAnimTexRanges[MAX_RANGES];
|
||||||
#ifndef SPRITE
|
uniform vec2 uAnimTexOffsets[MAX_OFFSETS];
|
||||||
uniform vec2 uAnimTexRanges[MAX_RANGES];
|
|
||||||
uniform vec2 uAnimTexOffsets[MAX_OFFSETS];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uniform vec4 uParam; // x - time
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
attribute vec4 aCoord;
|
attribute vec4 aCoord;
|
||||||
attribute vec4 aTexCoord;
|
attribute vec4 aTexCoord;
|
||||||
|
attribute vec4 aNormal;
|
||||||
|
|
||||||
#ifndef PASS_SHADOW
|
#ifndef PASS_SHADOW
|
||||||
attribute vec4 aNormal;
|
|
||||||
attribute vec4 aColor;
|
attribute vec4 aColor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -41,12 +46,13 @@ varying vec2 vTexCoord;
|
|||||||
void main() {
|
void main() {
|
||||||
vec4 coord = uModel * vec4(aCoord.xyz, 1.0);
|
vec4 coord = uModel * vec4(aCoord.xyz, 1.0);
|
||||||
|
|
||||||
#ifndef SPRITE
|
|
||||||
|
if (uType != TYPE_SPRITE) {
|
||||||
#ifndef PASS_SHADOW
|
#ifndef PASS_SHADOW
|
||||||
// animated texture coordinates
|
// animated texture coordinates
|
||||||
vec2 range = uAnimTexRanges[int(aTexCoord.z)]; // x - start index, y - count
|
vec2 range = uAnimTexRanges[int(aTexCoord.z)]; // x - start index, y - count
|
||||||
|
|
||||||
float f = fract((aTexCoord.w + uParam.x * 4.0 - range.x) / range.y) * range.y;
|
float f = fract((aTexCoord.w + uTime * 4.0 - range.x) / range.y) * range.y;
|
||||||
vec2 offset = uAnimTexOffsets[int(range.x + f)]; // texCoord offset from first frame
|
vec2 offset = uAnimTexOffsets[int(range.x + f)]; // texCoord offset from first frame
|
||||||
|
|
||||||
vTexCoord = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated
|
vTexCoord = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated
|
||||||
@@ -54,21 +60,21 @@ varying vec2 vTexCoord;
|
|||||||
#else
|
#else
|
||||||
vTexCoord = aTexCoord.xy * TEXCOORD_SCALE;
|
vTexCoord = aTexCoord.xy * TEXCOORD_SCALE;
|
||||||
#endif
|
#endif
|
||||||
#else
|
} else {
|
||||||
coord.xyz += uViewInv[0].xyz * aTexCoord.z - uViewInv[1].xyz * aTexCoord.w;
|
coord.xyz += uViewInv[0].xyz * aTexCoord.z - uViewInv[1].xyz * aTexCoord.w;
|
||||||
#ifndef PASS_SHADOW
|
#ifndef PASS_SHADOW
|
||||||
vTexCoord = aTexCoord.xy * TEXCOORD_SCALE;
|
vTexCoord = aTexCoord.xy * TEXCOORD_SCALE;
|
||||||
vNormal = vec4(uViewPos.xyz - coord.xyz, 0.0);
|
vNormal = vec4(uViewPos.xyz - coord.xyz, 0.0);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
}
|
||||||
|
|
||||||
#ifndef PASS_SHADOW
|
#ifndef PASS_SHADOW
|
||||||
vColor = aColor;
|
vColor = aColor;
|
||||||
|
|
||||||
#if defined(CAUSTICS)
|
if (uCaustics != 0) {
|
||||||
float sum = coord.x + coord.y + coord.z;
|
float sum = coord.x + coord.y + coord.z;
|
||||||
vColor.xyz *= abs(sin(sum / 512.0 + uParam.x)) * 1.5 + 0.5; // color dodge
|
vColor.xyz *= abs(sin(sum / 512.0 + uTime)) * 1.5 + 0.5; // color dodge
|
||||||
#endif
|
}
|
||||||
|
|
||||||
vViewVec = uViewPos - coord.xyz;
|
vViewVec = uViewPos - coord.xyz;
|
||||||
|
|
||||||
@@ -76,6 +82,7 @@ varying vec2 vTexCoord;
|
|||||||
vLightTargetDist = dot(dist, dist) / (MAX_SHADOW_DIST * MAX_SHADOW_DIST);
|
vLightTargetDist = dot(dist, dist) / (MAX_SHADOW_DIST * MAX_SHADOW_DIST);
|
||||||
|
|
||||||
vLightProj = uLightProj * coord;
|
vLightProj = uLightProj * coord;
|
||||||
|
|
||||||
vCoord = coord.xyz;
|
vCoord = coord.xyz;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -130,19 +137,32 @@ varying vec2 vTexCoord;
|
|||||||
#define CMP(a,b) float(a > b)
|
#define CMP(a,b) float(a > b)
|
||||||
|
|
||||||
#ifdef SHADOW_DEPTH
|
#ifdef SHADOW_DEPTH
|
||||||
#define SHADOW(V) CMP(texture2D(sShadow, (V).xy).x, p.z)
|
#define compare(p, z) CMP(texture2D(sShadow, (p)).x, (z));
|
||||||
#elif defined(SHADOW_COLOR)
|
#elif defined(SHADOW_COLOR)
|
||||||
float unpack(vec4 value) {
|
float unpack(vec4 value) {
|
||||||
vec4 bitSh = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);
|
vec4 bitSh = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);
|
||||||
return dot(value, bitSh);
|
return dot(value, bitSh);
|
||||||
}
|
}
|
||||||
#define SHADOW(V) CMP(unpack(texture2D(sShadow, (V).xy)), p.z)
|
#define compare(p, z) CMP(unpack(texture2D(sShadow, (p))), (z));
|
||||||
#else
|
|
||||||
#define SHADOW(v) 1.0
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
float SHADOW(vec3 p) {
|
||||||
|
vec2 t = vec2(0.0, 1.0 / 1024.0);
|
||||||
|
vec2 c = floor(p.xy * 1024.0 + 0.5) / 1024.0;
|
||||||
|
vec4 s;
|
||||||
|
s.x = compare(c + t.xx, p.z);
|
||||||
|
s.y = compare(c + t.xy, p.z);
|
||||||
|
s.z = compare(c + t.yx, p.z);
|
||||||
|
s.w = compare(c + t.yy, p.z);
|
||||||
|
vec2 f = fract(p.xy * 1024.0 + 0.5);
|
||||||
|
return mix(mix(s.x, s.y, f.y), mix(s.z, s.w, f.y), f.x);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float getShadow(vec4 lightProj) {
|
float getShadow(vec4 lightProj) {
|
||||||
|
vec3 p = lightProj.xyz / lightProj.w;
|
||||||
|
if (lightProj.w < 0.0) return 1.0;
|
||||||
|
|
||||||
vec2 poissonDisk[16];
|
vec2 poissonDisk[16];
|
||||||
poissonDisk[ 0] = vec2( -0.94201624, -0.39906216 );
|
poissonDisk[ 0] = vec2( -0.94201624, -0.39906216 );
|
||||||
poissonDisk[ 1] = vec2( 0.94558609, -0.76890725 );
|
poissonDisk[ 1] = vec2( 0.94558609, -0.76890725 );
|
||||||
@@ -160,21 +180,22 @@ varying vec2 vTexCoord;
|
|||||||
poissonDisk[13] = vec2( -0.81409955, 0.91437590 );
|
poissonDisk[13] = vec2( -0.81409955, 0.91437590 );
|
||||||
poissonDisk[14] = vec2( 0.19984126, 0.78641367 );
|
poissonDisk[14] = vec2( 0.19984126, 0.78641367 );
|
||||||
poissonDisk[15] = vec2( 0.14383161, -0.14100790 );
|
poissonDisk[15] = vec2( 0.14383161, -0.14100790 );
|
||||||
|
//return SHADOW(p);
|
||||||
vec3 p = lightProj.xyz / lightProj.w;
|
|
||||||
|
|
||||||
if (lightProj.w < 0.0) return 1.0;
|
|
||||||
|
|
||||||
float rShadow = 0.0;
|
float rShadow = 0.0;
|
||||||
for (int i = 0; i < 16; i += 1)
|
for (int i = 0; i < 16; i += 1)
|
||||||
rShadow += SHADOW(p + vec3(poissonDisk[i] * 2.0, 0.0) * (1.0 / 1024.0));
|
rShadow += SHADOW(p + vec3(poissonDisk[i] * 1.5, 0.0) * (1.0 / 1024.0));
|
||||||
rShadow /= 16.0;
|
rShadow /= 16.0;
|
||||||
|
|
||||||
rShadow = clamp(rShadow * 1.25, 0.0, 1.0); // apply contrast (1.25)
|
|
||||||
|
|
||||||
float fade = min(1.0, vLightTargetDist);
|
float fade = min(1.0, vLightTargetDist);
|
||||||
return mix(rShadow, 1.0, fade);
|
return mix(rShadow, 1.0, fade);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3 calcLight(vec3 normal, vec3 pos, vec4 color) {
|
||||||
|
vec3 lv = pos - vCoord.xyz;
|
||||||
|
float lum = max(0.0, dot(normal, normalize(lv)));
|
||||||
|
float att = max(0.0, 1.0 - dot(lv, lv) / color.w);
|
||||||
|
return color.xyz * (lum * att);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
@@ -183,16 +204,10 @@ varying vec2 vTexCoord;
|
|||||||
discard;
|
discard;
|
||||||
|
|
||||||
#ifdef PASS_SHADOW
|
#ifdef PASS_SHADOW
|
||||||
float dx = dFdx(gl_FragCoord.z);
|
|
||||||
float dy = dFdy(gl_FragCoord.z);
|
|
||||||
float bias = 4.0 * max(dx, dy);
|
|
||||||
float depth = gl_FragCoord.z + bias;
|
|
||||||
|
|
||||||
#ifdef SHADOW_COLOR
|
#ifdef SHADOW_COLOR
|
||||||
gl_FragColor = pack(depth);
|
gl_FragColor = pack(gl_FragCoord.z);
|
||||||
#else
|
#else
|
||||||
gl_FragColor = vec4(1.0);
|
gl_FragColor = vec4(1.0);
|
||||||
gl_FragDepth = depth;
|
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
color.xyz *= uColor.xyz;
|
color.xyz *= uColor.xyz;
|
||||||
@@ -201,32 +216,33 @@ varying vec2 vTexCoord;
|
|||||||
color.xyz = pow(abs(color.xyz), vec3(2.2)); // to linear space
|
color.xyz = pow(abs(color.xyz), vec3(2.2)); // to linear space
|
||||||
|
|
||||||
// calc point lights
|
// calc point lights
|
||||||
vec3 normal = normalize(vNormal.xyz);
|
if (uType != TYPE_FLASH) {
|
||||||
vec3 viewVec = normalize(vViewVec);
|
vec3 normal = normalize(vNormal.xyz);
|
||||||
vec3 light = vec3(0.0);
|
vec3 viewVec = normalize(vViewVec);
|
||||||
for (int i = 0; i < MAX_LIGHTS; i++) {
|
vec3 light = vec3(0.0);
|
||||||
vec3 lv = uLightPos[i] - vCoord.xyz;
|
|
||||||
vec4 lc = uLightColor[i];
|
for (int i = 1; i < MAX_LIGHTS; i++) // additional lights
|
||||||
float lum = max(0.0, dot(normal, normalize(lv)));
|
light += calcLight(normal, uLightPos[i], uLightColor[i]);
|
||||||
float att = max(0.0, 1.0 - dot(lv, lv) / lc.w);
|
|
||||||
light += lc.xyz * (lum * att);
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply lighting
|
// apply lighting
|
||||||
#ifdef SPRITE
|
if (uType == TYPE_SPRITE) {
|
||||||
color.xyz *= light + vColor.w;
|
light += vColor.w * uColor.w;
|
||||||
#else
|
}
|
||||||
float shadow = getShadow(vLightProj);
|
|
||||||
|
|
||||||
vec3 dlight = mix(vec3(uColor.w * uColor.w), light + uColor.w, shadow);
|
if (uType == TYPE_ROOM) {
|
||||||
dlight *= dot(normal, viewVec) * 0.5 + 0.5; // backlight
|
light += mix(min(uColor.w, vColor.w), vColor.w, getShadow(vLightProj));
|
||||||
|
}
|
||||||
vec3 slight = light + mix(uColor.w, vColor.w, shadow);
|
|
||||||
|
|
||||||
light = mix(slight, dlight, vNormal.w);
|
|
||||||
|
|
||||||
|
if (uType == TYPE_ENTITY) {
|
||||||
|
float shadow = getShadow(vLightProj);
|
||||||
|
vec3 lum = calcLight(normal, uLightPos[0], uLightColor[0]) * shadow + uColor.w;
|
||||||
|
light += lum;
|
||||||
|
light *= dot(normal, viewVec) * 0.2 + 0.8; // apply backlight
|
||||||
|
}
|
||||||
color.xyz *= light;
|
color.xyz *= light;
|
||||||
#endif
|
} else {
|
||||||
|
color.w = uColor.w;
|
||||||
|
}
|
||||||
|
|
||||||
color.xyz = pow(abs(color.xyz), vec3(1.0/2.2)); // back to gamma space
|
color.xyz = pow(abs(color.xyz), vec3(1.0/2.2)); // back to gamma space
|
||||||
|
|
||||||
|
22
src/shader.h
22
src/shader.h
@@ -5,22 +5,22 @@
|
|||||||
|
|
||||||
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
|
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
|
||||||
enum SamplerType { sDiffuse, sShadow, sMAX };
|
enum SamplerType { sDiffuse, sShadow, sMAX };
|
||||||
enum UniformType { uViewProj, uViewInv, uModel, uLightProj, uParam, uColor, uViewPos, uLightPos, uLightColor, uLightTarget, uAnimTexRanges, uAnimTexOffsets, uMAX };
|
enum UniformType { uType, uCaustics, uTime, uViewProj, uViewInv, uModel, uLightProj, uColor, uViewPos, uLightPos, uLightColor, uLightTarget, uAnimTexRanges, uAnimTexOffsets, uMAX };
|
||||||
|
|
||||||
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" };
|
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" };
|
||||||
const char *SamplerName[sMAX] = { "sDiffuse", "sShadow" };
|
const char *SamplerName[sMAX] = { "sDiffuse", "sShadow" };
|
||||||
const char *UniformName[uMAX] = { "uViewProj", "uViewInv", "uModel", "uLightProj", "uParam", "uColor", "uViewPos", "uLightPos", "uLightColor", "uLightTarget", "uAnimTexRanges", "uAnimTexOffsets" };
|
const char *UniformName[uMAX] = { "uType", "uCaustics", "uTime", "uViewProj", "uViewInv", "uModel", "uLightProj", "uColor", "uViewPos", "uLightPos", "uLightColor", "uLightTarget", "uAnimTexRanges", "uAnimTexOffsets" };
|
||||||
|
|
||||||
struct Shader {
|
struct Shader {
|
||||||
GLuint ID;
|
GLuint ID;
|
||||||
GLint uID[uMAX];
|
GLint uID[uMAX];
|
||||||
|
|
||||||
|
enum : GLint { SPRITE, ROOM, ENTITY, FLASH };
|
||||||
|
|
||||||
Shader(const char *text, const char *defines = "") {
|
Shader(const char *text, const char *defines = "") {
|
||||||
#ifdef MOBILE
|
#ifdef MOBILE
|
||||||
#define GLSL_DEFINE "#extension GL_EXT_frag_depth : enable\n"\
|
#define GLSL_DEFINE "#define MOBILE\n"\
|
||||||
"#extension GL_OES_standard_derivatives : enable\n"\
|
"precision highp int;\n"\
|
||||||
"#define MOBILE\n"\
|
|
||||||
"#define gl_FragDepth gl_FragDepthEXT\n"\
|
|
||||||
"precision highp float;\n"
|
"precision highp float;\n"
|
||||||
#else
|
#else
|
||||||
#define GLSL_DEFINE "#version 120\n"
|
#define GLSL_DEFINE "#version 120\n"
|
||||||
@@ -74,6 +74,16 @@ struct Shader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setParam(UniformType uType, const int &value, int count = 1) {
|
||||||
|
if (uID[uType] != -1)
|
||||||
|
glUniform1iv(uID[uType], count, (GLint*)&value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setParam(UniformType uType, const float &value, int count = 1) {
|
||||||
|
if (uID[uType] != -1)
|
||||||
|
glUniform1fv(uID[uType], count, (GLfloat*)&value);
|
||||||
|
}
|
||||||
|
|
||||||
void setParam(UniformType uType, const vec2 &value, int count = 1) {
|
void setParam(UniformType uType, const vec2 &value, int count = 1) {
|
||||||
if (uID[uType] != -1)
|
if (uID[uType] != -1)
|
||||||
glUniform2fv(uID[uType], count, (GLfloat*)&value);
|
glUniform2fv(uID[uType], count, (GLfloat*)&value);
|
||||||
|
@@ -407,7 +407,7 @@ double samples[28];
|
|||||||
int res = decoder->decode(&frames[i], count - i);
|
int res = decoder->decode(&frames[i], count - i);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
if (!(flags & Flags::LOOP)) {
|
if (!(flags & Flags::LOOP)) {
|
||||||
if (i == 0) isPlaying = false;
|
isPlaying = false;
|
||||||
break;
|
break;
|
||||||
} else
|
} else
|
||||||
decoder->replay();
|
decoder->replay();
|
||||||
|
@@ -4,11 +4,12 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
|
|
||||||
struct Texture {
|
struct Texture {
|
||||||
GLuint ID;
|
GLuint ID;
|
||||||
int width, height;
|
int width, height;
|
||||||
bool depth;
|
bool depth;
|
||||||
|
Texture *dummy;
|
||||||
|
|
||||||
Texture(int width, int height, bool depth, void *data = NULL) : width(width), height(height) {
|
Texture(int width, int height, bool depth, void *data = NULL) : width(width), height(height), dummy(NULL) {
|
||||||
glGenTextures(1, &ID);
|
glGenTextures(1, &ID);
|
||||||
bind(0);
|
bind(0);
|
||||||
|
|
||||||
@@ -33,9 +34,13 @@ struct Texture {
|
|||||||
|
|
||||||
GLint format = depth ? GL_DEPTH_COMPONENT : GL_RGBA;
|
GLint format = depth ? GL_DEPTH_COMPONENT : GL_RGBA;
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, depth ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE, data);
|
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, depth ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE, data);
|
||||||
|
|
||||||
|
if (depth)
|
||||||
|
dummy = new Texture(width, height, false, NULL); // some drivers can't render to texture without color target, create dummy color target for fix it
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Texture() {
|
virtual ~Texture() {
|
||||||
|
delete dummy;
|
||||||
glDeleteTextures(1, &ID);
|
glDeleteTextures(1, &ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user