1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-02-24 07:22:58 +01: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 "camera.h"
#define NO_CLIP_PLANE 1000000.0f
#define FOG_DIST (18 * 1024)
#define WATER_FOG_DIST (8 * 1024)
//#define WATER_USE_GRID
@ -27,10 +29,12 @@ const char GUI[] =
;
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));
/*
char def[255], ext[255];
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);
if (caustics)
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
strcat(def, "#define WATER_USE_GRID %d\n");
#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() {
for (int i = 0; i < sizeof(shaders) / sizeof(shaders[0]); i++)
delete shaders[i];
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];
}
int getIndex(Core::Pass pass, Shader::Type type, bool caustics) {
int index = int(pass) * Shader::MAX * 2 + type * 2 + int(caustics);
ASSERT(index < sizeof(shaders) / sizeof(shaders[0]));
return index;
Shader* compile(Core::Pass pass, Shader::Type type, bool caustics = false, bool alphaTest = false, bool clipPlane = false) {
char def[255], 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");
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;
int index = getIndex(pass, type, caustics);
ASSERT(shaders[index] != NULL);
shaders[index]->bind();
Shader *shader = shaders[pass][type][caustics][alphaTest][clipPlane];
if (!shader)
shader = compile(pass, type, caustics, alphaTest, clipPlane);
ASSERT(shader != NULL);
shader->bind();
}
};
@ -425,7 +485,7 @@ struct WaterCache {
if (!item || !item->caustics) {
Core::blackTex->bind(sReflect);
Core::active.shader->setParam(uRoomSize, vec4(0.0f));
game->setWaterParams(-10000000.0f);
game->setWaterParams(-NO_CLIP_PLANE);
} else {
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));
@ -559,7 +619,7 @@ struct WaterCache {
game->updateParams();
game->renderCompose(underwater ? item.from : item.to);
Core::invalidateTarget(false, true);
game->setClipParams(1.0f, 1000000.0f);
game->setClipParams(1.0f, NO_CLIP_PLANE);
game->updateParams();
camera->reflectPlane = NULL;

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) {}
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 renderCompose(int roomIndex) {}
};

View File

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

View File

@ -2011,11 +2011,9 @@ struct Lara : Character {
Basis b(basis);
b.rotate(quat(vec3(1, 0, 0), -PI * 0.5f));
b.translate(offset);
Core::setBlending(bmAlpha);
Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha));
Core::active.shader->setParam(uBasis, b);
mesh->renderModel(level->extra.muzzleFlash);
Core::setBlending(bmNone);
}
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)) {
mat4 matrix = getMatrix();
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, 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);
}
virtual void setShader(Core::Pass pass, Shader::Type type, bool caustics) {
shaderCache->bind(pass, type, caustics);
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 renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {
@ -391,7 +391,7 @@ struct Level : IGame {
}
#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) {
setShader(Core::pass, type, false);
return;
@ -399,7 +399,7 @@ struct Level : IGame {
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) {
Core::color = vec4(waterCache->color, intensity);
@ -447,7 +447,7 @@ struct Level : IGame {
// render room sprites
if (mesh->hasRoomSprites(roomIndex)) {
setRoomParams(roomIndex, 1.0, Shader::SPRITE);
setRoomParams(roomIndex, 1.0, Shader::SPRITE, true);
sh = Core::active.shader;
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
@ -554,7 +554,7 @@ struct Level : IGame {
if (entity.type == TR::Entity::CRYSTAL)
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
vec3 pos = controller->getPos();
@ -615,18 +615,21 @@ 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) / sizeof(shaderCache->shaders[0]); i++) {
Shader *sh = shaderCache->shaders[i];
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);
// 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();
@ -728,7 +731,7 @@ struct Level : IGame {
void render() {
Core::invalidateTarget(true, true);
params.clipHeight = 1000000.0f;
params.clipHeight = NO_CLIP_PLANE;
params.clipSign = 1.0f;
params.waterHeight = params.clipHeight;
Core::resetStates();

View File

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

View File

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