1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-19 11:21:31 +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 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

View File

@@ -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);

View File

@@ -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);
}
*/
}
}
};

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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*)&params));
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*)&params));
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);

View File

@@ -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();

View File

@@ -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
}

View File

@@ -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) {

View File

@@ -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);
}
}
};

View File

@@ -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);
}

View File

@@ -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;
}