1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-08-13 16:44:50 +02:00

#23 uber-shaders

This commit is contained in:
XProger
2017-03-05 23:59:19 +03:00
parent 1849874dae
commit 6e6ed3b2d0
16 changed files with 578 additions and 398 deletions

View File

@@ -17,6 +17,7 @@ struct IGame {
virtual ~IGame() {} virtual ~IGame() {}
virtual TR::Level* getLevel() { return NULL; } virtual TR::Level* getLevel() { return NULL; }
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) {}
}; };
struct Controller { struct Controller {
@@ -54,7 +55,7 @@ struct Controller {
Controller(IGame *game, int entity) : game(game), level(game->getLevel()), entity(entity), animation(level, getModel()), state(animation.state), layers(NULL), actionCommand(NULL) { Controller(IGame *game, int entity) : game(game), level(game->getLevel()), entity(entity), animation(level, getModel()), state(animation.state), layers(NULL), actionCommand(NULL) {
TR::Entity &e = getEntity(); TR::Entity &e = getEntity();
pos = vec3((float)e.x, (float)e.y, (float)e.z); pos = vec3(float(e.x), float(e.y), float(e.z));
angle = vec3(0.0f, e.rotation, 0.0f); angle = vec3(0.0f, e.rotation, 0.0f);
TR::Model *m = getModel(); TR::Model *m = getModel();
joints = m ? new Basis[m->mCount] : NULL; joints = m ? new Basis[m->mCount] : NULL;
@@ -493,7 +494,7 @@ struct Controller {
} }
*/ */
virtual void render(Frustum *frustum, MeshBuilder *mesh) { // TODO: animation.calcJoints virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) { // TODO: animation.calcJoints
mat4 matrix = getMatrix(); mat4 matrix = getMatrix();
Box box = animation.getBoundingBox(vec3(0, 0, 0), 0); Box box = animation.getBoundingBox(vec3(0, 0, 0), 0);

View File

@@ -6,6 +6,30 @@
#include <windows.h> #include <windows.h>
#include <gl/GL.h> #include <gl/GL.h>
#include <gl/glext.h> #include <gl/glext.h>
#elif ANDROID
#define MOBILE
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <dlfcn.h>
#define GL_TEXTURE_COMPARE_MODE 0x884C
#define GL_TEXTURE_COMPARE_FUNC 0x884D
#define GL_COMPARE_REF_TO_TEXTURE 0x884E
#undef GL_RGBA32F
#undef GL_RGBA16F
#undef GL_HALF_FLOAT
#define GL_RGBA32F GL_RGBA
#define GL_RGBA16F GL_RGBA
#define GL_HALF_FLOAT GL_HALF_FLOAT_OES
#define PFNGLGENVERTEXARRAYSPROC PFNGLGENVERTEXARRAYSOESPROC
#define PFNGLDELETEVERTEXARRAYSPROC PFNGLDELETEVERTEXARRAYSOESPROC
#define PFNGLBINDVERTEXARRAYPROC PFNGLBINDVERTEXARRAYOESPROC
#define glGenVertexArrays glGenVertexArraysOES
#define glDeleteVertexArrays glDeleteVertexArraysOES
#define glBindVertexArray glBindVertexArrayOES
#elif __linux__ #elif __linux__
#define LINUX 1 #define LINUX 1
#include <GL/gl.h> #include <GL/gl.h>
@@ -18,16 +42,11 @@
#include <OpenGL/gl.h> #include <OpenGL/gl.h>
#include <OpenGL/glext.h> #include <OpenGL/glext.h>
#include <AGL/agl.h> #include <AGL/agl.h>
/* #define glGenVertexArrays glGenVertexArraysAPPLE
* In compatibility mode, Mac OS X only supports OpenGL 2 (no VAO), but it does #define glDeleteVertexArrays glDeleteVertexArraysAPPLE
* support the Apple-specific VAO extension which is older and in all relevant #define glBindVertexArray glBindVertexArrayAPPLE
* parts 100% compatible. So use those functions instead.
*/
#define glBindVertexArray glBindVertexArrayAPPLE
#define glGenVertexArrays glGenVertexArraysAPPLE
#define glDeleteVertexArrays glDeleteVertexArraysAPPLE
#elif __EMSCRIPTEN__ #elif __EMSCRIPTEN__
#define MOBILE 1 #define MOBILE
#include <emscripten.h> #include <emscripten.h>
#include <html5.h> #include <html5.h>
#include <GLES3/gl3.h> #include <GLES3/gl3.h>
@@ -46,7 +65,11 @@
#include "input.h" #include "input.h"
#include "sound.h" #include "sound.h"
#if defined(WIN32) || defined(LINUX) #if defined(WIN32) || defined(LINUX) || defined(ANDROID)
#ifdef ANDROID
#define GetProc(x) dlsym(libGL, x);
#else
void* GetProc(const char *name) { void* GetProc(const char *name) {
#ifdef WIN32 #ifdef WIN32
return (void*)wglGetProcAddress(name); return (void*)wglGetProcAddress(name);
@@ -54,6 +77,7 @@
return (void*)glXGetProcAddress((GLubyte*)name); return (void*)glXGetProcAddress((GLubyte*)name);
#endif #endif
} }
#endif
#define GetProcOGL(x) x=(decltype(x))GetProc(#x); #define GetProcOGL(x) x=(decltype(x))GetProc(#x);
@@ -61,7 +85,15 @@
#ifdef WIN32 #ifdef WIN32
PFNGLACTIVETEXTUREPROC glActiveTexture; PFNGLACTIVETEXTUREPROC glActiveTexture;
#endif #endif
// Shader
#if defined(WIN32) || defined(LINUX)
// Profiling
#ifdef PROFILE
PFNGLOBJECTLABELPROC glObjectLabel;
PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup;
PFNGLPOPDEBUGGROUPPROC glPopDebugGroup;
#endif
// Shader
PFNGLCREATEPROGRAMPROC glCreateProgram; PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLDELETEPROGRAMPROC glDeleteProgram; PFNGLDELETEPROGRAMPROC glDeleteProgram;
PFNGLLINKPROGRAMPROC glLinkProgram; PFNGLLINKPROGRAMPROC glLinkProgram;
@@ -84,15 +116,7 @@
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
// Mesh // Render to texture
PFNGLGENBUFFERSARBPROC glGenBuffers;
PFNGLDELETEBUFFERSARBPROC glDeleteBuffers;
PFNGLBINDBUFFERARBPROC glBindBuffer;
PFNGLBUFFERDATAARBPROC glBufferData;
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
// Render to texture
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
@@ -101,13 +125,20 @@
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer; PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
PFNGLDRAWBUFFERSPROC glDrawBuffers; // Mesh
// Profiling PFNGLGENBUFFERSARBPROC glGenBuffers;
#ifdef PROFILE PFNGLDELETEBUFFERSARBPROC glDeleteBuffers;
PFNGLOBJECTLABELPROC glObjectLabel; PFNGLBINDBUFFERARBPROC glBindBuffer;
PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup; PFNGLBUFFERDATAARBPROC glBufferData;
PFNGLPOPDEBUGGROUPPROC glPopDebugGroup;
#endif #endif
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
#endif
#ifdef MOBILE
PFNGLDISCARDFRAMEBUFFEREXTPROC glDiscardFramebufferEXT;
#endif #endif
#define MAX_LIGHTS 3 #define MAX_LIGHTS 3
@@ -152,7 +183,7 @@ namespace Core {
Texture *blackTex, *whiteTex; Texture *blackTex, *whiteTex;
enum Pass { passCompose, passShadow, passAmbient, passFilter, passWater } pass; enum Pass { passCompose, passShadow, passAmbient, passFilter, passWater, passMAX } pass;
GLuint FBO; GLuint FBO;
struct RenderTargetCache { struct RenderTargetCache {
@@ -167,6 +198,7 @@ namespace Core {
struct { struct {
Shader *shader; Shader *shader;
Texture *textures[8]; Texture *textures[8];
Texture *target;
GLuint VAO; GLuint VAO;
} active; } active;
@@ -176,9 +208,10 @@ namespace Core {
} stats; } stats;
struct { struct {
bool VAO;
bool depthTexture; bool depthTexture;
bool shadowSampler; bool shadowSampler;
bool VAO; bool discardFrame;
bool texFloat, texFloatLinear; bool texFloat, texFloatLinear;
bool texHalf, texHalfLinear; bool texHalf, texHalfLinear;
} support; } support;
@@ -198,10 +231,22 @@ namespace Core {
} }
void init() { void init() {
#if defined(WIN32) || defined(LINUX) #ifdef ANDROID
void *libGL = dlopen("libGLESv2.so", RTLD_LAZY);
#endif
#if defined(WIN32) || defined(LINUX) || defined(ANDROID)
#ifdef WIN32 #ifdef WIN32
GetProcOGL(glActiveTexture); GetProcOGL(glActiveTexture);
#endif #endif
#if defined(WIN32) || defined(LINUX)
#ifdef PROFILE
GetProcOGL(glObjectLabel);
GetProcOGL(glPushDebugGroup);
GetProcOGL(glPopDebugGroup);
#endif
GetProcOGL(glCreateProgram); GetProcOGL(glCreateProgram);
GetProcOGL(glDeleteProgram); GetProcOGL(glDeleteProgram);
GetProcOGL(glLinkProgram); GetProcOGL(glLinkProgram);
@@ -225,14 +270,6 @@ namespace Core {
GetProcOGL(glDisableVertexAttribArray); GetProcOGL(glDisableVertexAttribArray);
GetProcOGL(glVertexAttribPointer); GetProcOGL(glVertexAttribPointer);
GetProcOGL(glGenBuffers);
GetProcOGL(glDeleteBuffers);
GetProcOGL(glBindBuffer);
GetProcOGL(glBufferData);
GetProcOGL(glGenVertexArrays);
GetProcOGL(glDeleteVertexArrays);
GetProcOGL(glBindVertexArray);
GetProcOGL(glGenFramebuffers); GetProcOGL(glGenFramebuffers);
GetProcOGL(glBindFramebuffer); GetProcOGL(glBindFramebuffer);
GetProcOGL(glGenRenderbuffers); GetProcOGL(glGenRenderbuffers);
@@ -241,19 +278,29 @@ namespace Core {
GetProcOGL(glFramebufferRenderbuffer); GetProcOGL(glFramebufferRenderbuffer);
GetProcOGL(glRenderbufferStorage); GetProcOGL(glRenderbufferStorage);
GetProcOGL(glCheckFramebufferStatus); GetProcOGL(glCheckFramebufferStatus);
GetProcOGL(glDrawBuffers);
#ifdef PROFILE GetProcOGL(glGenBuffers);
GetProcOGL(glObjectLabel); GetProcOGL(glDeleteBuffers);
GetProcOGL(glPushDebugGroup); GetProcOGL(glBindBuffer);
GetProcOGL(glPopDebugGroup); GetProcOGL(glBufferData);
#endif #endif
#ifdef MOBILE
GetProcOGL(glDiscardFramebufferEXT);
#endif #endif
GetProcOGL(glGenVertexArrays);
GetProcOGL(glDeleteVertexArrays);
GetProcOGL(glBindVertexArray);
#endif
char *ext = (char*)glGetString(GL_EXTENSIONS); char *ext = (char*)glGetString(GL_EXTENSIONS);
//LOG("%s\n", ext);
support.depthTexture = extSupport(ext, "_depth_texture");
support.shadowSampler = extSupport(ext, "EXT_shadow_samplers") || extSupport(ext, "GL_ARB_shadow");
support.VAO = extSupport(ext, "_vertex_array_object"); support.VAO = extSupport(ext, "_vertex_array_object");
support.depthTexture = extSupport(ext, "_depth_texture");
support.shadowSampler = false;//extSupport(ext, "_shadow_samplers") || extSupport(ext, "GL_ARB_shadow");
support.discardFrame = extSupport(ext, "_discard_framebuffer");
support.texFloatLinear = extSupport(ext, "GL_ARB_texture_float") || extSupport(ext, "_texture_float_linear"); support.texFloatLinear = extSupport(ext, "GL_ARB_texture_float") || extSupport(ext, "_texture_float_linear");
support.texFloat = support.texFloatLinear || extSupport(ext, "_texture_float"); support.texFloat = support.texFloatLinear || extSupport(ext, "_texture_float");
support.texHalfLinear = extSupport(ext, "GL_ARB_texture_float") || extSupport(ext, "_texture_half_float_linear"); support.texHalfLinear = extSupport(ext, "GL_ARB_texture_float") || extSupport(ext, "_texture_half_float_linear");
@@ -265,9 +312,10 @@ namespace Core {
LOG("Version : %s\n", glGetString(GL_VERSION)); LOG("Version : %s\n", glGetString(GL_VERSION));
LOG("supports:\n"); LOG("supports:\n");
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false");
LOG(" depth texture : %s\n", support.depthTexture ? "true" : "false"); LOG(" depth texture : %s\n", support.depthTexture ? "true" : "false");
LOG(" shadow sampler : %s\n", support.shadowSampler ? "true" : "false"); LOG(" shadow sampler : %s\n", support.shadowSampler ? "true" : "false");
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false"); LOG(" discard frame : %s\n", support.discardFrame ? "true" : "false");
LOG(" float textures : float = %s, half = %s\n", LOG(" float textures : float = %s, half = %s\n",
support.texFloat ? (support.texFloatLinear ? "linear" : "nearest") : "false", support.texFloat ? (support.texFloatLinear ? "linear" : "nearest") : "false",
support.texHalf ? (support.texHalfLinear ? "linear" : "nearest") : "false"); support.texHalf ? (support.texHalfLinear ? "linear" : "nearest") : "false");
@@ -326,9 +374,10 @@ namespace Core {
return cache.count++; return cache.count++;
} }
void clear(const vec4 &color) { void clear(bool clearColor, bool clearDepth, const vec4 &color) {
glClearColor(color.x, color.y, color.z, color.w); glClearColor(color.x, color.y, color.z, color.w);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); if (GLbitfield mask = (clearColor ? GL_COLOR_BUFFER_BIT : 0) | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0))
glClear(mask);
} }
void setViewport(int x, int y, int width, int height) { void setViewport(int x, int y, int width, int height) {
@@ -352,6 +401,7 @@ namespace Core {
} }
void setBlending(BlendMode mode) { void setBlending(BlendMode mode) {
mode = bmNone;
switch (mode) { switch (mode) {
case bmNone : case bmNone :
glDisable(GL_BLEND); glDisable(GL_BLEND);
@@ -389,14 +439,24 @@ namespace Core {
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
} }
void setTarget(Texture *target, int face = 0) { void invalidateTarget(bool color, bool depth) {
#ifdef MOBILE
if (support.discardFrame && (color || depth)) {
int count = 0;
GLenum discard[2];
if (color) discard[count++] = active.target ? GL_COLOR_ATTACHMENT0 : GL_COLOR_EXT;
if (depth) discard[count++] = active.target ? GL_DEPTH_ATTACHMENT : GL_DEPTH_EXT;
glDiscardFramebufferEXT(GL_FRAMEBUFFER, count, discard);
}
#endif
}
void setTarget(Texture *target, bool clear = false, int face = 0) {
if (!target) { if (!target) {
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
glColorMask(true, true, true, true); glColorMask(true, true, true, true);
setViewport(0, 0, Core::width, Core::height); setViewport(0, 0, Core::width, Core::height);
return; } else {
}
GLenum texTarget = GL_TEXTURE_2D; GLenum texTarget = GL_TEXTURE_2D;
if (target->cube) if (target->cube)
texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
@@ -412,6 +472,11 @@ namespace Core {
glColorMask(false, false, false, false); glColorMask(false, false, false, false);
setViewport(0, 0, target->width, target->height); setViewport(0, 0, target->width, target->height);
} }
active.target = target;
if (clear)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
void copyTarget(Texture *texture, int xOffset, int yOffset, int x, int y, int width, int height) { void copyTarget(Texture *texture, int xOffset, int yOffset, int x, int y, int width, int height) {
texture->bind(sDiffuse); texture->bind(sDiffuse);

View File

@@ -491,7 +491,7 @@ namespace TR {
} flags; } flags;
// not exists in file // not exists in file
uint16 align; uint16 align;
int16 modelIndex; // index of representation in models (index + 1) or spriteSequences (-(index + 1)) arrays int32 modelIndex; // index of representation in models (index + 1) or spriteSequences (-(index + 1)) arrays
void *controller; // Controller implementation or NULL void *controller; // Controller implementation or NULL
bool isEnemy() { bool isEnemy() {
@@ -842,6 +842,7 @@ namespace TR {
} extra; } extra;
Level(Stream &stream, bool demo) { Level(Stream &stream, bool demo) {
int startPos = stream.pos;
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
cutEntity = -1; cutEntity = -1;
Tile8 *tiles8 = NULL; Tile8 *tiles8 = NULL;
@@ -863,14 +864,13 @@ namespace TR {
if (version == VER_TR1_PSX) { if (version == VER_TR1_PSX) {
uint32 offsetTexTiles; uint32 offsetTexTiles;
stream.seek(8); stream.seek(8);
stream.read(offsetTexTiles); stream.read(offsetTexTiles);
// sound offsets // sound offsets
uint16 numSounds; uint16 numSounds;
stream.setPos(22); stream.setPos(startPos + 22);
stream.read(numSounds); stream.read(numSounds);
stream.setPos(2086 + numSounds * 512); stream.setPos(startPos + 2086 + numSounds * 512);
soundOffsetsCount = numSounds; soundOffsetsCount = numSounds;
soundOffsets = new uint32[soundOffsetsCount]; soundOffsets = new uint32[soundOffsetsCount];
soundSize = new uint32[soundOffsetsCount]; soundSize = new uint32[soundOffsetsCount];
@@ -882,9 +882,9 @@ namespace TR {
soundDataSize += soundSize[i] = size * 8; soundDataSize += soundSize[i] = size * 8;
} }
// sound data // sound data
stream.setPos(2600 + numSounds * 512); stream.setPos(startPos + 2600 + numSounds * 512);
stream.read(soundData, soundDataSize); stream.read(soundData, soundDataSize);
stream.setPos(offsetTexTiles + 8); stream.setPos(startPos + offsetTexTiles + 8);
} else if (version == VER_TR1_PC) { } else if (version == VER_TR1_PC) {
// tiles // tiles
stream.read(tiles8, stream.read(tilesCount)); stream.read(tiles8, stream.read(tilesCount));
@@ -1580,7 +1580,7 @@ namespace TR {
info.trigger = Trigger::ACTIVATE; info.trigger = Trigger::ACTIVATE;
info.trigCmdCount = 0; info.trigCmdCount = 0;
if (s.floor == -127) if (uint8(s.floor) == TR::NO_ROOM)
return; return;
Room::Sector *sBelow = &s; Room::Sector *sBelow = &s;

View File

@@ -8,28 +8,27 @@
namespace Game { namespace Game {
Level *level; Level *level;
void startLevel(Stream &stream, const char *sndName, bool demo, bool home) { void startLevel(Stream *lvl, Stream *snd, bool demo, bool home) {
delete level; delete level;
level = new Level(stream, demo, home); level = new Level(*lvl, demo, home);
delete lvl;
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
//Sound::play(Sound::openWAD("05_Lara's_Themes.wav"), 1, 1, 0); //Sound::play(Sound::openWAD("05_Lara's_Themes.wav"), 1, 1, 0);
Sound::play(new Stream(sndName), vec3(0.0f), 1, 1, Sound::Flags::LOOP); Sound::play(snd, vec3(0.0f), 1, 1, Sound::Flags::LOOP);
#endif #endif
} }
void startLevel(const char *lvlName, const char *sndName, bool demo, bool home) { void init(Stream *lvl, Stream *snd) {
Stream stream(lvlName); Core::init();
startLevel(stream, sndName, demo, home); level = NULL;
startLevel(lvl, snd, false, false);
} }
void init(char *lvlName = NULL, char *sndName = NULL) { void init(char *lvlName = NULL, char *sndName = NULL) {
Core::init();
level = NULL;
if (!lvlName) lvlName = (char*)"LEVEL2.PSX"; if (!lvlName) lvlName = (char*)"LEVEL2.PSX";
if (!sndName) sndName = (char*)"05.ogg"; if (!sndName) sndName = (char*)"05.ogg";
startLevel(lvlName, sndName, false, false); init(new Stream(lvlName), new Stream(sndName));
} }
void free() { void free() {

View File

@@ -405,7 +405,7 @@ struct Lara : Character {
if (level->extra.braid > -1) if (level->extra.braid > -1)
braid = new Braid(this, vec3(-4.0f, 24.0f, -48.0f)); braid = new Braid(this, vec3(-4.0f, 24.0f, -48.0f));
//reset(15, vec3(70067, -256, 29104), -0.68f); // level 2 (pool)
#ifdef _DEBUG #ifdef _DEBUG
//reset(14, vec3(40448, 3584, 60928), PI * 0.5f, true); // gym (pool) //reset(14, vec3(40448, 3584, 60928), PI * 0.5f, true); // gym (pool)
@@ -414,7 +414,7 @@ struct Lara : Character {
//reset(61, vec3(27221, -1024, 29205), PI * 0.5f); // level 2 (blade) //reset(61, vec3(27221, -1024, 29205), PI * 0.5f); // level 2 (blade)
//reset(43, vec3(31400, -2560, 25200), PI); // level 2 (reach) //reset(43, vec3(31400, -2560, 25200), PI); // level 2 (reach)
//reset(16, vec3(60907, 0, 39642), PI * 3 / 2); // level 2 (hang & climb) //reset(16, vec3(60907, 0, 39642), PI * 3 / 2); // level 2 (hang & climb)
reset(19, vec3(60843, 1024, 30557), PI); // level 2 (block) //reset(19, vec3(60843, 1024, 30557), PI); // level 2 (block)
//reset(7, vec3(64108, -512, 16514), -PI * 0.5f); // level 2 (bat trigger) //reset(7, vec3(64108, -512, 16514), -PI * 0.5f); // level 2 (bat trigger)
//reset(15, vec3(70082, -512, 26935), PI * 0.5f); // level 2 (bear) //reset(15, vec3(70082, -512, 26935), PI * 0.5f); // level 2 (bear)
//reset(63, vec3(31390, -2048, 33472), 0.0f); // level 2 (trap floor) //reset(63, vec3(31390, -2048, 33472), 0.0f); // level 2 (trap floor)
@@ -2018,8 +2018,8 @@ struct Lara : Character {
Core::setBlending(bmNone); Core::setBlending(bmNone);
} }
virtual void render(Frustum *frustum, MeshBuilder *mesh) { virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
Controller::render(frustum, mesh); Controller::render(frustum, mesh, type, caustics);
chestOffset = animation.getJoints(getMatrix(), 7).pos; // TODO: move to update func chestOffset = animation.getJoints(getMatrix(), 7).pos; // TODO: move to update func
if (braid) if (braid)
@@ -2027,10 +2027,9 @@ 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();
Core::active.shader->setParam(uType, Shader::FLASH); game->setShader(Core::pass, Shader::FLASH, 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::active.shader->setParam(uType, Shader::ENTITY);
} }
} }
}; };

View File

@@ -33,10 +33,7 @@ const char GUI[] =
#define WATER_FOG_DIST (8 * 1024) #define WATER_FOG_DIST (8 * 1024)
struct Level : IGame { struct Level : IGame {
enum { shCompose, shShadow, shAmbient, shFilter, shWater, shGUI, shMAX };
TR::Level level; TR::Level level;
Shader *shaders[shMAX];
Texture *atlas; Texture *atlas;
Texture *cube; Texture *cube;
MeshBuilder *mesh; MeshBuilder *mesh;
@@ -54,6 +51,70 @@ struct Level : IGame {
float clipHeight; float clipHeight;
} params; } params;
struct ShaderCache {
Shader *shaders[int(Core::passMAX) * Shader::MAX * 2];
ShaderCache(int animTexRangesCount, int animTexOffsetsCount) {
memset(shaders, 0, sizeof(shaders));
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" };
const char *typeNames[] = { "SPRITE", "FLASH", "ROOM", "ENTITY", "MIRROR" };
for (int pass = Core::passCompose; pass <= Core::passAmbient; pass++)
for (int caustics = 0; caustics < 2; caustics++)
for (int type = Shader::SPRITE; type <= Shader::MIRROR; type++) {
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);
}
}
{
const char *typeNames[] = { "DROP", "STEP", "CAUSTICS", "MASK", "COMPOSE" };
for (int type = Shader::WATER_DROP; type <= Shader::WATER_COMPOSE; type++) {
sprintf(def, "%s#define WATER_%s\n#define WATER_FOG_DIST (1.0/%d.0)\n", ext, typeNames[type], WATER_FOG_DIST);
shaders[getIndex(Core::passWater, Shader::Type(type), false)] = new Shader(WATER, def);
}
}
shaders[getIndex(Core::passFilter, Shader::FILTER_DOWNSAMPLE, false)] = new Shader(FILTER, "");
}
~ShaderCache() {
for (int i = 0; i < sizeof(shaders) / sizeof(shaders[0]); i++)
delete shaders[i];
}
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;
}
void bind(Core::Pass pass, Shader::Type type, bool caustics = false) {
Core::pass = pass;
int index = getIndex(pass, type, caustics);
ASSERT(shaders[index] != NULL);
shaders[index]->bind();
}
} *shaderCache;
struct AmbientCache { struct AmbientCache {
Level *level; Level *level;
@@ -125,8 +186,7 @@ struct Level : IGame {
// second pass - downsample it // second pass - downsample it
Core::setDepthTest(false); Core::setDepthTest(false);
level->setPassShader(Core::passFilter); level->shaderCache->bind(Core::passFilter, Shader::FILTER_DOWNSAMPLE, false);
Core::active.shader->setParam(uType, Shader::FILTER_DOWNSAMPLE);
for (int i = 1; i < 4; i++) { for (int i = 1; i < 4; i++) {
int size = 64 >> (i << 1); int size = 64 >> (i << 1);
@@ -136,7 +196,7 @@ struct Level : IGame {
for (int j = 0; j < 6; j++) { for (int j = 0; j < 6; j++) {
Texture *src = textures[j * 4 + i - 1]; Texture *src = textures[j * 4 + i - 1];
Texture *dst = textures[j * 4 + i]; Texture *dst = textures[j * 4 + i];
Core::setTarget(dst); Core::setTarget(dst, true);
src->bind(sDiffuse); src->bind(sDiffuse);
level->mesh->renderQuad(); level->mesh->renderQuad();
} }
@@ -151,7 +211,6 @@ struct Level : IGame {
colors[j] = vec3(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f); colors[j] = vec3(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f);
colors[j] *= colors[j]; // to "linear" space colors[j] *= colors[j]; // to "linear" space
} }
Core::setTarget(NULL);
Core::setDepthTest(true); Core::setDepthTest(true);
} }
@@ -273,9 +332,8 @@ struct Level : IGame {
caustics = new Texture(512, 512, Texture::RGB16, false); caustics = new Texture(512, 512, Texture::RGB16, false);
blank = false; blank = false;
Core::setTarget(data[0]); Core::setTarget(data[0], true);
Core::clear(vec4(0.0f)); Core::invalidateTarget(false, true);
Core::setTarget(NULL);
} }
void free() { void free() {
@@ -399,9 +457,9 @@ struct Level : IGame {
void drop(Item &item) { void drop(Item &item) {
if (!dropCount) return; if (!dropCount) return;
level->setShader(Core::passWater, Shader::WATER_DROP, false);
vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f) }; vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f) };
Core::active.shader->setParam(uPosScale, rPosScale[0], 2); Core::active.shader->setParam(uPosScale, rPosScale[0], 2);
Core::active.shader->setParam(uType, Shader::WATER_DROP);
for (int i = 0; i < dropCount; i++) { for (int i = 0; i < dropCount; i++) {
Drop &drop = drops[i]; Drop &drop = drops[i];
@@ -412,9 +470,10 @@ struct Level : IGame {
Core::active.shader->setParam(uParam, vec4(p.x, p.z, drop.radius * DETAIL, drop.strength)); Core::active.shader->setParam(uParam, vec4(p.x, p.z, drop.radius * DETAIL, drop.strength));
item.data[0]->bind(sDiffuse); item.data[0]->bind(sDiffuse);
Core::setTarget(item.data[1]); Core::setTarget(item.data[1], true);
Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f)); Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f));
level->mesh->renderQuad(); level->mesh->renderQuad();
Core::invalidateTarget(false, true);
swap(item.data[0], item.data[1]); swap(item.data[0], item.data[1]);
} }
} }
@@ -422,23 +481,24 @@ struct Level : IGame {
void step(Item &item) { void step(Item &item) {
if (item.timer < SIMULATE_TIMESTEP) return; if (item.timer < SIMULATE_TIMESTEP) return;
Core::active.shader->setParam(uType, Shader::WATER_STEP); level->setShader(Core::passWater, Shader::WATER_STEP, false);
Core::active.shader->setParam(uParam, vec4(0.995f, 1.0f, 0, 0)); Core::active.shader->setParam(uParam, vec4(0.995f, 1.0f, 0, 0));
while (item.timer >= SIMULATE_TIMESTEP) { while (item.timer >= SIMULATE_TIMESTEP) {
// water step // water step
item.data[0]->bind(sDiffuse); item.data[0]->bind(sDiffuse);
Core::setTarget(item.data[1]); Core::setTarget(item.data[1], 0, true);
Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f)); Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f));
level->mesh->renderQuad(); level->mesh->renderQuad();
Core::invalidateTarget(false, true);
swap(item.data[0], item.data[1]); swap(item.data[0], item.data[1]);
item.timer -= SIMULATE_TIMESTEP; item.timer -= SIMULATE_TIMESTEP;
} }
// calc caustics // calc caustics
level->setShader(Core::passWater, Shader::WATER_CAUSTICS, false);
vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f / PLANE_DETAIL) }; vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f / PLANE_DETAIL) };
Core::active.shader->setParam(uType, Shader::WATER_CAUSTICS);
Core::active.shader->setParam(uPosScale, rPosScale[0], 2); Core::active.shader->setParam(uPosScale, rPosScale[0], 2);
float sx = item.size.x * DETAIL / (item.data[0]->width / 2); float sx = item.size.x * DETAIL / (item.data[0]->width / 2);
@@ -448,19 +508,19 @@ struct Level : IGame {
Core::whiteTex->bind(sReflect); Core::whiteTex->bind(sReflect);
item.data[0]->bind(sNormal); item.data[0]->bind(sNormal);
Core::setTarget(item.caustics); Core::setTarget(item.caustics, true);
level->mesh->renderPlane(); level->mesh->renderPlane();
Core::invalidateTarget(false, true);
} }
void render() { void render() {
if (!visible) return; if (!visible) return;
// mask underwater geometry by zero alpha // mask underwater geometry by zero alpha
level->setPassShader(Core::passWater);
level->atlas->bind(sNormal); level->atlas->bind(sNormal);
level->atlas->bind(sReflect); level->atlas->bind(sReflect);
Core::active.shader->setParam(uType, Shader::WATER_MASK); level->setShader(Core::passWater, Shader::WATER_MASK, false);
Core::active.shader->setParam(uTexParam, vec4(1.0f)); Core::active.shader->setParam(uTexParam, vec4(1.0f));
Core::setBlending(bmNone); Core::setBlending(bmNone);
Core::setCulling(cfNone); Core::setCulling(cfNone);
@@ -497,7 +557,7 @@ struct Level : IGame {
} }
// render mirror reflection // render mirror reflection
Core::setTarget(reflect); Core::setTarget(reflect, true);
vec3 p = item.pos; vec3 p = item.pos;
vec3 n = vec3(0, 1, 0); vec3 n = vec3(0, 1, 0);
@@ -511,6 +571,7 @@ struct Level : IGame {
level->params.clipSign = underwater ? -1.0f : 1.0f; level->params.clipSign = underwater ? -1.0f : 1.0f;
level->params.clipHeight = item.pos.y * level->params.clipSign; level->params.clipHeight = item.pos.y * level->params.clipSign;
level->renderCompose(underwater ? item.from : item.to); level->renderCompose(underwater ? item.from : item.to);
Core::invalidateTarget(false, true);
level->params.clipHeight = 1000000.0f; level->params.clipHeight = 1000000.0f;
level->params.clipSign = 1.0f; level->params.clipSign = 1.0f;
@@ -518,8 +579,6 @@ struct Level : IGame {
level->camera->setup(true); level->camera->setup(true);
// simulate water // simulate water
level->setPassShader(Core::passWater);
Core::setDepthTest(false); Core::setDepthTest(false);
item.mask->bind(sMask); item.mask->bind(sMask);
@@ -542,7 +601,7 @@ struct Level : IGame {
Core::lightColor[0] = vec4(lum, lum, lum, float(light.radius) * float(light.radius)); Core::lightColor[0] = vec4(lum, lum, lum, float(light.radius) * float(light.radius));
} }
Core::active.shader->setParam(uType, Shader::WATER_COMPOSE); level->setShader(Core::passWater, Shader::WATER_COMPOSE, false);
Core::active.shader->setParam(uViewProj, Core::mViewProj); Core::active.shader->setParam(uViewProj, Core::mViewProj);
Core::active.shader->setParam(uPosScale, item.pos, 2); Core::active.shader->setParam(uPosScale, item.pos, 2);
Core::active.shader->setParam(uViewPos, Core::viewPos); Core::active.shader->setParam(uViewPos, Core::viewPos);
@@ -627,6 +686,9 @@ struct Level : IGame {
waterCache->addDrop(pos, radius, strength); waterCache->addDrop(pos, radius, strength);
} }
virtual void setShader(Core::Pass pass, Shader::Type type, bool caustics) {
shaderCache->bind(pass, type, caustics);
}
Level(Stream &stream, bool demo, bool home) : level(stream, demo), lara(NULL), waterColor(0.6f, 0.9f, 0.9f) { Level(Stream &stream, bool demo, bool home) : level(stream, demo), lara(NULL), waterColor(0.6f, 0.9f, 0.9f) {
params.time = 0.0f; params.time = 0.0f;
@@ -637,7 +699,7 @@ struct Level : IGame {
mesh = new MeshBuilder(level); mesh = new MeshBuilder(level);
initTextures(); initTextures();
initShaders(); shaderCache = new ShaderCache(mesh->animTexRangesCount, mesh->animTexOffsetsCount);
initOverrides(); initOverrides();
for (int i = 0; i < level.entitiesBaseCount; i++) { for (int i = 0; i < level.entitiesBaseCount; i++) {
@@ -756,8 +818,7 @@ struct Level : IGame {
for (int i = 0; i < level.entitiesCount; i++) for (int i = 0; i < level.entitiesCount; i++)
delete (Controller*)level.entities[i].controller; delete (Controller*)level.entities[i].controller;
for (int i = 0; i < shMAX; i++) delete shaderCache;
delete shaders[i];
delete shadow; delete shadow;
delete ambientCache; delete ambientCache;
@@ -815,33 +876,6 @@ struct Level : IGame {
level.tiles = NULL; level.tiles = NULL;
} }
void initShaders() {
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");
sprintf(def, "%s#define PASS_COMPOSE\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, MAX_LIGHTS, mesh->animTexRangesCount, mesh->animTexOffsetsCount, FOG_DIST, WATER_FOG_DIST);
shaders[shCompose] = new Shader(SHADER, def);
sprintf(def, "%s#define PASS_SHADOW\n", ext);
shaders[shShadow] = new Shader(SHADER, def);
sprintf(def, "%s#define PASS_AMBIENT\n", ext);
shaders[shAmbient] = new Shader(SHADER, def);
shaders[shFilter] = new Shader(FILTER, "");
sprintf(def, "#define WATER_FOG_DIST (1.0/%d.0)\n", WATER_FOG_DIST);
shaders[shWater] = new Shader(WATER, def);
shaders[shGUI] = new Shader(GUI, "");
}
void initOverrides() { void initOverrides() {
/* /*
for (int i = 0; i < level.entitiesCount; i++) { for (int i = 0; i < level.entitiesCount; i++) {
@@ -954,15 +988,18 @@ struct Level : IGame {
} }
#endif #endif
void setRoomParams(int roomIndex, float intensity) { void setRoomParams(int roomIndex, float intensity, Shader::Type type) {
if (Core::pass == Core::passShadow) if (Core::pass == Core::passShadow) {
setShader(Core::pass, type, false);
return; return;
}
TR::Room &room = level.rooms[roomIndex]; TR::Room &room = level.rooms[roomIndex];
setShader(Core::pass, type, room.flags.water);
if (room.flags.water) { if (room.flags.water) {
Core::color = vec4(waterColor, intensity); Core::color = vec4(waterColor, intensity);
Core::active.shader->setParam(uCaustics, 1);
/* /*
// trace to water surface room // trace to water surface room
int wrIndex = roomIndex; int wrIndex = roomIndex;
@@ -972,10 +1009,9 @@ struct Level : IGame {
int sx = room.xSectors int sx = room.xSectors
*/ */
waterCache->bindCaustics(roomIndex); waterCache->bindCaustics(roomIndex);
} else { } else
Core::color = vec4(1.0f, 1.0f, 1.0f, intensity); Core::color = vec4(1.0f, 1.0f, 1.0f, intensity);
Core::active.shader->setParam(uCaustics, 0);
}
Core::active.shader->setParam(uColor, Core::color); Core::active.shader->setParam(uColor, Core::color);
} }
@@ -994,13 +1030,13 @@ struct Level : IGame {
room.flags.rendered = true; room.flags.rendered = true;
if (Core::pass != Core::passShadow) { if (Core::pass != Core::passShadow) {
setRoomParams(roomIndex, intensityf(room.ambient)); setRoomParams(roomIndex, intensityf(room.ambient), Shader::ROOM);
Shader *sh = Core::active.shader;
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
Basis qTemp = Core::basis; Basis qTemp = Core::basis;
Core::basis.translate(offset); Core::basis.translate(offset);
Shader *sh = Core::active.shader;
sh->setParam(uType, Shader::ROOM);
sh->setParam(uBasis, Core::basis); sh->setParam(uBasis, Core::basis);
// render room geometry // render room geometry
@@ -1008,9 +1044,11 @@ struct Level : IGame {
// render room sprites // render room sprites
if (mesh->hasRoomSprites(roomIndex)) { if (mesh->hasRoomSprites(roomIndex)) {
Core::color.w = 1.0; setRoomParams(roomIndex, 1.0, Shader::SPRITE);
sh->setParam(uType, Shader::SPRITE); sh = Core::active.shader;
sh->setParam(uColor, Core::color); sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
sh->setParam(uBasis, Core::basis);
mesh->renderRoomSprites(roomIndex); mesh->renderRoomSprites(roomIndex);
} }
@@ -1108,7 +1146,11 @@ struct Level : IGame {
return; return;
int16 lum = entity.intensity == -1 ? room.ambient : entity.intensity; int16 lum = entity.intensity == -1 ? room.ambient : entity.intensity;
setRoomParams(entity.room, isModel ? controller->specular : intensityf(lum));
Shader::Type type = isModel ? Shader::ENTITY : Shader::SPRITE;
if (entity.type == TR::Entity::CRYSTAL)
type = Shader::MIRROR;
setRoomParams(entity.room, isModel ? controller->specular : intensityf(lum), type);
if (isModel) { // model if (isModel) { // model
vec3 pos = controller->getPos(); vec3 pos = controller->getPos();
@@ -1119,18 +1161,18 @@ struct Level : IGame {
memcpy(controller->ambient, cube.colors, sizeof(cube.colors)); // store last calculated ambient into controller memcpy(controller->ambient, cube.colors, sizeof(cube.colors)); // store last calculated ambient into controller
} }
getLight(pos, entity.room); getLight(pos, entity.room);
Core::active.shader->setParam(uType, Shader::ENTITY);
Core::active.shader->setParam(uAmbient, controller->ambient[0], 6); Core::active.shader->setParam(uAmbient, controller->ambient[0], 6);
} else { // sprite } else { // sprite
Core::active.shader->setParam(uType, Shader::SPRITE);
Core::lightPos[0] = vec3(0); Core::lightPos[0] = vec3(0);
Core::lightColor[0] = vec4(0, 0, 0, 1); Core::lightColor[0] = vec4(0, 0, 0, 1);
} }
Core::active.shader->setParam(uViewProj, Core::mViewProj);
Core::active.shader->setParam(uLightProj, Core::mLightProj);
Core::active.shader->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS); Core::active.shader->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
Core::active.shader->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS); Core::active.shader->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
controller->render(camera->frustum, mesh); controller->render(camera->frustum, mesh, type, room.flags.water);
} }
void update() { void update() {
@@ -1155,6 +1197,9 @@ struct Level : IGame {
waterCache->update(); waterCache->update();
} }
void setup() { void setup() {
PROFILE_MARKER("SETUP"); PROFILE_MARKER("SETUP");
@@ -1168,19 +1213,20 @@ struct Level : IGame {
if (!Core::support.VAO) if (!Core::support.VAO)
mesh->bind(); mesh->bind();
//Core::mViewProj = Core::mLightProj;
// set frame constants for all shaders // set frame constants for all shaders
Shader *sh = Core::active.shader; for (int i = 0; i < sizeof(shaderCache->shaders) / sizeof(shaderCache->shaders[0]); i++) {
Shader *sh = shaderCache->shaders[i];
if (!sh) continue;
sh->bind(); sh->bind();
sh->setParam(uViewProj, Core::mViewProj); sh->setParam(uViewProj, Core::mViewProj);
sh->setParam(uLightProj, Core::mLightProj); sh->setParam(uLightProj, Core::mLightProj);
sh->setParam(uViewInv, Core::mViewInv); sh->setParam(uViewInv, Core::mViewInv);
sh->setParam(uViewPos, Core::viewPos); sh->setParam(uViewPos, Core::viewPos);
sh->setParam(uParam, *((vec4*)&params)); sh->setParam(uParam, *((vec4*)&params));
sh->setParam(uLightsCount, 3);
sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount); sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount); sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
}
Core::basis.identity(); Core::basis.identity();
// clear visibility flag for rooms // clear visibility flag for rooms
@@ -1196,8 +1242,6 @@ struct Level : IGame {
PROFILE_MARKER("ROOMS"); PROFILE_MARKER("ROOMS");
getLight(lara->pos, lara->getRoomIndex()); getLight(lara->pos, lara->getRoomIndex());
Core::active.shader->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
Core::active.shader->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
#ifdef LEVEL_EDITOR #ifdef LEVEL_EDITOR
for (int i = 0; i < level.roomsCount; i++) for (int i = 0; i < level.roomsCount; i++)
@@ -1264,62 +1308,51 @@ struct Level : IGame {
return true; return true;
} }
void setPassShader(Core::Pass pass) {
Core::pass = pass;
Shader *sh = NULL;
switch (pass) {
case Core::passCompose : sh = shaders[shCompose]; break;
case Core::passShadow : sh = shaders[shShadow]; break;
case Core::passAmbient : sh = shaders[shAmbient]; break;
case Core::passFilter : sh = shaders[shFilter]; break;
case Core::passWater : sh = shaders[shWater]; break;
}
ASSERT(sh);
sh->bind();
}
void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) { void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {
PROFILE_MARKER("ENVIRONMENT"); PROFILE_MARKER("ENVIRONMENT");
// first pass render level into cube faces // first pass render level into cube faces
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
setupCubeCamera(pos, i); setupCubeCamera(pos, i);
setPassShader(Core::passAmbient); Core::pass = Core::passAmbient;
Texture *target = targets[0]->cube ? targets[0] : targets[i * stride]; Texture *target = targets[0]->cube ? targets[0] : targets[i * stride];
Core::setTarget(target, i); Core::setTarget(target, true, i);
Core::clear(vec4(0, 0, 0, 1));
renderScene(roomIndex); renderScene(roomIndex);
Core::invalidateTarget(false, true);
} }
Core::setTarget(NULL);
} }
void renderShadows(int roomIndex) { void renderShadows(int roomIndex) {
PROFILE_MARKER("PASS_SHADOW"); PROFILE_MARKER("PASS_SHADOW");
Core::pass = Core::passShadow;
if (!setupLightCamera()) return; if (!setupLightCamera()) return;
shadow->unbind(sShadow); shadow->unbind(sShadow);
setPassShader(Core::passShadow);
Core::setBlending(bmNone); Core::setBlending(bmNone);
Core::setTarget(shadow); bool colorShadow = shadow->format == Texture::Format::RGBA ? true : false;
Core::clear(vec4(1.0)); if (colorShadow)
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
Core::setTarget(shadow, true);
Core::setCulling(cfBack); Core::setCulling(cfBack);
renderScene(roomIndex); renderScene(roomIndex);
Core::invalidateTarget(!colorShadow, colorShadow);
Core::setCulling(cfFront); Core::setCulling(cfFront);
Core::setTarget(NULL); if (colorShadow)
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
} }
void renderCompose(int roomIndex) { void renderCompose(int roomIndex) {
PROFILE_MARKER("PASS_COMPOSE"); PROFILE_MARKER("PASS_COMPOSE");
setPassShader(Core::passCompose); Core::pass = Core::passCompose;
Core::setBlending(bmAlpha); Core::setBlending(bmAlpha);
Core::setDepthTest(true); Core::setDepthTest(true);
Core::setDepthWrite(true); Core::setDepthWrite(true);
Core::clear(vec4(0.0f, 0.0f, 0.0f, 1.0f));
shadow->bind(sShadow); shadow->bind(sShadow);
renderScene(roomIndex); renderScene(roomIndex);
Core::setBlending(bmNone); Core::setBlending(bmNone);
} }
void render() { void render() {
Core::invalidateTarget(true, true);
params.clipHeight = 1000000.0f; params.clipHeight = 1000000.0f;
params.clipSign = 1.0f; params.clipSign = 1.0f;
params.waterHeight = params.clipHeight; params.waterHeight = params.clipHeight;
@@ -1329,6 +1362,7 @@ struct Level : IGame {
waterCache->reset(); waterCache->reset();
renderShadows(lara->getRoomIndex()); renderShadows(lara->getRoomIndex());
Core::setTarget(NULL, true);
Core::setViewport(0, 0, Core::width, Core::height); Core::setViewport(0, 0, Core::width, Core::height);
waterCache->checkVisibility = true; waterCache->checkVisibility = true;
@@ -1410,7 +1444,6 @@ struct Level : IGame {
/*
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glPushMatrix(); glPushMatrix();
glLoadIdentity(); glLoadIdentity();
@@ -1419,10 +1452,7 @@ struct Level : IGame {
glLoadIdentity(); glLoadIdentity();
glOrtho(0, Core::width, 0, Core::height, 0, 1); glOrtho(0, Core::width, 0, Core::height, 0, 1);
if (waterCache->count) shadow->bind(sDiffuse);
waterCache->items[0].data[0]->bind(sDiffuse);
else
atlas->bind(sDiffuse);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
@@ -1448,12 +1478,12 @@ struct Level : IGame {
glPopMatrix(); glPopMatrix();
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glPopMatrix(); glPopMatrix();
*/
Core::setBlending(bmAlpha); Core::setBlending(bmAlpha);
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room); // Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
// Debug::Level::lights(level, lara->getRoomIndex()); // Debug::Level::lights(level, lara->getRoomIndex());
Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y); // Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
// Core::setDepthTest(false); // Core::setDepthTest(false);
// Debug::Level::portals(level); // Debug::Level::portals(level);
// Core::setDepthTest(true); // Core::setDepthTest(true);

View File

@@ -437,6 +437,7 @@ struct MeshBuilder {
iCount += 6; iCount += 6;
} }
} }
LOG("MegaMesh: %d %d %d\n", iCount, vCount, aCount);
// compile buffer and ranges // compile buffer and ranges
mesh = new Mesh(indices, iCount, vertices, vCount, aCount); mesh = new Mesh(indices, iCount, vertices, vCount, aCount);

View File

@@ -18,8 +18,7 @@ extern "C" {
} }
void EMSCRIPTEN_KEEPALIVE game_level_load(char *data, int size, int home) { void EMSCRIPTEN_KEEPALIVE game_level_load(char *data, int size, int home) {
Stream stream(data, size); Game::startLevel(new Stream(data, size), NULL, false, home);
Game::startLevel(stream, NULL, false, home);
} }
} }

View File

@@ -149,6 +149,7 @@
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<RandomizedBaseAddress>false</RandomizedBaseAddress> <RandomizedBaseAddress>false</RandomizedBaseAddress>
<AssemblyDebug>true</AssemblyDebug>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">

View File

@@ -119,6 +119,44 @@ void joyUpdate() {
joyFree(); joyFree();
} }
// touch
typedef BOOL (__stdcall *PREGISTERTOUCHWINDOW)(HWND, ULONG);
typedef BOOL (__stdcall *PGETTOUCHINPUTINFO)(HTOUCHINPUT, UINT, PTOUCHINPUT, int);
typedef BOOL (__stdcall *PCLOSETOUCHINPUTHANDLE)(HTOUCHINPUT);
PREGISTERTOUCHWINDOW RegisterTouchWindowX;
PGETTOUCHINPUTINFO GetTouchInputInfoX;
PCLOSETOUCHINPUTHANDLE CloseTouchInputHandleX;
#define MAX_TOUCH_COUNT 10
void touchInit(HWND hWnd) {
int value = GetSystemMetrics(SM_DIGITIZER);
if (value) {
HMODULE hUser32 = LoadLibrary("user32.dll");
RegisterTouchWindowX = (PREGISTERTOUCHWINDOW)GetProcAddress(hUser32, "RegisterTouchWindow");
GetTouchInputInfoX = (PGETTOUCHINPUTINFO)GetProcAddress(hUser32, "GetTouchInputInfo");
CloseTouchInputHandleX = (PCLOSETOUCHINPUTHANDLE)GetProcAddress(hUser32, "CloseTouchInputHandle");
if (RegisterTouchWindowX && GetTouchInputInfoX && CloseTouchInputHandleX)
RegisterTouchWindowX(hWnd, 0);
}
}
void touchUpdate(HTOUCHINPUT hTouch, int count) {
TOUCHINPUT touches[MAX_TOUCH_COUNT];
count = min(count, MAX_TOUCH_COUNT);
if (!GetTouchInputInfoX(hTouch, count, touches, sizeof(TOUCHINPUT)))
return;
LOG("touch [ ", count);
for (int i = 0; i < count; i++)
LOG("%d (%d, %d) ", i, touches[i].x, touches[i].y);
LOG("]\n");
CloseTouchInputHandleX(hTouch);
}
// sound // sound
#define SND_SIZE 4704*2 #define SND_SIZE 4704*2
@@ -242,6 +280,9 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara
joyInit(); joyInit();
return 1; return 1;
// touch // touch
case WM_TOUCH :
touchUpdate((HTOUCHINPUT)lParam, wParam);
break;
// TODO // TODO
// sound // sound
default : default :
@@ -293,6 +334,7 @@ int main(int argc, char** argv) {
Sound::channelsCount = 0; Sound::channelsCount = 0;
touchInit(hWnd);
joyInit(); joyInit();
sndInit(hWnd); sndInit(hWnd);

View File

@@ -1,7 +1,11 @@
R"====( R"====(
#ifdef GL_ES #ifdef GL_ES
precision highp int; precision lowp int;
precision highp float; precision highp float;
#else
#define lowp
#define mediump
#define highp
#endif #endif
varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
@@ -16,14 +20,6 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
varying vec4 vColor; varying vec4 vColor;
#endif #endif
#define TYPE_SPRITE 0
#define TYPE_FLASH 1
#define TYPE_ROOM 2
#define TYPE_ENTITY 3
#define TYPE_MIRROR 4
uniform int uType;
#ifdef PASS_COMPOSE #ifdef PASS_COMPOSE
uniform vec3 uViewPos; uniform vec3 uViewPos;
uniform int uCaustics; uniform int uCaustics;
@@ -78,7 +74,7 @@ uniform int uType;
#endif #endif
#ifdef PASS_COMPOSE #ifdef PASS_COMPOSE
if (uType != TYPE_SPRITE) { #ifndef TYPE_SPRITE
// animated texture coordinates // animated texture coordinates
vec2 range = uAnimTexRanges[int(aTexCoord.z)]; // x - start index, y - count vec2 range = uAnimTexRanges[int(aTexCoord.z)]; // x - start index, y - count
@@ -88,16 +84,15 @@ uniform int uType;
vTexCoord.xy = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated vTexCoord.xy = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated
vNormal = vec4(mulQuat(rBasisRot, aNormal.xyz), aNormal.w); vNormal = vec4(mulQuat(rBasisRot, aNormal.xyz), aNormal.w);
if (uCaustics != 0) { #ifdef CAUSTICS
float sum = coord.x + coord.y + coord.z; float sum = coord.x + coord.y + coord.z;
vColor.xyz *= abs(sin(sum / 512.0 + uParam.x)) * 1.5 + 0.5; // color dodge vColor.xyz *= abs(sin(sum / 512.0 + uParam.x)) * 1.5 + 0.5; // color dodge
} #endif
#else
} else {
coord.xyz += uViewInv[0].xyz * aTexCoord.z - uViewInv[1].xyz * aTexCoord.w; coord.xyz += uViewInv[0].xyz * aTexCoord.z - uViewInv[1].xyz * aTexCoord.w;
vTexCoord.xy = aTexCoord.xy * TEXCOORD_SCALE; vTexCoord.xy = aTexCoord.xy * TEXCOORD_SCALE;
vNormal = vec4(uViewPos.xyz - coord.xyz, 0.0); vNormal = vec4(uViewPos.xyz - coord.xyz, 0.0);
} #endif
vTexCoord.zw = clamp((coord.xz - uRoomSize.xy) / (uRoomSize.zw - uRoomSize.xy), vec2(0.0), vec2(1.0)); vTexCoord.zw = clamp((coord.xz - uRoomSize.xy) / (uRoomSize.zw - uRoomSize.xy), vec2(0.0), vec2(1.0));
@@ -118,7 +113,6 @@ uniform int uType;
uniform vec4 uColor; uniform vec4 uColor;
#ifdef PASS_COMPOSE #ifdef PASS_COMPOSE
uniform samplerCube sEnvironment; uniform samplerCube sEnvironment;
uniform int uLightsCount;
uniform vec3 uLightPos[MAX_LIGHTS]; uniform vec3 uLightPos[MAX_LIGHTS];
uniform vec4 uLightColor[MAX_LIGHTS]; uniform vec4 uLightColor[MAX_LIGHTS];
uniform vec3 uAmbient[6]; uniform vec3 uAmbient[6];
@@ -140,14 +134,14 @@ uniform int uType;
#ifdef SHADOW_SAMPLER #ifdef SHADOW_SAMPLER
uniform sampler2DShadow sShadow; uniform sampler2DShadow sShadow;
#ifdef MOBILE #ifdef GL_ES
#define SHADOW(V) (shadow2DEXT(sShadow, V)) #define SHADOW(V) (shadow2DEXT(sShadow, V))
#else #else
#define SHADOW(V) (shadow2D(sShadow, V).x) #define SHADOW(V) (shadow2D(sShadow, V).x)
#endif #endif
#else #else
uniform sampler2D sShadow; uniform sampler2D sShadow;
#define CMP(a,b) float(a > b) #define CMP(a,b) step(b, a)
#ifdef SHADOW_DEPTH #ifdef SHADOW_DEPTH
#define compare(p, z) CMP(texture2D(sShadow, (p)).x, (z)); #define compare(p, z) CMP(texture2D(sShadow, (p)).x, (z));
@@ -160,6 +154,8 @@ uniform int uType;
#endif #endif
float SHADOW(vec3 p) { float SHADOW(vec3 p) {
return compare(p.xy, p.z);
/*
vec2 t = vec2(0.0, 1.0 / 1024.0); vec2 t = vec2(0.0, 1.0 / 1024.0);
vec2 c = floor(p.xy * 1024.0 + 0.5) / 1024.0; vec2 c = floor(p.xy * 1024.0 + 0.5) / 1024.0;
vec4 s; vec4 s;
@@ -169,40 +165,55 @@ uniform int uType;
s.w = compare(c + t.yy, p.z); s.w = compare(c + t.yy, p.z);
vec2 f = fract(p.xy * 1024.0 + 0.5); 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); return mix(mix(s.x, s.y, f.y), mix(s.z, s.w, f.y), f.x);
*/
} }
#endif #endif
float getShadow(vec4 lightProj) { float getShadow(vec4 lightProj) {
vec3 p = lightProj.xyz / lightProj.w; vec3 poissonDisk[16];
if (lightProj.w < 0.0) return 1.0; 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);
vec2 poissonDisk[16]; poissonDisk[ 2] = vec3(-0.09418410, -0.92938870, 0.0) * (1.5 / 1024.0);
poissonDisk[ 0] = vec2( -0.94201624, -0.39906216 ); poissonDisk[ 3] = vec3( 0.34495938, 0.29387760, 0.0) * (1.5 / 1024.0);
poissonDisk[ 1] = vec2( 0.94558609, -0.76890725 ); poissonDisk[ 4] = vec3(-0.91588581, 0.45771432, 0.0) * (1.5 / 1024.0);
poissonDisk[ 2] = vec2( -0.09418410, -0.92938870 ); poissonDisk[ 5] = vec3(-0.81544232, -0.87912464, 0.0) * (1.5 / 1024.0);
poissonDisk[ 3] = vec2( 0.34495938, 0.29387760 ); poissonDisk[ 6] = vec3(-0.38277543, 0.27676845, 0.0) * (1.5 / 1024.0);
poissonDisk[ 4] = vec2( -0.91588581, 0.45771432 ); poissonDisk[ 7] = vec3( 0.97484398, 0.75648379, 0.0) * (1.5 / 1024.0);
poissonDisk[ 5] = vec2( -0.81544232, -0.87912464 ); poissonDisk[ 8] = vec3( 0.44323325, -0.97511554, 0.0) * (1.5 / 1024.0);
poissonDisk[ 6] = vec2( -0.38277543, 0.27676845 ); poissonDisk[ 9] = vec3( 0.53742981, -0.47373420, 0.0) * (1.5 / 1024.0);
poissonDisk[ 7] = vec2( 0.97484398, 0.75648379 ); poissonDisk[10] = vec3(-0.26496911, -0.41893023, 0.0) * (1.5 / 1024.0);
poissonDisk[ 8] = vec2( 0.44323325, -0.97511554 ); poissonDisk[11] = vec3( 0.79197514, 0.19090188, 0.0) * (1.5 / 1024.0);
poissonDisk[ 9] = vec2( 0.53742981, -0.47373420 ); poissonDisk[12] = vec3(-0.24188840, 0.99706507, 0.0) * (1.5 / 1024.0);
poissonDisk[10] = vec2( -0.26496911, -0.41893023 ); poissonDisk[13] = vec3(-0.81409955, 0.91437590, 0.0) * (1.5 / 1024.0);
poissonDisk[11] = vec2( 0.79197514, 0.19090188 ); poissonDisk[14] = vec3( 0.19984126, 0.78641367, 0.0) * (1.5 / 1024.0);
poissonDisk[12] = vec2( -0.24188840, 0.99706507 ); poissonDisk[15] = vec3( 0.14383161, -0.14100790, 0.0) * (1.5 / 1024.0);
poissonDisk[13] = vec2( -0.81409955, 0.91437590 );
poissonDisk[14] = vec2( 0.19984126, 0.78641367 );
poissonDisk[15] = vec2( 0.14383161, -0.14100790 );
float rShadow = 0.0; float rShadow = 0.0;
for (int i = 0; i < 16; i += 1) vec3 p = lightProj.xyz / lightProj.w;
rShadow += SHADOW(p + vec3(poissonDisk[i] * 1.5, 0.0) * (1.0 / 1024.0));
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; rShadow /= 16.0;
vec3 lv = uLightPos[0].xyz - vCoord.xyz; vec3 lv = uLightPos[0].xyz - vCoord.xyz;
float fade = clamp(dot(lv, lv) / uLightColor[0].w, 0.0, 1.0); float fade = clamp(dot(lv, lv) / uLightColor[0].w, 0.0, 1.0);
return mix(rShadow, 1.0, fade); return clamp(mix(rShadow, 1.0, fade), -lightProj.w, 1.0);
} }
vec3 calcLight(vec3 normal, vec3 pos, vec4 color) { vec3 calcLight(vec3 normal, vec3 pos, vec4 color) {
@@ -227,13 +238,12 @@ uniform int uType;
sqr.z * mix(uAmbient[5], uAmbient[4], pos.z); sqr.z * mix(uAmbient[5], uAmbient[4], pos.z);
} }
#ifdef CAUSTICS
float calcCaustics(vec3 n) { float calcCaustics(vec3 n) {
if (uCaustics != 0) {
vec2 fade = smoothstep(uRoomSize.xy, uRoomSize.xy + vec2(256.0), vCoord.xz) * (1.0 - smoothstep(uRoomSize.zw - vec2(256.0), uRoomSize.zw, vCoord.xz)); vec2 fade = smoothstep(uRoomSize.xy, uRoomSize.xy + vec2(256.0), vCoord.xz) * (1.0 - smoothstep(uRoomSize.zw - vec2(256.0), uRoomSize.zw, vCoord.xz));
return texture2D(sReflect, vTexCoord.zw).r * (max(0.0, -n.y)) * fade.x * fade.y; return texture2D(sReflect, vTexCoord.zw).r * (max(0.0, -n.y)) * fade.x * fade.y;
} else
return 0.0;
} }
#endif
vec3 applyFog(vec3 color, vec3 fogColor, float factor) { vec3 applyFog(vec3 color, vec3 fogColor, float factor) {
float fog = clamp(1.0 / exp(factor), 0.0, 1.0); float fog = clamp(1.0 / exp(factor), 0.0, 1.0);
@@ -268,9 +278,10 @@ uniform int uType;
#endif #endif
vec4 color = texture2D(sDiffuse, vTexCoord.xy); vec4 color = texture2D(sDiffuse, vTexCoord.xy);
if (color.w <= 0.6) {
discard; // if (color.w <= 0.6) {
} // discard;
// }
#ifdef PASS_SHADOW #ifdef PASS_SHADOW
#ifdef SHADOW_COLOR #ifdef SHADOW_COLOR
@@ -288,7 +299,7 @@ uniform int uType;
color.xyz *= vColor.w; color.xyz *= vColor.w;
#else #else
// calc point lights // calc point lights
if (uType != TYPE_FLASH) { #ifndef TYPE_FLASH
vec3 normal = normalize(vNormal.xyz); vec3 normal = normalize(vNormal.xyz);
//vec3 n = getNormal();; //vec3 n = getNormal();;
@@ -299,50 +310,62 @@ uniform int uType;
vec3 viewVec = normalize(vViewVec); vec3 viewVec = normalize(vViewVec);
vec3 light = vec3(0.0); vec3 light = vec3(0.0);
for (int i = 1; i < MAX_LIGHTS; i++) // additional lights // for (int i = 1; i < 3; i++) // additional lights
light += calcLight(normal, uLightPos[i], uLightColor[i]); light += calcLight(normal, uLightPos[1], uLightColor[1]);
light += calcLight(normal, uLightPos[2], uLightColor[2]);
// apply lighting // apply lighting
if (uType == TYPE_SPRITE) { #ifdef TYPE_SPRITE
light += vColor.w * uColor.w; light += vColor.w * uColor.w;
} #endif
if (uType == TYPE_ROOM) { #ifdef TYPE_ROOM
float rShadow = dot(normal, uLightPos[0].xyz - vCoord) > 0.0 ? getShadow(vLightProj) : 1.0; float rShadow = dot(normal, uLightPos[0].xyz - vCoord) > 0.0 ? getShadow(vLightProj) : 1.0;
//light += calcLight(normal, uLightPos[0], uLightColor[0]); //light += calcLight(normal, uLightPos[0], uLightColor[0]);
light += mix(min(uColor.w, vColor.w), vColor.w, rShadow); light += mix(min(uColor.w, vColor.w), vColor.w, rShadow);
#ifdef CAUSTICS
light += calcCaustics(normal); light += calcCaustics(normal);
} #endif
//color.xyz = vec3(rShadow);
//light.xyz = vec3(1.0);
#endif
if (uType == TYPE_ENTITY) { #ifdef TYPE_ENTITY
vec3 rAmbient = calcAmbient(normal); vec3 rAmbient = calcAmbient(normal);
float rShadow = getShadow(vLightProj); float rShadow = getShadow(vLightProj);
light += calcLight(normal, uLightPos[0], uLightColor[0]) * rShadow + rAmbient; light += calcLight(normal, uLightPos[0], uLightColor[0]) * rShadow + rAmbient;
color.xyz += calcSpecular(normal, viewVec, uLightPos[0], uLightColor[0], uColor.w * rShadow + 0.03); color.xyz += calcSpecular(normal, viewVec, uLightPos[0], uLightColor[0], uColor.w * rShadow + 0.03);
#ifdef CAUSTICS
light += calcCaustics(normal); light += calcCaustics(normal);
} #endif
//color.xyz = vec3(rShadow);
//light.xyz = vec3(1.0);
#endif
if (uType == TYPE_MIRROR) { #ifdef TYPE_MIRROR
vec3 rv = reflect(-viewVec, normal); vec3 rv = reflect(-viewVec, normal);
color.xyz = uColor.xyz * pow(abs(textureCube(sEnvironment, normalize(rv)).xyz), vec3(2.2)); color.xyz = uColor.xyz * pow(abs(textureCube(sEnvironment, normalize(rv)).xyz), vec3(2.2));
light.xyz = vec3(1.0); light.xyz = vec3(1.0);
} #endif
color.xyz *= light; color.xyz *= light;
} else {
#else // ifndef TYPE_FLASH
color.w = uColor.w; color.w = uColor.w;
}
#endif
#endif #endif
color = sqrt(color); // back to "gamma" space color = sqrt(color); // back to "gamma" space
#ifdef PASS_COMPOSE #ifdef PASS_COMPOSE
color.xyz = applyFog(color.xyz, vec3(0.0), length(vViewVec) * FOG_DIST); color.xyz = applyFog(color.xyz, vec3(0.0), length(vViewVec) * FOG_DIST);
if (uCaustics != 0) { #ifdef CAUSTICS
float d = abs((vCoord.y - max(uViewPos.y, uParam.y)) / normalize(vViewVec).y); float d = abs((vCoord.y - max(uViewPos.y, uParam.y)) / normalize(vViewVec).y);
d *= step(0.0, vCoord.y - uParam.y); d *= step(0.0, vCoord.y - uParam.y);
color.xyz = applyFog(color.xyz, uColor.xyz * 0.2, d * WATER_FOG_DIST); color.xyz = applyFog(color.xyz, uColor.xyz * 0.2, d * WATER_FOG_DIST);
} #endif
#endif #endif
gl_FragColor = color; gl_FragColor = color;

View File

@@ -5,20 +5,22 @@
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX }; enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
enum SamplerType { sDiffuse, sNormal, sReflect, sShadow, sEnvironment, sMask, sMAX }; enum SamplerType { sDiffuse, sNormal, sReflect, sShadow, sEnvironment, sMask, sMAX };
enum UniformType { uType, uCaustics, uParam, uTexParam, uViewProj, uViewInv, uBasis, uLightProj, uColor, uAmbient, uViewPos, uLightsCount, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uRoomSize, uPosScale, uMAX }; enum UniformType { uParam, uTexParam, uViewProj, uViewInv, uBasis, uLightProj, uColor, uAmbient, uViewPos, uLightPos, uLightColor, uAnimTexRanges, uAnimTexOffsets, uRoomSize, uPosScale, uMAX };
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" }; const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" };
const char *SamplerName[sMAX] = { "sDiffuse", "sNormal", "sReflect", "sShadow", "sEnvironment", "sMask" }; const char *SamplerName[sMAX] = { "sDiffuse", "sNormal", "sReflect", "sShadow", "sEnvironment", "sMask" };
const char *UniformName[uMAX] = { "uType", "uCaustics", "uParam", "uTexParam", "uViewProj", "uViewInv", "uBasis", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightsCount", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets", "uRoomSize", "uPosScale" }; const char *UniformName[uMAX] = { "uParam", "uTexParam", "uViewProj", "uViewInv", "uBasis", "uLightProj", "uColor", "uAmbient", "uViewPos", "uLightPos", "uLightColor", "uAnimTexRanges", "uAnimTexOffsets", "uRoomSize", "uPosScale" };
struct Shader { struct Shader {
GLuint ID; GLuint ID;
GLint uID[uMAX]; GLint uID[uMAX];
enum : GLint { enum Type : GLint {
NONE = 0,
/* shader */ SPRITE = 0, FLASH = 1, ROOM = 2, ENTITY = 3, MIRROR = 4, /* shader */ SPRITE = 0, FLASH = 1, ROOM = 2, ENTITY = 3, MIRROR = 4,
/* filter */ FILTER_DOWNSAMPLE = 0, /* filter */ FILTER_DOWNSAMPLE = 0,
/* water */ WATER_DROP = 0, WATER_STEP = 1, WATER_CAUSTICS = 2, WATER_MASK = 3, WATER_COMPOSE = 4, /* water */ WATER_DROP = 0, WATER_STEP = 1, WATER_CAUSTICS = 2, WATER_MASK = 3, WATER_COMPOSE = 4,
MAX = 5
}; };
Shader(const char *text, const char *defines = "") { Shader(const char *text, const char *defines = "") {

View File

@@ -61,7 +61,7 @@ struct Sprite : Controller {
} }
} }
virtual void render(Frustum *frustum, MeshBuilder *mesh) { virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
Basis basis(Core::basis); Basis basis(Core::basis);
basis.translate(pos); basis.translate(pos);
Core::active.shader->setParam(uBasis, basis); Core::active.shader->setParam(uBasis, basis);

View File

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

View File

@@ -12,9 +12,6 @@
#ifndef ANDROID #ifndef ANDROID
#define LOG(...) printf(__VA_ARGS__) #define LOG(...) printf(__VA_ARGS__)
#else
#include <android/log.h>
#define LOG(...) __android_log_print(ANDROID_LOG_INFO,"X5",__VA_ARGS__)
#endif #endif
#else #else
@@ -26,6 +23,13 @@
// #endif // #endif
#endif #endif
#ifdef ANDROID
#include <android/log.h>
#undef LOG
#define LOG(...) __android_log_print(ANDROID_LOG_INFO,"OpenLara",__VA_ARGS__)
#endif
#define EPS FLT_EPSILON #define EPS FLT_EPSILON
#define INF INFINITY #define INF INFINITY
#define PI 3.14159265358979323846f #define PI 3.14159265358979323846f
@@ -34,9 +38,9 @@
#define RAD2DEG (180.0f / PI) #define RAD2DEG (180.0f / PI)
#define randf() ((float)rand()/RAND_MAX) #define randf() ((float)rand()/RAND_MAX)
typedef char int8; typedef signed char int8;
typedef short int16; typedef signed short int16;
typedef int int32; typedef signed int int32;
typedef unsigned char uint8; typedef unsigned char uint8;
typedef unsigned short uint16; typedef unsigned short uint16;
typedef unsigned int uint32; typedef unsigned int uint32;

View File

@@ -1,24 +1,23 @@
R"====( R"====(
#ifdef GL_ES #ifdef GL_ES
precision highp int; precision lowp int;
precision highp float; precision highp float;
#endif #endif
varying vec3 vCoord; varying vec3 vCoord;
varying vec2 vTexCoord; varying vec2 vTexCoord;
varying vec4 vProjCoord; varying vec4 vProjCoord;
varying vec3 vRefPos1; varying vec4 vOldPos;
varying vec3 vRefPos2; varying vec4 vNewPos;
varying vec3 vViewVec; varying vec3 vViewVec;
varying vec3 vLightVec; varying vec3 vLightVec;
/*
#define WATER_DROP 0 #define WATER_DROP 0
#define WATER_STEP 1 #define WATER_STEP 1
#define WATER_CAUSTICS 2 #define WATER_CAUSTICS 2
#define WATER_MASK 3 #define WATER_MASK 3
#define WATER_COMPOSE 4 #define WATER_COMPOSE 4
*/
uniform int uType;
uniform vec3 uViewPos; uniform vec3 uViewPos;
uniform mat4 uViewProj; uniform mat4 uViewProj;
uniform vec3 uLightPos; uniform vec3 uLightPos;
@@ -39,14 +38,14 @@ uniform sampler2D sNormal;
void main() { void main() {
vTexCoord = (aCoord.xy * 0.5 + 0.5) * uTexParam.zw; vTexCoord = (aCoord.xy * 0.5 + 0.5) * uTexParam.zw;
if (uType >= WATER_MASK) { #if defined(WATER_MASK) || defined(WATER_COMPOSE)
float height = 0.0; float height = 0.0;
if (uType == WATER_COMPOSE) { #ifdef WATER_COMPOSE
vTexCoord = (aCoord.xy * (1.0 / 48.0) * 0.5 + 0.5) * uTexParam.zw; vTexCoord = (aCoord.xy * (1.0 / 48.0) * 0.5 + 0.5) * uTexParam.zw;
height = texture2D(sNormal, vTexCoord).x; height = texture2D(sNormal, vTexCoord).x;
} #endif
vCoord = vec3(aCoord.x, height, aCoord.y) * uPosScale[1] + uPosScale[0]; vCoord = vec3(aCoord.x, height, aCoord.y) * uPosScale[1] + uPosScale[0];
@@ -54,28 +53,28 @@ uniform sampler2D sNormal;
vProjCoord = cp; vProjCoord = cp;
gl_Position = cp; gl_Position = cp;
} else { #else
vProjCoord = vec4(0.0); vProjCoord = vec4(0.0);
vCoord = vec3(aCoord.xy, 0.0); vCoord = vec3(aCoord.xy, 0.0);
if (uType == WATER_CAUSTICS) { #ifdef WATER_CAUSTICS
vec3 rCoord = vec3(aCoord.x, 0.0, aCoord.y) * uPosScale[1]; vec3 rCoord = vec3(aCoord.x, aCoord.y, 0.0) * uPosScale[1].xzy;
vec4 info = texture2D(sNormal, (rCoord.xz * 0.5 + 0.5) * uTexParam.zw); vec4 info = texture2D(sNormal, (rCoord.xy * 0.5 + 0.5) * uTexParam.zw);
vec3 normal = vec3(info.z, -sqrt(1.0 - dot(info.zw, info.zw)), info.w); vec3 normal = vec3(info.z, info.w, sqrt(1.0 - dot(info.zw, info.zw)));
vec3 light = vec3(0.0, -1.0, 0.0); vec3 light = vec3(0.0, 0.0, 1.0);
vec3 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), ETA_AIR / ETA_WATER); vec3 refOld = refract(-light, vec3(0.0, 0.0, 1.0), 0.75);
vec3 ray = refract(-light, normal, ETA_AIR / ETA_WATER); vec3 refNew = refract(-light, normal, 0.75);
vRefPos1 = rCoord + vec3(0.0, 0.0, 0.0); vOldPos = vec4(rCoord + refOld * (-0.25 / refOld.z) + refOld * ((-refOld.z - 1.0) / refOld.z), 1.0);
vRefPos2 = rCoord + vec3(0.0, info.r, 0.0) + ray / ray.y; vNewPos = vec4(rCoord + refNew * ((info.r - 0.25) / refNew.z) + refOld * ((-refNew.z - 1.0) / refOld.z), 1.0);
gl_Position = vec4((vRefPos2.xz + 0.0 * refractedLight.xz / refractedLight.y), 0.0, 1.0); gl_Position = vec4(vNewPos.xy + refOld.xy / refOld.z, 0.0, 1.0);
} else { #else
vRefPos1 = vRefPos2 = vec3(0.0); vOldPos = vNewPos = vec4(0.0);
gl_Position = vec4(aCoord.xyz, 1.0); gl_Position = vec4(aCoord.xyz, 1.0);
} #endif
} #endif
vViewVec = uViewPos - vCoord.xyz; vViewVec = uViewPos - vCoord.xyz;
vLightVec = uLightPos - vCoord.xyz; vLightVec = uLightPos - vCoord.xyz;
} }
@@ -137,9 +136,10 @@ uniform sampler2D sNormal;
} }
vec4 caustics() { vec4 caustics() {
float area1 = length(dFdx(vRefPos1)) * length(dFdy(vRefPos1)); float rOldArea = length(dFdx(vOldPos.xyz)) * length(dFdy(vOldPos.xyz));
float area2 = length(dFdx(vRefPos2)) * length(dFdy(vRefPos2)); float rNewArea = length(dFdx(vNewPos.xyz)) * length(dFdy(vNewPos.xyz));
return vec4(vec3(area1 / area2 * 0.2), 1.0); float value = clamp(rOldArea / rNewArea * 0.2, 0.0, 1.0) * vOldPos.w;
return vec4(vec3(value), 1.0);
} }
vec4 mask() { vec4 mask() {
@@ -178,12 +178,28 @@ uniform sampler2D sNormal;
} }
vec4 pass() { vec4 pass() {
if (uType == WATER_DROP) return drop(); return
if (uType == WATER_STEP) return calc(); #ifdef WATER_DROP
if (uType == WATER_CAUSTICS) return caustics(); drop();
if (uType == WATER_MASK) return mask(); #endif
if (uType == WATER_COMPOSE) return compose();
return vec4(1.0, 0.0, 0.0, 1.0); #ifdef WATER_STEP
calc();
#endif
#ifdef WATER_CAUSTICS
caustics();
#endif
#ifdef WATER_MASK
mask();
#endif
#ifdef WATER_COMPOSE
compose();
#endif
vec4(1.0, 0.0, 0.0, 1.0);
} }
void main() { void main() {