diff --git a/src/cache.h b/src/cache.h index 2c8811b..71f85c9 100644 --- a/src/cache.h +++ b/src/cache.h @@ -11,6 +11,7 @@ #define FOG_DIST (18 * 1024) #define WATER_FOG_DIST (8 * 1024) //#define WATER_USE_GRID +#define UNDERWATER_COLOR "#define UNDERWATER_COLOR vec3(0.6, 0.9, 0.9)\n" const char SHADER[] = #include "shader.glsl" @@ -29,46 +30,55 @@ const char GUI[] = ; struct ShaderCache { + enum Effect { FX_NONE = 0, FX_UNDERWATER = 1, FX_ALPHA_TEST = 2, FX_CLIP_PLANE = 4 }; + 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) { memset(shaders, 0, sizeof(shaders)); 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); - compile(Core::passAmbient, Shader::ROOM, false, true, false); - compile(Core::passAmbient, Shader::ROOM, false, false, true); - compile(Core::passAmbient, Shader::ROOM, false, true, true); - compile(Core::passAmbient, Shader::ROOM, true, false, false); - compile(Core::passAmbient, Shader::SPRITE, false, true, false); - compile(Core::passAmbient, Shader::SPRITE, false, true, true); + if (Core::settings.ambient) { + compile(Core::passAmbient, Shader::ROOM, FX_NONE); + compile(Core::passAmbient, Shader::ROOM, FX_ALPHA_TEST); + compile(Core::passAmbient, Shader::ROOM, FX_CLIP_PLANE); + compile(Core::passAmbient, Shader::ROOM, FX_ALPHA_TEST | FX_CLIP_PLANE); + compile(Core::passAmbient, Shader::ROOM, FX_UNDERWATER); + 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); - compile(Core::passCompose, Shader::ROOM, false, true, false); - compile(Core::passCompose, Shader::ROOM, false, true, true); - compile(Core::passCompose, Shader::ROOM, false, false, true); - compile(Core::passCompose, Shader::ROOM, true, false, false); - compile(Core::passCompose, Shader::ROOM, true, false, true); - 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); + if (Core::settings.water) { + compile(Core::passWater, Shader::WATER_MASK, FX_NONE); + compile(Core::passWater, Shader::WATER_STEP, FX_NONE); + compile(Core::passWater, Shader::WATER_CAUSTICS, FX_NONE); + compile(Core::passWater, Shader::WATER_COMPOSE, FX_NONE); + compile(Core::passWater, Shader::WATER_DROP, FX_NONE); + } - 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::passWater , Shader::WATER_STEP, false, false, false); - compile(Core::passWater , Shader::WATER_CAUSTICS, false, false, false); - compile(Core::passWater , Shader::WATER_COMPOSE, false, false, false); - compile(Core::passWater , Shader::WATER_DROP, false, false, false); + compile(Core::passCompose, Shader::ROOM, FX_NONE); + compile(Core::passCompose, Shader::ROOM, FX_ALPHA_TEST); + compile(Core::passCompose, Shader::ROOM, FX_ALPHA_TEST | FX_CLIP_PLANE); + compile(Core::passCompose, Shader::ROOM, FX_CLIP_PLANE); + 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"); } @@ -76,25 +86,26 @@ struct ShaderCache { ~ShaderCache() { for (int pass = 0; pass < Core::passMAX; pass++) for (int type = 0; type < Shader::MAX; type++) - for (int caustics = 0; caustics < 2; caustics++) - for (int alphaTest = 0; alphaTest < 2; alphaTest++) - for (int clipPlane = 0; clipPlane < 2; clipPlane++) - delete shaders[pass][type][caustics][alphaTest][clipPlane]; + for (int fx = 0; fx < sizeof(shaders[Core::passMAX][Shader::MAX]) / sizeof(shaders[Core::passMAX][Shader::MAX][FX_NONE]); fx++) + delete shaders[pass][type][fx]; } - 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]; ext[0] = 0; - if (Core::support.shadowSampler) { - #ifdef MOBILE - strcat(ext, "#extension GL_EXT_shadow_samplers : require\n"); - #endif - strcat(ext, "#define SHADOW_SAMPLER\n"); - } else - if (Core::support.depthTexture) - strcat(ext, "#define SHADOW_DEPTH\n"); - else - strcat(ext, "#define SHADOW_COLOR\n"); + if (Core::settings.shadows) { + if (Core::support.shadowSampler) { + #ifdef MOBILE + strcat(ext, "#extension GL_EXT_shadow_samplers : require\n"); + #endif + strcat(ext, "#define SHADOW_SAMPLER\n"); + } else { + if (Core::support.depthTexture) + strcat(ext, "#define SHADOW_DEPTH\n"); + else + strcat(ext, "#define SHADOW_COLOR\n"); + } + } const char *passNames[] = { "COMPOSE", "SHADOW", "AMBIENT", "FILTER", "WATER" }; const char *src = NULL; @@ -109,16 +120,20 @@ struct ShaderCache { int animTexRangesCount = game->getMesh()->animTexRangesCount; 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); - if (caustics) strcat(def, "#define CAUSTICS\n"); - if (alphaTest) strcat(def, "#define ALPHA_TEST\n"); - if (clipPlane) strcat(def, "#define CLIP_PLANE\n"); + if (fx & FX_UNDERWATER) strcat(def, "#define UNDERWATER\n" UNDERWATER_COLOR); + if (fx & FX_ALPHA_TEST) strcat(def, "#define ALPHA_TEST\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; } case Core::passWater : { static const char *typeNames[] = { "DROP", "STEP", "CAUSTICS", "MASK", "COMPOSE" }; src = WATER; 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 strcat(def, "#define WATER_USE_GRID\n"); #endif @@ -133,17 +148,26 @@ struct ShaderCache { } default : ASSERT(false); } - LOG("shader: compile %s -> %s %s%s%s\n", passNames[pass], typ, caustics ? "caustics " : "", alphaTest ? "alphaTest " : "", clipPlane ? "clipPlane" : ""); - return shaders[pass][type][caustics][alphaTest][clipPlane] = new Shader(src, def); + 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][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; - Shader *shader = shaders[pass][type][caustics][alphaTest][clipPlane]; + Shader *shader = shaders[pass][type][fx]; if (!shader) - shader = compile(pass, type, caustics, alphaTest, clipPlane); + shader = compile(pass, type, fx); ASSERT(shader != NULL); 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 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++) { int size = 64 >> (i << 1); @@ -291,7 +315,6 @@ struct WaterCache { TR::Level *level; Texture *refract; Texture *reflect; - vec3 color; struct Item { int from, to, caust; @@ -312,6 +335,7 @@ struct WaterCache { } void init(IGame *game) { + TR::Level *level = game->getLevel(); 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 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[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); + mask = new Texture(w, h, Texture::RGB16, false, m, false); + delete[] m; + blank = false; - Core::setTarget(data[0], true); - Core::invalidateTarget(false, true); + // Core::setTarget(data[0], true); + // Core::invalidateTarget(false, true); } void free() { @@ -394,7 +419,7 @@ struct WaterCache { Drop(const vec3 &pos, float radius, float strength) : pos(pos), radius(radius), strength(strength) {} } 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); } @@ -494,7 +519,7 @@ struct WaterCache { void drop(Item &item) { 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)); vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f) }; @@ -520,7 +545,7 @@ struct WaterCache { void step(Item &item) { 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(uParam, vec4(0.995f, 1.0f, 0, 0)); @@ -537,7 +562,7 @@ struct WaterCache { // 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) }; Core::active.shader->setParam(uPosScale, rPosScale[0], 2); @@ -557,11 +582,19 @@ struct WaterCache { if (!visible) return; // 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::setCulling(cfNone); - Core::setDepthWrite(false); + Core::setColorWrite(false, false, false, true); + Core::setDepthWrite(false); + Core::setCulling(cfNone); for (int i = 0; i < count; i++) { Item &item = items[i]; @@ -587,11 +620,6 @@ struct WaterCache { Item &item = items[i]; if (!item.visible) continue; - if (item.blank) { - item.init(game); - item.blank = false; - } - // render mirror reflection Core::setTarget(reflect, true); vec3 p = item.pos; @@ -639,13 +667,10 @@ struct WaterCache { Core::lightColor[0] = vec4(lum, lum, lum, float(light.radius) * float(light.radius)); } - game->setShader(Core::passWater, Shader::WATER_COMPOSE, false); - Core::active.shader->setParam(uViewProj, Core::mViewProj); - Core::active.shader->setParam(uViewPos, Core::viewPos); + game->setShader(Core::passWater, Shader::WATER_COMPOSE); Core::active.shader->setParam(uLightPos, Core::lightPos[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(uColor, vec4(color * 0.2f, 1.0f)); float sx = item.size.x * DETAIL / (item.data[0]->width / 2); float sz = item.size.z * DETAIL / (item.data[0]->height / 2); @@ -659,9 +684,9 @@ struct WaterCache { #ifdef WATER_USE_GRID 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); - level->mesh->renderPlane(); + game->getMesh()->renderPlane(); #else - Core::active.shader->setParam(uPosScale, item.pos, 2); + Core::active.shader->setParam(uPosScale, item.pos, 2); game->getMesh()->renderQuad(); #endif Core::setCulling(cfFront); @@ -716,4 +741,6 @@ struct LightCache { }; */ +#undef UNDERWATER_COLOR + #endif \ No newline at end of file diff --git a/src/camera.h b/src/camera.h index 4661e9b..e15fea2 100644 --- a/src/camera.h +++ b/src/camera.h @@ -161,7 +161,7 @@ struct Camera : Controller { if (Input::down[ikS]) v = v - d; if (Input::down[ikA]) 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.translate(pos); diff --git a/src/controller.h b/src/controller.h index fb77806..8604fcb 100644 --- a/src/controller.h +++ b/src/controller.h @@ -24,7 +24,7 @@ struct IGame { virtual void setWaterParams(float height) {} virtual void updateParams() {} 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 renderCompose(int roomIndex) {} }; @@ -487,21 +487,45 @@ struct Controller { return matrix; } -/* void renderShadow(MeshBuilder *mesh, const vec3 &pos, const vec3 &offset, const vec3 &size, float angle) { + /* mat4 m; m.identity(); 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)); + m.scale(vec3(size.x, 0.0f, size.z) * (1.0f / 1024.0f)); - Core::active.shader->setParam(uModel, m); - Core::active.shader->setParam(uColor, vec4(0.0f, 0.0f, 0.0f, 0.5f)); + game->setShader(Core::pass, Shader::FLASH, false, false); + 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::setBlending(bmMultiply); 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 mat4 matrix = getMatrix(); @@ -540,13 +564,12 @@ struct Controller { frameIndex = Core::frameIndex; - /* // blob shadow // TODO: fake AO - if (TR::castShadow(entity.type)) { + // blob shadow // TODO: fake AO + if (!Core::settings.shadows && Core::pass == Core::passCompose && TR::castShadow(entity.type)) { TR::Level::FloorInfo 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); - } - */ + } } }; diff --git a/src/core.h b/src/core.h index 6679915..74e8a21 100644 --- a/src/core.h +++ b/src/core.h @@ -183,6 +183,9 @@ struct Texture; #define PROFILE_LABEL(id, name, label) #endif +enum CullMode { cfNone, cfBack, cfFront }; +enum BlendMode { bmNone, bmAlpha, bmAdd, bmMultiply, bmScreen }; + namespace Core { int width, height; int frameIndex; @@ -192,7 +195,7 @@ namespace Core { vec3 viewPos; vec3 lightPos[MAX_LIGHTS]; vec4 lightColor[MAX_LIGHTS]; - vec4 color; + vec4 params; Texture *blackTex, *whiteTex; @@ -209,10 +212,13 @@ namespace Core { } rtCache[2]; struct { - Shader *shader; - Texture *textures[8]; - Texture *target; - GLuint VAO; + Shader *shader; + Texture *textures[8]; + Texture *target; + int targetFace; + GLuint VAO; + BlendMode blendMode; + CullMode cullMode; } active; struct { @@ -230,15 +236,19 @@ namespace Core { bool texHalf, texHalfLinear; bool shaderBinary; } support; + + struct { + bool ambient; + bool lighting; + bool shadows; + bool water; + } settings; } #include "texture.h" #include "shader.h" #include "mesh.h" -enum CullMode { cfNone, cfBack, cfFront }; -enum BlendMode { bmNone, bmAlpha, bmAdd, bmMultiply, bmScreen }; - namespace Core { bool extSupport(const char *str, const char *ext) { @@ -336,8 +346,8 @@ namespace Core { LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false"); LOG(" depth texture : %s\n", support.depthTexture ? "true" : "false"); LOG(" shadow sampler : %s\n", support.shadowSampler ? "true" : "false"); - LOG(" discard frame : %s\n", support.discardFrame ? "true" : "false"); - LOG(" NPOT textures : %s\n", support.texNPOT ? "true" : "false"); + LOG(" discard frame : %s\n", support.discardFrame ? "true" : "false"); + LOG(" NPOT textures : %s\n", support.texNPOT ? "true" : "false"); LOG(" float textures : float = %s, half = %s\n", support.texFloat ? (support.texFloatLinear ? "linear" : "nearest") : "false", support.texHalf ? (support.texHalfLinear ? "linear" : "nearest") : "false"); @@ -353,10 +363,10 @@ namespace Core { frameIndex = 0; - uint32 data = 0xFF000000; - blackTex = new Texture(1, 1, Texture::RGBA, false, &data); + uint32 data = 0x00000000; + blackTex = new Texture(1, 1, Texture::RGBA, false, &data, false); data = 0xFFFFFFFF; - whiteTex = new Texture(1, 1, Texture::RGBA, false, &data); + whiteTex = new Texture(1, 1, Texture::RGBA, false, &data, false); } void free() { @@ -396,17 +406,23 @@ namespace Core { return cache.count++; } - void clear(bool clearColor, bool clearDepth, const vec4 &color) { - glClearColor(color.x, color.y, color.z, color.w); + void clear(bool clearColor, bool clearDepth) { if (GLbitfield mask = (clearColor ? GL_COLOR_BUFFER_BIT : 0) | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0)) 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) { glViewport(x, y, width, height); } void setCulling(CullMode mode) { + if (active.cullMode == mode) + return; + switch (mode) { case cfNone : glDisable(GL_CULL_FACE); @@ -418,11 +434,16 @@ namespace Core { break; } - if (mode != cfNone) + if (mode != cfNone && active.cullMode == cfNone) glEnable(GL_CULL_FACE); + + active.cullMode = mode; } void setBlending(BlendMode mode) { + if (active.blendMode == mode) + return; + switch (mode) { case bmNone : glDisable(GL_BLEND); @@ -441,8 +462,10 @@ namespace Core { break; } - if (mode != bmNone) + if (mode != bmNone && active.blendMode == bmNone) glEnable(GL_BLEND); + + active.blendMode = mode; } 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) { + if (target == active.target && face == active.targetFace) + return; + if (!target) { glBindFramebuffer(GL_FRAMEBUFFER, 0); glColorMask(true, true, true, true); @@ -493,10 +519,12 @@ namespace Core { glColorMask(false, false, false, false); setViewport(0, 0, target->width, target->height); } - active.target = target; if (clear) 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) { @@ -506,7 +534,9 @@ namespace Core { void resetStates() { memset(&active, 0, sizeof(active)); - glEnable(GL_DEPTH_TEST); + setDepthTest(true); + active.blendMode = bmAlpha; + active.cullMode = cfNone; setCulling(cfFront); setBlending(bmNone); } diff --git a/src/game.h b/src/game.h index 49db3db..17dfa15 100644 --- a/src/game.h +++ b/src/game.h @@ -20,6 +20,12 @@ namespace Game { void init(Stream *lvl, Stream *snd) { 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; startLevel(lvl, snd, false, false); } diff --git a/src/lara.h b/src/lara.h index 9c0b173..c599619 100644 --- a/src/lara.h +++ b/src/lara.h @@ -213,6 +213,7 @@ struct Lara : Character { Inventory inventory; int lastPickUp; int viewTarget; + int roomPrev; // water out from room struct Braid { Lara *lara; @@ -405,7 +406,7 @@ struct Lara : Character { if (level->extra.braid > -1) braid = new Braid(this, vec3(-4.0f, 24.0f, -48.0f)); - //reset(15, vec3(70067, -256, 29104), -0.68f); // level 2 (pool) + #ifdef _DEBUG //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)) { alignToWall(LARA_RADIUS); + roomPrev = getRoomIndex(); getEntity().room = roomAbove; pos.y = float(info.floor); 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) { game->waterDrop(pos, 128.0f, 0.2f); + specular = LARA_WET_SPECULAR; return animation.setAnim(ANIM_TO_ONWATER); } @@ -2011,7 +2014,7 @@ struct Lara : Character { Basis b(basis); b.rotate(quat(vec3(1, 0, 0), -PI * 0.5f)); 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); mesh->renderModel(level->extra.muzzleFlash); } diff --git a/src/level.h b/src/level.h index e9c70d1..86ba28b 100644 --- a/src/level.h +++ b/src/level.h @@ -24,12 +24,12 @@ struct Level : IGame { Camera *camera; Texture *shadow; - struct { + struct Params { float time; float waterHeight; float clipSign; float clipHeight; - } params; + } *params = (Params*)&Core::params; ShaderCache *shaderCache; AmbientCache *ambientCache; @@ -49,24 +49,25 @@ struct Level : IGame { } virtual void setClipParams(float clipSign, float clipHeight) { - params.clipSign = clipSign; - params.clipHeight = clipHeight; + params->clipSign = clipSign; + params->clipHeight = clipHeight; } virtual void setWaterParams(float height) { - params.waterHeight = height; + params->waterHeight = height; } virtual void updateParams() { - Core::active.shader->setParam(uParam, *((vec4*)¶ms)); + Core::active.shader->setParam(uParam, Core::params); } 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) { - shaderCache->bind(pass, type, caustics, alphaTest, params.clipHeight != NO_CLIP_PLANE); + virtual void setShader(Core::Pass pass, Shader::Type type, bool underwater = false, bool alphaTest = false) { + 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) { @@ -88,13 +89,14 @@ struct Level : IGame { Core::setDepthTest(true); Core::setDepthWrite(true); - shadow->bind(sShadow); + if (shadow) + shadow->bind(sShadow); renderScene(roomIndex); } //============================== Level(Stream &stream, bool demo, bool home) : level(stream, demo), lara(NULL) { - params.time = 0.0f; + params->time = 0.0f; #ifdef _DEBUG Debug::init(); @@ -204,8 +206,9 @@ struct Level : IGame { level.cameraController = camera; - ambientCache = new AmbientCache(this); - waterCache = new WaterCache(this); + ambientCache = Core::settings.ambient ? new AmbientCache(this) : NULL; + waterCache = Core::settings.water ? new WaterCache(this) : NULL; + shadow = Core::settings.shadows ? new Texture(1024, 1024, Texture::SHADOW, false) : NULL; initReflections(); for (int i = 0; i < level.soundSourcesCount; i++) { @@ -236,8 +239,6 @@ struct Level : IGame { } void initTextures() { - shadow = new Texture(1024, 1024, Texture::SHADOW, false); - if (!level.tilesCount) { atlas = NULL; return; @@ -327,95 +328,28 @@ struct Level : IGame { } } -#ifdef LEVEL_EDITOR - 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) { + void setRoomParams(int roomIndex, Shader::Type type, float diffuse, float ambient, float specular, float alpha, bool alphaTest = false) { if (Core::pass == Core::passShadow) { - setShader(Core::pass, type, false); + setShader(Core::pass, type); return; } 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); if (room.flags.water) { - Core::color = vec4(waterCache->color, intensity); - /* - // trace to water surface room - int wrIndex = roomIndex; + if (waterCache) + waterCache->bindCaustics(roomIndex); + setWaterParams(float(room.info.yTop)); + } - room.sectors[sx * room.zSectors + sz]; - - 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); + Core::active.shader->setParam(uMaterial, vec4(diffuse, ambient, specular, alpha)); } void renderRoom(int roomIndex, int from = TR::NO_ROOM) { @@ -427,7 +361,7 @@ struct Level : IGame { // room geometry & sprites if (!room.flags.rendered) { // skip if already rendered - if (room.flags.water) + if (waterCache && room.flags.water) waterCache->setVisible(roomIndex); room.flags.rendered = true; @@ -445,7 +379,7 @@ struct Level : IGame { 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; sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS); sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS); @@ -458,7 +392,7 @@ struct Level : IGame { // render room sprites if (range.sprites.iCount) { 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; sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS); sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS); @@ -494,7 +428,7 @@ struct Level : IGame { frustum = *camFrustum; 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); renderRoom(p.roomIndex, roomIndex); } @@ -556,6 +490,7 @@ struct Level : IGame { Controller *controller = (Controller*)entity.controller; + TR::Room &room = level.rooms[entity.room]; if (!room.flags.rendered || entity.flags.invisible || entity.flags.rendered) return; @@ -566,25 +501,29 @@ struct Level : IGame { if (entity.type == TR::Entity::CRYSTAL) 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 vec3 pos = controller->getPos(); - AmbientCache::Cube cube; - if (Core::frameIndex != controller->frameIndex) { - ambientCache->getAmbient(entity.room, pos, cube); - if (cube.status == AmbientCache::Cube::READY) - memcpy(controller->ambient, cube.colors, sizeof(cube.colors)); // store last calculated ambient into controller + if (Core::settings.ambient) { + AmbientCache::Cube cube; + if (Core::frameIndex != controller->frameIndex) { + ambientCache->getAmbient(entity.room, pos, cube); + 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); - Core::active.shader->setParam(uAmbient, controller->ambient[0], 6); } else { // sprite Core::lightPos[0] = vec3(0); 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(uLightColor, Core::lightColor[0], MAX_LIGHTS); @@ -592,7 +531,7 @@ struct Level : IGame { } void update() { - params.time += Core::deltaTime; + params->time += Core::deltaTime; for (int i = 0; i < level.entitiesCount; i++) { TR::Entity &e = level.entities[i]; @@ -601,7 +540,7 @@ struct Level : IGame { if (controller) { 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; waterCache->addDrop(w->dropPos, w->dropRadius, w->dropStrength); } @@ -610,7 +549,8 @@ struct Level : IGame { } camera->update(); - waterCache->update(); + if (waterCache) + waterCache->update(); } void setup() { @@ -627,22 +567,6 @@ struct Level : IGame { if (!Core::support.VAO) mesh->bind(); //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*)¶ms)); - sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount); - sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount); - } - } Core::basis.identity(); // clear visibility flag for rooms @@ -731,35 +655,42 @@ struct Level : IGame { shadow->unbind(sShadow); bool colorShadow = shadow->format == Texture::Format::RGBA ? true : false; 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::setCulling(cfBack); renderScene(roomIndex); Core::invalidateTarget(!colorShadow, colorShadow); Core::setCulling(cfFront); if (colorShadow) - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + Core::setClearColor(vec4(0.0f, 0.0f, 0.0f, 0.0f)); } void render() { Core::invalidateTarget(true, true); - params.clipHeight = NO_CLIP_PLANE; - params.clipSign = 1.0f; - params.waterHeight = params.clipHeight; + params->clipHeight = NO_CLIP_PLANE; + params->clipSign = 1.0f; + params->waterHeight = params->clipHeight; Core::resetStates(); - ambientCache->precessQueue(); - waterCache->reset(); + if (ambientCache) + ambientCache->precessQueue(); + if (waterCache) + waterCache->reset(); + if (shadow) + renderShadows(lara->getRoomIndex()); - renderShadows(lara->getRoomIndex()); Core::setTarget(NULL, true); Core::setViewport(0, 0, Core::width, Core::height); - waterCache->checkVisibility = true; - renderCompose(camera->getRoomIndex()); - waterCache->checkVisibility = false; + if (waterCache) + waterCache->checkVisibility = true; - waterCache->render(); + renderCompose(camera->getRoomIndex()); + + if (waterCache) { + waterCache->checkVisibility = false; + waterCache->render(); + } // Core::mViewInv = camera->mViewInv; // Core::mView = Core::mViewInv.inverse(); @@ -832,8 +763,8 @@ struct Level : IGame { glEnd(); Core::setDepthTest(true); - /* + glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); @@ -871,7 +802,7 @@ struct Level : IGame { glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); - */ + Core::setBlending(bmAlpha); // Debug::Level::rooms(level, lara->pos, lara->getEntity().room); @@ -886,7 +817,7 @@ struct Level : IGame { /* static int dbg_ambient = 0; - dbg_ambient = int(params.time * 2) % 4; + dbg_ambient = int(params->time * 2) % 4; shadow->unbind(sShadow); atlas->bind(sDiffuse); diff --git a/src/mesh.h b/src/mesh.h index 301e126..d5fd5c7 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -138,7 +138,10 @@ struct MeshBuilder { MeshRange sprites; MeshRange **meshes; } *rooms; - MeshRange *models; + struct ModelRange { + MeshRange geometry; + bool opaque; + } *models; MeshRange *sequences; // procedured MeshRange shadowBlob; @@ -180,7 +183,8 @@ struct MeshBuilder { iCount += d.rCount * 6 + 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++) { TR::Room::Mesh &m = r.meshes[j]; @@ -203,7 +207,7 @@ struct MeshBuilder { } // get models info - models = new MeshRange[level.modelsCount]; + models = new ModelRange[level.modelsCount]; for (int i = 0; i < level.modelsCount; i++) { TR::Model &model = level.models[i]; for (int j = 0; j < model.mCount; j++) { @@ -311,21 +315,23 @@ struct MeshBuilder { // build models geometry for (int i = 0; i < level.modelsCount; i++) { TR::Model &model = level.models[i]; - MeshRange &range = models[i]; + ModelRange &range = models[i]; int vStart = vCount; - range.vStart = vStart; - range.iStart = iCount; + range.geometry.vStart = vStart; + range.geometry.iStart = iCount; + range.opaque = true; for (int j = 0; j < model.mCount; j++) { int index = level.meshOffsets[model.mStart + j]; if (!index && model.mStart + j > 0) continue; aCount++; TR::Mesh &mesh = level.meshes[index]; - 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); + bool opaque = buildMesh(true, 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.iCount = iCount - range.iStart; + range.geometry.iCount = iCount - range.geometry.iStart; } // build sprite sequences @@ -429,7 +435,7 @@ struct MeshBuilder { for (int i = 0; i < level.spriteSequencesCount; i++) mesh->initRange(sequences[i]); for (int i = 0; i < level.modelsCount; i++) - mesh->initRange(models[i]); + mesh->initRange(models[i].geometry); mesh->initRange(shadowBlob); mesh->initRange(bar); 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; + bool isOpaque = true; for (int j = 0; j < d.rCount; 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 (t.attribute != 0) + isOpaque = false; + if (opaque != (t.attribute == 0)) continue; @@ -570,6 +580,9 @@ struct MeshBuilder { 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)) continue; @@ -586,16 +599,22 @@ struct MeshBuilder { 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 }; + bool isOpaque = true; for (int j = 0; j < mesh.rCount; j++) { TR::Rectangle &f = mesh.rectangles[j]; bool textured = !(f.texture & 0x8000); TR::ObjectTexture &t = textured ? level.objectTextures[f.texture] : whiteTile; + if (t.attribute != 0) + isOpaque = false; + if (opaque != (t.attribute == 0)) continue; @@ -619,6 +638,9 @@ struct MeshBuilder { bool textured = !(f.texture & 0x8000); TR::ObjectTexture &t = textured ? level.objectTextures[f.texture] : whiteTile; + if (t.attribute != 0) + isOpaque = false; + if (opaque != (t.attribute == 0)) continue; @@ -636,6 +658,8 @@ struct MeshBuilder { vCount++; } } + + return isOpaque; } vec2 getTexCoord(const TR::ObjectTexture &tex) { @@ -791,7 +815,7 @@ struct MeshBuilder { } void renderModel(int modelIndex) { - mesh->render(models[modelIndex]); + mesh->render(models[modelIndex].geometry); } void renderSprite(int sequenceIndex, int frame) { @@ -860,7 +884,7 @@ struct MeshBuilder { 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"; Basis basis; basis.identity(); diff --git a/src/shader.glsl b/src/shader.glsl index c801d9f..53991cd 100644 --- a/src/shader.glsl +++ b/src/shader.glsl @@ -12,18 +12,19 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords #ifndef PASS_SHADOW #ifndef PASS_AMBIENT - varying vec3 vCoord; - varying vec4 vNormal; - varying vec3 vViewVec; - varying vec4 vLightProj; + varying vec3 vCoord; + varying vec4 vNormal; + varying vec3 vViewVec; + varying vec4 vLightProj; #endif - varying vec4 vColor; + varying vec4 vColor; + uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha #endif #ifdef PASS_COMPOSE uniform vec3 uViewPos; - uniform vec4 uParam; - #ifdef CAUSTICS + uniform vec4 uParam; // x - time, y - water height, z - clip plane sign, w - clip plane height + #ifdef UNDERWATER uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ #endif #endif @@ -82,6 +83,15 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords #ifndef PASS_SHADOW 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 #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 vNormal = vec4(mulQuat(rBasisRot, aNormal.xyz), aNormal.w); - #ifdef CAUSTICS + #ifdef UNDERWATER float sum = coord.x + coord.y + coord.z; vColor.xyz *= abs(sin(sum / 512.0 + uParam.x)) * 1.5 + 0.5; // color dodge #endif @@ -105,7 +115,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords vNormal = vec4(uViewPos.xyz - coord.xyz, 0.0); #endif - #ifdef CAUSTICS + #ifdef UNDERWATER vTexCoord.zw = clamp((coord.xz - uRoomSize.xy) / (uRoomSize.zw - uRoomSize.xy), vec2(0.0), vec2(1.0)); #else vTexCoord.zw = vec2(1.0); @@ -123,14 +133,23 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords gl_Position = uViewProj * coord; } #else - uniform sampler2D sDiffuse; - uniform sampler2D sReflect; - uniform vec4 uColor; + uniform sampler2D sDiffuse; + + #if defined(UNDERWATER) && defined(OPT_WATER) + uniform sampler2D sReflect; + #endif + #ifdef PASS_COMPOSE - uniform samplerCube sEnvironment; - uniform vec3 uLightPos[MAX_LIGHTS]; - uniform vec4 uLightColor[MAX_LIGHTS]; - uniform vec3 uAmbient[6]; + #ifdef TYPE_MIRROR + uniform samplerCube sEnvironment; + #endif + + #ifdef OPT_AMBIENT + uniform vec3 uAmbient[6]; + #endif + + uniform vec3 uLightPos[MAX_LIGHTS]; + uniform vec4 uLightColor[MAX_LIGHTS]; #endif #ifdef PASS_SHADOW @@ -147,94 +166,78 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords #ifdef PASS_COMPOSE - #ifdef SHADOW_SAMPLER - uniform sampler2DShadow sShadow; - #ifdef GL_ES - #define SHADOW(V) (shadow2DEXT(sShadow, V)) + #ifdef OPT_SHADOW + #ifdef SHADOW_SAMPLER + uniform sampler2DShadow sShadow; + #ifdef GL_ES + #define SHADOW(V) (shadow2DEXT(sShadow, V)) + #else + #define SHADOW(V) (shadow2D(sShadow, V).x) + #endif #else - #define SHADOW(V) (shadow2D(sShadow, V).x) - #endif - #else - uniform sampler2D sShadow; - #define CMP(a,b) step(b, a) + uniform sampler2D sShadow; + #define CMP(a,b) step(b, a) - #ifdef SHADOW_DEPTH - #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); + #ifdef SHADOW_DEPTH + #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 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 - 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); - */ + float getShadow(vec4 lightProj) { + vec3 p = lightProj.xyz / lightProj.w; + + float rShadow = 0.0; + rShadow += SHADOW(p + (vec3(-0.94201624, -0.39906216, 0.0) * (1.5 / 1024.0))); + rShadow += SHADOW(p + (vec3( 0.94558609, -0.76890725, 0.0) * (1.5 / 1024.0))); + rShadow += SHADOW(p + (vec3(-0.09418410, -0.92938870, 0.0) * (1.5 / 1024.0))); + rShadow += SHADOW(p + (vec3( 0.34495938, 0.29387760, 0.0) * (1.5 / 1024.0))); + rShadow += SHADOW(p + (vec3(-0.91588581, 0.45771432, 0.0) * (1.5 / 1024.0))); + rShadow += SHADOW(p + (vec3(-0.81544232, -0.87912464, 0.0) * (1.5 / 1024.0))); + rShadow += SHADOW(p + (vec3(-0.38277543, 0.27676845, 0.0) * (1.5 / 1024.0))); + 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 - 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 lv = pos - vCoord.xyz; 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); } - vec3 calcAmbient(vec3 n) { - vec3 sqr = n * n; - vec3 pos = step(0.0, n); - return sqr.x * mix(uAmbient[1], uAmbient[0], pos.x) + - sqr.y * mix(uAmbient[3], uAmbient[2], pos.y) + - sqr.z * mix(uAmbient[5], uAmbient[4], pos.z); - } + #ifdef OPT_AMBIENT + vec3 calcAmbient(vec3 n) { + vec3 sqr = n * n; + vec3 pos = step(0.0, n); + return sqr.x * mix(uAmbient[1], uAmbient[0], pos.x) + + 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) { 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 @@ -285,6 +290,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords #ifdef ALPHA_TEST if (color.w <= 0.1) discard; + //color.xyz *= vec3(1.0, 0.0, 0.0); #endif #ifdef PASS_SHADOW @@ -294,9 +300,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords gl_FragColor = vec4(1.0); #endif #else - color.xyz *= uColor.xyz; color.xyz *= vColor.xyz; - color.xyz *= color.xyz; // to "linear" space #ifdef PASS_AMBIENT @@ -308,42 +312,62 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords vec3 viewVec = normalize(vViewVec); vec3 light = vec3(0.0); - light += calcLight(normal, uLightPos[1], uLightColor[1]); - light += calcLight(normal, uLightPos[2], uLightColor[2]); + #ifdef OPT_LIGHTING + light += calcLight(normal, uLightPos[1], uLightColor[1]); + light += calcLight(normal, uLightPos[2], uLightColor[2]); + #endif // apply lighting #ifdef TYPE_SPRITE - light += vColor.w * uColor.w; + light += vColor.w * uMaterial.y; // apply diffuse intensity #endif #ifdef TYPE_ROOM - light += mix(min(uColor.w, vColor.w), vColor.w, getShadow()); - #ifdef CAUSTICS + #ifdef OPT_SHADOW + light += mix(min(uMaterial.y, vColor.w), vColor.w, getShadow()); + #else + light += vColor.w; + #endif + #if defined(UNDERWATER) && defined(OPT_WATER) light += calcCaustics(normal); #endif #endif - #ifdef TYPE_ENTITY - vec3 rAmbient = calcAmbient(normal); - float rShadow = getShadow(); - 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_ENTITY + vec3 mainLight = calcLight(normal, uLightPos[0], uLightColor[0]); + float mainSpec = uMaterial.z; - #ifdef TYPE_MIRROR - vec3 rv = reflect(-viewVec, normal); - color.xyz = uColor.xyz * pow(abs(textureCube(sEnvironment, normalize(rv)).xyz), vec3(2.2)); - light.xyz = vec3(1.0); + #ifdef OPT_SHADOW + float rShadow = getShadow(); + mainLight *= rShadow; + 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 color.xyz *= light; #else // ifndef TYPE_FLASH - color.w *= uColor.w; + color.w *= uMaterial.w; #endif #endif @@ -351,14 +375,21 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords color.xyz = sqrt(color.xyz); // back to "gamma" space #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); - #ifdef CAUSTICS + #if defined(UNDERWATER) && defined(OPT_WATER) float d = abs((vCoord.y - max(uViewPos.y, uParam.y)) / normalize(vViewVec).y); - d *= step(0.0, vCoord.y - uParam.y); - color.xyz = applyFog(color.xyz, uColor.xyz * 0.2, d * WATER_FOG_DIST); + d *= step(0.0, vCoord.y - uParam.y); + color.xyz = applyFog(color.xyz, UNDERWATER_COLOR * 0.2, d * WATER_FOG_DIST); #endif #endif + color.xyz *= 1.5; // add contrast + gl_FragColor = color; #endif } diff --git a/src/shader.h b/src/shader.h index 741943c..60515d1 100644 --- a/src/shader.h +++ b/src/shader.h @@ -3,13 +3,53 @@ #include "core.h" -enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX }; -enum SamplerType { sDiffuse, sNormal, sReflect, sShadow, sEnvironment, sMask, sMAX }; -enum UniformType { uParam, uTexParam, uViewProj, uViewInv, uBasis, uLightProj, uColor, uAmbient, uViewPos, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uRoomSize, uPosScale, uMAX }; +#define SHADER_ATTRIBS(E) \ + E( aCoord ) \ + E( aTexCoord ) \ + E( aNormal ) \ + E( aColor ) -const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" }; -const char *SamplerName[sMAX] = { "sDiffuse", "sNormal", "sReflect", "sShadow", "sEnvironment", "sMask" }; -const char *UniformName[uMAX] = { "uParam", "uTexParam", "uViewProj", "uViewInv", "uBasis", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets", "uRoomSize", "uPosScale" }; +#define SHADER_SAMPLERS(E) \ + E( sDiffuse ) \ + 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 { GLuint ID; @@ -26,7 +66,7 @@ struct Shader { Shader(const char *source, const char *defines = "") { char fileName[255]; - + //LOG(hello[0]); // generate shader file path if (Core::support.shaderBinary) { uint32 hash = fnv32(defines, strlen(defines), fnv32(source, strlen(source))); @@ -131,11 +171,13 @@ struct Shader { memset(params, 0, sizeof(params)); } - void bind() { + bool bind() { if (Core::active.shader != this) { Core::active.shader = this; glUseProgram(ID); + return true; } + return false; } inline bool checkParam(UniformType uType, const void *value, int size) { diff --git a/src/texture.h b/src/texture.h index 769dfb2..98fef48 100644 --- a/src/texture.h +++ b/src/texture.h @@ -4,7 +4,7 @@ #include "core.h" 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; int width, height; @@ -38,14 +38,14 @@ struct Texture { if (format == RGBA_HALF) { if (Core::support.texHalf) - filter = Core::support.texHalfLinear; + filter = filter && Core::support.texHalfLinear; else format = RGBA_FLOAT; } if (format == RGBA_FLOAT) { if (Core::support.texFloat) - filter = Core::support.texFloatLinear; + filter = filter && Core::support.texFloatLinear; else format = RGBA; } @@ -66,6 +66,7 @@ struct Texture { GLuint ifmt, fmt; GLenum type; } formats[MAX] = { + { GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE }, // LUMINANCE { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, // RGBA { GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }, // RGB16 { GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }, // RGBA16 @@ -88,14 +89,19 @@ struct Texture { } void bind(int sampler) { - Core::active.textures[sampler] = this; - glActiveTexture(GL_TEXTURE0 + sampler); - glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, ID); + if (Core::active.textures[sampler] != this) { + Core::active.textures[sampler] = this; + glActiveTexture(GL_TEXTURE0 + sampler); + glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, ID); + } } void unbind(int sampler) { - glActiveTexture(GL_TEXTURE0 + sampler); - glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, 0); + if (Core::active.textures[sampler]) { + Core::active.textures[sampler] = NULL; + glActiveTexture(GL_TEXTURE0 + sampler); + glBindTexture(cube ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D, 0); + } } }; diff --git a/src/trigger.h b/src/trigger.h index b1b0bf1..66827b0 100644 --- a/src/trigger.h +++ b/src/trigger.h @@ -301,7 +301,7 @@ struct Crystal : Controller { virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) { 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); Controller::render(frustum, mesh, type, caustics); } diff --git a/src/water.glsl b/src/water.glsl index 73df7d6..3fd9b34 100644 --- a/src/water.glsl +++ b/src/water.glsl @@ -19,7 +19,6 @@ uniform vec3 uPosScale[2]; uniform vec4 uTexParam; uniform vec4 uParam; -uniform vec4 uColor; uniform sampler2D sNormal; @@ -107,7 +106,7 @@ uniform sampler2D sNormal; vec4 calc() { 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); 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 rNewArea = length(dFdx(vNewPos.xyz)) * length(dFdy(vNewPos.xyz)); 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() { - return vec4(0.0); + return vec4(1.0, 1.0, 1.0, 0.0); } vec4 compose() { @@ -164,11 +163,11 @@ uniform sampler2D sNormal; 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); 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; }