mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-12 08:04:09 +02:00
#23 uber-shaders
This commit is contained in:
@@ -17,6 +17,7 @@ struct IGame {
|
||||
virtual ~IGame() {}
|
||||
virtual TR::Level* getLevel() { return NULL; }
|
||||
virtual void waterDrop(const vec3 &pos, float radius, float strength) {}
|
||||
virtual void setShader(Core::Pass pass, Shader::Type type, bool caustics) {}
|
||||
};
|
||||
|
||||
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) {
|
||||
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);
|
||||
TR::Model *m = getModel();
|
||||
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();
|
||||
|
||||
Box box = animation.getBoundingBox(vec3(0, 0, 0), 0);
|
||||
|
333
src/core.h
333
src/core.h
@@ -6,6 +6,30 @@
|
||||
#include <windows.h>
|
||||
#include <gl/GL.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__
|
||||
#define LINUX 1
|
||||
#include <GL/gl.h>
|
||||
@@ -18,16 +42,11 @@
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glext.h>
|
||||
#include <AGL/agl.h>
|
||||
/*
|
||||
* In compatibility mode, Mac OS X only supports OpenGL 2 (no VAO), but it does
|
||||
* support the Apple-specific VAO extension which is older and in all relevant
|
||||
* parts 100% compatible. So use those functions instead.
|
||||
*/
|
||||
#define glBindVertexArray glBindVertexArrayAPPLE
|
||||
#define glGenVertexArrays glGenVertexArraysAPPLE
|
||||
#define glDeleteVertexArrays glDeleteVertexArraysAPPLE
|
||||
#define glGenVertexArrays glGenVertexArraysAPPLE
|
||||
#define glDeleteVertexArrays glDeleteVertexArraysAPPLE
|
||||
#define glBindVertexArray glBindVertexArrayAPPLE
|
||||
#elif __EMSCRIPTEN__
|
||||
#define MOBILE 1
|
||||
#define MOBILE
|
||||
#include <emscripten.h>
|
||||
#include <html5.h>
|
||||
#include <GLES3/gl3.h>
|
||||
@@ -46,68 +65,80 @@
|
||||
#include "input.h"
|
||||
#include "sound.h"
|
||||
|
||||
#if defined(WIN32) || defined(LINUX)
|
||||
void* GetProc(const char *name) {
|
||||
#ifdef WIN32
|
||||
return (void*)wglGetProcAddress(name);
|
||||
#elif LINUX
|
||||
return (void*)glXGetProcAddress((GLubyte*)name);
|
||||
#endif
|
||||
}
|
||||
#if defined(WIN32) || defined(LINUX) || defined(ANDROID)
|
||||
|
||||
#ifdef ANDROID
|
||||
#define GetProc(x) dlsym(libGL, x);
|
||||
#else
|
||||
void* GetProc(const char *name) {
|
||||
#ifdef WIN32
|
||||
return (void*)wglGetProcAddress(name);
|
||||
#elif LINUX
|
||||
return (void*)glXGetProcAddress((GLubyte*)name);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#define GetProcOGL(x) x=(decltype(x))GetProc(#x);
|
||||
|
||||
// Texture
|
||||
#ifdef WIN32
|
||||
PFNGLACTIVETEXTUREPROC glActiveTexture;
|
||||
PFNGLACTIVETEXTUREPROC glActiveTexture;
|
||||
#endif
|
||||
// Shader
|
||||
PFNGLCREATEPROGRAMPROC glCreateProgram;
|
||||
PFNGLDELETEPROGRAMPROC glDeleteProgram;
|
||||
PFNGLLINKPROGRAMPROC glLinkProgram;
|
||||
PFNGLUSEPROGRAMPROC glUseProgram;
|
||||
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
|
||||
PFNGLCREATESHADERPROC glCreateShader;
|
||||
PFNGLDELETESHADERPROC glDeleteShader;
|
||||
PFNGLSHADERSOURCEPROC glShaderSource;
|
||||
PFNGLATTACHSHADERPROC glAttachShader;
|
||||
PFNGLCOMPILESHADERPROC glCompileShader;
|
||||
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
|
||||
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
|
||||
PFNGLUNIFORM1IVPROC glUniform1iv;
|
||||
PFNGLUNIFORM1FVPROC glUniform1fv;
|
||||
PFNGLUNIFORM2FVPROC glUniform2fv;
|
||||
PFNGLUNIFORM3FVPROC glUniform3fv;
|
||||
PFNGLUNIFORM4FVPROC glUniform4fv;
|
||||
PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
|
||||
PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
|
||||
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
|
||||
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
|
||||
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
|
||||
// Mesh
|
||||
PFNGLGENBUFFERSARBPROC glGenBuffers;
|
||||
PFNGLDELETEBUFFERSARBPROC glDeleteBuffers;
|
||||
PFNGLBINDBUFFERARBPROC glBindBuffer;
|
||||
PFNGLBUFFERDATAARBPROC glBufferData;
|
||||
|
||||
#if defined(WIN32) || defined(LINUX)
|
||||
// Profiling
|
||||
#ifdef PROFILE
|
||||
PFNGLOBJECTLABELPROC glObjectLabel;
|
||||
PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup;
|
||||
PFNGLPOPDEBUGGROUPPROC glPopDebugGroup;
|
||||
#endif
|
||||
// Shader
|
||||
PFNGLCREATEPROGRAMPROC glCreateProgram;
|
||||
PFNGLDELETEPROGRAMPROC glDeleteProgram;
|
||||
PFNGLLINKPROGRAMPROC glLinkProgram;
|
||||
PFNGLUSEPROGRAMPROC glUseProgram;
|
||||
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
|
||||
PFNGLCREATESHADERPROC glCreateShader;
|
||||
PFNGLDELETESHADERPROC glDeleteShader;
|
||||
PFNGLSHADERSOURCEPROC glShaderSource;
|
||||
PFNGLATTACHSHADERPROC glAttachShader;
|
||||
PFNGLCOMPILESHADERPROC glCompileShader;
|
||||
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
|
||||
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
|
||||
PFNGLUNIFORM1IVPROC glUniform1iv;
|
||||
PFNGLUNIFORM1FVPROC glUniform1fv;
|
||||
PFNGLUNIFORM2FVPROC glUniform2fv;
|
||||
PFNGLUNIFORM3FVPROC glUniform3fv;
|
||||
PFNGLUNIFORM4FVPROC glUniform4fv;
|
||||
PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
|
||||
PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
|
||||
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
|
||||
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
|
||||
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
|
||||
// Render to texture
|
||||
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
|
||||
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
|
||||
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
|
||||
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
|
||||
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
|
||||
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
|
||||
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
|
||||
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
|
||||
// Mesh
|
||||
PFNGLGENBUFFERSARBPROC glGenBuffers;
|
||||
PFNGLDELETEBUFFERSARBPROC glDeleteBuffers;
|
||||
PFNGLBINDBUFFERARBPROC glBindBuffer;
|
||||
PFNGLBUFFERDATAARBPROC glBufferData;
|
||||
#endif
|
||||
|
||||
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
|
||||
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
|
||||
PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
|
||||
// Render to texture
|
||||
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
|
||||
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
|
||||
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
|
||||
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
|
||||
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
|
||||
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
|
||||
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
|
||||
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
|
||||
PFNGLDRAWBUFFERSPROC glDrawBuffers;
|
||||
// Profiling
|
||||
#ifdef PROFILE
|
||||
PFNGLOBJECTLABELPROC glObjectLabel;
|
||||
PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup;
|
||||
PFNGLPOPDEBUGGROUPPROC glPopDebugGroup;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MOBILE
|
||||
PFNGLDISCARDFRAMEBUFFEREXTPROC glDiscardFramebufferEXT;
|
||||
#endif
|
||||
|
||||
#define MAX_LIGHTS 3
|
||||
@@ -152,7 +183,7 @@ namespace Core {
|
||||
|
||||
Texture *blackTex, *whiteTex;
|
||||
|
||||
enum Pass { passCompose, passShadow, passAmbient, passFilter, passWater } pass;
|
||||
enum Pass { passCompose, passShadow, passAmbient, passFilter, passWater, passMAX } pass;
|
||||
|
||||
GLuint FBO;
|
||||
struct RenderTargetCache {
|
||||
@@ -167,6 +198,7 @@ namespace Core {
|
||||
struct {
|
||||
Shader *shader;
|
||||
Texture *textures[8];
|
||||
Texture *target;
|
||||
GLuint VAO;
|
||||
} active;
|
||||
|
||||
@@ -176,9 +208,10 @@ namespace Core {
|
||||
} stats;
|
||||
|
||||
struct {
|
||||
bool VAO;
|
||||
bool depthTexture;
|
||||
bool shadowSampler;
|
||||
bool VAO;
|
||||
bool discardFrame;
|
||||
bool texFloat, texFloatLinear;
|
||||
bool texHalf, texHalfLinear;
|
||||
} support;
|
||||
@@ -198,62 +231,76 @@ namespace Core {
|
||||
}
|
||||
|
||||
void init() {
|
||||
#if defined(WIN32) || defined(LINUX)
|
||||
#ifdef WIN32
|
||||
GetProcOGL(glActiveTexture);
|
||||
#ifdef ANDROID
|
||||
void *libGL = dlopen("libGLESv2.so", RTLD_LAZY);
|
||||
#endif
|
||||
GetProcOGL(glCreateProgram);
|
||||
GetProcOGL(glDeleteProgram);
|
||||
GetProcOGL(glLinkProgram);
|
||||
GetProcOGL(glUseProgram);
|
||||
GetProcOGL(glGetProgramInfoLog);
|
||||
GetProcOGL(glCreateShader);
|
||||
GetProcOGL(glDeleteShader);
|
||||
GetProcOGL(glShaderSource);
|
||||
GetProcOGL(glAttachShader);
|
||||
GetProcOGL(glCompileShader);
|
||||
GetProcOGL(glGetShaderInfoLog);
|
||||
GetProcOGL(glGetUniformLocation);
|
||||
GetProcOGL(glUniform1iv);
|
||||
GetProcOGL(glUniform1fv);
|
||||
GetProcOGL(glUniform2fv);
|
||||
GetProcOGL(glUniform3fv);
|
||||
GetProcOGL(glUniform4fv);
|
||||
GetProcOGL(glUniformMatrix4fv);
|
||||
GetProcOGL(glBindAttribLocation);
|
||||
GetProcOGL(glEnableVertexAttribArray);
|
||||
GetProcOGL(glDisableVertexAttribArray);
|
||||
GetProcOGL(glVertexAttribPointer);
|
||||
|
||||
GetProcOGL(glGenBuffers);
|
||||
GetProcOGL(glDeleteBuffers);
|
||||
GetProcOGL(glBindBuffer);
|
||||
GetProcOGL(glBufferData);
|
||||
GetProcOGL(glGenVertexArrays);
|
||||
GetProcOGL(glDeleteVertexArrays);
|
||||
GetProcOGL(glBindVertexArray);
|
||||
#if defined(WIN32) || defined(LINUX) || defined(ANDROID)
|
||||
#ifdef WIN32
|
||||
GetProcOGL(glActiveTexture);
|
||||
#endif
|
||||
|
||||
GetProcOGL(glGenFramebuffers);
|
||||
GetProcOGL(glBindFramebuffer);
|
||||
GetProcOGL(glGenRenderbuffers);
|
||||
GetProcOGL(glBindRenderbuffer);
|
||||
GetProcOGL(glFramebufferTexture2D);
|
||||
GetProcOGL(glFramebufferRenderbuffer);
|
||||
GetProcOGL(glRenderbufferStorage);
|
||||
GetProcOGL(glCheckFramebufferStatus);
|
||||
GetProcOGL(glDrawBuffers);
|
||||
#if defined(WIN32) || defined(LINUX)
|
||||
#ifdef PROFILE
|
||||
GetProcOGL(glObjectLabel);
|
||||
GetProcOGL(glPushDebugGroup);
|
||||
GetProcOGL(glPopDebugGroup);
|
||||
#endif
|
||||
|
||||
#ifdef PROFILE
|
||||
GetProcOGL(glObjectLabel);
|
||||
GetProcOGL(glPushDebugGroup);
|
||||
GetProcOGL(glPopDebugGroup);
|
||||
GetProcOGL(glCreateProgram);
|
||||
GetProcOGL(glDeleteProgram);
|
||||
GetProcOGL(glLinkProgram);
|
||||
GetProcOGL(glUseProgram);
|
||||
GetProcOGL(glGetProgramInfoLog);
|
||||
GetProcOGL(glCreateShader);
|
||||
GetProcOGL(glDeleteShader);
|
||||
GetProcOGL(glShaderSource);
|
||||
GetProcOGL(glAttachShader);
|
||||
GetProcOGL(glCompileShader);
|
||||
GetProcOGL(glGetShaderInfoLog);
|
||||
GetProcOGL(glGetUniformLocation);
|
||||
GetProcOGL(glUniform1iv);
|
||||
GetProcOGL(glUniform1fv);
|
||||
GetProcOGL(glUniform2fv);
|
||||
GetProcOGL(glUniform3fv);
|
||||
GetProcOGL(glUniform4fv);
|
||||
GetProcOGL(glUniformMatrix4fv);
|
||||
GetProcOGL(glBindAttribLocation);
|
||||
GetProcOGL(glEnableVertexAttribArray);
|
||||
GetProcOGL(glDisableVertexAttribArray);
|
||||
GetProcOGL(glVertexAttribPointer);
|
||||
|
||||
GetProcOGL(glGenFramebuffers);
|
||||
GetProcOGL(glBindFramebuffer);
|
||||
GetProcOGL(glGenRenderbuffers);
|
||||
GetProcOGL(glBindRenderbuffer);
|
||||
GetProcOGL(glFramebufferTexture2D);
|
||||
GetProcOGL(glFramebufferRenderbuffer);
|
||||
GetProcOGL(glRenderbufferStorage);
|
||||
GetProcOGL(glCheckFramebufferStatus);
|
||||
|
||||
GetProcOGL(glGenBuffers);
|
||||
GetProcOGL(glDeleteBuffers);
|
||||
GetProcOGL(glBindBuffer);
|
||||
GetProcOGL(glBufferData);
|
||||
#endif
|
||||
|
||||
#ifdef MOBILE
|
||||
GetProcOGL(glDiscardFramebufferEXT);
|
||||
#endif
|
||||
|
||||
GetProcOGL(glGenVertexArrays);
|
||||
GetProcOGL(glDeleteVertexArrays);
|
||||
GetProcOGL(glBindVertexArray);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
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.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.texFloat = support.texFloatLinear || extSupport(ext, "_texture_float");
|
||||
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("supports:\n");
|
||||
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false");
|
||||
LOG(" depth texture : %s\n", support.depthTexture ? "true" : "false");
|
||||
LOG(" shadow sampler : %s\n", support.shadowSampler ? "true" : "false");
|
||||
LOG(" 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",
|
||||
support.texFloat ? (support.texFloatLinear ? "linear" : "nearest") : "false",
|
||||
support.texHalf ? (support.texHalfLinear ? "linear" : "nearest") : "false");
|
||||
@@ -282,11 +330,11 @@ namespace Core {
|
||||
lightColor[i] = vec4(0, 0, 0, 1);
|
||||
|
||||
frameIndex = 0;
|
||||
|
||||
|
||||
uint32 data = 0xFF000000;
|
||||
blackTex = new Texture(1, 1, Texture::RGBA, false, &data);
|
||||
data = 0xFFFFFFFF;
|
||||
whiteTex = new Texture(1, 1, Texture::RGBA, false, &data);
|
||||
whiteTex = new Texture(1, 1, Texture::RGBA, false, &data);
|
||||
}
|
||||
|
||||
void free() {
|
||||
@@ -326,9 +374,10 @@ namespace Core {
|
||||
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);
|
||||
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) {
|
||||
@@ -352,6 +401,7 @@ namespace Core {
|
||||
}
|
||||
|
||||
void setBlending(BlendMode mode) {
|
||||
mode = bmNone;
|
||||
switch (mode) {
|
||||
case bmNone :
|
||||
glDisable(GL_BLEND);
|
||||
@@ -389,28 +439,43 @@ namespace Core {
|
||||
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) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glColorMask(true, true, true, true);
|
||||
setViewport(0, 0, Core::width, Core::height);
|
||||
return;
|
||||
} else {
|
||||
GLenum texTarget = GL_TEXTURE_2D;
|
||||
if (target->cube)
|
||||
texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
|
||||
|
||||
bool depth = target->format == Texture::DEPTH || target->format == Texture::SHADOW;
|
||||
int rtIndex = cacheRenderTarget(depth, target->width, target->height);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
|
||||
glFramebufferTexture2D (GL_FRAMEBUFFER, depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, texTarget, target->ID, 0);
|
||||
glFramebufferRenderbuffer (GL_FRAMEBUFFER, depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rtCache[depth].items[rtIndex].ID);
|
||||
|
||||
if (depth)
|
||||
glColorMask(false, false, false, false);
|
||||
setViewport(0, 0, target->width, target->height);
|
||||
}
|
||||
active.target = target;
|
||||
|
||||
GLenum texTarget = GL_TEXTURE_2D;
|
||||
if (target->cube)
|
||||
texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
|
||||
|
||||
bool depth = target->format == Texture::DEPTH || target->format == Texture::SHADOW;
|
||||
int rtIndex = cacheRenderTarget(depth, target->width, target->height);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
|
||||
glFramebufferTexture2D (GL_FRAMEBUFFER, depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, texTarget, target->ID, 0);
|
||||
glFramebufferRenderbuffer (GL_FRAMEBUFFER, depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rtCache[depth].items[rtIndex].ID);
|
||||
|
||||
if (depth)
|
||||
glColorMask(false, false, false, false);
|
||||
setViewport(0, 0, target->width, target->height);
|
||||
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) {
|
||||
|
18
src/format.h
18
src/format.h
@@ -491,7 +491,7 @@ namespace TR {
|
||||
} flags;
|
||||
// not exists in file
|
||||
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
|
||||
|
||||
bool isEnemy() {
|
||||
@@ -842,6 +842,7 @@ namespace TR {
|
||||
} extra;
|
||||
|
||||
Level(Stream &stream, bool demo) {
|
||||
int startPos = stream.pos;
|
||||
memset(this, 0, sizeof(*this));
|
||||
cutEntity = -1;
|
||||
Tile8 *tiles8 = NULL;
|
||||
@@ -863,14 +864,13 @@ namespace TR {
|
||||
|
||||
if (version == VER_TR1_PSX) {
|
||||
uint32 offsetTexTiles;
|
||||
|
||||
stream.seek(8);
|
||||
stream.read(offsetTexTiles);
|
||||
// sound offsets
|
||||
uint16 numSounds;
|
||||
stream.setPos(22);
|
||||
stream.setPos(startPos + 22);
|
||||
stream.read(numSounds);
|
||||
stream.setPos(2086 + numSounds * 512);
|
||||
stream.setPos(startPos + 2086 + numSounds * 512);
|
||||
soundOffsetsCount = numSounds;
|
||||
soundOffsets = new uint32[soundOffsetsCount];
|
||||
soundSize = new uint32[soundOffsetsCount];
|
||||
@@ -882,9 +882,9 @@ namespace TR {
|
||||
soundDataSize += soundSize[i] = size * 8;
|
||||
}
|
||||
// sound data
|
||||
stream.setPos(2600 + numSounds * 512);
|
||||
stream.setPos(startPos + 2600 + numSounds * 512);
|
||||
stream.read(soundData, soundDataSize);
|
||||
stream.setPos(offsetTexTiles + 8);
|
||||
stream.setPos(startPos + offsetTexTiles + 8);
|
||||
} else if (version == VER_TR1_PC) {
|
||||
// tiles
|
||||
stream.read(tiles8, stream.read(tilesCount));
|
||||
@@ -1580,8 +1580,8 @@ namespace TR {
|
||||
info.trigger = Trigger::ACTIVATE;
|
||||
info.trigCmdCount = 0;
|
||||
|
||||
if (s.floor == -127)
|
||||
return;
|
||||
if (uint8(s.floor) == TR::NO_ROOM)
|
||||
return;
|
||||
|
||||
Room::Sector *sBelow = &s;
|
||||
while (sBelow->roomBelow != NO_ROOM) sBelow = &getSector(sBelow->roomBelow, x, z, dx, dz);
|
||||
@@ -1610,7 +1610,7 @@ namespace TR {
|
||||
int dx = x % 1024;
|
||||
int dz = z % 1024;
|
||||
|
||||
for (int i = 0; i < info.trigCmdCount; i++) {
|
||||
for (int i = 0; i < info.trigCmdCount; i++) {
|
||||
FloorData::TriggerCommand cmd = info.trigCmd[i];
|
||||
if (cmd.action != Action::ACTIVATE) continue;
|
||||
|
||||
|
25
src/game.h
25
src/game.h
@@ -8,30 +8,29 @@
|
||||
namespace Game {
|
||||
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;
|
||||
level = new Level(stream, demo, home);
|
||||
level = new Level(*lvl, demo, home);
|
||||
delete lvl;
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
//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);
|
||||
#endif
|
||||
Sound::play(snd, vec3(0.0f), 1, 1, Sound::Flags::LOOP);
|
||||
#endif
|
||||
}
|
||||
|
||||
void startLevel(const char *lvlName, const char *sndName, bool demo, bool home) {
|
||||
Stream stream(lvlName);
|
||||
startLevel(stream, sndName, demo, home);
|
||||
}
|
||||
|
||||
void init(char *lvlName = NULL, char *sndName = NULL) {
|
||||
void init(Stream *lvl, Stream *snd) {
|
||||
Core::init();
|
||||
level = NULL;
|
||||
|
||||
startLevel(lvl, snd, false, false);
|
||||
}
|
||||
|
||||
void init(char *lvlName = NULL, char *sndName = NULL) {
|
||||
if (!lvlName) lvlName = (char*)"LEVEL2.PSX";
|
||||
if (!sndName) sndName = (char*)"05.ogg";
|
||||
startLevel(lvlName, sndName, false, false);
|
||||
init(new Stream(lvlName), new Stream(sndName));
|
||||
}
|
||||
|
||||
|
||||
void free() {
|
||||
delete level;
|
||||
Core::free();
|
||||
|
11
src/lara.h
11
src/lara.h
@@ -405,7 +405,7 @@ struct Lara : Character {
|
||||
|
||||
if (level->extra.braid > -1)
|
||||
braid = new Braid(this, vec3(-4.0f, 24.0f, -48.0f));
|
||||
|
||||
//reset(15, vec3(70067, -256, 29104), -0.68f); // level 2 (pool)
|
||||
#ifdef _DEBUG
|
||||
//reset(14, vec3(40448, 3584, 60928), PI * 0.5f, true); // gym (pool)
|
||||
|
||||
@@ -414,7 +414,7 @@ struct Lara : Character {
|
||||
//reset(61, vec3(27221, -1024, 29205), PI * 0.5f); // level 2 (blade)
|
||||
//reset(43, vec3(31400, -2560, 25200), PI); // level 2 (reach)
|
||||
//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(15, vec3(70082, -512, 26935), PI * 0.5f); // level 2 (bear)
|
||||
//reset(63, vec3(31390, -2048, 33472), 0.0f); // level 2 (trap floor)
|
||||
@@ -2018,8 +2018,8 @@ struct Lara : Character {
|
||||
Core::setBlending(bmNone);
|
||||
}
|
||||
|
||||
virtual void render(Frustum *frustum, MeshBuilder *mesh) {
|
||||
Controller::render(frustum, mesh);
|
||||
virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
|
||||
Controller::render(frustum, mesh, type, caustics);
|
||||
chestOffset = animation.getJoints(getMatrix(), 7).pos; // TODO: move to update func
|
||||
|
||||
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)) {
|
||||
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, 13, true), vec3( 10, -50, 150), arms[1].shotTimer);
|
||||
Core::active.shader->setParam(uType, Shader::ENTITY);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
264
src/level.h
264
src/level.h
@@ -33,10 +33,7 @@ const char GUI[] =
|
||||
#define WATER_FOG_DIST (8 * 1024)
|
||||
|
||||
struct Level : IGame {
|
||||
enum { shCompose, shShadow, shAmbient, shFilter, shWater, shGUI, shMAX };
|
||||
|
||||
TR::Level level;
|
||||
Shader *shaders[shMAX];
|
||||
Texture *atlas;
|
||||
Texture *cube;
|
||||
MeshBuilder *mesh;
|
||||
@@ -54,6 +51,70 @@ struct Level : IGame {
|
||||
float clipHeight;
|
||||
} 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 {
|
||||
Level *level;
|
||||
|
||||
@@ -125,8 +186,7 @@ struct Level : IGame {
|
||||
// second pass - downsample it
|
||||
Core::setDepthTest(false);
|
||||
|
||||
level->setPassShader(Core::passFilter);
|
||||
Core::active.shader->setParam(uType, Shader::FILTER_DOWNSAMPLE);
|
||||
level->shaderCache->bind(Core::passFilter, Shader::FILTER_DOWNSAMPLE, false);
|
||||
|
||||
for (int i = 1; i < 4; i++) {
|
||||
int size = 64 >> (i << 1);
|
||||
@@ -136,7 +196,7 @@ struct Level : IGame {
|
||||
for (int j = 0; j < 6; j++) {
|
||||
Texture *src = textures[j * 4 + i - 1];
|
||||
Texture *dst = textures[j * 4 + i];
|
||||
Core::setTarget(dst);
|
||||
Core::setTarget(dst, true);
|
||||
src->bind(sDiffuse);
|
||||
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] *= colors[j]; // to "linear" space
|
||||
}
|
||||
Core::setTarget(NULL);
|
||||
|
||||
Core::setDepthTest(true);
|
||||
}
|
||||
@@ -273,9 +332,8 @@ struct Level : IGame {
|
||||
caustics = new Texture(512, 512, Texture::RGB16, false);
|
||||
blank = false;
|
||||
|
||||
Core::setTarget(data[0]);
|
||||
Core::clear(vec4(0.0f));
|
||||
Core::setTarget(NULL);
|
||||
Core::setTarget(data[0], true);
|
||||
Core::invalidateTarget(false, true);
|
||||
}
|
||||
|
||||
void free() {
|
||||
@@ -399,10 +457,10 @@ struct Level : IGame {
|
||||
void drop(Item &item) {
|
||||
if (!dropCount) return;
|
||||
|
||||
level->setShader(Core::passWater, Shader::WATER_DROP, false);
|
||||
vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f) };
|
||||
Core::active.shader->setParam(uPosScale, rPosScale[0], 2);
|
||||
Core::active.shader->setParam(uType, Shader::WATER_DROP);
|
||||
|
||||
|
||||
for (int i = 0; i < dropCount; 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));
|
||||
|
||||
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));
|
||||
level->mesh->renderQuad();
|
||||
Core::invalidateTarget(false, true);
|
||||
swap(item.data[0], item.data[1]);
|
||||
}
|
||||
}
|
||||
@@ -422,23 +481,24 @@ struct Level : IGame {
|
||||
void step(Item &item) {
|
||||
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));
|
||||
|
||||
while (item.timer >= SIMULATE_TIMESTEP) {
|
||||
// water step
|
||||
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));
|
||||
level->mesh->renderQuad();
|
||||
Core::invalidateTarget(false, true);
|
||||
swap(item.data[0], item.data[1]);
|
||||
item.timer -= SIMULATE_TIMESTEP;
|
||||
}
|
||||
|
||||
|
||||
// calc caustics
|
||||
level->setShader(Core::passWater, Shader::WATER_CAUSTICS, false);
|
||||
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);
|
||||
|
||||
float sx = item.size.x * DETAIL / (item.data[0]->width / 2);
|
||||
@@ -448,19 +508,19 @@ struct Level : IGame {
|
||||
|
||||
Core::whiteTex->bind(sReflect);
|
||||
item.data[0]->bind(sNormal);
|
||||
Core::setTarget(item.caustics);
|
||||
Core::setTarget(item.caustics, true);
|
||||
level->mesh->renderPlane();
|
||||
Core::invalidateTarget(false, true);
|
||||
}
|
||||
|
||||
void render() {
|
||||
if (!visible) return;
|
||||
|
||||
// mask underwater geometry by zero alpha
|
||||
level->setPassShader(Core::passWater);
|
||||
level->atlas->bind(sNormal);
|
||||
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::setBlending(bmNone);
|
||||
Core::setCulling(cfNone);
|
||||
@@ -497,7 +557,7 @@ struct Level : IGame {
|
||||
}
|
||||
|
||||
// render mirror reflection
|
||||
Core::setTarget(reflect);
|
||||
Core::setTarget(reflect, true);
|
||||
vec3 p = item.pos;
|
||||
vec3 n = vec3(0, 1, 0);
|
||||
|
||||
@@ -511,15 +571,14 @@ struct Level : IGame {
|
||||
level->params.clipSign = underwater ? -1.0f : 1.0f;
|
||||
level->params.clipHeight = item.pos.y * level->params.clipSign;
|
||||
level->renderCompose(underwater ? item.from : item.to);
|
||||
Core::invalidateTarget(false, true);
|
||||
level->params.clipHeight = 1000000.0f;
|
||||
level->params.clipSign = 1.0f;
|
||||
|
||||
|
||||
level->camera->reflectPlane = NULL;
|
||||
level->camera->setup(true);
|
||||
|
||||
// simulate water
|
||||
level->setPassShader(Core::passWater);
|
||||
|
||||
Core::setDepthTest(false);
|
||||
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::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(uPosScale, item.pos, 2);
|
||||
Core::active.shader->setParam(uViewPos, Core::viewPos);
|
||||
@@ -627,6 +686,9 @@ struct Level : IGame {
|
||||
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) {
|
||||
params.time = 0.0f;
|
||||
@@ -637,7 +699,7 @@ struct Level : IGame {
|
||||
mesh = new MeshBuilder(level);
|
||||
|
||||
initTextures();
|
||||
initShaders();
|
||||
shaderCache = new ShaderCache(mesh->animTexRangesCount, mesh->animTexOffsetsCount);
|
||||
initOverrides();
|
||||
|
||||
for (int i = 0; i < level.entitiesBaseCount; i++) {
|
||||
@@ -756,8 +818,7 @@ struct Level : IGame {
|
||||
for (int i = 0; i < level.entitiesCount; i++)
|
||||
delete (Controller*)level.entities[i].controller;
|
||||
|
||||
for (int i = 0; i < shMAX; i++)
|
||||
delete shaders[i];
|
||||
delete shaderCache;
|
||||
|
||||
delete shadow;
|
||||
delete ambientCache;
|
||||
@@ -815,33 +876,6 @@ struct Level : IGame {
|
||||
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() {
|
||||
/*
|
||||
for (int i = 0; i < level.entitiesCount; i++) {
|
||||
@@ -954,15 +988,18 @@ struct Level : IGame {
|
||||
}
|
||||
#endif
|
||||
|
||||
void setRoomParams(int roomIndex, float intensity) {
|
||||
if (Core::pass == Core::passShadow)
|
||||
void setRoomParams(int roomIndex, float intensity, Shader::Type type) {
|
||||
if (Core::pass == Core::passShadow) {
|
||||
setShader(Core::pass, type, false);
|
||||
return;
|
||||
}
|
||||
|
||||
TR::Room &room = level.rooms[roomIndex];
|
||||
|
||||
setShader(Core::pass, type, room.flags.water);
|
||||
|
||||
if (room.flags.water) {
|
||||
Core::color = vec4(waterColor, intensity);
|
||||
Core::active.shader->setParam(uCaustics, 1);
|
||||
/*
|
||||
// trace to water surface room
|
||||
int wrIndex = roomIndex;
|
||||
@@ -972,10 +1009,9 @@ struct Level : IGame {
|
||||
int sx = room.xSectors
|
||||
*/
|
||||
waterCache->bindCaustics(roomIndex);
|
||||
} else {
|
||||
} else
|
||||
Core::color = vec4(1.0f, 1.0f, 1.0f, intensity);
|
||||
Core::active.shader->setParam(uCaustics, 0);
|
||||
}
|
||||
|
||||
Core::active.shader->setParam(uColor, Core::color);
|
||||
}
|
||||
|
||||
@@ -994,13 +1030,13 @@ struct Level : IGame {
|
||||
room.flags.rendered = true;
|
||||
|
||||
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;
|
||||
Core::basis.translate(offset);
|
||||
|
||||
Shader *sh = Core::active.shader;
|
||||
sh->setParam(uType, Shader::ROOM);
|
||||
sh->setParam(uBasis, Core::basis);
|
||||
|
||||
// render room geometry
|
||||
@@ -1008,9 +1044,11 @@ struct Level : IGame {
|
||||
|
||||
// render room sprites
|
||||
if (mesh->hasRoomSprites(roomIndex)) {
|
||||
Core::color.w = 1.0;
|
||||
sh->setParam(uType, Shader::SPRITE);
|
||||
sh->setParam(uColor, Core::color);
|
||||
setRoomParams(roomIndex, 1.0, Shader::SPRITE);
|
||||
sh = Core::active.shader;
|
||||
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
||||
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
||||
sh->setParam(uBasis, Core::basis);
|
||||
mesh->renderRoomSprites(roomIndex);
|
||||
}
|
||||
|
||||
@@ -1108,7 +1146,11 @@ struct Level : IGame {
|
||||
return;
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
getLight(pos, entity.room);
|
||||
Core::active.shader->setParam(uType, Shader::ENTITY);
|
||||
Core::active.shader->setParam(uAmbient, controller->ambient[0], 6);
|
||||
} else { // sprite
|
||||
Core::active.shader->setParam(uType, Shader::SPRITE);
|
||||
Core::lightPos[0] = vec3(0);
|
||||
Core::lightColor[0] = vec4(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
Core::active.shader->setParam(uViewProj, Core::mViewProj);
|
||||
Core::active.shader->setParam(uLightProj, Core::mLightProj);
|
||||
Core::active.shader->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
||||
Core::active.shader->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
||||
|
||||
controller->render(camera->frustum, mesh);
|
||||
controller->render(camera->frustum, mesh, type, room.flags.water);
|
||||
}
|
||||
|
||||
void update() {
|
||||
@@ -1155,6 +1197,9 @@ struct Level : IGame {
|
||||
waterCache->update();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void setup() {
|
||||
PROFILE_MARKER("SETUP");
|
||||
|
||||
@@ -1168,19 +1213,20 @@ struct Level : IGame {
|
||||
|
||||
if (!Core::support.VAO)
|
||||
mesh->bind();
|
||||
|
||||
//Core::mViewProj = Core::mLightProj;
|
||||
// set frame constants for all shaders
|
||||
Shader *sh = Core::active.shader;
|
||||
sh->bind();
|
||||
sh->setParam(uViewProj, Core::mViewProj);
|
||||
sh->setParam(uLightProj, Core::mLightProj);
|
||||
sh->setParam(uViewInv, Core::mViewInv);
|
||||
sh->setParam(uViewPos, Core::viewPos);
|
||||
sh->setParam(uParam, *((vec4*)¶ms));
|
||||
sh->setParam(uLightsCount, 3);
|
||||
sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
|
||||
sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
|
||||
|
||||
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*)¶ms));
|
||||
sh->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
|
||||
sh->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
|
||||
}
|
||||
Core::basis.identity();
|
||||
|
||||
// clear visibility flag for rooms
|
||||
@@ -1196,8 +1242,6 @@ struct Level : IGame {
|
||||
PROFILE_MARKER("ROOMS");
|
||||
|
||||
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
|
||||
for (int i = 0; i < level.roomsCount; i++)
|
||||
@@ -1264,62 +1308,51 @@ struct Level : IGame {
|
||||
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) {
|
||||
PROFILE_MARKER("ENVIRONMENT");
|
||||
// first pass render level into cube faces
|
||||
for (int i = 0; i < 6; i++) {
|
||||
setupCubeCamera(pos, i);
|
||||
setPassShader(Core::passAmbient);
|
||||
Core::pass = Core::passAmbient;
|
||||
Texture *target = targets[0]->cube ? targets[0] : targets[i * stride];
|
||||
Core::setTarget(target, i);
|
||||
Core::clear(vec4(0, 0, 0, 1));
|
||||
Core::setTarget(target, true, i);
|
||||
renderScene(roomIndex);
|
||||
Core::invalidateTarget(false, true);
|
||||
}
|
||||
Core::setTarget(NULL);
|
||||
}
|
||||
|
||||
void renderShadows(int roomIndex) {
|
||||
PROFILE_MARKER("PASS_SHADOW");
|
||||
Core::pass = Core::passShadow;
|
||||
if (!setupLightCamera()) return;
|
||||
shadow->unbind(sShadow);
|
||||
setPassShader(Core::passShadow);
|
||||
Core::setBlending(bmNone);
|
||||
Core::setTarget(shadow);
|
||||
Core::clear(vec4(1.0));
|
||||
bool colorShadow = shadow->format == Texture::Format::RGBA ? true : false;
|
||||
if (colorShadow)
|
||||
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
Core::setTarget(shadow, true);
|
||||
Core::setCulling(cfBack);
|
||||
renderScene(roomIndex);
|
||||
Core::setCulling(cfFront);
|
||||
Core::setTarget(NULL);
|
||||
Core::invalidateTarget(!colorShadow, colorShadow);
|
||||
Core::setCulling(cfFront);
|
||||
if (colorShadow)
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
void renderCompose(int roomIndex) {
|
||||
PROFILE_MARKER("PASS_COMPOSE");
|
||||
setPassShader(Core::passCompose);
|
||||
Core::pass = Core::passCompose;
|
||||
|
||||
Core::setBlending(bmAlpha);
|
||||
Core::setDepthTest(true);
|
||||
Core::setDepthWrite(true);
|
||||
Core::clear(vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
shadow->bind(sShadow);
|
||||
renderScene(roomIndex);
|
||||
Core::setBlending(bmNone);
|
||||
}
|
||||
|
||||
void render() {
|
||||
Core::invalidateTarget(true, true);
|
||||
params.clipHeight = 1000000.0f;
|
||||
params.clipSign = 1.0f;
|
||||
params.waterHeight = params.clipHeight;
|
||||
@@ -1329,6 +1362,7 @@ struct Level : IGame {
|
||||
waterCache->reset();
|
||||
|
||||
renderShadows(lara->getRoomIndex());
|
||||
Core::setTarget(NULL, true);
|
||||
Core::setViewport(0, 0, Core::width, Core::height);
|
||||
|
||||
waterCache->checkVisibility = true;
|
||||
@@ -1410,7 +1444,6 @@ struct Level : IGame {
|
||||
|
||||
|
||||
|
||||
/*
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
@@ -1419,10 +1452,7 @@ struct Level : IGame {
|
||||
glLoadIdentity();
|
||||
glOrtho(0, Core::width, 0, Core::height, 0, 1);
|
||||
|
||||
if (waterCache->count)
|
||||
waterCache->items[0].data[0]->bind(sDiffuse);
|
||||
else
|
||||
atlas->bind(sDiffuse);
|
||||
shadow->bind(sDiffuse);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
@@ -1448,12 +1478,12 @@ struct Level : IGame {
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
*/
|
||||
|
||||
|
||||
Core::setBlending(bmAlpha);
|
||||
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||
// 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);
|
||||
// Debug::Level::portals(level);
|
||||
// Core::setDepthTest(true);
|
||||
|
@@ -437,6 +437,7 @@ struct MeshBuilder {
|
||||
iCount += 6;
|
||||
}
|
||||
}
|
||||
LOG("MegaMesh: %d %d %d\n", iCount, vCount, aCount);
|
||||
|
||||
// compile buffer and ranges
|
||||
mesh = new Mesh(indices, iCount, vertices, vCount, aCount);
|
||||
|
@@ -18,9 +18,8 @@ extern "C" {
|
||||
}
|
||||
|
||||
void EMSCRIPTEN_KEEPALIVE game_level_load(char *data, int size, int home) {
|
||||
Stream stream(data, size);
|
||||
Game::startLevel(stream, NULL, false, home);
|
||||
}
|
||||
Game::startLevel(new Stream(data, size), NULL, false, home);
|
||||
}
|
||||
}
|
||||
|
||||
InputKey joyToInputKey(int code) {
|
||||
|
@@ -149,6 +149,7 @@
|
||||
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<AssemblyDebug>true</AssemblyDebug>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">
|
||||
|
@@ -119,6 +119,44 @@ void joyUpdate() {
|
||||
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
|
||||
#define SND_SIZE 4704*2
|
||||
|
||||
@@ -182,7 +220,7 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara
|
||||
Input::reset();
|
||||
break;
|
||||
case WM_SIZE:
|
||||
Core::width = LOWORD(lParam);
|
||||
Core::width = LOWORD(lParam);
|
||||
Core::height = HIWORD(lParam);
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
@@ -242,6 +280,9 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara
|
||||
joyInit();
|
||||
return 1;
|
||||
// touch
|
||||
case WM_TOUCH :
|
||||
touchUpdate((HTOUCHINPUT)lParam, wParam);
|
||||
break;
|
||||
// TODO
|
||||
// sound
|
||||
default :
|
||||
@@ -293,6 +334,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
Sound::channelsCount = 0;
|
||||
|
||||
touchInit(hWnd);
|
||||
joyInit();
|
||||
sndInit(hWnd);
|
||||
|
||||
|
155
src/shader.glsl
155
src/shader.glsl
@@ -1,7 +1,11 @@
|
||||
R"====(
|
||||
#ifdef GL_ES
|
||||
precision highp int;
|
||||
precision lowp int;
|
||||
precision highp float;
|
||||
#else
|
||||
#define lowp
|
||||
#define mediump
|
||||
#define highp
|
||||
#endif
|
||||
|
||||
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;
|
||||
#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
|
||||
uniform vec3 uViewPos;
|
||||
uniform int uCaustics;
|
||||
@@ -78,7 +74,7 @@ uniform int uType;
|
||||
#endif
|
||||
|
||||
#ifdef PASS_COMPOSE
|
||||
if (uType != TYPE_SPRITE) {
|
||||
#ifndef TYPE_SPRITE
|
||||
// animated texture coordinates
|
||||
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
|
||||
vNormal = vec4(mulQuat(rBasisRot, aNormal.xyz), aNormal.w);
|
||||
|
||||
if (uCaustics != 0) {
|
||||
#ifdef CAUSTICS
|
||||
float sum = coord.x + coord.y + coord.z;
|
||||
vColor.xyz *= abs(sin(sum / 512.0 + uParam.x)) * 1.5 + 0.5; // color dodge
|
||||
}
|
||||
|
||||
} else {
|
||||
#endif
|
||||
#else
|
||||
coord.xyz += uViewInv[0].xyz * aTexCoord.z - uViewInv[1].xyz * aTexCoord.w;
|
||||
vTexCoord.xy = aTexCoord.xy * TEXCOORD_SCALE;
|
||||
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));
|
||||
|
||||
@@ -118,7 +113,6 @@ uniform int uType;
|
||||
uniform vec4 uColor;
|
||||
#ifdef PASS_COMPOSE
|
||||
uniform samplerCube sEnvironment;
|
||||
uniform int uLightsCount;
|
||||
uniform vec3 uLightPos[MAX_LIGHTS];
|
||||
uniform vec4 uLightColor[MAX_LIGHTS];
|
||||
uniform vec3 uAmbient[6];
|
||||
@@ -140,14 +134,14 @@ uniform int uType;
|
||||
|
||||
#ifdef SHADOW_SAMPLER
|
||||
uniform sampler2DShadow sShadow;
|
||||
#ifdef MOBILE
|
||||
#ifdef GL_ES
|
||||
#define SHADOW(V) (shadow2DEXT(sShadow, V))
|
||||
#else
|
||||
#define SHADOW(V) (shadow2D(sShadow, V).x)
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2D sShadow;
|
||||
#define CMP(a,b) float(a > b)
|
||||
#define CMP(a,b) step(b, a)
|
||||
|
||||
#ifdef SHADOW_DEPTH
|
||||
#define compare(p, z) CMP(texture2D(sShadow, (p)).x, (z));
|
||||
@@ -160,6 +154,8 @@ uniform int uType;
|
||||
#endif
|
||||
|
||||
float SHADOW(vec3 p) {
|
||||
return compare(p.xy, p.z);
|
||||
/*
|
||||
vec2 t = vec2(0.0, 1.0 / 1024.0);
|
||||
vec2 c = floor(p.xy * 1024.0 + 0.5) / 1024.0;
|
||||
vec4 s;
|
||||
@@ -169,40 +165,55 @@ uniform int uType;
|
||||
s.w = compare(c + t.yy, p.z);
|
||||
vec2 f = fract(p.xy * 1024.0 + 0.5);
|
||||
return mix(mix(s.x, s.y, f.y), mix(s.z, s.w, f.y), f.x);
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
float getShadow(vec4 lightProj) {
|
||||
vec3 p = lightProj.xyz / lightProj.w;
|
||||
if (lightProj.w < 0.0) return 1.0;
|
||||
|
||||
vec2 poissonDisk[16];
|
||||
poissonDisk[ 0] = vec2( -0.94201624, -0.39906216 );
|
||||
poissonDisk[ 1] = vec2( 0.94558609, -0.76890725 );
|
||||
poissonDisk[ 2] = vec2( -0.09418410, -0.92938870 );
|
||||
poissonDisk[ 3] = vec2( 0.34495938, 0.29387760 );
|
||||
poissonDisk[ 4] = vec2( -0.91588581, 0.45771432 );
|
||||
poissonDisk[ 5] = vec2( -0.81544232, -0.87912464 );
|
||||
poissonDisk[ 6] = vec2( -0.38277543, 0.27676845 );
|
||||
poissonDisk[ 7] = vec2( 0.97484398, 0.75648379 );
|
||||
poissonDisk[ 8] = vec2( 0.44323325, -0.97511554 );
|
||||
poissonDisk[ 9] = vec2( 0.53742981, -0.47373420 );
|
||||
poissonDisk[10] = vec2( -0.26496911, -0.41893023 );
|
||||
poissonDisk[11] = vec2( 0.79197514, 0.19090188 );
|
||||
poissonDisk[12] = vec2( -0.24188840, 0.99706507 );
|
||||
poissonDisk[13] = vec2( -0.81409955, 0.91437590 );
|
||||
poissonDisk[14] = vec2( 0.19984126, 0.78641367 );
|
||||
poissonDisk[15] = vec2( 0.14383161, -0.14100790 );
|
||||
vec3 poissonDisk[16];
|
||||
poissonDisk[ 0] = vec3(-0.94201624, -0.39906216, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 1] = vec3( 0.94558609, -0.76890725, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 2] = vec3(-0.09418410, -0.92938870, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 3] = vec3( 0.34495938, 0.29387760, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 4] = vec3(-0.91588581, 0.45771432, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 5] = vec3(-0.81544232, -0.87912464, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 6] = vec3(-0.38277543, 0.27676845, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 7] = vec3( 0.97484398, 0.75648379, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 8] = vec3( 0.44323325, -0.97511554, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[ 9] = vec3( 0.53742981, -0.47373420, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[10] = vec3(-0.26496911, -0.41893023, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[11] = vec3( 0.79197514, 0.19090188, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[12] = vec3(-0.24188840, 0.99706507, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[13] = vec3(-0.81409955, 0.91437590, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[14] = vec3( 0.19984126, 0.78641367, 0.0) * (1.5 / 1024.0);
|
||||
poissonDisk[15] = vec3( 0.14383161, -0.14100790, 0.0) * (1.5 / 1024.0);
|
||||
|
||||
float rShadow = 0.0;
|
||||
for (int i = 0; i < 16; i += 1)
|
||||
rShadow += SHADOW(p + vec3(poissonDisk[i] * 1.5, 0.0) * (1.0 / 1024.0));
|
||||
vec3 p = lightProj.xyz / lightProj.w;
|
||||
|
||||
rShadow += SHADOW(p + poissonDisk[0]);
|
||||
rShadow += SHADOW(p + poissonDisk[1]);
|
||||
rShadow += SHADOW(p + poissonDisk[2]);
|
||||
rShadow += SHADOW(p + poissonDisk[3]);
|
||||
rShadow += SHADOW(p + poissonDisk[4]);
|
||||
rShadow += SHADOW(p + poissonDisk[5]);
|
||||
rShadow += SHADOW(p + poissonDisk[6]);
|
||||
rShadow += SHADOW(p + poissonDisk[7]);
|
||||
rShadow += SHADOW(p + poissonDisk[8]);
|
||||
rShadow += SHADOW(p + poissonDisk[9]);
|
||||
rShadow += SHADOW(p + poissonDisk[10]);
|
||||
rShadow += SHADOW(p + poissonDisk[11]);
|
||||
rShadow += SHADOW(p + poissonDisk[12]);
|
||||
rShadow += SHADOW(p + poissonDisk[13]);
|
||||
rShadow += SHADOW(p + poissonDisk[14]);
|
||||
rShadow += SHADOW(p + poissonDisk[15]);
|
||||
|
||||
rShadow /= 16.0;
|
||||
|
||||
vec3 lv = uLightPos[0].xyz - vCoord.xyz;
|
||||
float fade = clamp(dot(lv, lv) / uLightColor[0].w, 0.0, 1.0);
|
||||
|
||||
return mix(rShadow, 1.0, fade);
|
||||
return clamp(mix(rShadow, 1.0, fade), -lightProj.w, 1.0);
|
||||
}
|
||||
|
||||
vec3 calcLight(vec3 normal, vec3 pos, vec4 color) {
|
||||
@@ -227,13 +238,12 @@ uniform int uType;
|
||||
sqr.z * mix(uAmbient[5], uAmbient[4], pos.z);
|
||||
}
|
||||
|
||||
float calcCaustics(vec3 n) {
|
||||
if (uCaustics != 0) {
|
||||
#ifdef CAUSTICS
|
||||
float calcCaustics(vec3 n) {
|
||||
vec2 fade = smoothstep(uRoomSize.xy, uRoomSize.xy + vec2(256.0), vCoord.xz) * (1.0 - smoothstep(uRoomSize.zw - vec2(256.0), uRoomSize.zw, vCoord.xz));
|
||||
return texture2D(sReflect, vTexCoord.zw).r * (max(0.0, -n.y)) * fade.x * fade.y;
|
||||
} else
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
vec3 applyFog(vec3 color, vec3 fogColor, float factor) {
|
||||
float fog = clamp(1.0 / exp(factor), 0.0, 1.0);
|
||||
@@ -268,9 +278,10 @@ uniform int uType;
|
||||
#endif
|
||||
|
||||
vec4 color = texture2D(sDiffuse, vTexCoord.xy);
|
||||
if (color.w <= 0.6) {
|
||||
discard;
|
||||
}
|
||||
|
||||
// if (color.w <= 0.6) {
|
||||
// discard;
|
||||
// }
|
||||
|
||||
#ifdef PASS_SHADOW
|
||||
#ifdef SHADOW_COLOR
|
||||
@@ -288,7 +299,7 @@ uniform int uType;
|
||||
color.xyz *= vColor.w;
|
||||
#else
|
||||
// calc point lights
|
||||
if (uType != TYPE_FLASH) {
|
||||
#ifndef TYPE_FLASH
|
||||
vec3 normal = normalize(vNormal.xyz);
|
||||
|
||||
//vec3 n = getNormal();;
|
||||
@@ -299,50 +310,62 @@ uniform int uType;
|
||||
vec3 viewVec = normalize(vViewVec);
|
||||
vec3 light = vec3(0.0);
|
||||
|
||||
for (int i = 1; i < MAX_LIGHTS; i++) // additional lights
|
||||
light += calcLight(normal, uLightPos[i], uLightColor[i]);
|
||||
// for (int i = 1; i < 3; i++) // additional lights
|
||||
light += calcLight(normal, uLightPos[1], uLightColor[1]);
|
||||
light += calcLight(normal, uLightPos[2], uLightColor[2]);
|
||||
|
||||
// apply lighting
|
||||
if (uType == TYPE_SPRITE) {
|
||||
#ifdef TYPE_SPRITE
|
||||
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;
|
||||
//light += calcLight(normal, uLightPos[0], uLightColor[0]);
|
||||
light += mix(min(uColor.w, vColor.w), vColor.w, rShadow);
|
||||
light += calcCaustics(normal);
|
||||
}
|
||||
#ifdef CAUSTICS
|
||||
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);
|
||||
float rShadow = getShadow(vLightProj);
|
||||
light += calcLight(normal, uLightPos[0], uLightColor[0]) * rShadow + rAmbient;
|
||||
color.xyz += calcSpecular(normal, viewVec, uLightPos[0], uLightColor[0], uColor.w * rShadow + 0.03);
|
||||
light += calcCaustics(normal);
|
||||
}
|
||||
#ifdef CAUSTICS
|
||||
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);
|
||||
color.xyz = uColor.xyz * pow(abs(textureCube(sEnvironment, normalize(rv)).xyz), vec3(2.2));
|
||||
light.xyz = vec3(1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
color.xyz *= light;
|
||||
} else {
|
||||
|
||||
#else // ifndef TYPE_FLASH
|
||||
|
||||
color.w = uColor.w;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
color = sqrt(color); // back to "gamma" space
|
||||
|
||||
#ifdef PASS_COMPOSE
|
||||
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);
|
||||
d *= step(0.0, vCoord.y - uParam.y);
|
||||
color.xyz = applyFog(color.xyz, uColor.xyz * 0.2, d * WATER_FOG_DIST);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
gl_FragColor = color;
|
||||
|
@@ -5,20 +5,22 @@
|
||||
|
||||
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
|
||||
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 *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 {
|
||||
GLuint ID;
|
||||
GLint uID[uMAX];
|
||||
|
||||
enum : GLint {
|
||||
enum Type : GLint {
|
||||
NONE = 0,
|
||||
/* shader */ SPRITE = 0, FLASH = 1, ROOM = 2, ENTITY = 3, MIRROR = 4,
|
||||
/* filter */ FILTER_DOWNSAMPLE = 0,
|
||||
/* 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 = "") {
|
||||
|
@@ -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.translate(pos);
|
||||
Core::active.shader->setParam(uBasis, basis);
|
||||
|
@@ -299,13 +299,11 @@ struct Crystal : Controller {
|
||||
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;
|
||||
sh->setParam(uType, Shader::MIRROR);
|
||||
sh->setParam(uColor, vec4(0.4f, 0.4f, 16.0f, 1.0f)); // blue color dodge
|
||||
environment->bind(sEnvironment);
|
||||
Controller::render(frustum, mesh);
|
||||
sh->setParam(uType, Shader::ENTITY);
|
||||
Controller::render(frustum, mesh, type, caustics);
|
||||
}
|
||||
};
|
||||
|
||||
|
16
src/utils.h
16
src/utils.h
@@ -12,9 +12,6 @@
|
||||
|
||||
#ifndef ANDROID
|
||||
#define LOG(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#include <android/log.h>
|
||||
#define LOG(...) __android_log_print(ANDROID_LOG_INFO,"X5",__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#else
|
||||
@@ -26,6 +23,13 @@
|
||||
// #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 INF INFINITY
|
||||
#define PI 3.14159265358979323846f
|
||||
@@ -34,9 +38,9 @@
|
||||
#define RAD2DEG (180.0f / PI)
|
||||
#define randf() ((float)rand()/RAND_MAX)
|
||||
|
||||
typedef char int8;
|
||||
typedef short int16;
|
||||
typedef int int32;
|
||||
typedef signed char int8;
|
||||
typedef signed short int16;
|
||||
typedef signed int int32;
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
|
@@ -1,24 +1,23 @@
|
||||
R"====(
|
||||
#ifdef GL_ES
|
||||
precision highp int;
|
||||
precision lowp int;
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
varying vec3 vCoord;
|
||||
varying vec2 vTexCoord;
|
||||
varying vec4 vProjCoord;
|
||||
varying vec3 vRefPos1;
|
||||
varying vec3 vRefPos2;
|
||||
varying vec4 vOldPos;
|
||||
varying vec4 vNewPos;
|
||||
varying vec3 vViewVec;
|
||||
varying vec3 vLightVec;
|
||||
|
||||
/*
|
||||
#define WATER_DROP 0
|
||||
#define WATER_STEP 1
|
||||
#define WATER_CAUSTICS 2
|
||||
#define WATER_MASK 3
|
||||
#define WATER_COMPOSE 4
|
||||
|
||||
uniform int uType;
|
||||
*/
|
||||
uniform vec3 uViewPos;
|
||||
uniform mat4 uViewProj;
|
||||
uniform vec3 uLightPos;
|
||||
@@ -39,14 +38,14 @@ uniform sampler2D sNormal;
|
||||
void main() {
|
||||
vTexCoord = (aCoord.xy * 0.5 + 0.5) * uTexParam.zw;
|
||||
|
||||
if (uType >= WATER_MASK) {
|
||||
#if defined(WATER_MASK) || defined(WATER_COMPOSE)
|
||||
|
||||
float height = 0.0;
|
||||
|
||||
if (uType == WATER_COMPOSE) {
|
||||
#ifdef WATER_COMPOSE
|
||||
vTexCoord = (aCoord.xy * (1.0 / 48.0) * 0.5 + 0.5) * uTexParam.zw;
|
||||
height = texture2D(sNormal, vTexCoord).x;
|
||||
}
|
||||
#endif
|
||||
|
||||
vCoord = vec3(aCoord.x, height, aCoord.y) * uPosScale[1] + uPosScale[0];
|
||||
|
||||
@@ -54,28 +53,28 @@ uniform sampler2D sNormal;
|
||||
|
||||
vProjCoord = cp;
|
||||
gl_Position = cp;
|
||||
} else {
|
||||
#else
|
||||
vProjCoord = vec4(0.0);
|
||||
vCoord = vec3(aCoord.xy, 0.0);
|
||||
if (uType == WATER_CAUSTICS) {
|
||||
vec3 rCoord = vec3(aCoord.x, 0.0, aCoord.y) * uPosScale[1];
|
||||
#ifdef WATER_CAUSTICS
|
||||
vec3 rCoord = vec3(aCoord.x, aCoord.y, 0.0) * uPosScale[1].xzy;
|
||||
|
||||
vec4 info = texture2D(sNormal, (rCoord.xz * 0.5 + 0.5) * uTexParam.zw);
|
||||
vec3 normal = vec3(info.z, -sqrt(1.0 - dot(info.zw, info.zw)), info.w);
|
||||
vec4 info = texture2D(sNormal, (rCoord.xy * 0.5 + 0.5) * uTexParam.zw);
|
||||
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 refractedLight = refract(-light, vec3(0.0, 1.0, 0.0), ETA_AIR / ETA_WATER);
|
||||
vec3 ray = refract(-light, normal, ETA_AIR / ETA_WATER);
|
||||
vec3 light = vec3(0.0, 0.0, 1.0);
|
||||
vec3 refOld = refract(-light, vec3(0.0, 0.0, 1.0), 0.75);
|
||||
vec3 refNew = refract(-light, normal, 0.75);
|
||||
|
||||
vRefPos1 = rCoord + vec3(0.0, 0.0, 0.0);
|
||||
vRefPos2 = rCoord + vec3(0.0, info.r, 0.0) + ray / ray.y;
|
||||
vOldPos = vec4(rCoord + refOld * (-0.25 / refOld.z) + refOld * ((-refOld.z - 1.0) / refOld.z), 1.0);
|
||||
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);
|
||||
} else {
|
||||
vRefPos1 = vRefPos2 = vec3(0.0);
|
||||
gl_Position = vec4(vNewPos.xy + refOld.xy / refOld.z, 0.0, 1.0);
|
||||
#else
|
||||
vOldPos = vNewPos = vec4(0.0);
|
||||
gl_Position = vec4(aCoord.xyz, 1.0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
vViewVec = uViewPos - vCoord.xyz;
|
||||
vLightVec = uLightPos - vCoord.xyz;
|
||||
}
|
||||
@@ -137,9 +136,10 @@ uniform sampler2D sNormal;
|
||||
}
|
||||
|
||||
vec4 caustics() {
|
||||
float area1 = length(dFdx(vRefPos1)) * length(dFdy(vRefPos1));
|
||||
float area2 = length(dFdx(vRefPos2)) * length(dFdy(vRefPos2));
|
||||
return vec4(vec3(area1 / area2 * 0.2), 1.0);
|
||||
float rOldArea = length(dFdx(vOldPos.xyz)) * length(dFdy(vOldPos.xyz));
|
||||
float rNewArea = length(dFdx(vNewPos.xyz)) * length(dFdy(vNewPos.xyz));
|
||||
float value = clamp(rOldArea / rNewArea * 0.2, 0.0, 1.0) * vOldPos.w;
|
||||
return vec4(vec3(value), 1.0);
|
||||
}
|
||||
|
||||
vec4 mask() {
|
||||
@@ -178,12 +178,28 @@ uniform sampler2D sNormal;
|
||||
}
|
||||
|
||||
vec4 pass() {
|
||||
if (uType == WATER_DROP) return drop();
|
||||
if (uType == WATER_STEP) return calc();
|
||||
if (uType == WATER_CAUSTICS) return caustics();
|
||||
if (uType == WATER_MASK) return mask();
|
||||
if (uType == WATER_COMPOSE) return compose();
|
||||
return vec4(1.0, 0.0, 0.0, 1.0);
|
||||
return
|
||||
#ifdef WATER_DROP
|
||||
drop();
|
||||
#endif
|
||||
|
||||
#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() {
|
||||
|
Reference in New Issue
Block a user