mirror of
https://github.com/XProger/OpenLara.git
synced 2025-01-17 21:09:00 +01: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:
parent
b0b7034476
commit
77f40a95c8
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;
|
||||
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
|
||||
PFNGLUNIFORM1IVPROC glUniform1iv;
|
||||
PFNGLUNIFORM1FVPROC glUniform1fv;
|
||||
PFNGLUNIFORM2FVPROC glUniform2fv;
|
||||
PFNGLUNIFORM3FVPROC glUniform3fv;
|
||||
PFNGLUNIFORM4FVPROC glUniform4fv;
|
||||
@ -86,9 +87,9 @@
|
||||
// Render to texture
|
||||
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
|
||||
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
|
||||
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
|
||||
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
|
||||
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
|
||||
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
|
||||
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
|
||||
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
|
||||
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
|
||||
@ -190,6 +191,7 @@ namespace Core {
|
||||
GetProcOGL(glGetShaderInfoLog);
|
||||
GetProcOGL(glGetUniformLocation);
|
||||
GetProcOGL(glUniform1iv);
|
||||
GetProcOGL(glUniform1fv);
|
||||
GetProcOGL(glUniform2fv);
|
||||
GetProcOGL(glUniform3fv);
|
||||
GetProcOGL(glUniform4fv);
|
||||
@ -209,9 +211,9 @@ namespace Core {
|
||||
|
||||
GetProcOGL(glGenFramebuffers);
|
||||
GetProcOGL(glBindFramebuffer);
|
||||
GetProcOGL(glFramebufferTexture2D);
|
||||
GetProcOGL(glGenRenderbuffers);
|
||||
GetProcOGL(glBindRenderbuffer);
|
||||
GetProcOGL(glFramebufferTexture2D);
|
||||
GetProcOGL(glFramebufferRenderbuffer);
|
||||
GetProcOGL(glRenderbufferStorage);
|
||||
GetProcOGL(glCheckFramebufferStatus);
|
||||
@ -227,18 +229,22 @@ namespace Core {
|
||||
//LOG("%s\n", ext);
|
||||
support.depthTexture = extSupport(ext, "_depth_texture");
|
||||
support.shadowSampler = extSupport(ext, "EXT_shadow_samplers") || extSupport(ext, "GL_ARB_shadow");
|
||||
support.VAO = (void*)glBindVertexArray != NULL;
|
||||
|
||||
LOG("Vendor : %s\n", glGetString(GL_VENDOR));
|
||||
support.VAO = extSupport(ext, "_vertex_array_object");
|
||||
|
||||
char *vendor = (char*)glGetString(GL_VENDOR);
|
||||
LOG("Vendor : %s\n", vendor);
|
||||
LOG("Renderer : %s\n", glGetString(GL_RENDERER));
|
||||
LOG("Version : %s\n", glGetString(GL_VERSION));
|
||||
|
||||
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(" vertex arrays : %s\n", support.VAO ? "true" : "false");
|
||||
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false");
|
||||
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);
|
||||
|
||||
Sound::init();
|
||||
@ -254,7 +260,7 @@ namespace Core {
|
||||
|
||||
void clear(const vec4 &color) {
|
||||
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) {
|
||||
@ -303,15 +309,18 @@ namespace Core {
|
||||
void setTarget(Texture *target) {
|
||||
if (!target) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glColorMask(true, true, true, true);
|
||||
return;
|
||||
}
|
||||
|
||||
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_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 };
|
||||
glDrawBuffers(target->depth ? 0 : 1, buffers);
|
||||
bool mask = !target->depth;
|
||||
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 lightIndex = getLightIndex(lara->pos, roomIndex);
|
||||
|
||||
@ -361,10 +361,12 @@ namespace Debug {
|
||||
float a = l.intensity / 8191.0f;
|
||||
vec3 p = vec3(l.x, l.y, l.z);
|
||||
vec4 color = vec4(a, a, a, 1);
|
||||
if (i == room) color.x = color.z = 0;
|
||||
Debug::Draw::point(p, color);
|
||||
//if (i == roomIndex && j == lightIndex)
|
||||
// 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;
|
||||
uint16 align; // ! not exists in file !
|
||||
uint16 intensity;
|
||||
uint32 attenuation;
|
||||
uint32 radius;
|
||||
} *lights;
|
||||
|
||||
struct Mesh {
|
||||
@ -924,7 +924,9 @@ namespace TR {
|
||||
light.intensity = stream.read(intensity);
|
||||
} else
|
||||
stream.read(light.intensity);
|
||||
stream.read(light.attenuation);
|
||||
stream.read(light.radius);
|
||||
|
||||
light.radius *= 2;
|
||||
}
|
||||
// meshes
|
||||
r.meshes = new Room::Mesh[stream.read(r.meshesCount)];
|
||||
@ -1107,7 +1109,6 @@ namespace TR {
|
||||
stream.read(c.x);
|
||||
stream.read(c.y);
|
||||
stream.read(c.z);
|
||||
c.w = 0;
|
||||
}
|
||||
int16 nCount;
|
||||
stream.read(nCount);
|
||||
@ -1120,6 +1121,7 @@ namespace TR {
|
||||
stream.read(n.y);
|
||||
stream.read(n.z);
|
||||
n.w = 1;
|
||||
c.w = 0x1FFF;
|
||||
} else { // intensity
|
||||
stream.read(c.w);
|
||||
n = { 0, 0, 0, 0 };
|
||||
@ -1173,6 +1175,7 @@ namespace TR {
|
||||
if (nCount > 0) { // normal
|
||||
stream.read(n);
|
||||
n.w = 1;
|
||||
c.w = 0x1FFF;
|
||||
} else { // intensity
|
||||
stream.read(c.w);
|
||||
n = { 0, 0, 0, 0 };
|
||||
|
@ -1733,6 +1733,7 @@ struct Lara : Character {
|
||||
mat4 m(matrix);
|
||||
m.rotateX(-PI * 0.5f);
|
||||
m.translate(offset);
|
||||
|
||||
Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha));
|
||||
renderMesh(m, mesh, level->extra.muzzleFlash->mStart);
|
||||
}
|
||||
@ -1741,10 +1742,12 @@ struct Lara : Character {
|
||||
Controller::render(frustum, mesh);
|
||||
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();
|
||||
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, 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 {
|
||||
enum { shStatic, shCaustics, shSprite, shShadowOpaque, shShadowSprite, shGUI, shMAX };
|
||||
enum { shDefault, shShadow, shGUI, shMAX };
|
||||
|
||||
TR::Level level;
|
||||
Shader *shaders[shMAX];
|
||||
@ -34,9 +34,8 @@ struct Level {
|
||||
Texture *shadow;
|
||||
|
||||
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
|
||||
Debug::init();
|
||||
#endif
|
||||
@ -215,17 +214,10 @@ struct Level {
|
||||
else
|
||||
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);
|
||||
shaders[shStatic] = new Shader(SHADER, def);
|
||||
sprintf(ext, "%s#define CAUSTICS\n", def);
|
||||
shaders[shCaustics] = new Shader(SHADER, ext);
|
||||
sprintf(ext, "%s#define SPRITE\n", def);
|
||||
shaders[shSprite] = new Shader(SHADER, ext);
|
||||
shaders[shDefault] = new Shader(SHADER, def);
|
||||
sprintf(def, "%s#define PASS_SHADOW\n", ext);
|
||||
shaders[shShadow] = new Shader(SHADER, def);
|
||||
sprintf(ext, "%s#define SPRITE\n", def);
|
||||
shaders[shGUI] = new Shader(GUI, "");
|
||||
}
|
||||
@ -331,17 +323,21 @@ struct Level {
|
||||
}
|
||||
#endif
|
||||
|
||||
Shader *setRoomShader(const TR::Room &room, float intensity) {
|
||||
if (Core::pass == Core::passShadow)
|
||||
return shaders[shShadowOpaque];
|
||||
void setRoomShader(const TR::Room &room, float intensity) {
|
||||
if (Core::pass == Core::passShadow) {
|
||||
shaders[shShadow]->bind();
|
||||
return;
|
||||
}
|
||||
|
||||
shaders[shDefault]->bind();
|
||||
if (room.flags.water) {
|
||||
Core::color = vec4(0.6f, 0.9f, 0.9f, intensity);
|
||||
return shaders[shCaustics];
|
||||
Core::active.shader->setParam(uCaustics, 1);
|
||||
} else {
|
||||
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) {
|
||||
@ -351,14 +347,13 @@ struct Level {
|
||||
TR::Room &room = level.rooms[roomIndex];
|
||||
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);
|
||||
// glDisable(GL_CULL_FACE);
|
||||
sh->bind();
|
||||
sh->setParam(uColor, Core::color);
|
||||
sh->setParam(uType, Shader::ROOM);
|
||||
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
|
||||
if (Core::pass != Core::passShadow)
|
||||
@ -379,8 +374,8 @@ struct Level {
|
||||
continue;
|
||||
rMesh.flags.rendered = true;
|
||||
|
||||
Core::color.w = intensityf(rMesh.intensity == -1 ? room.ambient : rMesh.intensity);
|
||||
sh->setParam(uColor, Core::color);
|
||||
//Core::color.w = intensityf(rMesh.intensity);//intensityf(rMesh.intensity == -1 ? room.ambient : rMesh.intensity);
|
||||
//sh->setParam(uColor, Core::color);
|
||||
|
||||
// render static mesh
|
||||
mat4 mTemp = Core::mModel;
|
||||
@ -396,29 +391,20 @@ struct Level {
|
||||
mat4 mTemp = Core::mModel;
|
||||
room.flags.rendered = true;
|
||||
|
||||
Core::lightColor[0] = vec4(0, 0, 0, 1);
|
||||
|
||||
Core::mModel.translate(offset);
|
||||
|
||||
// render room geometry
|
||||
sh->setParam(uModel, Core::mModel);
|
||||
|
||||
// render room geometry
|
||||
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);
|
||||
}
|
||||
|
||||
// render room sprites
|
||||
if (mesh->hasRoomSprites(roomIndex) && Core::pass != Core::passShadow) {
|
||||
sh = shaders[Core::pass == Core::passShadow ? shShadowSprite : shSprite];
|
||||
sh->bind();
|
||||
Core::color.w = 1.0f;
|
||||
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);
|
||||
Core::color.w = 1.0;
|
||||
sh->setParam(uType, Shader::SPRITE);
|
||||
sh->setParam(uColor, Core::color);
|
||||
mesh->renderRoomSprites(roomIndex);
|
||||
}
|
||||
|
||||
@ -453,32 +439,14 @@ struct Level {
|
||||
camera->frustum = camFrustum; // pop camera frustum
|
||||
}
|
||||
|
||||
int getLightIndex(const vec3 &pos, int &room) {
|
||||
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 getLightIndex(const vec3 &pos, int &room, float maxAtt = -1.0f, int depth = 0) {
|
||||
int idx = -1;
|
||||
|
||||
TR::Room &r = level.rooms[room];
|
||||
|
||||
for (int i = 0; i < r.lightsCount; 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) {
|
||||
maxAtt = att;
|
||||
idx = i;
|
||||
@ -488,7 +456,7 @@ struct Level {
|
||||
if (depth > 0)
|
||||
for (int i = 0; i < r.portalsCount; i++) {
|
||||
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) {
|
||||
room = nextRoom;
|
||||
idx = nextLight;
|
||||
@ -506,7 +474,7 @@ struct Level {
|
||||
TR::Room::Light &light = level.rooms[room].lights[idx];
|
||||
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::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 {
|
||||
Core::lightPos[0] = vec3(0);
|
||||
Core::lightColor[0] = vec4(0, 0, 0, 1);
|
||||
@ -525,19 +493,20 @@ struct Level {
|
||||
return;
|
||||
|
||||
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);
|
||||
Core::active.shader->setParam(uType, Shader::ENTITY);
|
||||
}
|
||||
|
||||
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::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);
|
||||
|
||||
((Controller*)entity.controller)->render(camera->frustum, mesh);
|
||||
@ -555,16 +524,6 @@ struct Level {
|
||||
}
|
||||
|
||||
camera->update();
|
||||
|
||||
static bool tmpFlag = false;
|
||||
|
||||
if (Input::down[ikEnter]) {
|
||||
if (!tmpFlag) {
|
||||
perspShadows = !perspShadows;
|
||||
tmpFlag = true;
|
||||
}
|
||||
} else
|
||||
tmpFlag = false;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
@ -581,25 +540,23 @@ struct Level {
|
||||
Core::active.shader = NULL;
|
||||
for (int i = 0; i < shMAX; i++) {
|
||||
shaders[i]->bind();
|
||||
shaders[i]->setParam(uViewProj, Core::mViewProj);
|
||||
shaders[i]->setParam(uLightProj, Core::mLightProj);
|
||||
shaders[i]->setParam(uViewInv, Core::mViewInv);
|
||||
shaders[i]->setParam(uViewPos, Core::viewPos);
|
||||
shaders[i]->setParam(uParam, vec4(time, 0, 0, 0));
|
||||
shaders[i]->setParam(uLightTarget, lara->pos);
|
||||
shaders[i]->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
|
||||
shaders[i]->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
|
||||
shaders[i]->setParam(uViewProj, Core::mViewProj);
|
||||
shaders[i]->setParam(uLightProj, Core::mLightProj);
|
||||
shaders[i]->setParam(uViewInv, Core::mViewInv);
|
||||
shaders[i]->setParam(uViewPos, Core::viewPos);
|
||||
shaders[i]->setParam(uTime, time);
|
||||
shaders[i]->setParam(uLightTarget, lara->pos);
|
||||
shaders[i]->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
|
||||
shaders[i]->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
|
||||
}
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
Core::setCulling(cfFront);
|
||||
|
||||
Core::mModel.identity();
|
||||
|
||||
// clear visible flags for rooms & static meshes
|
||||
for (int i = 0; i < level.roomsCount; 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++)
|
||||
room.meshes[j].flags.rendered = false; // clear visible flag for room static meshes
|
||||
@ -621,7 +578,7 @@ struct Level {
|
||||
|
||||
void renderEntities() {
|
||||
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++)
|
||||
renderEntity(level.entities[i]);
|
||||
}
|
||||
@ -638,27 +595,13 @@ struct Level {
|
||||
|
||||
// omni-spot light shadows
|
||||
int room = lara->getRoomIndex();
|
||||
int idx = getLightIndex2(lara->pos, room);
|
||||
int idx = getLightIndex(lara->pos, room);
|
||||
if (idx < 0) return false;
|
||||
|
||||
if (perspShadows) {
|
||||
TR::Room::Light &light = level.rooms[room].lights[idx];
|
||||
vec3 lightPos = vec3(float(light.x), float(light.y), float(light.z));
|
||||
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.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;
|
||||
}
|
||||
|
||||
TR::Room::Light &light = level.rooms[room].lights[idx];
|
||||
vec3 shadowLightPos = 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::mProj = mat4(120, 1.0f, camera->znear, camera->zfar);
|
||||
|
||||
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;
|
||||
Core::mLightProj = bias * Core::mProj * Core::mView; // * ( * ) ?
|
||||
|
||||
Shader *sh = shaders[shShadowOpaque];
|
||||
sh->bind();
|
||||
sh->setParam(uViewProj, Core::mViewProj);
|
||||
sh->setParam(uLightProj, Core::mLightProj);
|
||||
|
||||
sh = shaders[shShadowSprite];
|
||||
Shader *sh = shaders[shShadow];
|
||||
sh->bind();
|
||||
sh->setParam(uViewProj, Core::mViewProj);
|
||||
sh->setParam(uLightProj, Core::mLightProj);
|
||||
@ -688,15 +626,17 @@ struct Level {
|
||||
Core::setBlending(bmNone);
|
||||
Core::setTarget(shadow);
|
||||
Core::setViewport(0, 0, shadow->width, shadow->height);
|
||||
Core::clear(vec4(1.0));
|
||||
Core::clear(vec4(1.0));
|
||||
Core::setCulling(cfBack);
|
||||
renderScene();
|
||||
Core::setCulling(cfFront);
|
||||
Core::setTarget(NULL);
|
||||
shadow->bind(sShadow);
|
||||
}
|
||||
|
||||
void render() {
|
||||
renderShadows();
|
||||
|
||||
|
||||
Core::pass = Core::passOpaque;
|
||||
Core::setBlending(bmAlpha);
|
||||
Core::clear(vec4(0.0f));
|
||||
@ -733,7 +673,7 @@ struct Level {
|
||||
|
||||
Debug::begin();
|
||||
// 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::portals(level);
|
||||
// Debug::Level::meshes(level);
|
||||
|
@ -9,7 +9,8 @@
|
||||
<script type='text/javascript'>
|
||||
var statusElement = document.getElementById('status');
|
||||
var canvasElement = document.getElementById('canvas');
|
||||
|
||||
var proc;
|
||||
|
||||
var Module = {
|
||||
TOTAL_MEMORY: 64*1024*1024,
|
||||
preRun: [],
|
||||
@ -52,7 +53,7 @@
|
||||
var rate = 44100 / ctx.sampleRate;
|
||||
var framesCount = Math.ceil(count * rate);
|
||||
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) {
|
||||
var L = e.outputBuffer.getChannelData(0),
|
||||
R = e.outputBuffer.getChannelData(1);
|
||||
|
138
src/shader.glsl
138
src/shader.glsl
@ -2,14 +2,23 @@ R"====(
|
||||
varying vec2 vTexCoord;
|
||||
|
||||
#ifndef PASS_SHADOW
|
||||
varying vec4 vLightProj;
|
||||
varying vec3 vCoord;
|
||||
varying vec4 vNormal;
|
||||
varying vec3 vViewVec;
|
||||
varying vec4 vColor;
|
||||
varying vec3 vCoord;
|
||||
varying vec4 vNormal;
|
||||
varying vec3 vViewVec;
|
||||
varying vec4 vColor;
|
||||
varying vec4 vLightProj;
|
||||
varying float vLightTargetDist;
|
||||
#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
|
||||
uniform mat4 uViewProj;
|
||||
uniform mat4 uModel;
|
||||
@ -19,20 +28,16 @@ varying vec2 vTexCoord;
|
||||
|
||||
#ifndef PASS_SHADOW
|
||||
uniform vec3 uViewPos;
|
||||
|
||||
#ifndef SPRITE
|
||||
uniform vec2 uAnimTexRanges[MAX_RANGES];
|
||||
uniform vec2 uAnimTexOffsets[MAX_OFFSETS];
|
||||
#endif
|
||||
|
||||
uniform vec4 uParam; // x - time
|
||||
uniform vec2 uAnimTexRanges[MAX_RANGES];
|
||||
uniform vec2 uAnimTexOffsets[MAX_OFFSETS];
|
||||
#endif
|
||||
|
||||
|
||||
attribute vec4 aCoord;
|
||||
attribute vec4 aTexCoord;
|
||||
attribute vec4 aNormal;
|
||||
|
||||
#ifndef PASS_SHADOW
|
||||
attribute vec4 aNormal;
|
||||
attribute vec4 aColor;
|
||||
#endif
|
||||
|
||||
@ -41,12 +46,13 @@ varying vec2 vTexCoord;
|
||||
void main() {
|
||||
vec4 coord = uModel * vec4(aCoord.xyz, 1.0);
|
||||
|
||||
#ifndef SPRITE
|
||||
|
||||
if (uType != TYPE_SPRITE) {
|
||||
#ifndef PASS_SHADOW
|
||||
// animated texture coordinates
|
||||
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
|
||||
|
||||
vTexCoord = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated
|
||||
@ -54,21 +60,21 @@ varying vec2 vTexCoord;
|
||||
#else
|
||||
vTexCoord = aTexCoord.xy * TEXCOORD_SCALE;
|
||||
#endif
|
||||
#else
|
||||
} else {
|
||||
coord.xyz += uViewInv[0].xyz * aTexCoord.z - uViewInv[1].xyz * aTexCoord.w;
|
||||
#ifndef PASS_SHADOW
|
||||
vTexCoord = aTexCoord.xy * TEXCOORD_SCALE;
|
||||
vNormal = vec4(uViewPos.xyz - coord.xyz, 0.0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef PASS_SHADOW
|
||||
vColor = aColor;
|
||||
|
||||
#if defined(CAUSTICS)
|
||||
if (uCaustics != 0) {
|
||||
float sum = coord.x + coord.y + coord.z;
|
||||
vColor.xyz *= abs(sin(sum / 512.0 + uParam.x)) * 1.5 + 0.5; // color dodge
|
||||
#endif
|
||||
vColor.xyz *= abs(sin(sum / 512.0 + uTime)) * 1.5 + 0.5; // color dodge
|
||||
}
|
||||
|
||||
vViewVec = uViewPos - coord.xyz;
|
||||
|
||||
@ -76,6 +82,7 @@ varying vec2 vTexCoord;
|
||||
vLightTargetDist = dot(dist, dist) / (MAX_SHADOW_DIST * MAX_SHADOW_DIST);
|
||||
|
||||
vLightProj = uLightProj * coord;
|
||||
|
||||
vCoord = coord.xyz;
|
||||
#endif
|
||||
|
||||
@ -130,19 +137,32 @@ varying vec2 vTexCoord;
|
||||
#define CMP(a,b) float(a > b)
|
||||
|
||||
#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)
|
||||
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);
|
||||
return dot(value, bitSh);
|
||||
}
|
||||
#define SHADOW(V) CMP(unpack(texture2D(sShadow, (V).xy)), p.z)
|
||||
#else
|
||||
#define SHADOW(v) 1.0
|
||||
#define compare(p, z) CMP(unpack(texture2D(sShadow, (p))), (z));
|
||||
#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
|
||||
|
||||
float getShadow(vec4 lightProj) {
|
||||
vec3 p = lightProj.xyz / lightProj.w;
|
||||
if (lightProj.w < 0.0) return 1.0;
|
||||
|
||||
vec2 poissonDisk[16];
|
||||
poissonDisk[ 0] = vec2( -0.94201624, -0.39906216 );
|
||||
poissonDisk[ 1] = vec2( 0.94558609, -0.76890725 );
|
||||
@ -160,21 +180,22 @@ varying vec2 vTexCoord;
|
||||
poissonDisk[13] = vec2( -0.81409955, 0.91437590 );
|
||||
poissonDisk[14] = vec2( 0.19984126, 0.78641367 );
|
||||
poissonDisk[15] = vec2( 0.14383161, -0.14100790 );
|
||||
|
||||
vec3 p = lightProj.xyz / lightProj.w;
|
||||
|
||||
if (lightProj.w < 0.0) return 1.0;
|
||||
|
||||
//return SHADOW(p);
|
||||
float rShadow = 0.0;
|
||||
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 = clamp(rShadow * 1.25, 0.0, 1.0); // apply contrast (1.25)
|
||||
|
||||
float fade = min(1.0, vLightTargetDist);
|
||||
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
|
||||
|
||||
void main() {
|
||||
@ -183,16 +204,10 @@ varying vec2 vTexCoord;
|
||||
discard;
|
||||
|
||||
#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
|
||||
gl_FragColor = pack(depth);
|
||||
gl_FragColor = pack(gl_FragCoord.z);
|
||||
#else
|
||||
gl_FragColor = vec4(1.0);
|
||||
gl_FragDepth = depth;
|
||||
#endif
|
||||
#else
|
||||
color.xyz *= uColor.xyz;
|
||||
@ -201,32 +216,33 @@ varying vec2 vTexCoord;
|
||||
color.xyz = pow(abs(color.xyz), vec3(2.2)); // to linear space
|
||||
|
||||
// calc point lights
|
||||
vec3 normal = normalize(vNormal.xyz);
|
||||
vec3 viewVec = normalize(vViewVec);
|
||||
vec3 light = vec3(0.0);
|
||||
for (int i = 0; i < MAX_LIGHTS; i++) {
|
||||
vec3 lv = uLightPos[i] - vCoord.xyz;
|
||||
vec4 lc = uLightColor[i];
|
||||
float lum = max(0.0, dot(normal, normalize(lv)));
|
||||
float att = max(0.0, 1.0 - dot(lv, lv) / lc.w);
|
||||
light += lc.xyz * (lum * att);
|
||||
}
|
||||
if (uType != TYPE_FLASH) {
|
||||
vec3 normal = normalize(vNormal.xyz);
|
||||
vec3 viewVec = normalize(vViewVec);
|
||||
vec3 light = vec3(0.0);
|
||||
|
||||
for (int i = 1; i < MAX_LIGHTS; i++) // additional lights
|
||||
light += calcLight(normal, uLightPos[i], uLightColor[i]);
|
||||
|
||||
// apply lighting
|
||||
#ifdef SPRITE
|
||||
color.xyz *= light + vColor.w;
|
||||
#else
|
||||
float shadow = getShadow(vLightProj);
|
||||
// apply lighting
|
||||
if (uType == TYPE_SPRITE) {
|
||||
light += vColor.w * uColor.w;
|
||||
}
|
||||
|
||||
vec3 dlight = mix(vec3(uColor.w * uColor.w), light + uColor.w, shadow);
|
||||
dlight *= dot(normal, viewVec) * 0.5 + 0.5; // backlight
|
||||
|
||||
vec3 slight = light + mix(uColor.w, vColor.w, shadow);
|
||||
|
||||
light = mix(slight, dlight, vNormal.w);
|
||||
if (uType == TYPE_ROOM) {
|
||||
light += mix(min(uColor.w, vColor.w), vColor.w, getShadow(vLightProj));
|
||||
}
|
||||
|
||||
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;
|
||||
#endif
|
||||
} else {
|
||||
color.w = uColor.w;
|
||||
}
|
||||
|
||||
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 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 *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 {
|
||||
GLuint ID;
|
||||
GLint uID[uMAX];
|
||||
|
||||
enum : GLint { SPRITE, ROOM, ENTITY, FLASH };
|
||||
|
||||
Shader(const char *text, const char *defines = "") {
|
||||
#ifdef MOBILE
|
||||
#define GLSL_DEFINE "#extension GL_EXT_frag_depth : enable\n"\
|
||||
"#extension GL_OES_standard_derivatives : enable\n"\
|
||||
"#define MOBILE\n"\
|
||||
"#define gl_FragDepth gl_FragDepthEXT\n"\
|
||||
#define GLSL_DEFINE "#define MOBILE\n"\
|
||||
"precision highp int;\n"\
|
||||
"precision highp float;\n"
|
||||
#else
|
||||
#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) {
|
||||
if (uID[uType] != -1)
|
||||
glUniform2fv(uID[uType], count, (GLfloat*)&value);
|
||||
|
@ -407,7 +407,7 @@ double samples[28];
|
||||
int res = decoder->decode(&frames[i], count - i);
|
||||
if (res == 0) {
|
||||
if (!(flags & Flags::LOOP)) {
|
||||
if (i == 0) isPlaying = false;
|
||||
isPlaying = false;
|
||||
break;
|
||||
} else
|
||||
decoder->replay();
|
||||
|
@ -4,11 +4,12 @@
|
||||
#include "core.h"
|
||||
|
||||
struct Texture {
|
||||
GLuint ID;
|
||||
GLuint ID;
|
||||
int width, height;
|
||||
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);
|
||||
bind(0);
|
||||
|
||||
@ -33,9 +34,13 @@ struct Texture {
|
||||
|
||||
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);
|
||||
|
||||
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() {
|
||||
delete dummy;
|
||||
glDeleteTextures(1, &ID);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user