1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-17 18:36:43 +02:00

#23 on demand shader compilation, alpha test & clip plane in shader; #15 fix context backbuffer format

This commit is contained in:
XProger
2017-03-07 05:47:15 +03:00
parent 4e5e5c7ed9
commit e57e2e2e9d
7 changed files with 112 additions and 47 deletions

View File

@@ -6,6 +6,8 @@
#include "controller.h" #include "controller.h"
#include "camera.h" #include "camera.h"
#define NO_CLIP_PLANE 1000000.0f
#define FOG_DIST (18 * 1024) #define FOG_DIST (18 * 1024)
#define WATER_FOG_DIST (8 * 1024) #define WATER_FOG_DIST (8 * 1024)
//#define WATER_USE_GRID //#define WATER_USE_GRID
@@ -27,10 +29,12 @@ const char GUI[] =
; ;
struct ShaderCache { struct ShaderCache {
Shader *shaders[int(Core::passMAX) * Shader::MAX * 2]; IGame *game;
Shader *shaders[Core::passMAX][Shader::MAX][2][2][2];
ShaderCache(IGame *game) { ShaderCache(IGame *game) : game(game) {
memset(shaders, 0, sizeof(shaders)); memset(shaders, 0, sizeof(shaders));
/*
char def[255], ext[255]; char def[255], ext[255];
ext[0] = 0; ext[0] = 0;
@@ -58,7 +62,7 @@ struct ShaderCache {
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], typeNames[type], MAX_LIGHTS, animTexRangesCount, animTexOffsetsCount, FOG_DIST, WATER_FOG_DIST); sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define FOG_DIST (1.0/%d.0)\n#define WATER_FOG_DIST (1.0/%d.0)\n", ext, passNames[pass], typeNames[type], MAX_LIGHTS, animTexRangesCount, animTexOffsetsCount, FOG_DIST, WATER_FOG_DIST);
if (caustics) if (caustics)
strcat(def, "#define CAUSTICS\n"); strcat(def, "#define CAUSTICS\n");
shaders[getIndex(Core::Pass(pass), Shader::Type(type), caustics == 1)] = new Shader(SHADER, def); shaders[pass][Shader::MAX * caustics + type] = new Shader(SHADER, def);
} }
} }
@@ -70,28 +74,84 @@ struct ShaderCache {
#ifdef WATER_USE_GRID #ifdef WATER_USE_GRID
strcat(def, "#define WATER_USE_GRID %d\n"); strcat(def, "#define WATER_USE_GRID %d\n");
#endif #endif
shaders[getIndex(Core::passWater, Shader::Type(type), false)] = new Shader(WATER, def); shaders[Core::passWater][type] = new Shader(WATER, def);
} }
} }
shaders[getIndex(Core::passFilter, Shader::FILTER_DOWNSAMPLE, false)] = new Shader(FILTER, ""); shaders[Core::passFilter][Shader::FILTER_DOWNSAMPLE] = new Shader(FILTER, "");
*/
} }
~ShaderCache() { ~ShaderCache() {
for (int i = 0; i < sizeof(shaders) / sizeof(shaders[0]); i++) for (int pass = 0; pass < Core::passMAX; pass++)
delete shaders[i]; 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];
} }
int getIndex(Core::Pass pass, Shader::Type type, bool caustics) { Shader* compile(Core::Pass pass, Shader::Type type, bool caustics = false, bool alphaTest = false, bool clipPlane = false) {
int index = int(pass) * Shader::MAX * 2 + type * 2 + int(caustics); char def[255], ext[255];
ASSERT(index < sizeof(shaders) / sizeof(shaders[0])); ext[0] = 0;
return index; 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;
const char *typ = NULL;
switch (pass) {
case Core::passCompose :
case Core::passShadow :
case Core::passAmbient : {
static const char *typeNames[] = { "SPRITE", "FLASH", "ROOM", "ENTITY", "MIRROR" };
src = SHADER;
typ = typeNames[type];
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");
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);
#ifdef WATER_USE_GRID
strcat(def, "#define WATER_USE_GRID\n");
#endif
break;
}
case Core::passFilter : {
static const char *typeNames[] = { "DOWNSAMPLE" };
src = FILTER;
typ = typeNames[type];
sprintf(def, "%s#define PASS_%s\n#define FILTER_%s\n", ext, passNames[pass], typ);
break;
}
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);
} }
void bind(Core::Pass pass, Shader::Type type, bool caustics = false) { void bind(Core::Pass pass, Shader::Type type, bool caustics = false, bool alphaTest = false, bool clipPlane = false) {
Core::pass = pass; Core::pass = pass;
int index = getIndex(pass, type, caustics); Shader *shader = shaders[pass][type][caustics][alphaTest][clipPlane];
ASSERT(shaders[index] != NULL); if (!shader)
shaders[index]->bind(); shader = compile(pass, type, caustics, alphaTest, clipPlane);
ASSERT(shader != NULL);
shader->bind();
} }
}; };
@@ -425,7 +485,7 @@ struct WaterCache {
if (!item || !item->caustics) { if (!item || !item->caustics) {
Core::blackTex->bind(sReflect); Core::blackTex->bind(sReflect);
Core::active.shader->setParam(uRoomSize, vec4(0.0f)); Core::active.shader->setParam(uRoomSize, vec4(0.0f));
game->setWaterParams(-10000000.0f); game->setWaterParams(-NO_CLIP_PLANE);
} else { } else {
item->caustics->bind(sReflect); item->caustics->bind(sReflect);
Core::active.shader->setParam(uRoomSize, vec4(item->pos.x - item->size.x, item->pos.z - item->size.z, item->pos.x + item->size.x, item->pos.z + item->size.z)); Core::active.shader->setParam(uRoomSize, vec4(item->pos.x - item->size.x, item->pos.z - item->size.z, item->pos.x + item->size.x, item->pos.z + item->size.z));
@@ -559,7 +619,7 @@ struct WaterCache {
game->updateParams(); game->updateParams();
game->renderCompose(underwater ? item.from : item.to); game->renderCompose(underwater ? item.from : item.to);
Core::invalidateTarget(false, true); Core::invalidateTarget(false, true);
game->setClipParams(1.0f, 1000000.0f); game->setClipParams(1.0f, NO_CLIP_PLANE);
game->updateParams(); game->updateParams();
camera->reflectPlane = NULL; camera->reflectPlane = NULL;

View File

@@ -24,7 +24,7 @@ struct IGame {
virtual void setWaterParams(float height) {} virtual void setWaterParams(float height) {}
virtual void updateParams() {} virtual void updateParams() {}
virtual void waterDrop(const vec3 &pos, float radius, float strength) {} virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
virtual void setShader(Core::Pass pass, Shader::Type type, bool caustics) {} virtual void setShader(Core::Pass pass, Shader::Type type, bool caustics = false, bool alphaTest = false) {}
virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {} virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {}
virtual void renderCompose(int roomIndex) {} virtual void renderCompose(int roomIndex) {}
}; };

View File

@@ -6,15 +6,13 @@ R"====(
varying vec2 vTexCoord; varying vec2 vTexCoord;
#define FILTER_DOWNSAMPLE 0
uniform int uType; uniform int uType;
#ifdef VERTEX #ifdef VERTEX
attribute vec4 aCoord; attribute vec4 aCoord;
void main() { void main() {
vTexCoord = aCoord.zw; vTexCoord = aCoord.zw;
gl_Position = vec4(aCoord.xy, 0.0, 1.0); gl_Position = vec4(aCoord.xy, 0.0, 1.0);
} }
#else #else
@@ -38,8 +36,10 @@ uniform int uType;
} }
vec4 filter() { vec4 filter() {
if (uType == FILTER_DOWNSAMPLE) return downsample(); #ifdef FILTER_DOWNSAMPLE
return vec4(1.0, 0.0, 0.0, 1.0); return downsample();
#endif
return vec4(1.0, 0.0, 1.0, 1.0);
} }
void main() { void main() {

View File

@@ -2011,11 +2011,9 @@ struct Lara : Character {
Basis b(basis); Basis b(basis);
b.rotate(quat(vec3(1, 0, 0), -PI * 0.5f)); b.rotate(quat(vec3(1, 0, 0), -PI * 0.5f));
b.translate(offset); b.translate(offset);
Core::setBlending(bmAlpha);
Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha)); Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha));
Core::active.shader->setParam(uBasis, b); Core::active.shader->setParam(uBasis, b);
mesh->renderModel(level->extra.muzzleFlash); mesh->renderModel(level->extra.muzzleFlash);
Core::setBlending(bmNone);
} }
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) { virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
@@ -2028,8 +2026,12 @@ struct Lara : Character {
if (wpnCurrent != Weapon::SHOTGUN && Core::pass != Core::passShadow && (arms[0].shotTimer < MUZZLE_FLASH_TIME || arms[1].shotTimer < MUZZLE_FLASH_TIME)) { if (wpnCurrent != Weapon::SHOTGUN && Core::pass != Core::passShadow && (arms[0].shotTimer < MUZZLE_FLASH_TIME || arms[1].shotTimer < MUZZLE_FLASH_TIME)) {
mat4 matrix = getMatrix(); mat4 matrix = getMatrix();
game->setShader(Core::pass, Shader::FLASH, false); game->setShader(Core::pass, Shader::FLASH, false);
Core::setBlending(bmAlpha);
Core::setDepthWrite(false);
renderMuzzleFlash(mesh, animation.getJoints(matrix, 10, true), vec3(-10, -50, 150), arms[0].shotTimer); renderMuzzleFlash(mesh, animation.getJoints(matrix, 10, true), vec3(-10, -50, 150), arms[0].shotTimer);
renderMuzzleFlash(mesh, animation.getJoints(matrix, 13, true), vec3( 10, -50, 150), arms[1].shotTimer); renderMuzzleFlash(mesh, animation.getJoints(matrix, 13, true), vec3( 10, -50, 150), arms[1].shotTimer);
Core::setBlending(bmNone);
Core::setDepthWrite(true);
} }
} }
}; };

View File

@@ -65,8 +65,8 @@ struct Level : IGame {
waterCache->addDrop(pos, radius, strength); waterCache->addDrop(pos, radius, strength);
} }
virtual void setShader(Core::Pass pass, Shader::Type type, bool caustics) { virtual void setShader(Core::Pass pass, Shader::Type type, bool caustics = false, bool alphaTest = false) {
shaderCache->bind(pass, type, caustics); shaderCache->bind(pass, type, caustics, alphaTest, params.clipHeight != NO_CLIP_PLANE);
} }
virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) { virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {
@@ -391,7 +391,7 @@ struct Level : IGame {
} }
#endif #endif
void setRoomParams(int roomIndex, float intensity, Shader::Type type) { void setRoomParams(int roomIndex, float intensity, Shader::Type type, bool alphaTest = false) {
if (Core::pass == Core::passShadow) { if (Core::pass == Core::passShadow) {
setShader(Core::pass, type, false); setShader(Core::pass, type, false);
return; return;
@@ -399,7 +399,7 @@ struct Level : IGame {
TR::Room &room = level.rooms[roomIndex]; TR::Room &room = level.rooms[roomIndex];
setShader(Core::pass, type, room.flags.water); setShader(Core::pass, type, room.flags.water, alphaTest);
if (room.flags.water) { if (room.flags.water) {
Core::color = vec4(waterCache->color, intensity); Core::color = vec4(waterCache->color, intensity);
@@ -447,7 +447,7 @@ struct Level : IGame {
// render room sprites // render room sprites
if (mesh->hasRoomSprites(roomIndex)) { if (mesh->hasRoomSprites(roomIndex)) {
setRoomParams(roomIndex, 1.0, Shader::SPRITE); setRoomParams(roomIndex, 1.0, Shader::SPRITE, true);
sh = Core::active.shader; sh = Core::active.shader;
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS); sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS); sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
@@ -554,7 +554,7 @@ struct Level : IGame {
if (entity.type == TR::Entity::CRYSTAL) if (entity.type == TR::Entity::CRYSTAL)
type = Shader::MIRROR; type = Shader::MIRROR;
setRoomParams(entity.room, isModel ? controller->specular : intensityf(lum), type); setRoomParams(entity.room, isModel ? controller->specular : intensityf(lum), type, !isModel);
if (isModel) { // model if (isModel) { // model
vec3 pos = controller->getPos(); vec3 pos = controller->getPos();
@@ -615,18 +615,21 @@ struct Level : IGame {
if (!Core::support.VAO) if (!Core::support.VAO)
mesh->bind(); mesh->bind();
//Core::mViewProj = Core::mLightProj; //Core::mViewProj = Core::mLightProj;
// set frame constants for all shaders // set frame constants for all shaders
for (int i = 0; i < sizeof(shaderCache->shaders) / sizeof(shaderCache->shaders[0]); i++) { for (int i = 0; i < sizeof(shaderCache->shaders[Core::pass]) / sizeof(shaderCache->shaders[Core::pass][0]); i++) {
Shader *sh = shaderCache->shaders[i]; Shader **ptr = &shaderCache->shaders[Core::pass][i][0][0][0];
if (!sh) continue; for (int j = 0; j < 8; j++) {
sh->bind(); Shader *sh = *ptr++;
sh->setParam(uViewProj, Core::mViewProj); if (!sh) continue;
sh->setParam(uLightProj, Core::mLightProj); sh->bind();
sh->setParam(uViewInv, Core::mViewInv); sh->setParam(uViewProj, Core::mViewProj);
sh->setParam(uViewPos, Core::viewPos); sh->setParam(uLightProj, Core::mLightProj);
sh->setParam(uParam, *((vec4*)&params)); sh->setParam(uViewInv, Core::mViewInv);
sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount); sh->setParam(uViewPos, Core::viewPos);
sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount); sh->setParam(uParam, *((vec4*)&params));
sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
}
} }
Core::basis.identity(); Core::basis.identity();
@@ -728,7 +731,7 @@ struct Level : IGame {
void render() { void render() {
Core::invalidateTarget(true, true); Core::invalidateTarget(true, true);
params.clipHeight = 1000000.0f; params.clipHeight = NO_CLIP_PLANE;
params.clipSign = 1.0f; params.clipSign = 1.0f;
params.waterHeight = params.clipHeight; params.waterHeight = params.clipHeight;
Core::resetStates(); Core::resetStates();

View File

@@ -44,7 +44,7 @@ public class MainActivity extends Activity implements OnTouchListener, OnGeneric
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
view = new GLSurfaceView(this); view = new GLSurfaceView(this);
view.setEGLConfigChooser(5, 6, 5, 0, 16, 0); view.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
view.setEGLContextClientVersion(2); view.setEGLContextClientVersion(2);
view.setRenderer(wrapper = new Wrapper()); view.setRenderer(wrapper = new Wrapper());

View File

@@ -276,7 +276,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
void main() { void main() {
#ifndef PASS_SHADOW #ifndef PASS_SHADOW
#ifndef PASS_AMBIENT #ifndef PASS_AMBIENT
#if defined(TYPE_ENTITY) && defined(CAUSTICS) #ifdef CLIP_PLANE
if (vCoord.y * uParam.z > uParam.w) if (vCoord.y * uParam.z > uParam.w)
discard; discard;
#endif #endif
@@ -353,7 +353,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
#else // ifndef TYPE_FLASH #else // ifndef TYPE_FLASH
color.w = uColor.w; color.w *= uColor.w;
#endif #endif
#endif #endif