1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-21 04:11:53 +02:00

#23 refactoring of shader system

This commit is contained in:
XProger
2017-03-14 03:46:48 +03:00
parent ff313dabd0
commit 3d1fab932c
13 changed files with 542 additions and 420 deletions

View File

@@ -11,6 +11,7 @@
#define FOG_DIST (18 * 1024) #define FOG_DIST (18 * 1024)
#define WATER_FOG_DIST (8 * 1024) #define WATER_FOG_DIST (8 * 1024)
//#define WATER_USE_GRID //#define WATER_USE_GRID
#define UNDERWATER_COLOR "#define UNDERWATER_COLOR vec3(0.6, 0.9, 0.9)\n"
const char SHADER[] = const char SHADER[] =
#include "shader.glsl" #include "shader.glsl"
@@ -29,46 +30,55 @@ const char GUI[] =
; ;
struct ShaderCache { struct ShaderCache {
enum Effect { FX_NONE = 0, FX_UNDERWATER = 1, FX_ALPHA_TEST = 2, FX_CLIP_PLANE = 4 };
IGame *game; IGame *game;
Shader *shaders[Core::passMAX][Shader::MAX][2][2][2]; Shader *shaders[Core::passMAX][Shader::MAX][(FX_UNDERWATER | FX_ALPHA_TEST | FX_CLIP_PLANE) + 1];
ShaderCache(IGame *game) : game(game) { ShaderCache(IGame *game) : game(game) {
memset(shaders, 0, sizeof(shaders)); memset(shaders, 0, sizeof(shaders));
LOG("shader: cache warm up...\n"); LOG("shader: cache warm up...\n");
compile(Core::passShadow , Shader::ENTITY, false, false, false); if (Core::settings.shadows)
compile(Core::passShadow, Shader::ENTITY, FX_NONE);
compile(Core::passAmbient, Shader::ROOM, false, false, false); if (Core::settings.ambient) {
compile(Core::passAmbient, Shader::ROOM, false, true, false); compile(Core::passAmbient, Shader::ROOM, FX_NONE);
compile(Core::passAmbient, Shader::ROOM, false, false, true); compile(Core::passAmbient, Shader::ROOM, FX_ALPHA_TEST);
compile(Core::passAmbient, Shader::ROOM, false, true, true); compile(Core::passAmbient, Shader::ROOM, FX_CLIP_PLANE);
compile(Core::passAmbient, Shader::ROOM, true, false, false); compile(Core::passAmbient, Shader::ROOM, FX_ALPHA_TEST | FX_CLIP_PLANE);
compile(Core::passAmbient, Shader::SPRITE, false, true, false); compile(Core::passAmbient, Shader::ROOM, FX_UNDERWATER);
compile(Core::passAmbient, Shader::SPRITE, false, true, true); compile(Core::passAmbient, Shader::ROOM, FX_UNDERWATER | FX_CLIP_PLANE);
compile(Core::passAmbient, Shader::SPRITE, FX_ALPHA_TEST);
compile(Core::passAmbient, Shader::SPRITE, FX_ALPHA_TEST | FX_CLIP_PLANE);
}
compile(Core::passCompose, Shader::ROOM, false, false, false); if (Core::settings.water) {
compile(Core::passCompose, Shader::ROOM, false, true, false); compile(Core::passWater, Shader::WATER_MASK, FX_NONE);
compile(Core::passCompose, Shader::ROOM, false, true, true); compile(Core::passWater, Shader::WATER_STEP, FX_NONE);
compile(Core::passCompose, Shader::ROOM, false, false, true); compile(Core::passWater, Shader::WATER_CAUSTICS, FX_NONE);
compile(Core::passCompose, Shader::ROOM, true, false, false); compile(Core::passWater, Shader::WATER_COMPOSE, FX_NONE);
compile(Core::passCompose, Shader::ROOM, true, false, true); compile(Core::passWater, Shader::WATER_DROP, FX_NONE);
compile(Core::passCompose, Shader::ENTITY, false, false, false); }
compile(Core::passCompose, Shader::ENTITY, false, false, true);
compile(Core::passCompose, Shader::ENTITY, true, false, false);
compile(Core::passCompose, Shader::ENTITY, true, false, true);
compile(Core::passCompose, Shader::SPRITE, false, true, false);
compile(Core::passCompose, Shader::SPRITE, false, true, true);
compile(Core::passCompose, Shader::SPRITE, true, true, false);
compile(Core::passCompose, Shader::SPRITE, true, true, true);
compile(Core::passCompose, Shader::FLASH, false, true, false);
compile(Core::passFilter , Shader::FILTER_DOWNSAMPLE, false, false, false); compile(Core::passFilter, Shader::FILTER_DOWNSAMPLE, FX_NONE);
compile(Core::passWater , Shader::WATER_MASK, false, false, false); compile(Core::passCompose, Shader::ROOM, FX_NONE);
compile(Core::passWater , Shader::WATER_STEP, false, false, false); compile(Core::passCompose, Shader::ROOM, FX_ALPHA_TEST);
compile(Core::passWater , Shader::WATER_CAUSTICS, false, false, false); compile(Core::passCompose, Shader::ROOM, FX_ALPHA_TEST | FX_CLIP_PLANE);
compile(Core::passWater , Shader::WATER_COMPOSE, false, false, false); compile(Core::passCompose, Shader::ROOM, FX_CLIP_PLANE);
compile(Core::passWater , Shader::WATER_DROP, false, false, false); compile(Core::passCompose, Shader::ROOM, FX_UNDERWATER);
compile(Core::passCompose, Shader::ROOM, FX_UNDERWATER | FX_CLIP_PLANE);
compile(Core::passCompose, Shader::ENTITY, FX_NONE);
compile(Core::passCompose, Shader::ENTITY, FX_CLIP_PLANE);
compile(Core::passCompose, Shader::ENTITY, FX_UNDERWATER);
compile(Core::passCompose, Shader::ENTITY, FX_UNDERWATER | FX_CLIP_PLANE);
compile(Core::passCompose, Shader::SPRITE, FX_ALPHA_TEST);
compile(Core::passCompose, Shader::SPRITE, FX_ALPHA_TEST | FX_CLIP_PLANE);
compile(Core::passCompose, Shader::SPRITE, FX_UNDERWATER | FX_ALPHA_TEST);
compile(Core::passCompose, Shader::SPRITE, FX_UNDERWATER | FX_ALPHA_TEST | FX_CLIP_PLANE);
compile(Core::passCompose, Shader::FLASH, FX_ALPHA_TEST);
compile(Core::passCompose, Shader::MIRROR, FX_NONE);
LOG("shader: cache is ready\n"); LOG("shader: cache is ready\n");
} }
@@ -76,25 +86,26 @@ struct ShaderCache {
~ShaderCache() { ~ShaderCache() {
for (int pass = 0; pass < Core::passMAX; pass++) for (int pass = 0; pass < Core::passMAX; pass++)
for (int type = 0; type < Shader::MAX; type++) for (int type = 0; type < Shader::MAX; type++)
for (int caustics = 0; caustics < 2; caustics++) for (int fx = 0; fx < sizeof(shaders[Core::passMAX][Shader::MAX]) / sizeof(shaders[Core::passMAX][Shader::MAX][FX_NONE]); fx++)
for (int alphaTest = 0; alphaTest < 2; alphaTest++) delete shaders[pass][type][fx];
for (int clipPlane = 0; clipPlane < 2; clipPlane++)
delete shaders[pass][type][caustics][alphaTest][clipPlane];
} }
Shader* compile(Core::Pass pass, Shader::Type type, bool caustics = false, bool alphaTest = false, bool clipPlane = false) { Shader* compile(Core::Pass pass, Shader::Type type, int fx) {
char def[1024], ext[255]; char def[1024], ext[255];
ext[0] = 0; ext[0] = 0;
if (Core::support.shadowSampler) { if (Core::settings.shadows) {
#ifdef MOBILE if (Core::support.shadowSampler) {
strcat(ext, "#extension GL_EXT_shadow_samplers : require\n"); #ifdef MOBILE
#endif strcat(ext, "#extension GL_EXT_shadow_samplers : require\n");
strcat(ext, "#define SHADOW_SAMPLER\n"); #endif
} else strcat(ext, "#define SHADOW_SAMPLER\n");
if (Core::support.depthTexture) } else {
strcat(ext, "#define SHADOW_DEPTH\n"); if (Core::support.depthTexture)
else strcat(ext, "#define SHADOW_DEPTH\n");
strcat(ext, "#define SHADOW_COLOR\n"); else
strcat(ext, "#define SHADOW_COLOR\n");
}
}
const char *passNames[] = { "COMPOSE", "SHADOW", "AMBIENT", "FILTER", "WATER" }; const char *passNames[] = { "COMPOSE", "SHADOW", "AMBIENT", "FILTER", "WATER" };
const char *src = NULL; const char *src = NULL;
@@ -109,16 +120,20 @@ struct ShaderCache {
int animTexRangesCount = game->getMesh()->animTexRangesCount; int animTexRangesCount = game->getMesh()->animTexRangesCount;
int animTexOffsetsCount = game->getMesh()->animTexOffsetsCount; int animTexOffsetsCount = game->getMesh()->animTexOffsetsCount;
sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define FOG_DIST (1.0/%d.0)\n#define WATER_FOG_DIST (1.0/%d.0)\n", ext, passNames[pass], typ, MAX_LIGHTS, animTexRangesCount, animTexOffsetsCount, FOG_DIST, WATER_FOG_DIST); sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define FOG_DIST (1.0/%d.0)\n#define WATER_FOG_DIST (1.0/%d.0)\n", ext, passNames[pass], typ, MAX_LIGHTS, animTexRangesCount, animTexOffsetsCount, FOG_DIST, WATER_FOG_DIST);
if (caustics) strcat(def, "#define CAUSTICS\n"); if (fx & FX_UNDERWATER) strcat(def, "#define UNDERWATER\n" UNDERWATER_COLOR);
if (alphaTest) strcat(def, "#define ALPHA_TEST\n"); if (fx & FX_ALPHA_TEST) strcat(def, "#define ALPHA_TEST\n");
if (clipPlane) strcat(def, "#define CLIP_PLANE\n"); if (fx & FX_CLIP_PLANE) strcat(def, "#define CLIP_PLANE\n");
if (Core::settings.ambient) strcat(def, "#define OPT_AMBIENT\n");
if (Core::settings.lighting) strcat(def, "#define OPT_LIGHTING\n");
if (Core::settings.shadows) strcat(def, "#define OPT_SHADOW\n");
if (Core::settings.water) strcat(def, "#define OPT_WATER\n");
break; break;
} }
case Core::passWater : { case Core::passWater : {
static const char *typeNames[] = { "DROP", "STEP", "CAUSTICS", "MASK", "COMPOSE" }; static const char *typeNames[] = { "DROP", "STEP", "CAUSTICS", "MASK", "COMPOSE" };
src = WATER; src = WATER;
typ = typeNames[type]; typ = typeNames[type];
sprintf(def, "%s#define PASS_%s\n#define WATER_%s\n#define WATER_FOG_DIST (1.0/%d.0)\n", ext, passNames[pass], typ, WATER_FOG_DIST); sprintf(def, "%s#define PASS_%s\n#define WATER_%s\n#define WATER_FOG_DIST (1.0/%d.0)\n" UNDERWATER_COLOR, ext, passNames[pass], typ, WATER_FOG_DIST);
#ifdef WATER_USE_GRID #ifdef WATER_USE_GRID
strcat(def, "#define WATER_USE_GRID\n"); strcat(def, "#define WATER_USE_GRID\n");
#endif #endif
@@ -133,17 +148,26 @@ struct ShaderCache {
} }
default : ASSERT(false); default : ASSERT(false);
} }
LOG("shader: compile %s -> %s %s%s%s\n", passNames[pass], typ, caustics ? "caustics " : "", alphaTest ? "alphaTest " : "", clipPlane ? "clipPlane" : ""); LOG("shader: compile %s -> %s %s%s%s\n", passNames[pass], typ, (fx & FX_UNDERWATER) ? "underwater " : "", (fx & FX_ALPHA_TEST) ? "alphaTest " : "", (fx & FX_CLIP_PLANE) ? "clipPlane" : "");
return shaders[pass][type][caustics][alphaTest][clipPlane] = new Shader(src, def); return shaders[pass][type][fx] = new Shader(src, def);
} }
void bind(Core::Pass pass, Shader::Type type, bool caustics = false, bool alphaTest = false, bool clipPlane = false) { void bind(Core::Pass pass, Shader::Type type, int fx) {
Core::pass = pass; Core::pass = pass;
Shader *shader = shaders[pass][type][caustics][alphaTest][clipPlane]; Shader *shader = shaders[pass][type][fx];
if (!shader) if (!shader)
shader = compile(pass, type, caustics, alphaTest, clipPlane); shader = compile(pass, type, fx);
ASSERT(shader != NULL); ASSERT(shader != NULL);
shader->bind(); shader->bind();
// TODO: bindable uniform block
shader->setParam(uViewProj, Core::mViewProj);
shader->setParam(uLightProj, Core::mLightProj);
shader->setParam(uViewInv, Core::mViewInv);
shader->setParam(uViewPos, Core::viewPos);
shader->setParam(uParam, Core::params);
MeshBuilder *mesh = game->getMesh();
shader->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
shader->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
} }
}; };
@@ -220,7 +244,7 @@ struct AmbientCache {
// second pass - downsample it // second pass - downsample it
Core::setDepthTest(false); Core::setDepthTest(false);
game->setShader(Core::passFilter, Shader::FILTER_DOWNSAMPLE, false); game->setShader(Core::passFilter, Shader::FILTER_DOWNSAMPLE);
for (int i = 1; i < 4; i++) { for (int i = 1; i < 4; i++) {
int size = 64 >> (i << 1); int size = 64 >> (i << 1);
@@ -291,7 +315,6 @@ struct WaterCache {
TR::Level *level; TR::Level *level;
Texture *refract; Texture *refract;
Texture *reflect; Texture *reflect;
vec3 color;
struct Item { struct Item {
int from, to, caust; int from, to, caust;
@@ -312,6 +335,7 @@ struct WaterCache {
} }
void init(IGame *game) { void init(IGame *game) {
TR::Level *level = game->getLevel(); TR::Level *level = game->getLevel();
TR::Room &r = level->rooms[to]; // underwater room TR::Room &r = level->rooms[to]; // underwater room
@@ -356,21 +380,22 @@ struct WaterCache {
} }
} }
m[(x - minX) + w * (z - minZ)] = hasWater ? (hasFlow ? 0xFFFF : 0xFF00) : 0; m[(x - minX) + w * (z - minZ)] = hasWater ? (hasFlow ? 0xF81F : 0xF800) : 0;
} }
mask = new Texture(w, h, Texture::RGB16, false, m, false);
delete[] m;
size = vec3(float((maxX - minX) * 512), 1.0f, float((maxZ - minZ) * 512)); // half size size = vec3(float((maxX - minX) * 512), 1.0f, float((maxZ - minZ) * 512)); // half size
pos = vec3(r.info.x + minX * 1024 + size.x, float(posY), r.info.z + minZ * 1024 + size.z); pos = vec3(r.info.x + minX * 1024 + size.x, float(posY), r.info.z + minZ * 1024 + size.z);
data[0] = new Texture(w * 64, h * 64, Texture::RGBA_HALF, false); data[0] = new Texture(w * 64, h * 64, Texture::RGBA_HALF, false);
data[1] = new Texture(data[0]->width, data[0]->height, Texture::RGBA_HALF, false); data[1] = new Texture(w * 64, h * 64, Texture::RGBA_HALF, false);
caustics = new Texture(512, 512, Texture::RGB16, false); caustics = new Texture(512, 512, Texture::RGB16, false);
mask = new Texture(w, h, Texture::RGB16, false, m, false);
delete[] m;
blank = false; blank = false;
Core::setTarget(data[0], true); // Core::setTarget(data[0], true);
Core::invalidateTarget(false, true); // Core::invalidateTarget(false, true);
} }
void free() { void free() {
@@ -394,7 +419,7 @@ struct WaterCache {
Drop(const vec3 &pos, float radius, float strength) : pos(pos), radius(radius), strength(strength) {} Drop(const vec3 &pos, float radius, float strength) : pos(pos), radius(radius), strength(strength) {}
} drops[MAX_DROPS]; } drops[MAX_DROPS];
WaterCache(IGame *game) : game(game), level(game->getLevel()), refract(NULL), color(0.6f, 0.9f, 0.9f), count(0), checkVisibility(false), dropCount(0) { WaterCache(IGame *game) : game(game), level(game->getLevel()), refract(NULL), count(0), checkVisibility(false), dropCount(0) {
reflect = new Texture(512, 512, Texture::RGB16, false); reflect = new Texture(512, 512, Texture::RGB16, false);
} }
@@ -494,7 +519,7 @@ struct WaterCache {
void drop(Item &item) { void drop(Item &item) {
if (!dropCount) return; if (!dropCount) return;
game->setShader(Core::passWater, Shader::WATER_DROP, false); game->setShader(Core::passWater, Shader::WATER_DROP);
Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f)); Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f));
vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f) }; vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f) };
@@ -520,7 +545,7 @@ struct WaterCache {
void step(Item &item) { void step(Item &item) {
if (item.timer < SIMULATE_TIMESTEP) return; if (item.timer < SIMULATE_TIMESTEP) return;
game->setShader(Core::passWater, Shader::WATER_STEP, false); game->setShader(Core::passWater, Shader::WATER_STEP);
Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f)); Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f));
Core::active.shader->setParam(uParam, vec4(0.995f, 1.0f, 0, 0)); Core::active.shader->setParam(uParam, vec4(0.995f, 1.0f, 0, 0));
@@ -537,7 +562,7 @@ struct WaterCache {
// calc caustics // calc caustics
game->setShader(Core::passWater, Shader::WATER_CAUSTICS, false); game->setShader(Core::passWater, Shader::WATER_CAUSTICS);
vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f / PLANE_DETAIL) }; vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f / PLANE_DETAIL) };
Core::active.shader->setParam(uPosScale, rPosScale[0], 2); Core::active.shader->setParam(uPosScale, rPosScale[0], 2);
@@ -557,11 +582,19 @@ struct WaterCache {
if (!visible) return; if (!visible) return;
// mask underwater geometry by zero alpha // mask underwater geometry by zero alpha
game->setShader(Core::passWater, Shader::WATER_MASK, false); for (int i = 0; i < count; i++) {
Item &item = items[i];
if (item.visible && item.blank)
item.init(game);
}
Core::setTarget(NULL);
game->setShader(Core::passWater, Shader::WATER_MASK);
Core::active.shader->setParam(uTexParam, vec4(1.0f)); Core::active.shader->setParam(uTexParam, vec4(1.0f));
Core::setCulling(cfNone);
Core::setDepthWrite(false);
Core::setColorWrite(false, false, false, true); Core::setColorWrite(false, false, false, true);
Core::setDepthWrite(false);
Core::setCulling(cfNone);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
Item &item = items[i]; Item &item = items[i];
@@ -587,11 +620,6 @@ struct WaterCache {
Item &item = items[i]; Item &item = items[i];
if (!item.visible) continue; if (!item.visible) continue;
if (item.blank) {
item.init(game);
item.blank = false;
}
// render mirror reflection // render mirror reflection
Core::setTarget(reflect, true); Core::setTarget(reflect, true);
vec3 p = item.pos; vec3 p = item.pos;
@@ -639,13 +667,10 @@ struct WaterCache {
Core::lightColor[0] = vec4(lum, lum, lum, float(light.radius) * float(light.radius)); Core::lightColor[0] = vec4(lum, lum, lum, float(light.radius) * float(light.radius));
} }
game->setShader(Core::passWater, Shader::WATER_COMPOSE, false); game->setShader(Core::passWater, Shader::WATER_COMPOSE);
Core::active.shader->setParam(uViewProj, Core::mViewProj);
Core::active.shader->setParam(uViewPos, Core::viewPos);
Core::active.shader->setParam(uLightPos, Core::lightPos[0], 1); Core::active.shader->setParam(uLightPos, Core::lightPos[0], 1);
Core::active.shader->setParam(uLightColor, Core::lightColor[0], 1); Core::active.shader->setParam(uLightColor, Core::lightColor[0], 1);
Core::active.shader->setParam(uParam, vec4(float(Core::width) / refract->width, float(Core::height) / refract->height, 0.05f, 0.02f)); Core::active.shader->setParam(uParam, vec4(float(Core::width) / refract->width, float(Core::height) / refract->height, 0.05f, 0.02f));
Core::active.shader->setParam(uColor, vec4(color * 0.2f, 1.0f));
float sx = item.size.x * DETAIL / (item.data[0]->width / 2); float sx = item.size.x * DETAIL / (item.data[0]->width / 2);
float sz = item.size.z * DETAIL / (item.data[0]->height / 2); float sz = item.size.z * DETAIL / (item.data[0]->height / 2);
@@ -659,9 +684,9 @@ struct WaterCache {
#ifdef WATER_USE_GRID #ifdef WATER_USE_GRID
vec3 rPosScale[2] = { item.pos, item.size * vec3(1.0f / PLANE_DETAIL, 512.0f, 1.0f / PLANE_DETAIL) }; vec3 rPosScale[2] = { item.pos, item.size * vec3(1.0f / PLANE_DETAIL, 512.0f, 1.0f / PLANE_DETAIL) };
Core::active.shader->setParam(uPosScale, rPosScale[0], 2); Core::active.shader->setParam(uPosScale, rPosScale[0], 2);
level->mesh->renderPlane(); game->getMesh()->renderPlane();
#else #else
Core::active.shader->setParam(uPosScale, item.pos, 2); Core::active.shader->setParam(uPosScale, item.pos, 2);
game->getMesh()->renderQuad(); game->getMesh()->renderQuad();
#endif #endif
Core::setCulling(cfFront); Core::setCulling(cfFront);
@@ -716,4 +741,6 @@ struct LightCache {
}; };
*/ */
#undef UNDERWATER_COLOR
#endif #endif

View File

@@ -161,7 +161,7 @@ struct Camera : Controller {
if (Input::down[ikS]) v = v - d; if (Input::down[ikS]) v = v - d;
if (Input::down[ikA]) v = v + d.cross(vec3(0, 1, 0)); if (Input::down[ikA]) v = v + d.cross(vec3(0, 1, 0));
if (Input::down[ikD]) v = v - d.cross(vec3(0, 1, 0)); if (Input::down[ikD]) v = v - d.cross(vec3(0, 1, 0));
pos = pos + v.normal() * (Core::deltaTime * 512.0 * 10.0f); pos = pos + v.normal() * (Core::deltaTime * 512.0f * 10.0f);
mViewInv.identity(); mViewInv.identity();
mViewInv.translate(pos); mViewInv.translate(pos);

View File

@@ -24,7 +24,7 @@ struct IGame {
virtual void setWaterParams(float height) {} virtual void setWaterParams(float height) {}
virtual void updateParams() {} virtual void updateParams() {}
virtual void waterDrop(const vec3 &pos, float radius, float strength) {} virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
virtual void setShader(Core::Pass pass, Shader::Type type, bool caustics = false, bool alphaTest = false) {} virtual void setShader(Core::Pass pass, Shader::Type type, bool underwater = false, bool alphaTest = false) {}
virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {} virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {}
virtual void renderCompose(int roomIndex) {} virtual void renderCompose(int roomIndex) {}
}; };
@@ -487,8 +487,8 @@ struct Controller {
return matrix; return matrix;
} }
/*
void renderShadow(MeshBuilder *mesh, const vec3 &pos, const vec3 &offset, const vec3 &size, float angle) { void renderShadow(MeshBuilder *mesh, const vec3 &pos, const vec3 &offset, const vec3 &size, float angle) {
/*
mat4 m; mat4 m;
m.identity(); m.identity();
m.translate(pos); m.translate(pos);
@@ -496,12 +496,36 @@ struct Controller {
m.translate(vec3(offset.x, 0.0f, offset.z)); m.translate(vec3(offset.x, 0.0f, offset.z));
m.scale(vec3(size.x, 0.0f, size.z) * (1.0f / 1024.0f)); m.scale(vec3(size.x, 0.0f, size.z) * (1.0f / 1024.0f));
Core::active.shader->setParam(uModel, m); game->setShader(Core::pass, Shader::FLASH, false, false);
Core::active.shader->setParam(uColor, vec4(0.0f, 0.0f, 0.0f, 0.5f)); Core::active.shader->setParam(uBasis, Basis(m));
Core::active.shader->setParam(uColor, vec4(0.5f, 0.5f, 0.5f, 1.0f));
Core::active.shader->setParam(uAmbient, vec3(0.0f)); Core::active.shader->setParam(uAmbient, vec3(0.0f));
Core::setBlending(bmMultiply);
mesh->renderShadowSpot(); mesh->renderShadowSpot();
Core::setBlending(bmNone);
*/
mat4 m = Core::mViewProj;
m.translate(pos);
m.rotateY(angle);
m.translate(vec3(offset.x, 0.0f, offset.z));
m.scale(vec3(size.x, 0.0f, size.z) * (1.0f / 1024.0f));
Basis b;
b.identity();
game->setShader(Core::pass, Shader::FLASH, false, false);
Core::active.shader->setParam(uViewProj, m);
Core::active.shader->setParam(uBasis, b);
Core::active.shader->setParam(uMaterial, vec4(0.0f, 0.0f, 0.0f, 0.5f));
Core::active.shader->setParam(uAmbient, vec3(0.0f));
Core::setBlending(bmAlpha);
mesh->renderShadowSpot();
Core::setBlending(bmNone);
Core::active.shader->setParam(uViewProj, Core::mViewProj);
} }
*/
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) { // TODO: animation.calcJoints virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) { // TODO: animation.calcJoints
mat4 matrix = getMatrix(); mat4 matrix = getMatrix();
@@ -540,13 +564,12 @@ struct Controller {
frameIndex = Core::frameIndex; frameIndex = Core::frameIndex;
/* // blob shadow // TODO: fake AO // blob shadow // TODO: fake AO
if (TR::castShadow(entity.type)) { if (!Core::settings.shadows && Core::pass == Core::passCompose && TR::castShadow(entity.type)) {
TR::Level::FloorInfo info; TR::Level::FloorInfo info;
level->getFloorInfo(entity.room, entity.x, entity.y, entity.z, info); level->getFloorInfo(entity.room, entity.x, entity.y, entity.z, info);
renderShadow(mesh, vec3(float(entity.x), info.floor - 16.0f, float(entity.z)), box.center(), box.size() * 0.8f, angle.y); renderShadow(mesh, vec3(float(entity.x), info.floor - 16.0f, float(entity.z)), box.center(), box.size() * 0.8f, angle.y);
} }
*/
} }
}; };

View File

@@ -183,6 +183,9 @@ struct Texture;
#define PROFILE_LABEL(id, name, label) #define PROFILE_LABEL(id, name, label)
#endif #endif
enum CullMode { cfNone, cfBack, cfFront };
enum BlendMode { bmNone, bmAlpha, bmAdd, bmMultiply, bmScreen };
namespace Core { namespace Core {
int width, height; int width, height;
int frameIndex; int frameIndex;
@@ -192,7 +195,7 @@ namespace Core {
vec3 viewPos; vec3 viewPos;
vec3 lightPos[MAX_LIGHTS]; vec3 lightPos[MAX_LIGHTS];
vec4 lightColor[MAX_LIGHTS]; vec4 lightColor[MAX_LIGHTS];
vec4 color; vec4 params;
Texture *blackTex, *whiteTex; Texture *blackTex, *whiteTex;
@@ -209,10 +212,13 @@ namespace Core {
} rtCache[2]; } rtCache[2];
struct { struct {
Shader *shader; Shader *shader;
Texture *textures[8]; Texture *textures[8];
Texture *target; Texture *target;
GLuint VAO; int targetFace;
GLuint VAO;
BlendMode blendMode;
CullMode cullMode;
} active; } active;
struct { struct {
@@ -230,15 +236,19 @@ namespace Core {
bool texHalf, texHalfLinear; bool texHalf, texHalfLinear;
bool shaderBinary; bool shaderBinary;
} support; } support;
struct {
bool ambient;
bool lighting;
bool shadows;
bool water;
} settings;
} }
#include "texture.h" #include "texture.h"
#include "shader.h" #include "shader.h"
#include "mesh.h" #include "mesh.h"
enum CullMode { cfNone, cfBack, cfFront };
enum BlendMode { bmNone, bmAlpha, bmAdd, bmMultiply, bmScreen };
namespace Core { namespace Core {
bool extSupport(const char *str, const char *ext) { bool extSupport(const char *str, const char *ext) {
@@ -353,10 +363,10 @@ namespace Core {
frameIndex = 0; frameIndex = 0;
uint32 data = 0xFF000000; uint32 data = 0x00000000;
blackTex = new Texture(1, 1, Texture::RGBA, false, &data); blackTex = new Texture(1, 1, Texture::RGBA, false, &data, false);
data = 0xFFFFFFFF; data = 0xFFFFFFFF;
whiteTex = new Texture(1, 1, Texture::RGBA, false, &data); whiteTex = new Texture(1, 1, Texture::RGBA, false, &data, false);
} }
void free() { void free() {
@@ -396,17 +406,23 @@ namespace Core {
return cache.count++; return cache.count++;
} }
void clear(bool clearColor, bool clearDepth, const vec4 &color) { void clear(bool clearColor, bool clearDepth) {
glClearColor(color.x, color.y, color.z, color.w);
if (GLbitfield mask = (clearColor ? GL_COLOR_BUFFER_BIT : 0) | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0)) if (GLbitfield mask = (clearColor ? GL_COLOR_BUFFER_BIT : 0) | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0))
glClear(mask); glClear(mask);
} }
void setClearColor(const vec4 &color) {
glClearColor(color.x, color.y, color.z, color.w);
}
void setViewport(int x, int y, int width, int height) { void setViewport(int x, int y, int width, int height) {
glViewport(x, y, width, height); glViewport(x, y, width, height);
} }
void setCulling(CullMode mode) { void setCulling(CullMode mode) {
if (active.cullMode == mode)
return;
switch (mode) { switch (mode) {
case cfNone : case cfNone :
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
@@ -418,11 +434,16 @@ namespace Core {
break; break;
} }
if (mode != cfNone) if (mode != cfNone && active.cullMode == cfNone)
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
active.cullMode = mode;
} }
void setBlending(BlendMode mode) { void setBlending(BlendMode mode) {
if (active.blendMode == mode)
return;
switch (mode) { switch (mode) {
case bmNone : case bmNone :
glDisable(GL_BLEND); glDisable(GL_BLEND);
@@ -441,8 +462,10 @@ namespace Core {
break; break;
} }
if (mode != bmNone) if (mode != bmNone && active.blendMode == bmNone)
glEnable(GL_BLEND); glEnable(GL_BLEND);
active.blendMode = mode;
} }
void setColorWrite(bool r, bool g, bool b, bool a) { void setColorWrite(bool r, bool g, bool b, bool a) {
@@ -473,6 +496,9 @@ namespace Core {
} }
void setTarget(Texture *target, bool clear = false, int face = 0) { void setTarget(Texture *target, bool clear = false, int face = 0) {
if (target == active.target && face == active.targetFace)
return;
if (!target) { if (!target) {
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
glColorMask(true, true, true, true); glColorMask(true, true, true, true);
@@ -493,10 +519,12 @@ namespace Core {
glColorMask(false, false, false, false); glColorMask(false, false, false, false);
setViewport(0, 0, target->width, target->height); setViewport(0, 0, target->width, target->height);
} }
active.target = target;
if (clear) if (clear)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
active.target = target;
active.targetFace = face;
} }
void copyTarget(Texture *texture, int xOffset, int yOffset, int x, int y, int width, int height) { void copyTarget(Texture *texture, int xOffset, int yOffset, int x, int y, int width, int height) {
@@ -506,7 +534,9 @@ namespace Core {
void resetStates() { void resetStates() {
memset(&active, 0, sizeof(active)); memset(&active, 0, sizeof(active));
glEnable(GL_DEPTH_TEST); setDepthTest(true);
active.blendMode = bmAlpha;
active.cullMode = cfNone;
setCulling(cfFront); setCulling(cfFront);
setBlending(bmNone); setBlending(bmNone);
} }

View File

@@ -20,6 +20,12 @@ namespace Game {
void init(Stream *lvl, Stream *snd) { void init(Stream *lvl, Stream *snd) {
Core::init(); Core::init();
Core::settings.ambient = true;
Core::settings.lighting = true;
Core::settings.shadows = true;
Core::settings.water = Core::support.texFloat || Core::support.texHalf;
level = NULL; level = NULL;
startLevel(lvl, snd, false, false); startLevel(lvl, snd, false, false);
} }

View File

@@ -213,6 +213,7 @@ struct Lara : Character {
Inventory inventory; Inventory inventory;
int lastPickUp; int lastPickUp;
int viewTarget; int viewTarget;
int roomPrev; // water out from room
struct Braid { struct Braid {
Lara *lara; Lara *lara;
@@ -405,7 +406,7 @@ struct Lara : Character {
if (level->extra.braid > -1) if (level->extra.braid > -1)
braid = new Braid(this, vec3(-4.0f, 24.0f, -48.0f)); braid = new Braid(this, vec3(-4.0f, 24.0f, -48.0f));
//reset(15, vec3(70067, -256, 29104), -0.68f); // level 2 (pool)
#ifdef _DEBUG #ifdef _DEBUG
//reset(14, vec3(40448, 3584, 60928), PI * 0.5f, true); // gym (pool) //reset(14, vec3(40448, 3584, 60928), PI * 0.5f, true); // gym (pool)
@@ -1063,6 +1064,7 @@ struct Lara : Character {
if (h >= 0 && h <= (256 + 128) && (state == STATE_SURF_TREAD || animation.setState(STATE_SURF_TREAD)) && animation.setState(STATE_STOP)) { if (h >= 0 && h <= (256 + 128) && (state == STATE_SURF_TREAD || animation.setState(STATE_SURF_TREAD)) && animation.setState(STATE_STOP)) {
alignToWall(LARA_RADIUS); alignToWall(LARA_RADIUS);
roomPrev = getRoomIndex();
getEntity().room = roomAbove; getEntity().room = roomAbove;
pos.y = float(info.floor); pos.y = float(info.floor);
specular = LARA_WET_SPECULAR; specular = LARA_WET_SPECULAR;
@@ -1555,6 +1557,7 @@ struct Lara : Character {
if (state != STATE_SURF_TREAD && state != STATE_SURF_LEFT && state != STATE_SURF_RIGHT && state != STATE_SURF_SWIM && state != STATE_SURF_BACK && state != STATE_STOP) { if (state != STATE_SURF_TREAD && state != STATE_SURF_LEFT && state != STATE_SURF_RIGHT && state != STATE_SURF_SWIM && state != STATE_SURF_BACK && state != STATE_STOP) {
game->waterDrop(pos, 128.0f, 0.2f); game->waterDrop(pos, 128.0f, 0.2f);
specular = LARA_WET_SPECULAR;
return animation.setAnim(ANIM_TO_ONWATER); return animation.setAnim(ANIM_TO_ONWATER);
} }
@@ -2011,7 +2014,7 @@ struct Lara : Character {
Basis b(basis); Basis b(basis);
b.rotate(quat(vec3(1, 0, 0), -PI * 0.5f)); b.rotate(quat(vec3(1, 0, 0), -PI * 0.5f));
b.translate(offset); b.translate(offset);
Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha)); Core::active.shader->setParam(uMaterial, vec4(lum, 0.0f, 0.0f, alpha));
Core::active.shader->setParam(uBasis, b); Core::active.shader->setParam(uBasis, b);
mesh->renderModel(level->extra.muzzleFlash); mesh->renderModel(level->extra.muzzleFlash);
} }

View File

@@ -24,12 +24,12 @@ struct Level : IGame {
Camera *camera; Camera *camera;
Texture *shadow; Texture *shadow;
struct { struct Params {
float time; float time;
float waterHeight; float waterHeight;
float clipSign; float clipSign;
float clipHeight; float clipHeight;
} params; } *params = (Params*)&Core::params;
ShaderCache *shaderCache; ShaderCache *shaderCache;
AmbientCache *ambientCache; AmbientCache *ambientCache;
@@ -49,24 +49,25 @@ struct Level : IGame {
} }
virtual void setClipParams(float clipSign, float clipHeight) { virtual void setClipParams(float clipSign, float clipHeight) {
params.clipSign = clipSign; params->clipSign = clipSign;
params.clipHeight = clipHeight; params->clipHeight = clipHeight;
} }
virtual void setWaterParams(float height) { virtual void setWaterParams(float height) {
params.waterHeight = height; params->waterHeight = height;
} }
virtual void updateParams() { virtual void updateParams() {
Core::active.shader->setParam(uParam, *((vec4*)&params)); Core::active.shader->setParam(uParam, Core::params);
} }
virtual void waterDrop(const vec3 &pos, float radius, float strength) { virtual void waterDrop(const vec3 &pos, float radius, float strength) {
waterCache->addDrop(pos, radius, strength); if (waterCache)
waterCache->addDrop(pos, radius, strength);
} }
virtual void setShader(Core::Pass pass, Shader::Type type, bool caustics = false, bool alphaTest = false) { virtual void setShader(Core::Pass pass, Shader::Type type, bool underwater = false, bool alphaTest = false) {
shaderCache->bind(pass, type, caustics, alphaTest, params.clipHeight != NO_CLIP_PLANE); shaderCache->bind(pass, type, (underwater ? ShaderCache::FX_UNDERWATER : 0) | (alphaTest ? ShaderCache::FX_ALPHA_TEST : 0) | (params->clipHeight != NO_CLIP_PLANE ? ShaderCache::FX_CLIP_PLANE : 0));
} }
virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) { virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {
@@ -88,13 +89,14 @@ struct Level : IGame {
Core::setDepthTest(true); Core::setDepthTest(true);
Core::setDepthWrite(true); Core::setDepthWrite(true);
shadow->bind(sShadow); if (shadow)
shadow->bind(sShadow);
renderScene(roomIndex); renderScene(roomIndex);
} }
//============================== //==============================
Level(Stream &stream, bool demo, bool home) : level(stream, demo), lara(NULL) { Level(Stream &stream, bool demo, bool home) : level(stream, demo), lara(NULL) {
params.time = 0.0f; params->time = 0.0f;
#ifdef _DEBUG #ifdef _DEBUG
Debug::init(); Debug::init();
@@ -204,8 +206,9 @@ struct Level : IGame {
level.cameraController = camera; level.cameraController = camera;
ambientCache = new AmbientCache(this); ambientCache = Core::settings.ambient ? new AmbientCache(this) : NULL;
waterCache = new WaterCache(this); waterCache = Core::settings.water ? new WaterCache(this) : NULL;
shadow = Core::settings.shadows ? new Texture(1024, 1024, Texture::SHADOW, false) : NULL;
initReflections(); initReflections();
for (int i = 0; i < level.soundSourcesCount; i++) { for (int i = 0; i < level.soundSourcesCount; i++) {
@@ -236,8 +239,6 @@ struct Level : IGame {
} }
void initTextures() { void initTextures() {
shadow = new Texture(1024, 1024, Texture::SHADOW, false);
if (!level.tilesCount) { if (!level.tilesCount) {
atlas = NULL; atlas = NULL;
return; return;
@@ -327,95 +328,28 @@ struct Level : IGame {
} }
} }
#ifdef LEVEL_EDITOR void setRoomParams(int roomIndex, Shader::Type type, float diffuse, float ambient, float specular, float alpha, bool alphaTest = false) {
struct Light {
vec3 pos;
float radius;
float intensity;
} lights[255];
int lightsCount = 0;
int lightIntensity = 0.5f;
float lightRadius = 4096.0f;
int findLight(const vec3 &pos, float maxDist) const {
int index = 0;
for (int i = 0; i < lightsCount; i++) {
float d = (lights[i].pos - pos).length();
if (d < maxDist) {
maxDist = d;
index = i;
}
}
return index;
}
void addLight(const vec3 &pos, float radius) {
int index = findLight(pos, 1024.0f);
if (index > -1) {
lightRadius = lights[index].radius;
lightIntensity = lights[index].intensity;
} else
index = lightsCount++;
lights[index].pos = pos;
lights[index].radius = radius;
}
void removeLight(const vec3 &pos) {
int index = findLight(pos, 1024.0f);
if (index > -1)
lights[index] = lights[--lightsCount];
}
void updateLight(const vec3 &pos, float addRadius, float addIntensity) {
int index = findLight(pos, 1024.0f);
if (index > -1) {
lights[index].radius = max(lights[index].radius + addRadius, 256.0f);
lights[index].intensity = clamp(lights[index].intensity + addIntensity, 0.0f, 1.0f);
lightRadius = lights[index].radius;
lightIntensity = lights[index].intensity;
}
}
void updateEditor() {
}
void renderEditor() {
#ifdef _DEBUG
Debug::begin();
Debug::end();
#endif
}
#endif
void setRoomParams(int roomIndex, float intensity, Shader::Type type, bool alphaTest = false) {
if (Core::pass == Core::passShadow) { if (Core::pass == Core::passShadow) {
setShader(Core::pass, type, false); setShader(Core::pass, type);
return; return;
} }
TR::Room &room = level.rooms[roomIndex]; TR::Room &room = level.rooms[roomIndex];
if (room.flags.water)
setWaterParams(float(room.info.yTop));
else
setWaterParams(NO_CLIP_PLANE);
setShader(Core::pass, type, room.flags.water, alphaTest); setShader(Core::pass, type, room.flags.water, alphaTest);
if (room.flags.water) { if (room.flags.water) {
Core::color = vec4(waterCache->color, intensity); if (waterCache)
/* waterCache->bindCaustics(roomIndex);
// trace to water surface room setWaterParams(float(room.info.yTop));
int wrIndex = roomIndex; }
room.sectors[sx * room.zSectors + sz]; Core::active.shader->setParam(uMaterial, vec4(diffuse, ambient, specular, alpha));
int sx = room.xSectors
*/
waterCache->bindCaustics(roomIndex);
} else
Core::color = vec4(1.0f, 1.0f, 1.0f, intensity);
Core::active.shader->setParam(uColor, Core::color);
} }
void renderRoom(int roomIndex, int from = TR::NO_ROOM) { void renderRoom(int roomIndex, int from = TR::NO_ROOM) {
@@ -427,7 +361,7 @@ struct Level : IGame {
// room geometry & sprites // room geometry & sprites
if (!room.flags.rendered) { // skip if already rendered if (!room.flags.rendered) { // skip if already rendered
if (room.flags.water) if (waterCache && room.flags.water)
waterCache->setVisible(roomIndex); waterCache->setVisible(roomIndex);
room.flags.rendered = true; room.flags.rendered = true;
@@ -445,7 +379,7 @@ struct Level : IGame {
Core::setBlending(transp ? bmAlpha : bmNone); Core::setBlending(transp ? bmAlpha : bmNone);
setRoomParams(roomIndex, intensityf(room.ambient), Shader::ROOM, transp > 0); setRoomParams(roomIndex, Shader::ROOM, 1.0f, intensityf(room.ambient), 0.0f, 1.0f, transp > 0);
Shader *sh = Core::active.shader; Shader *sh = Core::active.shader;
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);
@@ -458,7 +392,7 @@ struct Level : IGame {
// render room sprites // render room sprites
if (range.sprites.iCount) { if (range.sprites.iCount) {
Core::setBlending(bmAlpha); Core::setBlending(bmAlpha);
setRoomParams(roomIndex, 1.0, Shader::SPRITE, true); setRoomParams(roomIndex, Shader::SPRITE, 1.0f, 1.0f, 0.0f, 1.0f, true);
Shader *sh = Core::active.shader; Shader *sh = Core::active.shader;
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);
@@ -494,7 +428,7 @@ struct Level : IGame {
frustum = *camFrustum; frustum = *camFrustum;
if (frustum.clipByPortal(v, 4, p.normal)) { if (frustum.clipByPortal(v, 4, p.normal)) {
if ((level.rooms[roomIndex].flags.water ^ level.rooms[p.roomIndex].flags.water) && v[0].y == v[1].y && v[0].y == v[2].y) if (waterCache &&(level.rooms[roomIndex].flags.water ^ level.rooms[p.roomIndex].flags.water) && v[0].y == v[1].y && v[0].y == v[2].y)
waterCache->setVisible(roomIndex, p.roomIndex); waterCache->setVisible(roomIndex, p.roomIndex);
renderRoom(p.roomIndex, roomIndex); renderRoom(p.roomIndex, roomIndex);
} }
@@ -556,6 +490,7 @@ struct Level : IGame {
Controller *controller = (Controller*)entity.controller; Controller *controller = (Controller*)entity.controller;
TR::Room &room = level.rooms[entity.room]; TR::Room &room = level.rooms[entity.room];
if (!room.flags.rendered || entity.flags.invisible || entity.flags.rendered) if (!room.flags.rendered || entity.flags.invisible || entity.flags.rendered)
return; return;
@@ -566,25 +501,29 @@ struct Level : IGame {
if (entity.type == TR::Entity::CRYSTAL) if (entity.type == TR::Entity::CRYSTAL)
type = Shader::MIRROR; type = Shader::MIRROR;
setRoomParams(entity.room, isModel ? controller->specular : intensityf(lum), type, !isModel); int roomIndex = entity.room;
// if (entity.type == TR::Entity::LARA && ((Lara*)entity.controller)->state == Lara::STATE_WATER_OUT)
// roomIndex = ((Lara*)entity.controller)->roomPrev;
setRoomParams(roomIndex, type, 1.0f, intensityf(lum), controller->specular, 1.0f, isModel ? mesh->models[entity.modelIndex].opaque : true);
if (isModel) { // model if (isModel) { // model
vec3 pos = controller->getPos(); vec3 pos = controller->getPos();
AmbientCache::Cube cube; if (Core::settings.ambient) {
if (Core::frameIndex != controller->frameIndex) { AmbientCache::Cube cube;
ambientCache->getAmbient(entity.room, pos, cube); if (Core::frameIndex != controller->frameIndex) {
if (cube.status == AmbientCache::Cube::READY) ambientCache->getAmbient(entity.room, pos, cube);
memcpy(controller->ambient, cube.colors, sizeof(cube.colors)); // store last calculated ambient into controller if (cube.status == AmbientCache::Cube::READY)
memcpy(controller->ambient, cube.colors, sizeof(cube.colors)); // store last calculated ambient into controller
}
Core::active.shader->setParam(uAmbient, controller->ambient[0], 6);
} }
getLight(pos, entity.room); getLight(pos, entity.room);
Core::active.shader->setParam(uAmbient, controller->ambient[0], 6);
} else { // sprite } else { // 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(uViewProj, Core::mViewProj);
Core::active.shader->setParam(uLightProj, Core::mLightProj);
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);
@@ -592,7 +531,7 @@ struct Level : IGame {
} }
void update() { void update() {
params.time += Core::deltaTime; params->time += Core::deltaTime;
for (int i = 0; i < level.entitiesCount; i++) { for (int i = 0; i < level.entitiesCount; i++) {
TR::Entity &e = level.entities[i]; TR::Entity &e = level.entities[i];
@@ -601,7 +540,7 @@ struct Level : IGame {
if (controller) { if (controller) {
controller->update(); controller->update();
if (e.type == TR::Entity::WATERFALL && ((Waterfall*)controller)->drop) { // add water drops for waterfalls if (waterCache && e.type == TR::Entity::WATERFALL && ((Waterfall*)controller)->drop) { // add water drops for waterfalls
Waterfall *w = (Waterfall*)controller; Waterfall *w = (Waterfall*)controller;
waterCache->addDrop(w->dropPos, w->dropRadius, w->dropStrength); waterCache->addDrop(w->dropPos, w->dropRadius, w->dropStrength);
} }
@@ -610,7 +549,8 @@ struct Level : IGame {
} }
camera->update(); camera->update();
waterCache->update(); if (waterCache)
waterCache->update();
} }
void setup() { void setup() {
@@ -627,22 +567,6 @@ struct Level : IGame {
if (!Core::support.VAO) if (!Core::support.VAO)
mesh->bind(); mesh->bind();
//Core::mViewProj = Core::mLightProj; //Core::mViewProj = Core::mLightProj;
// set frame constants for all shaders
for (int i = 0; i < sizeof(shaderCache->shaders[Core::pass]) / sizeof(shaderCache->shaders[Core::pass][0]); i++) {
Shader **ptr = &shaderCache->shaders[Core::pass][i][0][0][0];
for (int j = 0; j < 8; j++) {
Shader *sh = *ptr++;
if (!sh) continue;
sh->bind();
sh->setParam(uViewProj, Core::mViewProj);
sh->setParam(uLightProj, Core::mLightProj);
sh->setParam(uViewInv, Core::mViewInv);
sh->setParam(uViewPos, Core::viewPos);
sh->setParam(uParam, *((vec4*)&params));
sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
}
}
Core::basis.identity(); Core::basis.identity();
// clear visibility flag for rooms // clear visibility flag for rooms
@@ -731,35 +655,42 @@ struct Level : IGame {
shadow->unbind(sShadow); shadow->unbind(sShadow);
bool colorShadow = shadow->format == Texture::Format::RGBA ? true : false; bool colorShadow = shadow->format == Texture::Format::RGBA ? true : false;
if (colorShadow) if (colorShadow)
glClearColor(1.0f, 1.0f, 1.0f, 1.0f); Core::setClearColor(vec4(1.0f, 1.0f, 1.0f, 1.0f));
Core::setTarget(shadow, true); Core::setTarget(shadow, true);
Core::setCulling(cfBack); Core::setCulling(cfBack);
renderScene(roomIndex); renderScene(roomIndex);
Core::invalidateTarget(!colorShadow, colorShadow); Core::invalidateTarget(!colorShadow, colorShadow);
Core::setCulling(cfFront); Core::setCulling(cfFront);
if (colorShadow) if (colorShadow)
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); Core::setClearColor(vec4(0.0f, 0.0f, 0.0f, 0.0f));
} }
void render() { void render() {
Core::invalidateTarget(true, true); Core::invalidateTarget(true, true);
params.clipHeight = NO_CLIP_PLANE; params->clipHeight = NO_CLIP_PLANE;
params.clipSign = 1.0f; params->clipSign = 1.0f;
params.waterHeight = params.clipHeight; params->waterHeight = params->clipHeight;
Core::resetStates(); Core::resetStates();
ambientCache->precessQueue(); if (ambientCache)
waterCache->reset(); ambientCache->precessQueue();
if (waterCache)
waterCache->reset();
if (shadow)
renderShadows(lara->getRoomIndex());
renderShadows(lara->getRoomIndex());
Core::setTarget(NULL, true); Core::setTarget(NULL, true);
Core::setViewport(0, 0, Core::width, Core::height); Core::setViewport(0, 0, Core::width, Core::height);
waterCache->checkVisibility = true; if (waterCache)
renderCompose(camera->getRoomIndex()); waterCache->checkVisibility = true;
waterCache->checkVisibility = false;
waterCache->render(); renderCompose(camera->getRoomIndex());
if (waterCache) {
waterCache->checkVisibility = false;
waterCache->render();
}
// Core::mViewInv = camera->mViewInv; // Core::mViewInv = camera->mViewInv;
// Core::mView = Core::mViewInv.inverse(); // Core::mView = Core::mViewInv.inverse();
@@ -832,8 +763,8 @@ struct Level : IGame {
glEnd(); glEnd();
Core::setDepthTest(true); Core::setDepthTest(true);
/* /*
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glPushMatrix(); glPushMatrix();
glLoadIdentity(); glLoadIdentity();
@@ -871,7 +802,7 @@ struct Level : IGame {
glPopMatrix(); glPopMatrix();
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glPopMatrix(); glPopMatrix();
*/
Core::setBlending(bmAlpha); Core::setBlending(bmAlpha);
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room); // Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
@@ -886,7 +817,7 @@ struct Level : IGame {
/* /*
static int dbg_ambient = 0; static int dbg_ambient = 0;
dbg_ambient = int(params.time * 2) % 4; dbg_ambient = int(params->time * 2) % 4;
shadow->unbind(sShadow); shadow->unbind(sShadow);
atlas->bind(sDiffuse); atlas->bind(sDiffuse);

View File

@@ -138,7 +138,10 @@ struct MeshBuilder {
MeshRange sprites; MeshRange sprites;
MeshRange **meshes; MeshRange **meshes;
} *rooms; } *rooms;
MeshRange *models; struct ModelRange {
MeshRange geometry;
bool opaque;
} *models;
MeshRange *sequences; MeshRange *sequences;
// procedured // procedured
MeshRange shadowBlob; MeshRange shadowBlob;
@@ -180,7 +183,8 @@ struct MeshBuilder {
iCount += d.rCount * 6 + d.tCount * 3; iCount += d.rCount * 6 + d.tCount * 3;
vCount += d.rCount * 4 + d.tCount * 3; vCount += d.rCount * 4 + d.tCount * 3;
roomRemoveWaterSurfaces(r, iCount, vCount); if (Core::settings.water)
roomRemoveWaterSurfaces(r, iCount, vCount);
for (int j = 0; j < r.meshesCount; j++) { for (int j = 0; j < r.meshesCount; j++) {
TR::Room::Mesh &m = r.meshes[j]; TR::Room::Mesh &m = r.meshes[j];
@@ -203,7 +207,7 @@ struct MeshBuilder {
} }
// get models info // get models info
models = new MeshRange[level.modelsCount]; models = new ModelRange[level.modelsCount];
for (int i = 0; i < level.modelsCount; i++) { for (int i = 0; i < level.modelsCount; i++) {
TR::Model &model = level.models[i]; TR::Model &model = level.models[i];
for (int j = 0; j < model.mCount; j++) { for (int j = 0; j < model.mCount; j++) {
@@ -311,21 +315,23 @@ struct MeshBuilder {
// build models geometry // build models geometry
for (int i = 0; i < level.modelsCount; i++) { for (int i = 0; i < level.modelsCount; i++) {
TR::Model &model = level.models[i]; TR::Model &model = level.models[i];
MeshRange &range = models[i]; ModelRange &range = models[i];
int vStart = vCount; int vStart = vCount;
range.vStart = vStart; range.geometry.vStart = vStart;
range.iStart = iCount; range.geometry.iStart = iCount;
range.opaque = true;
for (int j = 0; j < model.mCount; j++) { for (int j = 0; j < model.mCount; j++) {
int index = level.meshOffsets[model.mStart + j]; int index = level.meshOffsets[model.mStart + j];
if (!index && model.mStart + j > 0) continue; if (!index && model.mStart + j > 0) continue;
aCount++; aCount++;
TR::Mesh &mesh = level.meshes[index]; TR::Mesh &mesh = level.meshes[index];
buildMesh( true, mesh, level, indices, vertices, iCount, vCount, vStart, j, 0, 0, 0, 0); bool opaque = buildMesh(true, mesh, level, indices, vertices, iCount, vCount, vStart, j, 0, 0, 0, 0);
buildMesh(false, mesh, level, indices, vertices, iCount, vCount, vStart, j, 0, 0, 0, 0); if (!opaque)
buildMesh(false, mesh, level, indices, vertices, iCount, vCount, vStart, j, 0, 0, 0, 0);
range.opaque &= opaque;
} }
range.geometry.iCount = iCount - range.geometry.iStart;
range.iCount = iCount - range.iStart;
} }
// build sprite sequences // build sprite sequences
@@ -429,7 +435,7 @@ struct MeshBuilder {
for (int i = 0; i < level.spriteSequencesCount; i++) for (int i = 0; i < level.spriteSequencesCount; i++)
mesh->initRange(sequences[i]); mesh->initRange(sequences[i]);
for (int i = 0; i < level.modelsCount; i++) for (int i = 0; i < level.modelsCount; i++)
mesh->initRange(models[i]); mesh->initRange(models[i].geometry);
mesh->initRange(shadowBlob); mesh->initRange(shadowBlob);
mesh->initRange(bar); mesh->initRange(bar);
mesh->initRange(quad); mesh->initRange(quad);
@@ -538,8 +544,9 @@ struct MeshBuilder {
} }
} }
void buildRoom(bool opaque, const TR::Room &room, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart) { bool buildRoom(bool opaque, const TR::Room &room, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart) {
const TR::Room::Data &d = room.data; const TR::Room::Data &d = room.data;
bool isOpaque = true;
for (int j = 0; j < d.rCount; j++) { for (int j = 0; j < d.rCount; j++) {
TR::Rectangle &f = d.rectangles[j]; TR::Rectangle &f = d.rectangles[j];
@@ -547,6 +554,9 @@ struct MeshBuilder {
if (f.vertices[0] == 0xFFFF) continue; // skip if marks as unused (removing water planes) if (f.vertices[0] == 0xFFFF) continue; // skip if marks as unused (removing water planes)
if (t.attribute != 0)
isOpaque = false;
if (opaque != (t.attribute == 0)) if (opaque != (t.attribute == 0))
continue; continue;
@@ -570,6 +580,9 @@ struct MeshBuilder {
if (f.vertices[0] == 0xFFFF) continue; // skip if marks as unused (removing water planes) if (f.vertices[0] == 0xFFFF) continue; // skip if marks as unused (removing water planes)
if (t.attribute != 0)
isOpaque = false;
if (opaque != (t.attribute == 0)) if (opaque != (t.attribute == 0))
continue; continue;
@@ -586,16 +599,22 @@ struct MeshBuilder {
vCount++; vCount++;
} }
} }
return isOpaque;
} }
void buildMesh(bool opaque, const TR::Mesh &mesh, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 joint, int x, int y, int z, int dir) { bool buildMesh(bool opaque, const TR::Mesh &mesh, const TR::Level &level, Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 joint, int x, int y, int z, int dir) {
TR::Color24 COLOR_WHITE = { 255, 255, 255 }; TR::Color24 COLOR_WHITE = { 255, 255, 255 };
bool isOpaque = true;
for (int j = 0; j < mesh.rCount; j++) { for (int j = 0; j < mesh.rCount; j++) {
TR::Rectangle &f = mesh.rectangles[j]; TR::Rectangle &f = mesh.rectangles[j];
bool textured = !(f.texture & 0x8000); bool textured = !(f.texture & 0x8000);
TR::ObjectTexture &t = textured ? level.objectTextures[f.texture] : whiteTile; TR::ObjectTexture &t = textured ? level.objectTextures[f.texture] : whiteTile;
if (t.attribute != 0)
isOpaque = false;
if (opaque != (t.attribute == 0)) if (opaque != (t.attribute == 0))
continue; continue;
@@ -619,6 +638,9 @@ struct MeshBuilder {
bool textured = !(f.texture & 0x8000); bool textured = !(f.texture & 0x8000);
TR::ObjectTexture &t = textured ? level.objectTextures[f.texture] : whiteTile; TR::ObjectTexture &t = textured ? level.objectTextures[f.texture] : whiteTile;
if (t.attribute != 0)
isOpaque = false;
if (opaque != (t.attribute == 0)) if (opaque != (t.attribute == 0))
continue; continue;
@@ -636,6 +658,8 @@ struct MeshBuilder {
vCount++; vCount++;
} }
} }
return isOpaque;
} }
vec2 getTexCoord(const TR::ObjectTexture &tex) { vec2 getTexCoord(const TR::ObjectTexture &tex) {
@@ -791,7 +815,7 @@ struct MeshBuilder {
} }
void renderModel(int modelIndex) { void renderModel(int modelIndex) {
mesh->render(models[modelIndex]); mesh->render(models[modelIndex].geometry);
} }
void renderSprite(int sequenceIndex, int frame) { void renderSprite(int sequenceIndex, int frame) {
@@ -860,7 +884,7 @@ struct MeshBuilder {
if (!text) return; if (!text) return;
Core::active.shader->setParam(uColor, color); Core::active.shader->setParam(uMaterial, vec4(1.0, 0.0, 0.0, 1.0));
//text = "a: b"; //text = "a: b";
Basis basis; Basis basis;
basis.identity(); basis.identity();

View File

@@ -12,18 +12,19 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
#ifndef PASS_SHADOW #ifndef PASS_SHADOW
#ifndef PASS_AMBIENT #ifndef PASS_AMBIENT
varying vec3 vCoord; varying vec3 vCoord;
varying vec4 vNormal; varying vec4 vNormal;
varying vec3 vViewVec; varying vec3 vViewVec;
varying vec4 vLightProj; varying vec4 vLightProj;
#endif #endif
varying vec4 vColor; varying vec4 vColor;
uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
#endif #endif
#ifdef PASS_COMPOSE #ifdef PASS_COMPOSE
uniform vec3 uViewPos; uniform vec3 uViewPos;
uniform vec4 uParam; uniform vec4 uParam; // x - time, y - water height, z - clip plane sign, w - clip plane height
#ifdef CAUSTICS #ifdef UNDERWATER
uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ
#endif #endif
#endif #endif
@@ -82,6 +83,15 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
#ifndef PASS_SHADOW #ifndef PASS_SHADOW
vColor = aColor; vColor = aColor;
vColor.xyz *= uMaterial.x; // apply diffuse intensity
#ifdef TYPE_MIRROR
vColor.xyz *= vec3(0.6, 0.6, 4.0); // blue color dodge for crystal
#endif
#ifdef UNDERWATER
#ifndef TYPE_ENTITY
vColor.xyz *= UNDERWATER_COLOR; // underwater blue color
#endif
#endif
#endif #endif
#ifdef PASS_COMPOSE #ifdef PASS_COMPOSE
@@ -95,7 +105,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
vTexCoord.xy = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated vTexCoord.xy = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated
vNormal = vec4(mulQuat(rBasisRot, aNormal.xyz), aNormal.w); vNormal = vec4(mulQuat(rBasisRot, aNormal.xyz), aNormal.w);
#ifdef CAUSTICS #ifdef UNDERWATER
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 + uParam.x)) * 1.5 + 0.5; // color dodge
#endif #endif
@@ -105,7 +115,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
vNormal = vec4(uViewPos.xyz - coord.xyz, 0.0); vNormal = vec4(uViewPos.xyz - coord.xyz, 0.0);
#endif #endif
#ifdef CAUSTICS #ifdef UNDERWATER
vTexCoord.zw = clamp((coord.xz - uRoomSize.xy) / (uRoomSize.zw - uRoomSize.xy), vec2(0.0), vec2(1.0)); vTexCoord.zw = clamp((coord.xz - uRoomSize.xy) / (uRoomSize.zw - uRoomSize.xy), vec2(0.0), vec2(1.0));
#else #else
vTexCoord.zw = vec2(1.0); vTexCoord.zw = vec2(1.0);
@@ -123,14 +133,23 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
gl_Position = uViewProj * coord; gl_Position = uViewProj * coord;
} }
#else #else
uniform sampler2D sDiffuse; uniform sampler2D sDiffuse;
uniform sampler2D sReflect;
uniform vec4 uColor; #if defined(UNDERWATER) && defined(OPT_WATER)
uniform sampler2D sReflect;
#endif
#ifdef PASS_COMPOSE #ifdef PASS_COMPOSE
uniform samplerCube sEnvironment; #ifdef TYPE_MIRROR
uniform vec3 uLightPos[MAX_LIGHTS]; uniform samplerCube sEnvironment;
uniform vec4 uLightColor[MAX_LIGHTS]; #endif
uniform vec3 uAmbient[6];
#ifdef OPT_AMBIENT
uniform vec3 uAmbient[6];
#endif
uniform vec3 uLightPos[MAX_LIGHTS];
uniform vec4 uLightColor[MAX_LIGHTS];
#endif #endif
#ifdef PASS_SHADOW #ifdef PASS_SHADOW
@@ -147,94 +166,78 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
#ifdef PASS_COMPOSE #ifdef PASS_COMPOSE
#ifdef SHADOW_SAMPLER #ifdef OPT_SHADOW
uniform sampler2DShadow sShadow; #ifdef SHADOW_SAMPLER
#ifdef GL_ES uniform sampler2DShadow sShadow;
#define SHADOW(V) (shadow2DEXT(sShadow, V)) #ifdef GL_ES
#define SHADOW(V) (shadow2DEXT(sShadow, V))
#else
#define SHADOW(V) (shadow2D(sShadow, V).x)
#endif
#else #else
#define SHADOW(V) (shadow2D(sShadow, V).x) uniform sampler2D sShadow;
#endif #define CMP(a,b) step(b, a)
#else
uniform sampler2D sShadow;
#define CMP(a,b) step(b, a)
#ifdef SHADOW_DEPTH #ifdef SHADOW_DEPTH
#define compare(p, z) CMP(texture2D(sShadow, (p)).x, (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 compare(p, z) CMP(unpack(texture2D(sShadow, (p))), (z));
#endif
float SHADOW(vec3 p) {
return compare(p.xy, p.z);
/*
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);
*/
} }
#define compare(p, z) CMP(unpack(texture2D(sShadow, (p))), (z));
#endif #endif
float SHADOW(vec3 p) { float getShadow(vec4 lightProj) {
return compare(p.xy, p.z); vec3 p = lightProj.xyz / lightProj.w;
/*
vec2 t = vec2(0.0, 1.0 / 1024.0); float rShadow = 0.0;
vec2 c = floor(p.xy * 1024.0 + 0.5) / 1024.0; rShadow += SHADOW(p + (vec3(-0.94201624, -0.39906216, 0.0) * (1.5 / 1024.0)));
vec4 s; rShadow += SHADOW(p + (vec3( 0.94558609, -0.76890725, 0.0) * (1.5 / 1024.0)));
s.x = compare(c + t.xx, p.z); rShadow += SHADOW(p + (vec3(-0.09418410, -0.92938870, 0.0) * (1.5 / 1024.0)));
s.y = compare(c + t.xy, p.z); rShadow += SHADOW(p + (vec3( 0.34495938, 0.29387760, 0.0) * (1.5 / 1024.0)));
s.z = compare(c + t.yx, p.z); rShadow += SHADOW(p + (vec3(-0.91588581, 0.45771432, 0.0) * (1.5 / 1024.0)));
s.w = compare(c + t.yy, p.z); rShadow += SHADOW(p + (vec3(-0.81544232, -0.87912464, 0.0) * (1.5 / 1024.0)));
vec2 f = fract(p.xy * 1024.0 + 0.5); rShadow += SHADOW(p + (vec3(-0.38277543, 0.27676845, 0.0) * (1.5 / 1024.0)));
return mix(mix(s.x, s.y, f.y), mix(s.z, s.w, f.y), f.x); rShadow += SHADOW(p + (vec3( 0.97484398, 0.75648379, 0.0) * (1.5 / 1024.0)));
*/ rShadow += SHADOW(p + (vec3( 0.44323325, -0.97511554, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3( 0.53742981, -0.47373420, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3(-0.26496911, -0.41893023, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3( 0.79197514, 0.19090188, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3(-0.24188840, 0.99706507, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3(-0.81409955, 0.91437590, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3( 0.19984126, 0.78641367, 0.0) * (1.5 / 1024.0)));
rShadow += SHADOW(p + (vec3( 0.14383161, -0.14100790, 0.0) * (1.5 / 1024.0)));
rShadow /= 16.0;
vec3 lv = uLightPos[0].xyz - vCoord.xyz;
float fade = clamp(dot(lv, lv) / uLightColor[0].w, 0.0, 1.0);
return mix(rShadow, 1.0, fade);
}
float getShadow() {
return min(dot(vNormal.xyz, uLightPos[0].xyz - vCoord), vLightProj.w) > 0.0 ? getShadow(vLightProj) : 1.0;
} }
#endif #endif
float getShadow(vec4 lightProj) {
vec3 poissonDisk[16];
poissonDisk[ 0] = vec3(-0.94201624, -0.39906216, 0.0) * (1.5 / 1024.0);
poissonDisk[ 1] = vec3( 0.94558609, -0.76890725, 0.0) * (1.5 / 1024.0);
poissonDisk[ 2] = vec3(-0.09418410, -0.92938870, 0.0) * (1.5 / 1024.0);
poissonDisk[ 3] = vec3( 0.34495938, 0.29387760, 0.0) * (1.5 / 1024.0);
poissonDisk[ 4] = vec3(-0.91588581, 0.45771432, 0.0) * (1.5 / 1024.0);
poissonDisk[ 5] = vec3(-0.81544232, -0.87912464, 0.0) * (1.5 / 1024.0);
poissonDisk[ 6] = vec3(-0.38277543, 0.27676845, 0.0) * (1.5 / 1024.0);
poissonDisk[ 7] = vec3( 0.97484398, 0.75648379, 0.0) * (1.5 / 1024.0);
poissonDisk[ 8] = vec3( 0.44323325, -0.97511554, 0.0) * (1.5 / 1024.0);
poissonDisk[ 9] = vec3( 0.53742981, -0.47373420, 0.0) * (1.5 / 1024.0);
poissonDisk[10] = vec3(-0.26496911, -0.41893023, 0.0) * (1.5 / 1024.0);
poissonDisk[11] = vec3( 0.79197514, 0.19090188, 0.0) * (1.5 / 1024.0);
poissonDisk[12] = vec3(-0.24188840, 0.99706507, 0.0) * (1.5 / 1024.0);
poissonDisk[13] = vec3(-0.81409955, 0.91437590, 0.0) * (1.5 / 1024.0);
poissonDisk[14] = vec3( 0.19984126, 0.78641367, 0.0) * (1.5 / 1024.0);
poissonDisk[15] = vec3( 0.14383161, -0.14100790, 0.0) * (1.5 / 1024.0);
float rShadow = 0.0;
vec3 p = lightProj.xyz / lightProj.w;
rShadow += SHADOW(p + poissonDisk[0]);
rShadow += SHADOW(p + poissonDisk[1]);
rShadow += SHADOW(p + poissonDisk[2]);
rShadow += SHADOW(p + poissonDisk[3]);
rShadow += SHADOW(p + poissonDisk[4]);
rShadow += SHADOW(p + poissonDisk[5]);
rShadow += SHADOW(p + poissonDisk[6]);
rShadow += SHADOW(p + poissonDisk[7]);
rShadow += SHADOW(p + poissonDisk[8]);
rShadow += SHADOW(p + poissonDisk[9]);
rShadow += SHADOW(p + poissonDisk[10]);
rShadow += SHADOW(p + poissonDisk[11]);
rShadow += SHADOW(p + poissonDisk[12]);
rShadow += SHADOW(p + poissonDisk[13]);
rShadow += SHADOW(p + poissonDisk[14]);
rShadow += SHADOW(p + poissonDisk[15]);
rShadow /= 16.0;
vec3 lv = uLightPos[0].xyz - vCoord.xyz;
float fade = clamp(dot(lv, lv) / uLightColor[0].w, 0.0, 1.0);
return mix(rShadow, 1.0, fade);
}
float getShadow() {
return min(dot(vNormal.xyz, uLightPos[0].xyz - vCoord), vLightProj.w) > 0.0 ? getShadow(vLightProj) : 1.0;
}
vec3 calcLight(vec3 normal, vec3 pos, vec4 color) { vec3 calcLight(vec3 normal, vec3 pos, vec4 color) {
vec3 lv = pos - vCoord.xyz; vec3 lv = pos - vCoord.xyz;
float lum = max(0.0, dot(normal, normalize(lv))); float lum = max(0.0, dot(normal, normalize(lv)));
@@ -249,18 +252,20 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
return vec3(spec); return vec3(spec);
} }
vec3 calcAmbient(vec3 n) { #ifdef OPT_AMBIENT
vec3 sqr = n * n; vec3 calcAmbient(vec3 n) {
vec3 pos = step(0.0, n); vec3 sqr = n * n;
return sqr.x * mix(uAmbient[1], uAmbient[0], pos.x) + vec3 pos = step(0.0, n);
sqr.y * mix(uAmbient[3], uAmbient[2], pos.y) + return sqr.x * mix(uAmbient[1], uAmbient[0], pos.x) +
sqr.z * mix(uAmbient[5], uAmbient[4], pos.z); sqr.y * mix(uAmbient[3], uAmbient[2], pos.y) +
} sqr.z * mix(uAmbient[5], uAmbient[4], pos.z);
}
#endif
#ifdef CAUSTICS #if defined(UNDERWATER) && defined(OPT_WATER)
float calcCaustics(vec3 n) { float calcCaustics(vec3 n) {
vec2 fade = smoothstep(uRoomSize.xy, uRoomSize.xy + vec2(256.0), vCoord.xz) * (1.0 - smoothstep(uRoomSize.zw - vec2(256.0), uRoomSize.zw, vCoord.xz)); vec2 fade = smoothstep(uRoomSize.xy, uRoomSize.xy + vec2(256.0), vCoord.xz) * (1.0 - smoothstep(uRoomSize.zw - vec2(256.0), uRoomSize.zw, vCoord.xz));
return texture2D(sReflect, vTexCoord.zw).r * (max(0.0, -n.y)) * fade.x * fade.y; return texture2D(sReflect, vTexCoord.zw).g * (max(0.0, -n.y)) * fade.x * fade.y;
} }
#endif #endif
@@ -285,6 +290,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
#ifdef ALPHA_TEST #ifdef ALPHA_TEST
if (color.w <= 0.1) if (color.w <= 0.1)
discard; discard;
//color.xyz *= vec3(1.0, 0.0, 0.0);
#endif #endif
#ifdef PASS_SHADOW #ifdef PASS_SHADOW
@@ -294,9 +300,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
gl_FragColor = vec4(1.0); gl_FragColor = vec4(1.0);
#endif #endif
#else #else
color.xyz *= uColor.xyz;
color.xyz *= vColor.xyz; color.xyz *= vColor.xyz;
color.xyz *= color.xyz; // to "linear" space color.xyz *= color.xyz; // to "linear" space
#ifdef PASS_AMBIENT #ifdef PASS_AMBIENT
@@ -308,42 +312,62 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
vec3 viewVec = normalize(vViewVec); vec3 viewVec = normalize(vViewVec);
vec3 light = vec3(0.0); vec3 light = vec3(0.0);
light += calcLight(normal, uLightPos[1], uLightColor[1]); #ifdef OPT_LIGHTING
light += calcLight(normal, uLightPos[2], uLightColor[2]); light += calcLight(normal, uLightPos[1], uLightColor[1]);
light += calcLight(normal, uLightPos[2], uLightColor[2]);
#endif
// apply lighting // apply lighting
#ifdef TYPE_SPRITE #ifdef TYPE_SPRITE
light += vColor.w * uColor.w; light += vColor.w * uMaterial.y; // apply diffuse intensity
#endif #endif
#ifdef TYPE_ROOM #ifdef TYPE_ROOM
light += mix(min(uColor.w, vColor.w), vColor.w, getShadow()); #ifdef OPT_SHADOW
#ifdef CAUSTICS light += mix(min(uMaterial.y, vColor.w), vColor.w, getShadow());
#else
light += vColor.w;
#endif
#if defined(UNDERWATER) && defined(OPT_WATER)
light += calcCaustics(normal); light += calcCaustics(normal);
#endif #endif
#endif #endif
#ifdef TYPE_ENTITY #ifdef TYPE_ENTITY
vec3 rAmbient = calcAmbient(normal); vec3 mainLight = calcLight(normal, uLightPos[0], uLightColor[0]);
float rShadow = getShadow(); float mainSpec = uMaterial.z;
light += calcLight(normal, uLightPos[0], uLightColor[0]) * rShadow + rAmbient;
color.xyz += calcSpecular(normal, viewVec, uLightPos[0], uLightColor[0], uColor.w * rShadow + 0.03);
#ifdef CAUSTICS
light += calcCaustics(normal);
#endif
#endif
#ifdef TYPE_MIRROR #ifdef OPT_SHADOW
vec3 rv = reflect(-viewVec, normal); float rShadow = getShadow();
color.xyz = uColor.xyz * pow(abs(textureCube(sEnvironment, normalize(rv)).xyz), vec3(2.2)); mainLight *= rShadow;
light.xyz = vec3(1.0); mainSpec *= rShadow;
#endif
light += mainLight;
#ifdef OPT_AMBIENT
light += calcAmbient(normal);
#else
light += uMaterial.y;
#endif
#ifdef UNDERWATER
if (vCoord.y > uParam.y) {
color.xyz *= UNDERWATER_COLOR;
#ifdef OPT_WATER
light += calcCaustics(normal);
#endif
} else
color.xyz += calcSpecular(normal, viewVec, uLightPos[0], uLightColor[0], mainSpec + 0.03);
#else
color.xyz += calcSpecular(normal, viewVec, uLightPos[0], uLightColor[0], mainSpec + 0.03);
#endif
#endif #endif
color.xyz *= light; color.xyz *= light;
#else // ifndef TYPE_FLASH #else // ifndef TYPE_FLASH
color.w *= uColor.w; color.w *= uMaterial.w;
#endif #endif
#endif #endif
@@ -351,14 +375,21 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
color.xyz = sqrt(color.xyz); // back to "gamma" space color.xyz = sqrt(color.xyz); // back to "gamma" space
#ifdef PASS_COMPOSE #ifdef PASS_COMPOSE
#ifdef TYPE_MIRROR
vec3 rv = reflect(-normalize(vViewVec), normalize(vNormal.xyz));
color.xyz = vColor.xyz * textureCube(sEnvironment, normalize(rv)).xyz;
#endif
color.xyz = applyFog(color.xyz, vec3(0.0), length(vViewVec) * FOG_DIST); color.xyz = applyFog(color.xyz, vec3(0.0), length(vViewVec) * FOG_DIST);
#ifdef CAUSTICS #if defined(UNDERWATER) && defined(OPT_WATER)
float d = abs((vCoord.y - max(uViewPos.y, uParam.y)) / normalize(vViewVec).y); float d = abs((vCoord.y - max(uViewPos.y, uParam.y)) / normalize(vViewVec).y);
d *= step(0.0, vCoord.y - uParam.y); d *= step(0.0, vCoord.y - uParam.y);
color.xyz = applyFog(color.xyz, uColor.xyz * 0.2, d * WATER_FOG_DIST); color.xyz = applyFog(color.xyz, UNDERWATER_COLOR * 0.2, d * WATER_FOG_DIST);
#endif #endif
#endif #endif
color.xyz *= 1.5; // add contrast
gl_FragColor = color; gl_FragColor = color;
#endif #endif
} }

View File

@@ -3,13 +3,53 @@
#include "core.h" #include "core.h"
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX }; #define SHADER_ATTRIBS(E) \
enum SamplerType { sDiffuse, sNormal, sReflect, sShadow, sEnvironment, sMask, sMAX }; E( aCoord ) \
enum UniformType { uParam, uTexParam, uViewProj, uViewInv, uBasis, uLightProj, uColor, uAmbient, uViewPos, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uRoomSize, uPosScale, uMAX }; E( aTexCoord ) \
E( aNormal ) \
E( aColor )
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" }; #define SHADER_SAMPLERS(E) \
const char *SamplerName[sMAX] = { "sDiffuse", "sNormal", "sReflect", "sShadow", "sEnvironment", "sMask" }; E( sDiffuse ) \
const char *UniformName[uMAX] = { "uParam", "uTexParam", "uViewProj", "uViewInv", "uBasis", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets", "uRoomSize", "uPosScale" }; E( sNormal ) \
E( sReflect ) \
E( sShadow ) \
E( sEnvironment ) \
E( sMask )
#define SHADER_UNIFORMS(E) \
E( uParam ) \
E( uTexParam ) \
E( uViewProj ) \
E( uViewInv ) \
E( uBasis ) \
E( uLightProj ) \
E( uMaterial ) \
E( uAmbient ) \
E( uViewPos ) \
E( uLightPos ) \
E( uLightColor ) \
E( uAnimTexRanges ) \
E( uAnimTexOffsets ) \
E( uRoomSize ) \
E( uPosScale )
#define ENUM(v) v,
#define STR(v) #v,
enum AttribType { SHADER_ATTRIBS(ENUM) aMAX };
enum SamplerType { SHADER_SAMPLERS(ENUM) sMAX };
enum UniformType { SHADER_UNIFORMS(ENUM) uMAX };
const char *AttribName[aMAX] = { SHADER_ATTRIBS(STR) };
const char *SamplerName[sMAX] = { SHADER_SAMPLERS(STR) };
const char *UniformName[uMAX] = { SHADER_UNIFORMS(STR) };
#undef SHADER_ATTRIBS
#undef SHADER_SAMPLERS
#undef SHADER_UNIFORMS
#undef ENUM
#undef STR
struct Shader { struct Shader {
GLuint ID; GLuint ID;
@@ -26,7 +66,7 @@ struct Shader {
Shader(const char *source, const char *defines = "") { Shader(const char *source, const char *defines = "") {
char fileName[255]; char fileName[255];
//LOG(hello[0]);
// generate shader file path // generate shader file path
if (Core::support.shaderBinary) { if (Core::support.shaderBinary) {
uint32 hash = fnv32(defines, strlen(defines), fnv32(source, strlen(source))); uint32 hash = fnv32(defines, strlen(defines), fnv32(source, strlen(source)));
@@ -131,11 +171,13 @@ struct Shader {
memset(params, 0, sizeof(params)); memset(params, 0, sizeof(params));
} }
void bind() { bool bind() {
if (Core::active.shader != this) { if (Core::active.shader != this) {
Core::active.shader = this; Core::active.shader = this;
glUseProgram(ID); glUseProgram(ID);
return true;
} }
return false;
} }
inline bool checkParam(UniformType uType, const void *value, int size) { inline bool checkParam(UniformType uType, const void *value, int size) {

View File

@@ -4,7 +4,7 @@
#include "core.h" #include "core.h"
struct Texture { struct Texture {
enum Format : uint32 { RGBA, RGB16, RGBA16, RGBA_FLOAT, RGBA_HALF, DEPTH, SHADOW, MAX }; enum Format : uint32 { LUMINANCE, RGBA, RGB16, RGBA16, RGBA_FLOAT, RGBA_HALF, DEPTH, SHADOW, MAX };
GLuint ID; GLuint ID;
int width, height; int width, height;
@@ -38,14 +38,14 @@ struct Texture {
if (format == RGBA_HALF) { if (format == RGBA_HALF) {
if (Core::support.texHalf) if (Core::support.texHalf)
filter = Core::support.texHalfLinear; filter = filter && Core::support.texHalfLinear;
else else
format = RGBA_FLOAT; format = RGBA_FLOAT;
} }
if (format == RGBA_FLOAT) { if (format == RGBA_FLOAT) {
if (Core::support.texFloat) if (Core::support.texFloat)
filter = Core::support.texFloatLinear; filter = filter && Core::support.texFloatLinear;
else else
format = RGBA; format = RGBA;
} }
@@ -66,6 +66,7 @@ struct Texture {
GLuint ifmt, fmt; GLuint ifmt, fmt;
GLenum type; GLenum type;
} formats[MAX] = { } formats[MAX] = {
{ GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE }, // LUMINANCE
{ GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, // RGBA { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, // RGBA
{ GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }, // RGB16 { GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }, // RGB16
{ GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }, // RGBA16 { GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }, // RGBA16
@@ -88,14 +89,19 @@ struct Texture {
} }
void bind(int sampler) { void bind(int sampler) {
Core::active.textures[sampler] = this; if (Core::active.textures[sampler] != this) {
glActiveTexture(GL_TEXTURE0 + sampler); Core::active.textures[sampler] = this;
glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, ID); glActiveTexture(GL_TEXTURE0 + sampler);
glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, ID);
}
} }
void unbind(int sampler) { void unbind(int sampler) {
glActiveTexture(GL_TEXTURE0 + sampler); if (Core::active.textures[sampler]) {
glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, 0); Core::active.textures[sampler] = NULL;
glActiveTexture(GL_TEXTURE0 + sampler);
glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, 0);
}
} }
}; };

View File

@@ -301,7 +301,7 @@ struct Crystal : Controller {
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) { virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
Shader *sh = Core::active.shader; Shader *sh = Core::active.shader;
sh->setParam(uColor, vec4(0.4f, 0.4f, 16.0f, 1.0f)); // blue color dodge sh->setParam(uMaterial, vec4(1.0f));
environment->bind(sEnvironment); environment->bind(sEnvironment);
Controller::render(frustum, mesh, type, caustics); Controller::render(frustum, mesh, type, caustics);
} }

View File

@@ -19,7 +19,6 @@ uniform vec3 uPosScale[2];
uniform vec4 uTexParam; uniform vec4 uTexParam;
uniform vec4 uParam; uniform vec4 uParam;
uniform vec4 uColor;
uniform sampler2D sNormal; uniform sampler2D sNormal;
@@ -107,7 +106,7 @@ uniform sampler2D sNormal;
vec4 calc() { vec4 calc() {
vec2 tc = gl_FragCoord.xy * uTexParam.xy; vec2 tc = gl_FragCoord.xy * uTexParam.xy;
if (texture2D(sMask, tc).x == 0.0) if (texture2D(sMask, tc).x < 0.5)
return vec4(0.0); return vec4(0.0);
vec4 v = texture2D(sDiffuse, tc); // height, speed, normal.xz vec4 v = texture2D(sDiffuse, tc); // height, speed, normal.xz
@@ -135,11 +134,11 @@ uniform sampler2D sNormal;
float rOldArea = length(dFdx(vOldPos.xyz)) * length(dFdy(vOldPos.xyz)); float rOldArea = length(dFdx(vOldPos.xyz)) * length(dFdy(vOldPos.xyz));
float rNewArea = length(dFdx(vNewPos.xyz)) * length(dFdy(vNewPos.xyz)); float rNewArea = length(dFdx(vNewPos.xyz)) * length(dFdy(vNewPos.xyz));
float value = clamp(rOldArea / rNewArea * 0.2, 0.0, 1.0) * vOldPos.w; float value = clamp(rOldArea / rNewArea * 0.2, 0.0, 1.0) * vOldPos.w;
return vec4(vec3(value), 1.0); return vec4(0.0, value, 0.0, 0.0);
} }
vec4 mask() { vec4 mask() {
return vec4(0.0); return vec4(1.0, 1.0, 1.0, 0.0);
} }
vec4 compose() { vec4 compose() {
@@ -164,11 +163,11 @@ uniform sampler2D sNormal;
float fresnel = calcFresnel(dot(normal, viewVec), 0.1, 2.0); float fresnel = calcFresnel(dot(normal, viewVec), 0.1, 2.0);
vec4 color = mix(refr, refl, fresnel) + spec; vec4 color = mix(refr, refl, fresnel) + spec * 1.5;
float d = abs((vCoord.y - uViewPos.y) / normalize(vViewVec).y); float d = abs((vCoord.y - uViewPos.y) / normalize(vViewVec).y);
d *= step(0.0, uViewPos.y - vCoord.y); // apply fog only when camera is underwater d *= step(0.0, uViewPos.y - vCoord.y); // apply fog only when camera is underwater
color.xyz = applyFog(color.xyz, uColor.xyz, d * WATER_FOG_DIST); color.xyz = applyFog(color.xyz, UNDERWATER_COLOR * 0.2, d * WATER_FOG_DIST);
return color; return color;
} }