1
0
mirror of https://github.com/XProger/OpenLara.git synced 2025-01-17 21:09:00 +01:00

#23 improve shadows quality; shader and lighting refactoring; fix muzzle flash alpha; increase light radius by 2; #15 WebGL version on Safari/Edge fix audio and shadows support

This commit is contained in:
XProger 2016-12-19 03:12:54 +03:00
parent b0b7034476
commit 77f40a95c8
11 changed files with 195 additions and 206 deletions

Binary file not shown.

View File

@ -67,6 +67,7 @@
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
PFNGLUNIFORM1IVPROC glUniform1iv;
PFNGLUNIFORM1FVPROC glUniform1fv;
PFNGLUNIFORM2FVPROC glUniform2fv;
PFNGLUNIFORM3FVPROC glUniform3fv;
PFNGLUNIFORM4FVPROC glUniform4fv;
@ -86,9 +87,9 @@
// Render to texture
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
@ -190,6 +191,7 @@ namespace Core {
GetProcOGL(glGetShaderInfoLog);
GetProcOGL(glGetUniformLocation);
GetProcOGL(glUniform1iv);
GetProcOGL(glUniform1fv);
GetProcOGL(glUniform2fv);
GetProcOGL(glUniform3fv);
GetProcOGL(glUniform4fv);
@ -209,9 +211,9 @@ namespace Core {
GetProcOGL(glGenFramebuffers);
GetProcOGL(glBindFramebuffer);
GetProcOGL(glFramebufferTexture2D);
GetProcOGL(glGenRenderbuffers);
GetProcOGL(glBindRenderbuffer);
GetProcOGL(glFramebufferTexture2D);
GetProcOGL(glFramebufferRenderbuffer);
GetProcOGL(glRenderbufferStorage);
GetProcOGL(glCheckFramebufferStatus);
@ -227,18 +229,22 @@ namespace Core {
//LOG("%s\n", ext);
support.depthTexture = extSupport(ext, "_depth_texture");
support.shadowSampler = extSupport(ext, "EXT_shadow_samplers") || extSupport(ext, "GL_ARB_shadow");
support.VAO = (void*)glBindVertexArray != NULL;
LOG("Vendor : %s\n", glGetString(GL_VENDOR));
support.VAO = extSupport(ext, "_vertex_array_object");
char *vendor = (char*)glGetString(GL_VENDOR);
LOG("Vendor : %s\n", vendor);
LOG("Renderer : %s\n", glGetString(GL_RENDERER));
LOG("Version : %s\n", glGetString(GL_VERSION));
LOG("supports:\n");
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(" vertex arrays : %s\n", support.VAO ? "true" : "false");
LOG(" vertex arrays : %s\n", support.VAO ? "true" : "false");
LOG("\n");
// if (strcmp(vendor, "WebKit") == 0) // TODO: check for safari
// support.depthTexture = support.shadowSampler = false; // depth textures is not supported in Safari browser in fact :(
glGenFramebuffers(1, &RT);
Sound::init();
@ -254,7 +260,7 @@ namespace Core {
void clear(const vec4 &color) {
glClearColor(color.x, color.y, color.z, color.w);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
void setViewport(int x, int y, int width, int height) {
@ -303,15 +309,18 @@ namespace Core {
void setTarget(Texture *target) {
if (!target) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glColorMask(true, true, true, true);
return;
}
glBindFramebuffer(GL_FRAMEBUFFER, RT);
glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target->ID, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, target->depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, target->dummy ? target->dummy->ID : 0, 0);
GLenum buffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(target->depth ? 0 : 1, buffers);
bool mask = !target->depth;
glColorMask(mask, mask, mask, mask);
// GLenum buffers[] = { GL_COLOR_ATTACHMENT0 };
// glDrawBuffers(target->depth ? 0 : 1, buffers);
}
}

View File

@ -350,7 +350,7 @@ namespace Debug {
}
}
void lights(const TR::Level &level) {
void lights(const TR::Level &level, int room) {
// int roomIndex = level.entities[lara->entity].room;
// int lightIndex = getLightIndex(lara->pos, roomIndex);
@ -361,10 +361,12 @@ namespace Debug {
float a = l.intensity / 8191.0f;
vec3 p = vec3(l.x, l.y, l.z);
vec4 color = vec4(a, a, a, 1);
if (i == room) color.x = color.z = 0;
Debug::Draw::point(p, color);
//if (i == roomIndex && j == lightIndex)
// color = vec4(0, 1, 0, 1);
Debug::Draw::sphere(p, l.attenuation, color);
Debug::Draw::sphere(p, l.radius, color);
}
}

View File

@ -271,7 +271,7 @@ namespace TR {
int32 x, y, z;
uint16 align; // ! not exists in file !
uint16 intensity;
uint32 attenuation;
uint32 radius;
} *lights;
struct Mesh {
@ -924,7 +924,9 @@ namespace TR {
light.intensity = stream.read(intensity);
} else
stream.read(light.intensity);
stream.read(light.attenuation);
stream.read(light.radius);
light.radius *= 2;
}
// meshes
r.meshes = new Room::Mesh[stream.read(r.meshesCount)];
@ -1107,7 +1109,6 @@ namespace TR {
stream.read(c.x);
stream.read(c.y);
stream.read(c.z);
c.w = 0;
}
int16 nCount;
stream.read(nCount);
@ -1120,6 +1121,7 @@ namespace TR {
stream.read(n.y);
stream.read(n.z);
n.w = 1;
c.w = 0x1FFF;
} else { // intensity
stream.read(c.w);
n = { 0, 0, 0, 0 };
@ -1173,6 +1175,7 @@ namespace TR {
if (nCount > 0) { // normal
stream.read(n);
n.w = 1;
c.w = 0x1FFF;
} else { // intensity
stream.read(c.w);
n = { 0, 0, 0, 0 };

View File

@ -1733,6 +1733,7 @@ struct Lara : Character {
mat4 m(matrix);
m.rotateX(-PI * 0.5f);
m.translate(offset);
Core::active.shader->setParam(uColor, vec4(lum, lum, lum, alpha));
renderMesh(m, mesh, level->extra.muzzleFlash->mStart);
}
@ -1741,10 +1742,12 @@ struct Lara : Character {
Controller::render(frustum, mesh);
chestOffset = animation.getJoints(getMatrix(), 7).getPos(); // TODO: move to update func
if (wpnCurrent != Weapon::SHOTGUN && Core::pass != Core::passShadow) {
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);
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);
}
}
};

View File

@ -22,7 +22,7 @@ const char GUI[] =
;
struct Level {
enum { shStatic, shCaustics, shSprite, shShadowOpaque, shShadowSprite, shGUI, shMAX };
enum { shDefault, shShadow, shGUI, shMAX };
TR::Level level;
Shader *shaders[shMAX];
@ -34,9 +34,8 @@ struct Level {
Texture *shadow;
float time;
bool perspShadows;
Level(const char *name, bool demo, bool home) : level(name, demo), lara(NULL), time(0.0f), perspShadows(false) {
Level(const char *name, bool demo, bool home) : level(name, demo), lara(NULL), time(0.0f) {
#ifdef _DEBUG
Debug::init();
#endif
@ -215,17 +214,10 @@ struct Level {
else
strcat(ext, "#define SHADOW_COLOR\n");
sprintf(def, "%s#define PASS_SHADOW\n", ext);
shaders[shShadowOpaque] = new Shader(SHADER, def);
strcat(def, "#define SPRITE\n");
shaders[shShadowSprite] = new Shader(SHADER, def);
sprintf(def, "%s#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define MAX_SHADOW_DIST %d.0\n", ext, MAX_LIGHTS, mesh->animTexRangesCount, mesh->animTexOffsetsCount, MAX_SHADOW_DIST);
shaders[shStatic] = new Shader(SHADER, def);
sprintf(ext, "%s#define CAUSTICS\n", def);
shaders[shCaustics] = new Shader(SHADER, ext);
sprintf(ext, "%s#define SPRITE\n", def);
shaders[shSprite] = new Shader(SHADER, ext);
shaders[shDefault] = new Shader(SHADER, def);
sprintf(def, "%s#define PASS_SHADOW\n", ext);
shaders[shShadow] = new Shader(SHADER, def);
sprintf(ext, "%s#define SPRITE\n", def);
shaders[shGUI] = new Shader(GUI, "");
}
@ -331,17 +323,21 @@ struct Level {
}
#endif
Shader *setRoomShader(const TR::Room &room, float intensity) {
if (Core::pass == Core::passShadow)
return shaders[shShadowOpaque];
void setRoomShader(const TR::Room &room, float intensity) {
if (Core::pass == Core::passShadow) {
shaders[shShadow]->bind();
return;
}
shaders[shDefault]->bind();
if (room.flags.water) {
Core::color = vec4(0.6f, 0.9f, 0.9f, intensity);
return shaders[shCaustics];
Core::active.shader->setParam(uCaustics, 1);
} else {
Core::color = vec4(1.0f, 1.0f, 1.0f, intensity);
return shaders[shStatic];
Core::active.shader->setParam(uCaustics, 0);
}
Core::active.shader->setParam(uColor, Core::color);
}
void renderRoom(int roomIndex, int from = -1) {
@ -351,14 +347,13 @@ struct Level {
TR::Room &room = level.rooms[roomIndex];
vec3 offset = vec3(float(room.info.x), 0.0f, float(room.info.z));
Shader *sh = setRoomShader(room, 1.0f);
setRoomShader(room, intensityf(room.ambient));
Shader *sh = Core::active.shader;
Core::lightColor[0] = vec4(0, 0, 0, 1);
// glDisable(GL_CULL_FACE);
sh->bind();
sh->setParam(uColor, Core::color);
sh->setParam(uType, Shader::ROOM);
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
// room static meshes
if (Core::pass != Core::passShadow)
@ -379,8 +374,8 @@ struct Level {
continue;
rMesh.flags.rendered = true;
Core::color.w = intensityf(rMesh.intensity == -1 ? room.ambient : rMesh.intensity);
sh->setParam(uColor, Core::color);
//Core::color.w = intensityf(rMesh.intensity);//intensityf(rMesh.intensity == -1 ? room.ambient : rMesh.intensity);
//sh->setParam(uColor, Core::color);
// render static mesh
mat4 mTemp = Core::mModel;
@ -396,29 +391,20 @@ struct Level {
mat4 mTemp = Core::mModel;
room.flags.rendered = true;
Core::lightColor[0] = vec4(0, 0, 0, 1);
Core::mModel.translate(offset);
// render room geometry
sh->setParam(uModel, Core::mModel);
// render room geometry
if (Core::pass == Core::passOpaque) {
Core::color.w = intensityf(room.ambient);
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
sh->setParam(uColor, Core::color);
mesh->renderRoomGeometry(roomIndex);
}
// render room sprites
if (mesh->hasRoomSprites(roomIndex) && Core::pass != Core::passShadow) {
sh = shaders[Core::pass == Core::passShadow ? shShadowSprite : shSprite];
sh->bind();
Core::color.w = 1.0f;
sh->setParam(uModel, Core::mModel);
sh->setParam(uColor, Core::color);
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
Core::color.w = 1.0;
sh->setParam(uType, Shader::SPRITE);
sh->setParam(uColor, Core::color);
mesh->renderRoomSprites(roomIndex);
}
@ -453,32 +439,14 @@ struct Level {
camera->frustum = camFrustum; // pop camera frustum
}
int getLightIndex(const vec3 &pos, int &room) {
int idx = -1;
float dist;
// for (int j = 0; j < level.roomsCount; j++)
int j = room;
for (int i = 0; i < level.rooms[j].lightsCount; i++) {
TR::Room::Light &light = level.rooms[j].lights[i];
float d = (pos - vec3(float(light.x), float(light.y), float(light.z))).length2();
if (idx == -1 || d < dist) {
idx = i;
dist = d;
// room = j;
}
}
return idx;
}
int getLightIndex2(const vec3 &pos, int &room, float maxAtt = -1.0f, int depth = 3) {
int getLightIndex(const vec3 &pos, int &room, float maxAtt = -1.0f, int depth = 0) {
int idx = -1;
TR::Room &r = level.rooms[room];
for (int i = 0; i < r.lightsCount; i++) {
TR::Room::Light &light = r.lights[i];
float att = max(0.0f, 1.0f - (pos - vec3(float(light.x), float(light.y), float(light.z))).length2() / ((float)light.attenuation * (float)light.attenuation));
float att = max(0.0f, 1.0f - (pos - vec3(float(light.x), float(light.y), float(light.z))).length2() / ((float)light.radius * (float)light.radius));
if (att > maxAtt) {
maxAtt = att;
idx = i;
@ -488,7 +456,7 @@ struct Level {
if (depth > 0)
for (int i = 0; i < r.portalsCount; i++) {
int nextRoom = r.portals[i].roomIndex;
int nextLight = getLightIndex2(pos, nextRoom, maxAtt, depth - 1);
int nextLight = getLightIndex(pos, nextRoom, maxAtt, depth - 1);
if (nextLight > -1) {
room = nextRoom;
idx = nextLight;
@ -506,7 +474,7 @@ struct Level {
TR::Room::Light &light = level.rooms[room].lights[idx];
float c = 1.0f - intensityf(level.rooms[room].lights[idx].intensity);
Core::lightPos[0] = vec3(float(light.x), float(light.y), float(light.z));
Core::lightColor[0] = vec4(c, c, c, (float)light.attenuation * (float)light.attenuation);
Core::lightColor[0] = vec4(c, c, c, (float)light.radius * (float)light.radius);
} else {
Core::lightPos[0] = vec3(0);
Core::lightColor[0] = vec4(0, 0, 0, 1);
@ -525,19 +493,20 @@ struct Level {
return;
int16 lum = entity.intensity == -1 ? room.ambient : entity.intensity;
setRoomShader(room, sqrtf(intensityf(lum)))->bind();
setRoomShader(room, intensityf(lum));
if (entity.modelIndex > 0) // model
if (entity.modelIndex > 0) { // model
getLight(((Controller*)entity.controller)->pos, entity.room);
Core::active.shader->setParam(uType, Shader::ENTITY);
}
if (entity.modelIndex < 0) { // sprite
shaders[Core::pass == Core::passShadow ? shShadowSprite : shSprite]->bind();
Core::active.shader->setParam(uType, Shader::SPRITE);
Core::lightPos[0] = vec3(0);
Core::lightColor[0] = vec4(0, 0, 0, 1);
}
Core::active.shader->setParam(uColor, Core::color);
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);
((Controller*)entity.controller)->render(camera->frustum, mesh);
@ -555,16 +524,6 @@ struct Level {
}
camera->update();
static bool tmpFlag = false;
if (Input::down[ikEnter]) {
if (!tmpFlag) {
perspShadows = !perspShadows;
tmpFlag = true;
}
} else
tmpFlag = false;
}
void setup() {
@ -581,25 +540,23 @@ struct Level {
Core::active.shader = NULL;
for (int i = 0; i < shMAX; i++) {
shaders[i]->bind();
shaders[i]->setParam(uViewProj, Core::mViewProj);
shaders[i]->setParam(uLightProj, Core::mLightProj);
shaders[i]->setParam(uViewInv, Core::mViewInv);
shaders[i]->setParam(uViewPos, Core::viewPos);
shaders[i]->setParam(uParam, vec4(time, 0, 0, 0));
shaders[i]->setParam(uLightTarget, lara->pos);
shaders[i]->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
shaders[i]->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
shaders[i]->setParam(uViewProj, Core::mViewProj);
shaders[i]->setParam(uLightProj, Core::mLightProj);
shaders[i]->setParam(uViewInv, Core::mViewInv);
shaders[i]->setParam(uViewPos, Core::viewPos);
shaders[i]->setParam(uTime, time);
shaders[i]->setParam(uLightTarget, lara->pos);
shaders[i]->setParam(uAnimTexRanges, mesh->animTexRanges[0], mesh->animTexRangesCount);
shaders[i]->setParam(uAnimTexOffsets, mesh->animTexOffsets[0], mesh->animTexOffsetsCount);
}
glEnable(GL_DEPTH_TEST);
Core::setCulling(cfFront);
Core::mModel.identity();
// clear visible flags for rooms & static meshes
for (int i = 0; i < level.roomsCount; i++) {
TR::Room &room = level.rooms[i];
room.flags.rendered = false; // clear visible flag for room geometry & sprites
room.flags.rendered = false; // clear visible flag for room geometry & sprites
for (int j = 0; j < room.meshesCount; j++)
room.meshes[j].flags.rendered = false; // clear visible flag for room static meshes
@ -621,7 +578,7 @@ struct Level {
void renderEntities() {
PROFILE_MARKER("ENTITIES");
shaders[Core::pass == Core::passShadow ? shShadowOpaque : shStatic]->bind();
shaders[Core::pass == Core::passShadow ? shShadow : shDefault]->bind();
for (int i = 0; i < level.entitiesCount; i++)
renderEntity(level.entities[i]);
}
@ -638,27 +595,13 @@ struct Level {
// omni-spot light shadows
int room = lara->getRoomIndex();
int idx = getLightIndex2(lara->pos, room);
int idx = getLightIndex(lara->pos, room);
if (idx < 0) return false;
if (perspShadows) {
TR::Room::Light &light = level.rooms[room].lights[idx];
vec3 lightPos = vec3(float(light.x), float(light.y), float(light.z));
Core::mView = mat4(lightPos, pos - vec3(0, 256, 0), vec3(0, -1, 0)).inverse();
Core::mProj = mat4(120, 1.0f, camera->znear, camera->zfar);
//Core::mProj.e22 /= camera->zfar;
//Core::mProj.e32 /= camera->zfar;
} else {
// fixed direct light shadows
float size = MAX_SHADOW_DIST;
float zfar = 8192.0f;
Core::mView = mat4(pos - vec3(1536, 4096, 1024), pos, vec3(1, 0, 0)).inverse();
Core::mProj = mat4(-size, size, -size, size, 0, zfar);
// Core::mProj.e22 /= zfar;
// Core::mProj.e23 /= zfar;
}
TR::Room::Light &light = level.rooms[room].lights[idx];
vec3 shadowLightPos = vec3(float(light.x), float(light.y), float(light.z));
Core::mView = mat4(shadowLightPos, pos - vec3(0, 256, 0), vec3(0, -1, 0)).inverse();
Core::mProj = mat4(120, 1.0f, camera->znear, camera->zfar);
Core::mViewProj = Core::mProj * Core::mView;
@ -667,12 +610,7 @@ struct Level {
bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f;
Core::mLightProj = bias * Core::mProj * Core::mView; // * ( * ) ?
Shader *sh = shaders[shShadowOpaque];
sh->bind();
sh->setParam(uViewProj, Core::mViewProj);
sh->setParam(uLightProj, Core::mLightProj);
sh = shaders[shShadowSprite];
Shader *sh = shaders[shShadow];
sh->bind();
sh->setParam(uViewProj, Core::mViewProj);
sh->setParam(uLightProj, Core::mLightProj);
@ -688,15 +626,17 @@ struct Level {
Core::setBlending(bmNone);
Core::setTarget(shadow);
Core::setViewport(0, 0, shadow->width, shadow->height);
Core::clear(vec4(1.0));
Core::clear(vec4(1.0));
Core::setCulling(cfBack);
renderScene();
Core::setCulling(cfFront);
Core::setTarget(NULL);
shadow->bind(sShadow);
}
void render() {
renderShadows();
Core::pass = Core::passOpaque;
Core::setBlending(bmAlpha);
Core::clear(vec4(0.0f));
@ -733,7 +673,7 @@ struct Level {
Debug::begin();
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
Debug::Level::lights(level);
Debug::Level::lights(level, lara->getRoomIndex());
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
// Debug::Level::portals(level);
// Debug::Level::meshes(level);

View File

@ -9,7 +9,8 @@
<script type='text/javascript'>
var statusElement = document.getElementById('status');
var canvasElement = document.getElementById('canvas');
var proc;
var Module = {
TOTAL_MEMORY: 64*1024*1024,
preRun: [],
@ -52,7 +53,7 @@
var rate = 44100 / ctx.sampleRate;
var framesCount = Math.ceil(count * rate);
var frames = Module._malloc(framesCount * 4); // interleaved short L, R
var proc = ctx.createScriptProcessor(count, 2, 2);
proc = ctx.createScriptProcessor(count, 2, 2);
proc.onaudioprocess = function(e) {
var L = e.outputBuffer.getChannelData(0),
R = e.outputBuffer.getChannelData(1);

View File

@ -2,14 +2,23 @@ R"====(
varying vec2 vTexCoord;
#ifndef PASS_SHADOW
varying vec4 vLightProj;
varying vec3 vCoord;
varying vec4 vNormal;
varying vec3 vViewVec;
varying vec4 vColor;
varying vec3 vCoord;
varying vec4 vNormal;
varying vec3 vViewVec;
varying vec4 vColor;
varying vec4 vLightProj;
varying float vLightTargetDist;
#endif
#define TYPE_SPRITE 0
#define TYPE_ROOM 1
#define TYPE_ENTITY 2
#define TYPE_FLASH 3
uniform int uType;
uniform int uCaustics;
uniform float uTime;
#ifdef VERTEX
uniform mat4 uViewProj;
uniform mat4 uModel;
@ -19,20 +28,16 @@ varying vec2 vTexCoord;
#ifndef PASS_SHADOW
uniform vec3 uViewPos;
#ifndef SPRITE
uniform vec2 uAnimTexRanges[MAX_RANGES];
uniform vec2 uAnimTexOffsets[MAX_OFFSETS];
#endif
uniform vec4 uParam; // x - time
uniform vec2 uAnimTexRanges[MAX_RANGES];
uniform vec2 uAnimTexOffsets[MAX_OFFSETS];
#endif
attribute vec4 aCoord;
attribute vec4 aTexCoord;
attribute vec4 aNormal;
#ifndef PASS_SHADOW
attribute vec4 aNormal;
attribute vec4 aColor;
#endif
@ -41,12 +46,13 @@ varying vec2 vTexCoord;
void main() {
vec4 coord = uModel * vec4(aCoord.xyz, 1.0);
#ifndef SPRITE
if (uType != TYPE_SPRITE) {
#ifndef PASS_SHADOW
// animated texture coordinates
vec2 range = uAnimTexRanges[int(aTexCoord.z)]; // x - start index, y - count
float f = fract((aTexCoord.w + uParam.x * 4.0 - range.x) / range.y) * range.y;
float f = fract((aTexCoord.w + uTime * 4.0 - range.x) / range.y) * range.y;
vec2 offset = uAnimTexOffsets[int(range.x + f)]; // texCoord offset from first frame
vTexCoord = (aTexCoord.xy + offset) * TEXCOORD_SCALE; // first frame + offset * isAnimated
@ -54,21 +60,21 @@ varying vec2 vTexCoord;
#else
vTexCoord = aTexCoord.xy * TEXCOORD_SCALE;
#endif
#else
} else {
coord.xyz += uViewInv[0].xyz * aTexCoord.z - uViewInv[1].xyz * aTexCoord.w;
#ifndef PASS_SHADOW
vTexCoord = aTexCoord.xy * TEXCOORD_SCALE;
vNormal = vec4(uViewPos.xyz - coord.xyz, 0.0);
#endif
#endif
}
#ifndef PASS_SHADOW
vColor = aColor;
#if defined(CAUSTICS)
if (uCaustics != 0) {
float sum = coord.x + coord.y + coord.z;
vColor.xyz *= abs(sin(sum / 512.0 + uParam.x)) * 1.5 + 0.5; // color dodge
#endif
vColor.xyz *= abs(sin(sum / 512.0 + uTime)) * 1.5 + 0.5; // color dodge
}
vViewVec = uViewPos - coord.xyz;
@ -76,6 +82,7 @@ varying vec2 vTexCoord;
vLightTargetDist = dot(dist, dist) / (MAX_SHADOW_DIST * MAX_SHADOW_DIST);
vLightProj = uLightProj * coord;
vCoord = coord.xyz;
#endif
@ -130,19 +137,32 @@ varying vec2 vTexCoord;
#define CMP(a,b) float(a > b)
#ifdef SHADOW_DEPTH
#define SHADOW(V) CMP(texture2D(sShadow, (V).xy).x, p.z)
#define compare(p, z) CMP(texture2D(sShadow, (p)).x, (z));
#elif defined(SHADOW_COLOR)
float unpack(vec4 value) {
vec4 bitSh = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);
return dot(value, bitSh);
}
#define SHADOW(V) CMP(unpack(texture2D(sShadow, (V).xy)), p.z)
#else
#define SHADOW(v) 1.0
#define compare(p, z) CMP(unpack(texture2D(sShadow, (p))), (z));
#endif
float SHADOW(vec3 p) {
vec2 t = vec2(0.0, 1.0 / 1024.0);
vec2 c = floor(p.xy * 1024.0 + 0.5) / 1024.0;
vec4 s;
s.x = compare(c + t.xx, p.z);
s.y = compare(c + t.xy, p.z);
s.z = compare(c + t.yx, p.z);
s.w = compare(c + t.yy, p.z);
vec2 f = fract(p.xy * 1024.0 + 0.5);
return mix(mix(s.x, s.y, f.y), mix(s.z, s.w, f.y), f.x);
}
#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 );
@ -160,21 +180,22 @@ varying vec2 vTexCoord;
poissonDisk[13] = vec2( -0.81409955, 0.91437590 );
poissonDisk[14] = vec2( 0.19984126, 0.78641367 );
poissonDisk[15] = vec2( 0.14383161, -0.14100790 );
vec3 p = lightProj.xyz / lightProj.w;
if (lightProj.w < 0.0) return 1.0;
//return SHADOW(p);
float rShadow = 0.0;
for (int i = 0; i < 16; i += 1)
rShadow += SHADOW(p + vec3(poissonDisk[i] * 2.0, 0.0) * (1.0 / 1024.0));
rShadow += SHADOW(p + vec3(poissonDisk[i] * 1.5, 0.0) * (1.0 / 1024.0));
rShadow /= 16.0;
rShadow = clamp(rShadow * 1.25, 0.0, 1.0); // apply contrast (1.25)
float fade = min(1.0, vLightTargetDist);
return mix(rShadow, 1.0, fade);
}
vec3 calcLight(vec3 normal, vec3 pos, vec4 color) {
vec3 lv = pos - vCoord.xyz;
float lum = max(0.0, dot(normal, normalize(lv)));
float att = max(0.0, 1.0 - dot(lv, lv) / color.w);
return color.xyz * (lum * att);
}
#endif
void main() {
@ -183,16 +204,10 @@ varying vec2 vTexCoord;
discard;
#ifdef PASS_SHADOW
float dx = dFdx(gl_FragCoord.z);
float dy = dFdy(gl_FragCoord.z);
float bias = 4.0 * max(dx, dy);
float depth = gl_FragCoord.z + bias;
#ifdef SHADOW_COLOR
gl_FragColor = pack(depth);
gl_FragColor = pack(gl_FragCoord.z);
#else
gl_FragColor = vec4(1.0);
gl_FragDepth = depth;
#endif
#else
color.xyz *= uColor.xyz;
@ -201,32 +216,33 @@ varying vec2 vTexCoord;
color.xyz = pow(abs(color.xyz), vec3(2.2)); // to linear space
// calc point lights
vec3 normal = normalize(vNormal.xyz);
vec3 viewVec = normalize(vViewVec);
vec3 light = vec3(0.0);
for (int i = 0; i < MAX_LIGHTS; i++) {
vec3 lv = uLightPos[i] - vCoord.xyz;
vec4 lc = uLightColor[i];
float lum = max(0.0, dot(normal, normalize(lv)));
float att = max(0.0, 1.0 - dot(lv, lv) / lc.w);
light += lc.xyz * (lum * att);
}
if (uType != TYPE_FLASH) {
vec3 normal = normalize(vNormal.xyz);
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]);
// apply lighting
#ifdef SPRITE
color.xyz *= light + vColor.w;
#else
float shadow = getShadow(vLightProj);
// apply lighting
if (uType == TYPE_SPRITE) {
light += vColor.w * uColor.w;
}
vec3 dlight = mix(vec3(uColor.w * uColor.w), light + uColor.w, shadow);
dlight *= dot(normal, viewVec) * 0.5 + 0.5; // backlight
vec3 slight = light + mix(uColor.w, vColor.w, shadow);
light = mix(slight, dlight, vNormal.w);
if (uType == TYPE_ROOM) {
light += mix(min(uColor.w, vColor.w), vColor.w, getShadow(vLightProj));
}
if (uType == TYPE_ENTITY) {
float shadow = getShadow(vLightProj);
vec3 lum = calcLight(normal, uLightPos[0], uLightColor[0]) * shadow + uColor.w;
light += lum;
light *= dot(normal, viewVec) * 0.2 + 0.8; // apply backlight
}
color.xyz *= light;
#endif
} else {
color.w = uColor.w;
}
color.xyz = pow(abs(color.xyz), vec3(1.0/2.2)); // back to gamma space

View File

@ -5,22 +5,22 @@
enum AttribType { aCoord, aTexCoord, aNormal, aColor, aMAX };
enum SamplerType { sDiffuse, sShadow, sMAX };
enum UniformType { uViewProj, uViewInv, uModel, uLightProj, uParam, uColor, uViewPos, uLightPos, uLightColor, uLightTarget, uAnimTexRanges, uAnimTexOffsets, uMAX };
enum UniformType { uType, uCaustics, uTime, uViewProj, uViewInv, uModel, uLightProj, uColor, uViewPos, uLightPos, uLightColor, uLightTarget, uAnimTexRanges, uAnimTexOffsets, uMAX };
const char *AttribName[aMAX] = { "aCoord", "aTexCoord", "aNormal", "aColor" };
const char *SamplerName[sMAX] = { "sDiffuse", "sShadow" };
const char *UniformName[uMAX] = { "uViewProj", "uViewInv", "uModel", "uLightProj", "uParam", "uColor", "uViewPos", "uLightPos", "uLightColor", "uLightTarget", "uAnimTexRanges", "uAnimTexOffsets" };
const char *UniformName[uMAX] = { "uType", "uCaustics", "uTime", "uViewProj", "uViewInv", "uModel", "uLightProj", "uColor", "uViewPos", "uLightPos", "uLightColor", "uLightTarget", "uAnimTexRanges", "uAnimTexOffsets" };
struct Shader {
GLuint ID;
GLint uID[uMAX];
enum : GLint { SPRITE, ROOM, ENTITY, FLASH };
Shader(const char *text, const char *defines = "") {
#ifdef MOBILE
#define GLSL_DEFINE "#extension GL_EXT_frag_depth : enable\n"\
"#extension GL_OES_standard_derivatives : enable\n"\
"#define MOBILE\n"\
"#define gl_FragDepth gl_FragDepthEXT\n"\
#define GLSL_DEFINE "#define MOBILE\n"\
"precision highp int;\n"\
"precision highp float;\n"
#else
#define GLSL_DEFINE "#version 120\n"
@ -74,6 +74,16 @@ struct Shader {
}
}
void setParam(UniformType uType, const int &value, int count = 1) {
if (uID[uType] != -1)
glUniform1iv(uID[uType], count, (GLint*)&value);
}
void setParam(UniformType uType, const float &value, int count = 1) {
if (uID[uType] != -1)
glUniform1fv(uID[uType], count, (GLfloat*)&value);
}
void setParam(UniformType uType, const vec2 &value, int count = 1) {
if (uID[uType] != -1)
glUniform2fv(uID[uType], count, (GLfloat*)&value);

View File

@ -407,7 +407,7 @@ double samples[28];
int res = decoder->decode(&frames[i], count - i);
if (res == 0) {
if (!(flags & Flags::LOOP)) {
if (i == 0) isPlaying = false;
isPlaying = false;
break;
} else
decoder->replay();

View File

@ -4,11 +4,12 @@
#include "core.h"
struct Texture {
GLuint ID;
GLuint ID;
int width, height;
bool depth;
Texture *dummy;
Texture(int width, int height, bool depth, void *data = NULL) : width(width), height(height) {
Texture(int width, int height, bool depth, void *data = NULL) : width(width), height(height), dummy(NULL) {
glGenTextures(1, &ID);
bind(0);
@ -33,9 +34,13 @@ struct Texture {
GLint format = depth ? GL_DEPTH_COMPONENT : GL_RGBA;
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, depth ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE, data);
if (depth)
dummy = new Texture(width, height, false, NULL); // some drivers can't render to texture without color target, create dummy color target for fix it
}
virtual ~Texture() {
delete dummy;
glDeleteTextures(1, &ID);
}