mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-13 16:44:50 +02:00
Merge remote-tracking branch 'refs/remotes/XProger/master'
This commit is contained in:
BIN
bin/OpenLara.exe
BIN
bin/OpenLara.exe
Binary file not shown.
113
src/cache.h
113
src/cache.h
@@ -131,7 +131,7 @@ struct ShaderCache {
|
||||
typ = typeNames[type];
|
||||
int animTexRangesCount = game->getMesh()->animTexRangesCount;
|
||||
int animTexOffsetsCount = game->getMesh()->animTexOffsetsCount;
|
||||
sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_RANGES %d\n#define MAX_OFFSETS %d\n#define FOG_DIST (1.0/%d.0)\n#define WATER_FOG_DIST (1.0/%d.0)\n#define SHADOW_TEX_SIZE %d.0\n", ext, passNames[pass], typ, MAX_LIGHTS, animTexRangesCount, animTexOffsetsCount, FOG_DIST, WATER_FOG_DIST, SHADOW_TEX_SIZE);
|
||||
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 MAX_CONTACTS %d\n#define FOG_DIST (1.0/%d.0)\n#define WATER_FOG_DIST (1.0/%d.0)\n#define SHADOW_TEX_SIZE %d.0\n", ext, passNames[pass], typ, MAX_LIGHTS, animTexRangesCount, animTexOffsetsCount, MAX_CONTACTS, FOG_DIST, WATER_FOG_DIST, SHADOW_TEX_SIZE);
|
||||
if (fx & FX_UNDERWATER) strcat(def, "#define UNDERWATER\n" UNDERWATER_COLOR);
|
||||
if (fx & FX_ALPHA_TEST) strcat(def, "#define ALPHA_TEST\n");
|
||||
if (fx & FX_CLIP_PLANE) strcat(def, "#define CLIP_PLANE\n");
|
||||
@@ -139,6 +139,7 @@ struct ShaderCache {
|
||||
if (Core::settings.detail.lighting) strcat(def, "#define OPT_LIGHTING\n");
|
||||
if (Core::settings.detail.shadows) strcat(def, "#define OPT_SHADOW\n");
|
||||
if (Core::settings.detail.water) strcat(def, "#define OPT_WATER\n");
|
||||
if (Core::settings.detail.contact) strcat(def, "#define OPT_CONTACT\n");
|
||||
break;
|
||||
}
|
||||
case Core::passWater : {
|
||||
@@ -181,7 +182,6 @@ struct ShaderCache {
|
||||
// TODO: bindable uniform block
|
||||
shader->setParam(uViewProj, Core::mViewProj);
|
||||
shader->setParam(uLightProj, Core::mLightProj);
|
||||
shader->setParam(uViewInv, Core::mViewInv);
|
||||
shader->setParam(uViewPos, Core::viewPos);
|
||||
shader->setParam(uParam, Core::params);
|
||||
MeshBuilder *mesh = game->getMesh();
|
||||
@@ -282,17 +282,14 @@ struct AmbientCache {
|
||||
// get result color from 1x1 textures
|
||||
for (int j = 0; j < 6; j++) {
|
||||
Core::setTarget(textures[j * 4 + 3]);
|
||||
|
||||
TR::Color32 color;
|
||||
glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &color);
|
||||
colors[j] = vec3(color.r / 255.0f, color.g / 255.0f, color.b / 255.0f);
|
||||
// colors[j] *= colors[j]; // to "linear" space
|
||||
colors[j] = Core::copyPixel(0, 0).xyz;
|
||||
}
|
||||
|
||||
Core::setDepthTest(true);
|
||||
}
|
||||
|
||||
void precessQueue() {
|
||||
game->setupBinding();
|
||||
for (int i = 0; i < tasksCount; i++) {
|
||||
Task &task = tasks[i];
|
||||
renderAmbient(task.room, task.sector, &task.cube->colors[0]);
|
||||
@@ -411,13 +408,11 @@ struct WaterCache {
|
||||
mask = new Texture(w, h, Texture::RGB16, false, m, false);
|
||||
delete[] m;
|
||||
|
||||
Core::setTarget(data[0], true);
|
||||
Core::setTarget(NULL);
|
||||
|
||||
blank = false;
|
||||
|
||||
// Core::setTarget(data[0], true);
|
||||
// Core::invalidateTarget(false, true);
|
||||
// texture may be initialized with trash, so...
|
||||
Core::setTarget(data[0], true);
|
||||
Core::validateRenderState(); // immediate clear
|
||||
}
|
||||
|
||||
void free() {
|
||||
@@ -430,7 +425,6 @@ struct WaterCache {
|
||||
|
||||
} items[MAX_SURFACES];
|
||||
int count, visible;
|
||||
bool checkVisibility;
|
||||
|
||||
int dropCount;
|
||||
struct Drop {
|
||||
@@ -441,7 +435,7 @@ struct WaterCache {
|
||||
Drop(const vec3 &pos, float radius, float strength) : pos(pos), radius(radius), strength(strength) {}
|
||||
} drops[MAX_DROPS];
|
||||
|
||||
WaterCache(IGame *game) : game(game), level(game->getLevel()), refract(NULL), count(0), checkVisibility(false), dropCount(0) {
|
||||
WaterCache(IGame *game) : game(game), level(game->getLevel()), refract(NULL), count(0), dropCount(0) {
|
||||
reflect = new Texture(512, 512, Texture::RGB16, false);
|
||||
}
|
||||
|
||||
@@ -473,8 +467,6 @@ struct WaterCache {
|
||||
}
|
||||
|
||||
void setVisible(int roomIndex, int nextRoom = TR::NO_ROOM) {
|
||||
if (!checkVisibility) return;
|
||||
|
||||
if (nextRoom == TR::NO_ROOM) { // setVisible(underwaterRoom) for caustics update
|
||||
for (int i = 0; i < count; i++)
|
||||
if (items[i].caust == roomIndex) {
|
||||
@@ -569,7 +561,7 @@ struct WaterCache {
|
||||
|
||||
game->setShader(Core::passWater, Shader::WATER_STEP);
|
||||
Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f));
|
||||
Core::active.shader->setParam(uParam, vec4(0.995f, 1.0f, 0, 0));
|
||||
Core::active.shader->setParam(uParam, vec4(0.995f, 1.0f, 0, Core::params.x));
|
||||
|
||||
while (item.timer >= SIMULATE_TIMESTEP) {
|
||||
// water step
|
||||
@@ -582,7 +574,6 @@ struct WaterCache {
|
||||
item.timer -= SIMULATE_TIMESTEP;
|
||||
}
|
||||
|
||||
|
||||
// calc caustics
|
||||
game->setShader(Core::passWater, Shader::WATER_CAUSTICS);
|
||||
vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f / PLANE_DETAIL) };
|
||||
@@ -602,13 +593,6 @@ struct WaterCache {
|
||||
|
||||
void renderMask() {
|
||||
// mask underwater geometry by zero alpha
|
||||
for (int i = 0; i < count; i++) {
|
||||
Item &item = items[i];
|
||||
if (item.visible && item.blank)
|
||||
item.init(game);
|
||||
}
|
||||
Core::setTarget(NULL);
|
||||
|
||||
game->setShader(Core::passWater, Shader::WATER_MASK);
|
||||
Core::active.shader->setParam(uTexParam, vec4(1.0f));
|
||||
|
||||
@@ -631,15 +615,15 @@ struct WaterCache {
|
||||
}
|
||||
|
||||
void getRefract() {
|
||||
int w = int(Core::viewport.z);
|
||||
int h = int(Core::viewport.w);
|
||||
int w = int(Core::viewportDef.z);
|
||||
int h = int(Core::viewportDef.w);
|
||||
|
||||
// get refraction texture
|
||||
if (!refract || w != refract->width || h != refract->height) {
|
||||
delete refract;
|
||||
refract = new Texture(w, h, Texture::RGBA, false);
|
||||
}
|
||||
Core::copyTarget(refract, 0, 0, int(Core::viewport.x), int(Core::viewport.y), w, h); // copy framebuffer into refraction texture
|
||||
Core::copyTarget(refract, 0, 0, int(Core::viewportDef.x), int(Core::viewportDef.y), w, h); // copy framebuffer into refraction texture
|
||||
}
|
||||
|
||||
void simulate() {
|
||||
@@ -658,7 +642,48 @@ struct WaterCache {
|
||||
}
|
||||
}
|
||||
Core::setDepthTest(true);
|
||||
Core::setTarget(NULL);
|
||||
}
|
||||
|
||||
void renderReflect() {
|
||||
if (!visible) return;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Item &item = items[i];
|
||||
if (item.visible && item.blank)
|
||||
item.init(game);
|
||||
}
|
||||
|
||||
// render mirror reflection
|
||||
Core::setTarget(reflect, true);
|
||||
Camera *camera = (Camera*)game->getCamera();
|
||||
game->setupBinding();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Item &item = items[i];
|
||||
if (!item.visible) continue;
|
||||
|
||||
vec3 p = item.pos;
|
||||
vec3 n = vec3(0, 1, 0);
|
||||
|
||||
vec4 reflectPlane = vec4(n.x, n.y, n.z, -n.dot(p));
|
||||
bool underwater = level->rooms[camera->getRoomIndex()].flags.water;
|
||||
|
||||
//bool underwater = level->camera->pos.y > item.pos.y;
|
||||
|
||||
camera->reflectPlane = &reflectPlane;
|
||||
camera->setup(true);
|
||||
|
||||
float sign = underwater ? -1.0f : 1.0f;
|
||||
game->setClipParams(sign, item.pos.y * sign);
|
||||
game->updateParams();
|
||||
game->renderView(underwater ? item.from : item.to, false);
|
||||
}
|
||||
Core::invalidateTarget(false, true);
|
||||
game->setClipParams(1.0f, NO_CLIP_PLANE);
|
||||
game->updateParams();
|
||||
|
||||
camera->reflectPlane = NULL;
|
||||
camera->setup(true);
|
||||
}
|
||||
|
||||
void render() {
|
||||
@@ -666,34 +691,6 @@ struct WaterCache {
|
||||
Item &item = items[i];
|
||||
if (!item.visible) continue;
|
||||
|
||||
// render mirror reflection
|
||||
Core::setTarget(reflect, true);
|
||||
Core::viewport = Core::viewportDef;
|
||||
vec3 p = item.pos;
|
||||
vec3 n = vec3(0, 1, 0);
|
||||
|
||||
vec4 reflectPlane = vec4(n.x, n.y, n.z, -n.dot(p));
|
||||
|
||||
Camera *camera = (Camera*)game->getCamera();
|
||||
|
||||
bool underwater = level->rooms[camera->getRoomIndex()].flags.water;
|
||||
|
||||
//bool underwater = level->camera->pos.y > item.pos.y;
|
||||
|
||||
camera->reflectPlane = &reflectPlane;
|
||||
float sign = underwater ? -1.0f : 1.0f;
|
||||
game->setClipParams(sign, item.pos.y * sign);
|
||||
game->updateParams();
|
||||
game->renderCompose(underwater ? item.from : item.to);
|
||||
Core::invalidateTarget(false, true);
|
||||
game->setClipParams(1.0f, NO_CLIP_PLANE);
|
||||
game->updateParams();
|
||||
|
||||
camera->reflectPlane = NULL;
|
||||
Core::setTarget(NULL);
|
||||
|
||||
camera->setup(true);
|
||||
|
||||
// render water plane
|
||||
if (level->rooms[item.from].lightsCount) {
|
||||
TR::Room::Light &light = level->rooms[item.from].lights[0];
|
||||
@@ -705,7 +702,7 @@ struct WaterCache {
|
||||
game->setShader(Core::passWater, Shader::WATER_COMPOSE);
|
||||
Core::active.shader->setParam(uLightPos, Core::lightPos[0], 1);
|
||||
Core::active.shader->setParam(uLightColor, Core::lightColor[0], 1);
|
||||
Core::active.shader->setParam(uParam, vec4(float(Core::width) / refract->width, float(Core::height) / refract->height, 0.05f, 0.02f));
|
||||
Core::active.shader->setParam(uParam, vec4(Core::viewportDef.z / refract->width, Core::viewportDef.w / refract->height, 0.05f, 0.02f));
|
||||
|
||||
float sx = item.size.x * DETAIL / (item.data[0]->width / 2);
|
||||
float sz = item.size.z * DETAIL / (item.data[0]->height / 2);
|
||||
|
@@ -30,7 +30,8 @@ struct IGame {
|
||||
virtual void setShader(Core::Pass pass, Shader::Type type, bool underwater = false, bool alphaTest = false) {}
|
||||
virtual void setupBinding() {}
|
||||
virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {}
|
||||
virtual void renderCompose(int roomIndex, bool genShadowMask = false) {}
|
||||
virtual void renderCompose(int roomIndex) {}
|
||||
virtual void renderView(int roomIndex, bool water) {}
|
||||
virtual void fxQuake(float time) {}
|
||||
|
||||
virtual bool invUse(TR::Entity::Type type) { return false; }
|
||||
|
358
src/core.h
358
src/core.h
@@ -43,8 +43,6 @@
|
||||
#define glProgramBinary glProgramBinaryOES
|
||||
|
||||
#define GL_PROGRAM_BINARY_LENGTH GL_PROGRAM_BINARY_LENGTH_OES
|
||||
#define GL_STENCIL_TEST_TWO_SIDE_EXT 0
|
||||
#define glActiveStencilFaceEXT(...)
|
||||
#elif __linux__
|
||||
#define LINUX 1
|
||||
#include <GL/gl.h>
|
||||
@@ -72,9 +70,6 @@
|
||||
#define GL_TEXTURE_COMPARE_MODE GL_TEXTURE_COMPARE_MODE_EXT
|
||||
#define GL_TEXTURE_COMPARE_FUNC GL_TEXTURE_COMPARE_FUNC_EXT
|
||||
#define GL_COMPARE_REF_TO_TEXTURE GL_COMPARE_REF_TO_TEXTURE_EXT
|
||||
|
||||
#define GL_STENCIL_TEST_TWO_SIDE_EXT 0
|
||||
#define glActiveStencilFaceEXT(...)
|
||||
#else
|
||||
#include <Carbon/Carbon.h>
|
||||
#include <AudioToolbox/AudioQueue.h>
|
||||
@@ -117,10 +112,8 @@
|
||||
#define GL_CLAMP_TO_BORDER GL_CLAMP_TO_BORDER_EXT
|
||||
#define GL_TEXTURE_BORDER_COLOR GL_TEXTURE_BORDER_COLOR_EXT
|
||||
|
||||
#define GL_STENCIL_TEST_TWO_SIDE_EXT 0
|
||||
#define glGetProgramBinary(...)
|
||||
#define glProgramBinary(...)
|
||||
#define glActiveStencilFaceEXT(...)
|
||||
#endif
|
||||
|
||||
namespace Core {
|
||||
@@ -204,10 +197,6 @@ namespace Core {
|
||||
PFNGLBINDBUFFERARBPROC glBindBuffer;
|
||||
PFNGLBUFFERDATAARBPROC glBufferData;
|
||||
PFNGLBUFFERSUBDATAARBPROC glBufferSubData;
|
||||
// Stencil
|
||||
PFNGLACTIVESTENCILFACEEXTPROC glActiveStencilFaceEXT;
|
||||
PFNGLSTENCILFUNCSEPARATEPROC glStencilFuncSeparate;
|
||||
PFNGLSTENCILOPSEPARATEPROC glStencilOpSeparate;
|
||||
#endif
|
||||
|
||||
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
|
||||
@@ -224,10 +213,41 @@ namespace Core {
|
||||
#define MAX_LIGHTS 4
|
||||
#define MAX_CACHED_LIGHTS 3
|
||||
#define MAX_RENDER_BUFFERS 32
|
||||
#define MAX_CONTACTS 15
|
||||
|
||||
struct Shader;
|
||||
struct Texture;
|
||||
|
||||
enum RenderState : int32 {
|
||||
RS_TARGET = 1 << 0,
|
||||
RS_VIEWPORT = 1 << 1,
|
||||
RS_DEPTH_TEST = 1 << 2,
|
||||
RS_DEPTH_WRITE = 1 << 3,
|
||||
RS_COLOR_WRITE_R = 1 << 4,
|
||||
RS_COLOR_WRITE_G = 1 << 5,
|
||||
RS_COLOR_WRITE_B = 1 << 6,
|
||||
RS_COLOR_WRITE_A = 1 << 7,
|
||||
RS_COLOR_WRITE = RS_COLOR_WRITE_R | RS_COLOR_WRITE_G | RS_COLOR_WRITE_B | RS_COLOR_WRITE_A,
|
||||
RS_CULL_BACK = 1 << 8,
|
||||
RS_CULL_FRONT = 1 << 9,
|
||||
RS_CULL = RS_CULL_BACK | RS_CULL_FRONT,
|
||||
RS_BLEND_ALPHA = 1 << 10,
|
||||
RS_BLEND_ADD = 1 << 11,
|
||||
RS_BLEND_MULTIPLY = 1 << 12,
|
||||
RS_BLEND_SCREEN = 1 << 13,
|
||||
RS_BLEND = RS_BLEND_ADD | RS_BLEND_ALPHA | RS_BLEND_MULTIPLY | RS_BLEND_SCREEN,
|
||||
};
|
||||
|
||||
typedef unsigned short Index;
|
||||
|
||||
struct Vertex {
|
||||
short4 coord; // xyz - position, w - joint index (for entities only)
|
||||
short4 normal; // xyz - vertex normal<61> w - unused
|
||||
short4 texCoord; // xy - texture coordinates, zw - trapezoid warping
|
||||
ubyte4 param; // xy - anim tex range and frame index, zw - unused
|
||||
ubyte4 color; // xyz - color, w - intensity
|
||||
};
|
||||
|
||||
namespace Core {
|
||||
struct {
|
||||
bool shaderBinary;
|
||||
@@ -240,7 +260,6 @@ namespace Core {
|
||||
bool texBorder;
|
||||
bool texFloat, texFloatLinear;
|
||||
bool texHalf, texHalfLinear;
|
||||
char stencil;
|
||||
#ifdef PROFILE
|
||||
bool profMarker;
|
||||
bool profTiming;
|
||||
@@ -298,13 +317,13 @@ extern int getTime();
|
||||
namespace Core {
|
||||
float eye;
|
||||
vec4 viewport, viewportDef;
|
||||
vec4 scissor;
|
||||
mat4 mView, mProj, mViewProj, mViewInv, mLightProj;
|
||||
Basis basis;
|
||||
vec3 viewPos;
|
||||
vec3 lightPos[MAX_LIGHTS];
|
||||
vec4 lightColor[MAX_LIGHTS];
|
||||
vec4 params;
|
||||
vec4 contacts[MAX_CONTACTS];
|
||||
|
||||
Texture *blackTex, *whiteTex;
|
||||
|
||||
@@ -322,19 +341,26 @@ namespace Core {
|
||||
} items[MAX_RENDER_BUFFERS];
|
||||
} rtCache[2];
|
||||
|
||||
int32 renderState;
|
||||
|
||||
struct {
|
||||
Shader *shader;
|
||||
Texture *textures[8];
|
||||
Texture *target;
|
||||
int targetFace;
|
||||
vec4 viewport;
|
||||
GLuint VAO;
|
||||
GLuint iBuffer;
|
||||
GLuint vBuffer;
|
||||
BlendMode blendMode;
|
||||
CullMode cullMode;
|
||||
bool stencilTwoSide;
|
||||
int32 renderState;
|
||||
} active;
|
||||
|
||||
struct {
|
||||
Texture *texture;
|
||||
bool clear;
|
||||
uint8 face;
|
||||
} reqTarget;
|
||||
|
||||
struct Stats {
|
||||
int dips, tris, frame, fps, fpsTime;
|
||||
#ifdef PROFILE
|
||||
@@ -367,6 +393,7 @@ namespace Core {
|
||||
bool lighting;
|
||||
bool shadows;
|
||||
bool water;
|
||||
bool contact;
|
||||
} detail;
|
||||
|
||||
struct {
|
||||
@@ -445,10 +472,6 @@ namespace Core {
|
||||
GetProcOGL(glBindBuffer);
|
||||
GetProcOGL(glBufferData);
|
||||
GetProcOGL(glBufferSubData);
|
||||
|
||||
GetProcOGL(glActiveStencilFaceEXT);
|
||||
GetProcOGL(glStencilFuncSeparate);
|
||||
GetProcOGL(glStencilOpSeparate);
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID) || defined(__EMSCRIPTEN__)
|
||||
@@ -478,14 +501,6 @@ namespace Core {
|
||||
support.texHalfLinear = extSupport(ext, "GL_ARB_texture_float") || extSupport(ext, "_texture_half_float_linear");
|
||||
support.texHalf = support.texHalfLinear || extSupport(ext, "_texture_half_float");
|
||||
|
||||
if (extSupport(ext, "_ATI_separate_stencil"))
|
||||
support.stencil = 2;
|
||||
else
|
||||
if (extSupport(ext, "_stencil_two_side"))
|
||||
support.stencil = 1;
|
||||
else
|
||||
support.stencil = 0;
|
||||
|
||||
#ifdef PROFILE
|
||||
support.profMarker = extSupport(ext, "_KHR_debug");
|
||||
support.profTiming = extSupport(ext, "_timer_query");
|
||||
@@ -508,7 +523,6 @@ namespace Core {
|
||||
LOG(" float textures : float = %s, half = %s\n",
|
||||
support.texFloat ? (support.texFloatLinear ? "linear" : "nearest") : "false",
|
||||
support.texHalf ? (support.texHalfLinear ? "linear" : "nearest") : "false");
|
||||
LOG(" stencil : %s\n", support.stencil == 2 ? "separate" : (support.stencil == 1 ? "two_side" : "false"));
|
||||
LOG("\n");
|
||||
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&defaultFBO);
|
||||
@@ -567,143 +581,142 @@ namespace Core {
|
||||
return cache.count++;
|
||||
}
|
||||
|
||||
void clear(bool clearColor, bool clearDepth, bool clearStencil = false) {
|
||||
if (GLbitfield mask = (clearColor ? GL_COLOR_BUFFER_BIT : 0) | (clearDepth ? GL_DEPTH_BUFFER_BIT : 0) | (clearStencil ? GL_STENCIL_BUFFER_BIT : 0))
|
||||
glClear(mask);
|
||||
void validateRenderState() {
|
||||
int32 mask = renderState ^ active.renderState;
|
||||
if (!mask) return;
|
||||
|
||||
if (mask & RS_TARGET) {
|
||||
Texture *target = reqTarget.texture;
|
||||
uint8 face = reqTarget.face;
|
||||
|
||||
if (target != active.target || face != active.targetFace) {
|
||||
|
||||
if (!target) { // may be a null
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
|
||||
} 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);
|
||||
}
|
||||
|
||||
active.target = target;
|
||||
active.targetFace = face;
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & RS_VIEWPORT) {
|
||||
if (viewport != active.viewport) {
|
||||
active.viewport = viewport;
|
||||
glViewport(int(viewport.x), int(viewport.y), int(viewport.z), int(viewport.w));
|
||||
}
|
||||
renderState &= ~RS_VIEWPORT;
|
||||
}
|
||||
|
||||
if (mask & RS_DEPTH_TEST) {
|
||||
if (renderState & RS_DEPTH_TEST)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
else
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
if (mask & RS_DEPTH_WRITE) {
|
||||
glDepthMask((renderState & RS_DEPTH_WRITE) != 0);
|
||||
}
|
||||
|
||||
if (mask & RS_COLOR_WRITE) {
|
||||
glColorMask((renderState & RS_COLOR_WRITE_R) != 0,
|
||||
(renderState & RS_COLOR_WRITE_G) != 0,
|
||||
(renderState & RS_COLOR_WRITE_B) != 0,
|
||||
(renderState & RS_COLOR_WRITE_A) != 0);
|
||||
}
|
||||
|
||||
if (mask & RS_CULL) {
|
||||
if (!(active.renderState & RS_CULL))
|
||||
glEnable(GL_CULL_FACE);
|
||||
switch (renderState & RS_CULL) {
|
||||
case RS_CULL_BACK : glCullFace(GL_BACK); break;
|
||||
case RS_CULL_FRONT : glCullFace(GL_FRONT); break;
|
||||
default : glDisable(GL_CULL_FACE);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & RS_BLEND) {
|
||||
if (!(active.renderState & RS_BLEND))
|
||||
glEnable(GL_BLEND);
|
||||
switch (renderState & RS_BLEND) {
|
||||
case RS_BLEND_ALPHA : glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break;
|
||||
case RS_BLEND_ADD : glBlendFunc(GL_ONE, GL_ONE); break;
|
||||
case RS_BLEND_MULTIPLY : glBlendFunc(GL_DST_COLOR, GL_ZERO); break;
|
||||
case RS_BLEND_SCREEN : glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); break;
|
||||
default : glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & RS_TARGET) { // for cler the RT & reset mask
|
||||
if (reqTarget.clear)
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
renderState &= ~RS_TARGET;
|
||||
}
|
||||
|
||||
active.renderState = renderState;
|
||||
}
|
||||
|
||||
void setClearColor(const vec4 &color) {
|
||||
glClearColor(color.x, color.y, color.z, color.w);
|
||||
}
|
||||
|
||||
void setClearStencil(int value) {
|
||||
glClearStencil(value);
|
||||
}
|
||||
|
||||
void setViewport(const vec4 &vp) {
|
||||
glViewport(int(vp.x), int(vp.y), int(vp.z), int(vp.w));
|
||||
viewport = vp;
|
||||
}
|
||||
|
||||
void setViewport(int x, int y, int width, int height) {
|
||||
setViewport(vec4(float(x), float(y), float(width), float(height)));
|
||||
}
|
||||
|
||||
void setScissor(int x, int y, int width, int height) {
|
||||
glScissor(x, y, width, height);
|
||||
scissor = vec4(float(x), float(y), float(width), float(height));
|
||||
viewport = vec4(float(x), float(y), float(width), float(height));
|
||||
renderState |= RS_VIEWPORT;
|
||||
}
|
||||
|
||||
void setCulling(CullMode mode) {
|
||||
if (active.cullMode == mode)
|
||||
return;
|
||||
|
||||
renderState &= ~RS_CULL;
|
||||
switch (mode) {
|
||||
case cfNone :
|
||||
glDisable(GL_CULL_FACE);
|
||||
case cfBack :
|
||||
glCullFace(GL_BACK);
|
||||
break;
|
||||
case cfFront :
|
||||
glCullFace(GL_FRONT);
|
||||
break;
|
||||
case cfNone : break;
|
||||
case cfBack : renderState |= RS_CULL_BACK; break;
|
||||
case cfFront : renderState |= RS_CULL_FRONT; break;
|
||||
}
|
||||
|
||||
if (mode != cfNone && active.cullMode == cfNone)
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
active.cullMode = mode;
|
||||
}
|
||||
|
||||
void setBlending(BlendMode mode) {
|
||||
if (active.blendMode == mode)
|
||||
return;
|
||||
|
||||
renderState &= ~RS_BLEND;
|
||||
switch (mode) {
|
||||
case bmNone :
|
||||
glDisable(GL_BLEND);
|
||||
break;
|
||||
case bmAlpha :
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
break;
|
||||
case bmAdd :
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
break;
|
||||
case bmMultiply :
|
||||
glBlendFunc(GL_DST_COLOR, GL_ZERO);
|
||||
break;
|
||||
case bmScreen :
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
|
||||
break;
|
||||
case bmNone : break;
|
||||
case bmAlpha : renderState |= RS_BLEND_ALPHA; break;
|
||||
case bmAdd : renderState |= RS_BLEND_ADD; break;
|
||||
case bmMultiply : renderState |= RS_BLEND_MULTIPLY; break;
|
||||
case bmScreen : renderState |= RS_BLEND_SCREEN; break;
|
||||
}
|
||||
|
||||
if (mode != bmNone && active.blendMode == bmNone)
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
active.blendMode = mode;
|
||||
}
|
||||
|
||||
void setColorWrite(bool r, bool g, bool b, bool a) {
|
||||
glColorMask(r, g, b, a);
|
||||
renderState &= ~RS_COLOR_WRITE;
|
||||
if (r) renderState |= RS_COLOR_WRITE_R;
|
||||
if (g) renderState |= RS_COLOR_WRITE_G;
|
||||
if (b) renderState |= RS_COLOR_WRITE_B;
|
||||
if (a) renderState |= RS_COLOR_WRITE_A;
|
||||
}
|
||||
|
||||
void setDepthWrite(bool write) {
|
||||
glDepthMask(write);
|
||||
if (write)
|
||||
renderState |= RS_DEPTH_WRITE;
|
||||
else
|
||||
renderState &= ~RS_DEPTH_WRITE;
|
||||
}
|
||||
|
||||
void setDepthTest(bool test) {
|
||||
if (test)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
renderState |= RS_DEPTH_TEST;
|
||||
else
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void setStencilTest(bool test) {
|
||||
if (test)
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
else
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
|
||||
void setScissorTest(bool test) {
|
||||
if (test)
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
else
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void setStencilTwoSide(int ref, bool test) { // preset for z-fail shadow volumes
|
||||
active.stencilTwoSide = test;
|
||||
if (test) {
|
||||
switch (Core::support.stencil) {
|
||||
case 0 :
|
||||
glStencilFunc(GL_ALWAYS, ref, ~0);
|
||||
break;
|
||||
case 1 :
|
||||
setCulling(cfNone);
|
||||
glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
|
||||
glActiveStencilFaceEXT(GL_BACK);
|
||||
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
|
||||
glStencilFunc(GL_ALWAYS, ref, ~0);
|
||||
glActiveStencilFaceEXT(GL_FRONT);
|
||||
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
|
||||
glStencilFunc(GL_ALWAYS, ref, ~0);
|
||||
break;
|
||||
case 2 :
|
||||
setCulling(cfNone);
|
||||
glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, ref, ~0);
|
||||
glStencilFuncSeparate(GL_BACK, GL_ALWAYS, ref, ~0);
|
||||
glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR, GL_KEEP);
|
||||
glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR, GL_KEEP);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (Core::support.stencil == 1)
|
||||
glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
|
||||
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
||||
glStencilFunc(GL_NOTEQUAL, ref, ~0);
|
||||
setCulling(cfFront);
|
||||
}
|
||||
renderState &= ~RS_DEPTH_TEST;
|
||||
}
|
||||
|
||||
void invalidateTarget(bool color, bool depth) {
|
||||
@@ -719,64 +732,59 @@ namespace Core {
|
||||
}
|
||||
|
||||
void setTarget(Texture *target, bool clear = false, int face = 0) {
|
||||
if (!target && defaultTarget)
|
||||
if (!target)
|
||||
target = defaultTarget;
|
||||
|
||||
if (target != active.target || face != active.targetFace) {
|
||||
if (!target) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO);
|
||||
glColorMask(true, true, true, true);
|
||||
bool color = !target || (target->format != Texture::DEPTH && target->format != Texture::SHADOW);
|
||||
setColorWrite(color, color, color, color);
|
||||
|
||||
if (!target) // backbuffer
|
||||
setViewport(int(viewportDef.x), int(viewportDef.y), int(viewportDef.z), int(viewportDef.w));
|
||||
} else {
|
||||
if (active.target == NULL || active.target == defaultTarget)
|
||||
viewportDef = viewport;
|
||||
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);
|
||||
else
|
||||
glColorMask(true, true, true, true);
|
||||
setViewport(0, 0, target->width, target->height);
|
||||
}
|
||||
|
||||
reqTarget.texture = target;
|
||||
reqTarget.clear = clear;
|
||||
reqTarget.face = face;
|
||||
renderState |= RS_TARGET;
|
||||
}
|
||||
|
||||
if (clear)
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
active.target = target;
|
||||
active.targetFace = face;
|
||||
}
|
||||
|
||||
void copyTarget(Texture *texture, int xOffset, int yOffset, int x, int y, int width, int height) {
|
||||
texture->bind(sDiffuse);
|
||||
void copyTarget(Texture *dst, int xOffset, int yOffset, int x, int y, int width, int height) {
|
||||
validateRenderState();
|
||||
dst->bind(sDiffuse);
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height);
|
||||
}
|
||||
|
||||
vec4 copyPixel(int x, int y) { // GPU sync!
|
||||
validateRenderState();
|
||||
ubyte4 c;
|
||||
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &c);
|
||||
return vec4(float(c.x), float(c.y), float(c.z), float(c.w)) * (1.0f / 255.0f);
|
||||
}
|
||||
|
||||
void beginFrame() {
|
||||
memset(&active, 0, sizeof(active));
|
||||
//memset(&active, 0, sizeof(active));
|
||||
setViewport(0, 0, Core::width, Core::height);
|
||||
viewportDef = viewport;
|
||||
setDepthTest(true);
|
||||
active.blendMode = bmAlpha;
|
||||
active.cullMode = cfNone;
|
||||
setCulling(cfFront);
|
||||
setBlending(bmNone);
|
||||
setBlending(bmAlpha);
|
||||
setDepthTest(true);
|
||||
setDepthWrite(true);
|
||||
setColorWrite(true, true, true, true);
|
||||
|
||||
Core::stats.start();
|
||||
}
|
||||
|
||||
void endFrame() {
|
||||
Core::stats.stop();
|
||||
}
|
||||
|
||||
void DIP(int iStart, int iCount) {
|
||||
validateRenderState();
|
||||
glDrawElements(GL_TRIANGLES, iCount, GL_UNSIGNED_SHORT, (Index*)NULL + iStart);
|
||||
stats.dips++;
|
||||
stats.tris += iCount / 3;
|
||||
}
|
||||
}
|
||||
|
||||
#include "mesh.h"
|
||||
|
12
src/debug.h
12
src/debug.h
@@ -60,6 +60,7 @@ namespace Debug {
|
||||
glUseProgram(0);
|
||||
Core::active.shader = NULL;
|
||||
Core::active.textures[0] = NULL;
|
||||
Core::validateRenderState();
|
||||
}
|
||||
|
||||
void end() {
|
||||
@@ -178,15 +179,16 @@ namespace Debug {
|
||||
glLoadIdentity();
|
||||
glOrtho(0, Core::width, Core::height, 0, 0, 1);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
Core::setDepthTest(false);
|
||||
Core::setCulling(cfNone);
|
||||
Core::validateRenderState();
|
||||
|
||||
glColor4fv((GLfloat*)&color);
|
||||
glRasterPos2f(pos.x, pos.y);
|
||||
glListBase(font);
|
||||
glCallLists(strlen(str), GL_UNSIGNED_BYTE, str);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
Core::setDepthTest(true);
|
||||
Core::setCulling(cfFront);
|
||||
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
@@ -412,7 +412,8 @@ namespace TR {
|
||||
struct Vertex {
|
||||
int16 x, y, z;
|
||||
|
||||
operator vec3() const { return vec3((float)x, (float)y, (float)z); };
|
||||
operator vec3() const { return vec3((float)x, (float)y, (float)z); }
|
||||
operator short3() const { return *((short3*)this); }
|
||||
};
|
||||
|
||||
struct Rectangle {
|
||||
@@ -480,7 +481,7 @@ namespace TR {
|
||||
uint16 meshesCount;
|
||||
int16 alternateRoom;
|
||||
struct {
|
||||
uint16 water:1, unused:14, rendered:1;
|
||||
uint16 water:1, unused:14, visible:1;
|
||||
} flags;
|
||||
|
||||
struct Portal {
|
||||
@@ -524,6 +525,10 @@ namespace TR {
|
||||
uint16 meshID;
|
||||
uint16 meshIndex; // index into static meshes array
|
||||
} *meshes;
|
||||
|
||||
vec3 getOffset() const {
|
||||
return vec3(float(info.x), 0.0f, float(info.z));
|
||||
}
|
||||
};
|
||||
|
||||
union FloorData {
|
||||
|
@@ -6,24 +6,11 @@
|
||||
#define MAX_CLIP_PLANES 16
|
||||
|
||||
struct Frustum {
|
||||
|
||||
struct Poly {
|
||||
vec3 vertices[MAX_CLIP_PLANES];
|
||||
int count;
|
||||
};
|
||||
|
||||
vec3 pos;
|
||||
vec4 planes[MAX_CLIP_PLANES * 2]; // + buffer for OBB visibility test
|
||||
int start, count;
|
||||
#ifdef _DEBUG
|
||||
int dbg;
|
||||
Poly debugPoly;
|
||||
#endif
|
||||
|
||||
void calcPlanes(const mat4 &m) {
|
||||
#ifdef _DEBUG
|
||||
dbg = 0;
|
||||
#endif
|
||||
start = 0;
|
||||
count = 5;
|
||||
planes[0] = vec4(m.e30 - m.e20, m.e31 - m.e21, m.e32 - m.e22, m.e33 - m.e23); // near
|
||||
@@ -35,71 +22,6 @@ struct Frustum {
|
||||
planes[i] *= 1.0f / planes[i].xyz.length();
|
||||
}
|
||||
|
||||
void calcPlanes(const Poly &poly) {
|
||||
count = 1 + poly.count; // add one for near plane (not changing)
|
||||
ASSERT(count < MAX_CLIP_PLANES);
|
||||
if (count < 4) return;
|
||||
|
||||
vec3 e1 = poly.vertices[0] - pos;
|
||||
for (int i = 1; i < count; i++) {
|
||||
vec3 e2 = poly.vertices[i % poly.count] - pos;
|
||||
planes[i].xyz = e1.cross(e2).normal();
|
||||
planes[i].w = -(pos.dot(planes[i].xyz));
|
||||
e1 = e2;
|
||||
}
|
||||
}
|
||||
|
||||
void clipPlane(const Poly &src, Poly &dst, const vec4 &plane) {
|
||||
dst.count = 0;
|
||||
if (!src.count) return;
|
||||
|
||||
float t1 = src.vertices[0].dot(plane.xyz) + plane.w;
|
||||
|
||||
for (int i = 0; i < src.count; i++) {
|
||||
const vec3 &v1 = src.vertices[i];
|
||||
const vec3 &v2 = src.vertices[(i + 1) % src.count];
|
||||
|
||||
float t2 = v2.dot(plane.xyz) + plane.w;
|
||||
|
||||
// hack for big float numbers
|
||||
int s1 = (int)t1;
|
||||
int s2 = (int)t2;
|
||||
|
||||
if (s1 >= 0) {
|
||||
dst.vertices[dst.count++] = v1;
|
||||
ASSERT(dst.count < MAX_CLIP_PLANES);
|
||||
}
|
||||
|
||||
if ((s1 ^ s2) < 0) { // check for opposite signs
|
||||
float k1 = t2 / (t2 - t1);
|
||||
float k2 = t1 / (t2 - t1);
|
||||
dst.vertices[dst.count++] = v1 * (float)k1 - v2 * (float)k2;
|
||||
ASSERT(dst.count < MAX_CLIP_PLANES);
|
||||
}
|
||||
|
||||
t1 = t2;
|
||||
}
|
||||
}
|
||||
|
||||
bool clipByPortal(const vec3 *vertices, int vCount, const vec3 &normal) {
|
||||
if (normal.dot(pos - vertices[0]) < 0.0f) // check portal winding order
|
||||
return false;
|
||||
|
||||
Poly poly[2];
|
||||
|
||||
poly[0].count = vCount;
|
||||
memmove(poly[0].vertices, vertices, sizeof(vec3) * poly[0].count);
|
||||
#ifdef _DEBUG
|
||||
debugPoly.count = 0;
|
||||
#endif
|
||||
int j = 0;
|
||||
for (int i = 1; i < count; i++, j ^= 1)
|
||||
clipPlane(poly[j], poly[j ^ 1], planes[i]);
|
||||
|
||||
calcPlanes(poly[j]);
|
||||
return count >= 4;
|
||||
}
|
||||
|
||||
// AABB visibility check
|
||||
bool isVisible(const vec3 &min, const vec3 &max) const {
|
||||
if (count < 4) return false;
|
||||
|
@@ -23,6 +23,7 @@ namespace Game {
|
||||
Core::settings.detail.lighting = true;
|
||||
Core::settings.detail.shadows = true;
|
||||
Core::settings.detail.water = Core::support.texFloat || Core::support.texHalf;
|
||||
Core::settings.detail.contact = false;
|
||||
|
||||
Core::settings.controls.retarget = true;
|
||||
|
||||
|
@@ -33,7 +33,7 @@ namespace Input {
|
||||
{ ikRight, ikJoyRight },
|
||||
{ ikUp, ikJoyUp },
|
||||
{ ikDown, ikJoyDown },
|
||||
{ ikAlt, ikJoyX },
|
||||
{ ikD, ikJoyX },
|
||||
{ ikShift, ikJoyRB },
|
||||
{ ikCtrl, ikJoyA },
|
||||
{ ikSpace, ikJoyY },
|
||||
@@ -111,7 +111,7 @@ namespace Input {
|
||||
}
|
||||
} head;
|
||||
|
||||
enum TouchButton { bNone, bWeapon, bWalk, bAction, bJump, bMAX };
|
||||
enum TouchButton { bNone, bWeapon, bWalk, bAction, bJump, bInventory, bMAX };
|
||||
enum TouchZone { zMove, zLook, zButton, zMAX };
|
||||
|
||||
float touchTimerVis, touchTimerTap;
|
||||
@@ -245,11 +245,12 @@ namespace Input {
|
||||
float radius = offset;
|
||||
vec2 center = vec2(Core::width - offset * 0.7f, Core::height - offset * 0.7f);
|
||||
|
||||
btnRadius = Core::height * (25.0f / 1080.0f);
|
||||
btnPos[bWeapon] = center;
|
||||
btnPos[bJump] = center + vec2(cosf(-PI * 0.5f), sinf(-PI * 0.5f)) * radius;
|
||||
btnPos[bAction] = center + vec2(cosf(-PI * 3.0f / 4.0f), sinf(-PI * 3.0f / 4.0f)) * radius;
|
||||
btnPos[bWalk] = center + vec2(cosf(-PI), sinf(-PI)) * radius;
|
||||
btnRadius = Core::height * (25.0f / 1080.0f);
|
||||
btnPos[bInventory] = vec2(Core::width - btnRadius * 2.0f, btnRadius * 2.0f);
|
||||
|
||||
// touch update
|
||||
if (checkTouchZone(zMove))
|
||||
@@ -309,6 +310,7 @@ namespace Input {
|
||||
case bWalk : state[cWalk] = true; break;
|
||||
case bAction : state[cAction] = true; break;
|
||||
case bJump : state[cJump] = true; break;
|
||||
case bInventory : state[cInventory] = true; break;
|
||||
default : ;
|
||||
}
|
||||
}
|
||||
|
@@ -297,7 +297,7 @@ struct Inventory {
|
||||
if (type != TR::Entity::NONE) {
|
||||
int i = contains(type);
|
||||
if (i >= 0)
|
||||
pageItemIndex[page] = getItemIndex(page, i);
|
||||
pageItemIndex[page] = getLocalIndex(i);
|
||||
}
|
||||
|
||||
index = targetIndex = pageItemIndex[page];
|
||||
@@ -322,16 +322,27 @@ struct Inventory {
|
||||
}
|
||||
}
|
||||
|
||||
int getItemIndex(Page page, int index) {
|
||||
int getGlobalIndex(Page page, int localIndex) {
|
||||
for (int i = 0; i < itemsCount; i++)
|
||||
if (items[i]->desc.page == page) {
|
||||
if (!index)
|
||||
if (!localIndex)
|
||||
return i;
|
||||
index--;
|
||||
localIndex--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getLocalIndex(int globalIndex) {
|
||||
Page page = items[globalIndex]->desc.page;
|
||||
|
||||
int idx = 0;
|
||||
for (int i = 0; i < globalIndex; i++)
|
||||
if (items[i]->desc.page == page)
|
||||
idx++;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
float getAngle(int index, int count) {
|
||||
return PI * 2.0f / float(count) * index;
|
||||
}
|
||||
@@ -347,7 +358,7 @@ struct Inventory {
|
||||
}
|
||||
|
||||
bool showHealthBar() {
|
||||
int idx = getItemIndex(page, index);
|
||||
int idx = getGlobalIndex(page, index);
|
||||
TR::Entity::Type type = items[idx]->type;
|
||||
return active && phaseRing == 1.0f && index == targetIndex && phasePage == 1.0f && (type == TR::Entity::INV_MEDIKIT_SMALL || type == TR::Entity::INV_MEDIKIT_BIG);
|
||||
}
|
||||
@@ -372,10 +383,12 @@ struct Inventory {
|
||||
bool ready = active && phaseRing == 1.0f && phasePage == 1.0f;
|
||||
|
||||
if (index == targetIndex && targetPage == page && ready && !chosen) {
|
||||
if (Input::state[cLeft]) { phaseSelect = 0.0f; targetIndex = (targetIndex - 1 + count) % count; }
|
||||
if (Input::state[cRight]) { phaseSelect = 0.0f; targetIndex = (targetIndex + 1) % count; }
|
||||
if (Input::state[cUp] && page < PAGE_ITEMS && getItemsCount(page + 1)) { phasePage = 0.0f; targetPage = Page(page + 1); }
|
||||
if (Input::state[cDown] && page > PAGE_OPTION && getItemsCount(page - 1)) { phasePage = 0.0f; targetPage = Page(page - 1); }
|
||||
float s = Input::touchTimerVis > 0.0f ? -1.0f : 1.0f;
|
||||
|
||||
if (Input::state[cLeft] || Input::joy.L.x < -0.5f || Input::joy.R.x > 0.5f) { phaseSelect = 0.0f; targetIndex = (targetIndex - 1 + count) % count; }
|
||||
if (Input::state[cRight] || Input::joy.L.x > 0.5f || Input::joy.R.x < -0.5f) { phaseSelect = 0.0f; targetIndex = (targetIndex + 1) % count; }
|
||||
if ((Input::state[cUp] || Input::joy.L.y < -0.5f || Input::joy.R.y > 0.5f) && page < PAGE_ITEMS && getItemsCount(page + 1)) { phasePage = 0.0f; targetPage = Page(page + 1); }
|
||||
if ((Input::state[cDown] || Input::joy.L.y > 0.5f || Input::joy.R.y < -0.5f) && page > PAGE_OPTION && getItemsCount(page - 1)) { phasePage = 0.0f; targetPage = Page(page - 1); }
|
||||
|
||||
if (index != targetIndex) {
|
||||
vec3 p;
|
||||
@@ -385,7 +398,7 @@ struct Inventory {
|
||||
|
||||
vec3 p;
|
||||
|
||||
Item *item = items[getItemIndex(page, index)];
|
||||
Item *item = items[getGlobalIndex(page, index)];
|
||||
|
||||
if (index == targetIndex && ready) {
|
||||
if (Input::state[cAction] && (phaseChoose == 0.0f || (phaseChoose == 1.0f && item->anim->isEnded))) {
|
||||
@@ -410,7 +423,7 @@ struct Inventory {
|
||||
|
||||
float w = 90.0f * DEG2RAD * Core::deltaTime;
|
||||
|
||||
int itemIndex = index == targetIndex ? getItemIndex(page, index) : -1;
|
||||
int itemIndex = index == targetIndex ? getGlobalIndex(page, index) : -1;
|
||||
|
||||
for (int i = 0; i < itemsCount; i++) {
|
||||
items[i]->update();
|
||||
@@ -610,10 +623,10 @@ struct Inventory {
|
||||
vec3(0.4f), vec3(0.2f), vec3(0.4f), vec3(0.5f), vec3(0.4f), vec3(0.6f)
|
||||
};
|
||||
|
||||
Core::lightPos[0] = vec3(1000, 2000, 1000);
|
||||
Core::lightColor[0] = vec4(1, 1, 1, 8192);
|
||||
for (int i = 1; i < MAX_LIGHTS; i++)
|
||||
Core::lightColor[1] = vec4(0, 0, 0, 1);
|
||||
for (int i = 0; i < MAX_LIGHTS; i++) {
|
||||
Core::lightPos[i] = vec3(0, 0, 0);
|
||||
Core::lightColor[i] = vec4(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
Core::active.shader->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
||||
Core::active.shader->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
||||
@@ -642,7 +655,7 @@ struct Inventory {
|
||||
}
|
||||
|
||||
if (index == targetIndex)
|
||||
renderItemText(items[getItemIndex(page, index)], UI::width);
|
||||
renderItemText(items[getGlobalIndex(page, index)], UI::width);
|
||||
}
|
||||
};
|
||||
|
||||
|
13
src/lara.h
13
src/lara.h
@@ -425,10 +425,8 @@ struct Lara : Character {
|
||||
|
||||
if (level->extra.braid > -1)
|
||||
braid = new Braid(this, vec3(-4.0f, 24.0f, -48.0f));
|
||||
|
||||
#ifdef _DEBUG
|
||||
//reset(14, vec3(40448, 3584, 60928), PI * 0.5f, true); // gym (pool)
|
||||
|
||||
//reset(14, vec3(40448, 3584, 60928), PI * 0.5f, STAND_ONWATER); // gym (pool)
|
||||
//reset(14, vec3(20215, 6656, 52942), PI); // level 1 (bridge)
|
||||
//reset(15, vec3(70067, -256, 29104), -0.68f); // level 2 (pool)
|
||||
//reset(61, vec3(27221, -1024, 29205), PI * 0.5f); // level 2 (blade)
|
||||
@@ -1301,6 +1299,7 @@ struct Lara : Character {
|
||||
damageTime = LARA_DAMAGE_TIME;
|
||||
health = min(LARA_MAX_HEALTH, health + (item == TR::Entity::INV_MEDIKIT_SMALL ? LARA_MAX_HEALTH / 2 : LARA_MAX_HEALTH));
|
||||
playSound(TR::SND_HEALTH, pos, Sound::PAN);
|
||||
//TODO: remove medikit item
|
||||
break;
|
||||
case TR::Entity::INV_PUZZLE_1 :
|
||||
case TR::Entity::INV_PUZZLE_2 :
|
||||
@@ -1557,12 +1556,16 @@ struct Lara : Character {
|
||||
if (state == STATE_HANDSTAND || state == STATE_HANG_UP)
|
||||
return STAND_HANG;
|
||||
|
||||
if (stand == STAND_ONWATER && state != STATE_DIVE && state != STATE_STOP)
|
||||
if (stand == STAND_ONWATER && state != STATE_STOP) {
|
||||
if (!getRoom().flags.water && state != STATE_WATER_OUT)
|
||||
return STAND_AIR;
|
||||
if (state != STATE_DIVE)
|
||||
return stand;
|
||||
}
|
||||
|
||||
if (getRoom().flags.water) {
|
||||
wpnHide();
|
||||
if (stand != STAND_UNDERWATER && (state != STATE_FALL && state != STATE_FALL_BACK && state != STATE_SWAN_DIVE && state != STATE_FAST_DIVE))
|
||||
if (stand != STAND_UNDERWATER && stand != STAND_ONWATER && (state != STATE_FALL && state != STATE_REACH && state != STATE_SWAN_DIVE && state != STATE_FAST_DIVE))
|
||||
animation.setAnim(ANIM_FALL_FORTH);
|
||||
return STAND_UNDERWATER;
|
||||
}
|
||||
|
439
src/level.h
439
src/level.h
@@ -101,28 +101,18 @@ struct Level : IGame {
|
||||
virtual void renderEnvironment(int roomIndex, const vec3 &pos, Texture **targets, int stride = 0) {
|
||||
PROFILE_MARKER("ENVIRONMENT");
|
||||
Core::eye = 0.0f;
|
||||
setupBinding();
|
||||
// first pass render level into cube faces
|
||||
for (int i = 0; i < 6; i++) {
|
||||
setupCubeCamera(pos, i);
|
||||
Core::pass = Core::passAmbient;
|
||||
Texture *target = targets[0]->cube ? targets[0] : targets[i * stride];
|
||||
Core::setTarget(target, true, i);
|
||||
renderScene(roomIndex);
|
||||
renderView(roomIndex, false);
|
||||
Core::invalidateTarget(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void renderCompose(int roomIndex, bool genShadowMask = false) {
|
||||
PROFILE_MARKER("PASS_COMPOSE");
|
||||
|
||||
if (shadow) shadow->bind(sShadow);
|
||||
|
||||
Core::setDepthTest(true);
|
||||
Core::setDepthWrite(true);
|
||||
Core::pass = Core::passCompose;
|
||||
renderScene(roomIndex);
|
||||
}
|
||||
|
||||
virtual void fxQuake(float time) {
|
||||
camera->shake = time;
|
||||
}
|
||||
@@ -411,8 +401,14 @@ struct Level : IGame {
|
||||
fwrite(data, 1024 * 1024 * 4, 1, f);
|
||||
fclose(f);
|
||||
*/
|
||||
/*
|
||||
memset(data, 255, 4 * 1024 * 1024);
|
||||
for (int i = 0; i < 1024; i++)
|
||||
for (int j = 0; j < 1024; j++)
|
||||
data[i * 1024 + j].b = data[i * 1024 + j].g = ((i % 8 == 0) || (j % 8 == 0)) ? 0 : 255;
|
||||
*/
|
||||
|
||||
atlas = new Texture(1024, 1024, Texture::RGBA, false, data);
|
||||
atlas = new Texture(1024, 1024, Texture::RGBA, false, data, true, false); // TODO: generate mips
|
||||
PROFILE_LABEL(TEXTURE, atlas->ID, "atlas");
|
||||
|
||||
uint32 whitePix = 0xFFFFFFFF;
|
||||
@@ -494,91 +490,8 @@ struct Level : IGame {
|
||||
}
|
||||
|
||||
Core::active.shader->setParam(uMaterial, vec4(diffuse, ambient, specular, alpha));
|
||||
}
|
||||
|
||||
void renderRoom(int roomIndex, int from = TR::NO_ROOM) {
|
||||
ASSERT(roomIndex >= 0 && roomIndex < level.roomsCount);
|
||||
PROFILE_MARKER("ROOM");
|
||||
|
||||
TR::Room &room = level.rooms[roomIndex];
|
||||
vec3 offset = vec3(float(room.info.x), 0.0f, float(room.info.z));
|
||||
|
||||
// room geometry & sprites
|
||||
if (!room.flags.rendered) { // skip if already rendered
|
||||
if (waterCache && room.flags.water)
|
||||
waterCache->setVisible(roomIndex);
|
||||
|
||||
room.flags.rendered = true;
|
||||
|
||||
if (Core::pass != Core::passShadow) {
|
||||
|
||||
Basis qTemp = Core::basis;
|
||||
Core::basis.translate(offset);
|
||||
|
||||
MeshBuilder::RoomRange &range = mesh->rooms[roomIndex];
|
||||
|
||||
for (int transp = 0; transp < 2; transp++) {
|
||||
if (!range.geometry[transp].iCount)
|
||||
continue;
|
||||
|
||||
Core::setBlending(transp ? bmAlpha : bmNone);
|
||||
|
||||
setRoomParams(roomIndex, Shader::ROOM, 1.0f, intensityf(room.ambient), 0.0f, 1.0f, transp > 0);
|
||||
Shader *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);
|
||||
|
||||
// render room geometry
|
||||
mesh->renderRoomGeometry(roomIndex, transp > 0);
|
||||
}
|
||||
|
||||
// render room sprites
|
||||
if (range.sprites.iCount) {
|
||||
Core::setBlending(bmAlpha);
|
||||
setRoomParams(roomIndex, Shader::SPRITE, 1.0f, 1.0f, 0.0f, 1.0f, true);
|
||||
Shader *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);
|
||||
}
|
||||
|
||||
Core::basis = qTemp;
|
||||
}
|
||||
Core::setBlending(bmNone);
|
||||
} else
|
||||
return;
|
||||
|
||||
#ifdef LEVEL_EDITOR
|
||||
return;
|
||||
#endif
|
||||
|
||||
// render rooms through portals recursively
|
||||
Frustum *camFrustum = camera->frustum; // push camera frustum
|
||||
Frustum frustum;
|
||||
camera->frustum = &frustum;
|
||||
|
||||
for (int i = 0; i < room.portalsCount; i++) {
|
||||
TR::Room::Portal &p = room.portals[i];
|
||||
|
||||
if (p.roomIndex == from) continue;
|
||||
|
||||
vec3 v[] = {
|
||||
offset + p.vertices[0],
|
||||
offset + p.vertices[1],
|
||||
offset + p.vertices[2],
|
||||
offset + p.vertices[3],
|
||||
};
|
||||
|
||||
frustum = *camFrustum;
|
||||
if (frustum.clipByPortal(v, 4, p.normal)) {
|
||||
if (waterCache &&(level.rooms[roomIndex].flags.water ^ level.rooms[p.roomIndex].flags.water) && v[0].y == v[1].y && v[0].y == v[2].y)
|
||||
waterCache->setVisible(roomIndex, p.roomIndex);
|
||||
renderRoom(p.roomIndex, roomIndex);
|
||||
}
|
||||
}
|
||||
camera->frustum = camFrustum; // pop camera frustum
|
||||
if (Core::settings.detail.contact)
|
||||
Core::active.shader->setParam(uContacts, Core::contacts[0], MAX_CONTACTS);
|
||||
}
|
||||
|
||||
void setMainLight(Controller *controller) {
|
||||
@@ -586,6 +499,88 @@ struct Level : IGame {
|
||||
Core::lightColor[0] = vec4(controller->mainLightColor.xyz, 1.0f / controller->mainLightColor.w);
|
||||
}
|
||||
|
||||
void renderRooms(int *roomsList, int roomsCount) {
|
||||
PROFILE_MARKER("ROOMS");
|
||||
|
||||
for (int i = 0; i < level.roomsCount; i++)
|
||||
level.rooms[i].flags.visible = false;
|
||||
|
||||
for (int i = 0; i < roomsCount; i++)
|
||||
level.rooms[roomsList[i]].flags.visible = true;
|
||||
|
||||
if (Core::pass == Core::passShadow)
|
||||
return;
|
||||
|
||||
if (Core::settings.detail.contact) {
|
||||
Sphere spheres[MAX_CONTACTS];
|
||||
int spheresCount;
|
||||
lara->getSpheres(spheres, spheresCount);
|
||||
|
||||
for (int i = 0; i < MAX_CONTACTS; i++)
|
||||
if (i < spheresCount)
|
||||
Core::contacts[i] = vec4(spheres[i].center, PI * spheres[i].radius * spheres[i].radius * 0.25f);
|
||||
else
|
||||
Core::contacts[i] = vec4(0.0f);
|
||||
}
|
||||
|
||||
setMainLight(lara);
|
||||
|
||||
bool hasGeom[2], hasSprite;
|
||||
hasGeom[0] = hasGeom[1] = hasSprite = false;
|
||||
|
||||
Basis basis;
|
||||
basis.identity();
|
||||
|
||||
Core::setBlending(bmNone);
|
||||
for (int transp = 0; transp < 2; transp++) {
|
||||
for (int i = 0; i < roomsCount; i++) {
|
||||
int roomIndex = roomsList[i];
|
||||
MeshBuilder::RoomRange &range = mesh->rooms[roomIndex];
|
||||
|
||||
if (!range.geometry[transp].iCount)
|
||||
continue;
|
||||
|
||||
setRoomParams(roomIndex, Shader::ROOM, 1.0f, intensityf(level.rooms[roomIndex].ambient), 0.0f, 1.0f, transp > 0);
|
||||
Shader *sh = Core::active.shader;
|
||||
|
||||
if (!hasGeom[transp]) {
|
||||
hasGeom[transp] = true;
|
||||
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
||||
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
||||
}
|
||||
|
||||
basis.pos = level.rooms[roomIndex].getOffset();
|
||||
sh->setParam(uBasis, basis);
|
||||
mesh->renderRoomGeometry(roomIndex, transp > 0);
|
||||
}
|
||||
Core::setBlending(bmAlpha);
|
||||
}
|
||||
|
||||
basis.rot = Core::mViewInv.getRot();
|
||||
for (int i = 0; i < roomsCount; i++) {
|
||||
level.rooms[roomsList[i]].flags.visible = true;
|
||||
|
||||
int roomIndex = roomsList[i];
|
||||
MeshBuilder::RoomRange &range = mesh->rooms[roomIndex];
|
||||
|
||||
if (!range.sprites.iCount)
|
||||
continue;
|
||||
|
||||
setRoomParams(roomIndex, Shader::SPRITE, 1.0f, 1.0f, 0.0f, 1.0f, true);
|
||||
Shader *sh = Core::active.shader;
|
||||
if (!hasSprite) {
|
||||
sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS);
|
||||
sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS);
|
||||
}
|
||||
|
||||
basis.pos = level.rooms[roomIndex].getOffset();
|
||||
sh->setParam(uBasis, basis);
|
||||
mesh->renderRoomSprites(roomIndex);
|
||||
}
|
||||
|
||||
Core::setBlending(bmNone);
|
||||
}
|
||||
|
||||
void renderEntity(const TR::Entity &entity) {
|
||||
//if (entity.room != lara->getRoomIndex()) return;
|
||||
if (entity.type == TR::Entity::NONE || !entity.modelIndex) return;
|
||||
@@ -597,10 +592,9 @@ struct Level : IGame {
|
||||
|
||||
Controller *controller = (Controller*)entity.controller;
|
||||
|
||||
|
||||
TR::Room &room = level.rooms[entity.room];
|
||||
if (entity.type != TR::Entity::LARA) // TODO: remove this hack (collect conjugate room entities)
|
||||
if (!room.flags.rendered || entity.flags.invisible || entity.flags.rendered)
|
||||
if (!room.flags.visible || entity.flags.invisible || entity.flags.rendered)
|
||||
return;
|
||||
|
||||
int16 lum = entity.intensity == -1 ? room.ambient : entity.intensity;
|
||||
@@ -610,8 +604,6 @@ struct Level : IGame {
|
||||
type = Shader::MIRROR;
|
||||
|
||||
int roomIndex = entity.room;
|
||||
// if (entity.type == TR::Entity::LARA && ((Lara*)entity.controller)->state == Lara::STATE_WATER_OUT)
|
||||
// roomIndex = ((Lara*)entity.controller)->roomPrev;
|
||||
|
||||
setRoomParams(roomIndex, type, 1.0f, intensityf(lum), controller->specular, 1.0f, isModel ? !mesh->models[entity.modelIndex - 1].opaque : true);
|
||||
|
||||
@@ -688,31 +680,6 @@ struct Level : IGame {
|
||||
camera->setup(Core::pass == Core::passCompose);
|
||||
|
||||
setupBinding();
|
||||
|
||||
// clear visibility flag for rooms
|
||||
for (int i = 0; i < level.roomsCount; i++)
|
||||
level.rooms[i].flags.rendered = false;
|
||||
|
||||
if (Core::pass != Core::passAmbient)
|
||||
for (int i = 0; i < level.entitiesCount; i++)
|
||||
level.entities[i].flags.rendered = false;
|
||||
}
|
||||
|
||||
void renderRooms(int roomIndex) {
|
||||
PROFILE_MARKER("ROOMS");
|
||||
|
||||
setMainLight(lara);
|
||||
|
||||
#ifdef LEVEL_EDITOR
|
||||
for (int i = 0; i < level.roomsCount; i++)
|
||||
renderRoom(i);
|
||||
#else
|
||||
if (!camera->cutscene)
|
||||
renderRoom(roomIndex);
|
||||
else // TODO: use brain
|
||||
for (int i = 0; i < level.roomsCount; i++)
|
||||
renderRoom(i);
|
||||
#endif
|
||||
}
|
||||
|
||||
void renderEntities() {
|
||||
@@ -727,12 +694,161 @@ struct Level : IGame {
|
||||
}
|
||||
}
|
||||
|
||||
void renderScene(int roomIndex) {
|
||||
PROFILE_MARKER("SCENE");
|
||||
setup();
|
||||
renderRooms(roomIndex);
|
||||
bool checkPortal(const TR::Room &room, const TR::Room::Portal &portal, const vec4 &viewPort, vec4 &clipPort) {
|
||||
vec3 n = portal.normal;
|
||||
vec3 v = Core::viewPos - (room.getOffset() + portal.vertices[0]);
|
||||
|
||||
if (n.dot(v) <= 0.0f)
|
||||
return false;
|
||||
|
||||
int zClip = 0;
|
||||
vec4 p[4];
|
||||
|
||||
clipPort = vec4(INF, INF, -INF, -INF);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
p[i] = Core::mViewProj * vec4(vec3(portal.vertices[i]) + room.getOffset(), 1.0f);
|
||||
|
||||
if (p[i].w > 0.0f) {
|
||||
p[i].xyz *= (1.0f / p[i].w);
|
||||
|
||||
clipPort.x = min(clipPort.x, p[i].x);
|
||||
clipPort.y = min(clipPort.y, p[i].y);
|
||||
clipPort.z = max(clipPort.z, p[i].x);
|
||||
clipPort.w = max(clipPort.w, p[i].y);
|
||||
} else
|
||||
zClip++;
|
||||
}
|
||||
|
||||
if (zClip == 4)
|
||||
return false;
|
||||
|
||||
if (zClip > 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
vec4 &a = p[i];
|
||||
vec4 &b = p[(i + 1) % 4];
|
||||
|
||||
if ((a.w > 0.0f) ^ (b.w > 0.0f)) {
|
||||
|
||||
if (a.x < 0.0f && b.x < 0.0f)
|
||||
clipPort.x = -1.0f;
|
||||
else
|
||||
if (a.x > 0.0f && b.x > 0.0f)
|
||||
clipPort.z = 1.0f;
|
||||
else {
|
||||
clipPort.x = -1.0f;
|
||||
clipPort.z = 1.0f;
|
||||
}
|
||||
|
||||
if (a.y < 0.0f && b.y < 0.0f)
|
||||
clipPort.y = -1.0f;
|
||||
else
|
||||
if (a.y > 0.0f && b.y > 0.0f)
|
||||
clipPort.w = 1.0f;
|
||||
else {
|
||||
clipPort.y = -1.0f;
|
||||
clipPort.w = 1.0f;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clipPort.x > clipPort.z || clipPort.y > clipPort.w)
|
||||
return false;
|
||||
|
||||
if (clipPort.x > viewPort.z || clipPort.y > viewPort.w || clipPort.z < viewPort.x || clipPort.w < viewPort.y)
|
||||
return false;
|
||||
|
||||
clipPort.x = max(clipPort.x, viewPort.x);
|
||||
clipPort.y = max(clipPort.y, viewPort.y);
|
||||
clipPort.z = min(clipPort.z, viewPort.z);
|
||||
clipPort.w = min(clipPort.w, viewPort.w);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void getVisibleRooms(int *roomsList, int &roomsCount, int from, int to, const vec4 &viewPort, bool water, int count = 0) {
|
||||
if (camera->cutscene) {
|
||||
roomsCount = level.roomsCount;
|
||||
for (int i = 0; i < roomsCount; i++)
|
||||
roomsList[i] = i;
|
||||
return;
|
||||
}
|
||||
|
||||
if (count > 16) {
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
TR::Room &room = level.rooms[to];
|
||||
|
||||
if (!room.flags.visible) {
|
||||
if (Core::pass == Core::passCompose && water && waterCache && from != TR::NO_ROOM && (level.rooms[from].flags.water ^ level.rooms[to].flags.water))
|
||||
waterCache->setVisible(from, to);
|
||||
|
||||
room.flags.visible = true;
|
||||
roomsList[roomsCount++] = to;
|
||||
}
|
||||
|
||||
vec4 clipPort;
|
||||
for (int i = 0; i < room.portalsCount; i++) {
|
||||
TR::Room::Portal &p = room.portals[i];
|
||||
|
||||
if (from == room.portals[i].roomIndex || !checkPortal(room, p, viewPort, clipPort))
|
||||
continue;
|
||||
|
||||
getVisibleRooms(roomsList, roomsCount, to, p.roomIndex, clipPort, water, count + 1);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void renderView(int roomIndex, bool water) {
|
||||
PROFILE_MARKER("VIEW");
|
||||
Core::Pass pass = Core::pass;
|
||||
|
||||
if (water && waterCache) {
|
||||
waterCache->reset();
|
||||
}
|
||||
|
||||
for (int i = 0; i < level.roomsCount; i++)
|
||||
level.rooms[i].flags.visible = false;
|
||||
|
||||
int roomsList[128];
|
||||
int roomsCount = 0;
|
||||
|
||||
getVisibleRooms(roomsList, roomsCount, TR::NO_ROOM, roomIndex, vec4(-1.0f, -1.0f, 1.0f, 1.0f), water);
|
||||
|
||||
if (water && waterCache) {
|
||||
for (int i = 0; i < roomsCount; i++)
|
||||
waterCache->setVisible(roomsList[i]);
|
||||
waterCache->renderReflect();
|
||||
waterCache->simulate();
|
||||
}
|
||||
|
||||
// clear visibility flag for rooms
|
||||
if (Core::pass != Core::passAmbient)
|
||||
for (int i = 0; i < level.entitiesCount; i++)
|
||||
level.entities[i].flags.rendered = false;
|
||||
|
||||
if (water) {
|
||||
Core::setTarget(NULL, true); // render to back buffer
|
||||
setupBinding();
|
||||
}
|
||||
|
||||
camera->setup(Core::pass == Core::passCompose);
|
||||
|
||||
Core::pass = pass;
|
||||
|
||||
renderRooms(roomsList, roomsCount);
|
||||
|
||||
if (Core::pass != Core::passAmbient)
|
||||
renderEntities();
|
||||
|
||||
if (water && waterCache && waterCache->visible) {
|
||||
waterCache->renderMask();
|
||||
waterCache->getRefract();
|
||||
waterCache->render();
|
||||
}
|
||||
}
|
||||
|
||||
void setupCubeCamera(const vec3 &pos, int face) {
|
||||
@@ -750,9 +866,10 @@ struct Level : IGame {
|
||||
Core::mViewInv = mat4(pos, pos + dir, up);
|
||||
Core::mView = Core::mViewInv.inverse();
|
||||
Core::mProj = mat4(90, 1.0f, camera->znear, camera->zfar);
|
||||
Core::mViewProj = Core::mProj * Core::mView;
|
||||
}
|
||||
|
||||
bool setupLightCamera() {
|
||||
void setupLightCamera() {
|
||||
vec3 pos = lara->getBoundingBox().center();
|
||||
|
||||
Core::mViewInv = mat4(lara->mainLightPos, pos, vec3(0, -1, 0));
|
||||
@@ -764,8 +881,6 @@ struct Level : IGame {
|
||||
bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f;
|
||||
|
||||
Core::mLightProj = bias * (Core::mProj * Core::mView);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void renderShadows(int roomIndex) {
|
||||
@@ -775,16 +890,18 @@ struct Level : IGame {
|
||||
shadow->unbind(sShadow);
|
||||
bool colorShadow = shadow->format == Texture::Format::RGBA ? true : false;
|
||||
if (colorShadow)
|
||||
Core::setClearColor(vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
Core::setTarget(shadow);
|
||||
if (!setupLightCamera()) return;
|
||||
Core::clear(true, true);
|
||||
Core::setClearColor(vec4(1.0f));
|
||||
Core::setTarget(shadow, true);
|
||||
setupLightCamera();
|
||||
Core::setCulling(cfBack);
|
||||
renderScene(roomIndex);
|
||||
|
||||
setup();
|
||||
renderView(roomIndex, false);
|
||||
|
||||
Core::invalidateTarget(!colorShadow, colorShadow);
|
||||
Core::setCulling(cfFront);
|
||||
if (colorShadow)
|
||||
Core::setClearColor(vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
Core::setClearColor(vec4(0.0f));
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
@@ -869,14 +986,14 @@ struct Level : IGame {
|
||||
glLoadIdentity();
|
||||
glOrtho(0, Core::width, 0, Core::height, 0, 1);
|
||||
|
||||
if (shadow)
|
||||
shadow->bind(sDiffuse);
|
||||
if (waterCache->reflect)
|
||||
waterCache->reflect->bind(sDiffuse);
|
||||
else
|
||||
atlas->bind(sDiffuse);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
Core::setCulling(cfNone);
|
||||
Core::setDepthTest(false);
|
||||
Core::setBlending(bmNone);
|
||||
|
||||
glColor3f(10, 10, 10);
|
||||
int w = Core::active.textures[sDiffuse]->width / 2;
|
||||
@@ -890,9 +1007,6 @@ struct Level : IGame {
|
||||
glColor3f(1, 1, 1);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
@@ -914,7 +1028,7 @@ struct Level : IGame {
|
||||
// Box bbox = lara->getBoundingBox();
|
||||
// Debug::Draw::box(bbox.min, bbox.max, vec4(1, 0, 1, 1));
|
||||
|
||||
Core::setBlending(bmAlpha);
|
||||
// Core::setBlending(bmAlpha);
|
||||
// Debug::Level::rooms(level, lara->pos, lara->getEntity().room);
|
||||
// Debug::Level::lights(level, lara->getRoomIndex(), lara);
|
||||
// Debug::Level::sectors(level, lara->getRoomIndex(), (int)lara->pos.y);
|
||||
@@ -928,7 +1042,7 @@ struct Level : IGame {
|
||||
// Debug::Level::path(level, (Enemy*)level.entities[86].controller);
|
||||
// Debug::Level::debugOverlaps(level, lara->box);
|
||||
|
||||
Core::setBlending(bmNone);
|
||||
// Core::setBlending(bmNone);
|
||||
|
||||
Debug::Level::info(level, lara->getEntity(), lara->animation);
|
||||
|
||||
@@ -945,28 +1059,14 @@ struct Level : IGame {
|
||||
|
||||
if (ambientCache)
|
||||
ambientCache->precessQueue();
|
||||
if (waterCache)
|
||||
waterCache->reset();
|
||||
if (shadow)
|
||||
renderShadows(lara->getRoomIndex());
|
||||
|
||||
Core::setClearStencil(128);
|
||||
Core::setTarget(NULL, true);
|
||||
if (shadow) shadow->bind(sShadow);
|
||||
Core::pass = Core::passCompose;
|
||||
|
||||
if (waterCache)
|
||||
waterCache->checkVisibility = true;
|
||||
|
||||
renderCompose(camera->getRoomIndex(), true);
|
||||
|
||||
if (waterCache) {
|
||||
waterCache->checkVisibility = false;
|
||||
if (waterCache->visible) {
|
||||
waterCache->renderMask();
|
||||
waterCache->getRefract();
|
||||
waterCache->simulate();
|
||||
waterCache->render();
|
||||
}
|
||||
}
|
||||
setup();
|
||||
renderView(camera->getRoomIndex(), true);
|
||||
}
|
||||
|
||||
void renderInventory() {
|
||||
@@ -1013,11 +1113,8 @@ struct Level : IGame {
|
||||
bool copyBg = title && lastTitle != title;
|
||||
|
||||
if (copyBg) {
|
||||
vec4 vp = Core::viewportDef;
|
||||
Core::defaultTarget = inventory.background[0];
|
||||
Core::setTarget(Core::defaultTarget, true);
|
||||
renderGame();
|
||||
Core::viewportDef = vp;
|
||||
Core::defaultTarget = NULL;
|
||||
|
||||
inventory.prepareBackground();
|
||||
|
191
src/mesh.h
191
src/mesh.h
@@ -10,15 +10,6 @@
|
||||
#define TEX_OXYGEN_BAR_X 1002
|
||||
#define TEX_OXYGEN_BAR_Y 1000
|
||||
|
||||
typedef unsigned short Index;
|
||||
|
||||
struct Vertex {
|
||||
short4 coord; // xyz - position, w - unused
|
||||
short4 texCoord; // xy - texture coordinates, z - anim tex range index, w - anim tex frame index
|
||||
short4 normal; // xyz - vertex normal<61> w - unused
|
||||
ubyte4 color; // xyz - color, w - intensity
|
||||
};
|
||||
|
||||
struct MeshRange {
|
||||
int iStart;
|
||||
int iCount;
|
||||
@@ -29,14 +20,16 @@ struct MeshRange {
|
||||
|
||||
void setup() const {
|
||||
glEnableVertexAttribArray(aCoord);
|
||||
glEnableVertexAttribArray(aTexCoord);
|
||||
glEnableVertexAttribArray(aNormal);
|
||||
glEnableVertexAttribArray(aTexCoord);
|
||||
glEnableVertexAttribArray(aParam);
|
||||
glEnableVertexAttribArray(aColor);
|
||||
|
||||
Vertex *v = (Vertex*)NULL + vStart;
|
||||
glVertexAttribPointer(aCoord, 4, GL_SHORT, false, sizeof(Vertex), &v->coord);
|
||||
glVertexAttribPointer(aTexCoord, 4, GL_SHORT, false, sizeof(Vertex), &v->texCoord);
|
||||
glVertexAttribPointer(aNormal, 4, GL_SHORT, true, sizeof(Vertex), &v->normal);
|
||||
glVertexAttribPointer(aTexCoord, 4, GL_SHORT, true, sizeof(Vertex), &v->texCoord);
|
||||
glVertexAttribPointer(aParam, 4, GL_UNSIGNED_BYTE, false, sizeof(Vertex), &v->param);
|
||||
glVertexAttribPointer(aColor, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex), &v->color);
|
||||
}
|
||||
|
||||
@@ -114,12 +107,6 @@ struct Mesh {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, Core::active.vBuffer = ID[1]);
|
||||
}
|
||||
|
||||
void DIP(const MeshRange &range) {
|
||||
glDrawElements(GL_TRIANGLES, range.iCount, GL_UNSIGNED_SHORT, (Index*)NULL + range.iStart);
|
||||
Core::stats.dips++;
|
||||
Core::stats.tris += range.iCount / 3;
|
||||
}
|
||||
|
||||
void render(const MeshRange &range) {
|
||||
range.bind(VAO);
|
||||
|
||||
@@ -128,15 +115,7 @@ struct Mesh {
|
||||
range.setup();
|
||||
};
|
||||
|
||||
if (Core::active.stencilTwoSide && Core::support.stencil == 0) {
|
||||
Core::setCulling(cfBack);
|
||||
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);
|
||||
DIP(range);
|
||||
Core::setCulling(cfFront);
|
||||
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);
|
||||
}
|
||||
|
||||
DIP(range);
|
||||
Core::DIP(range.iStart, range.iCount);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -189,7 +168,7 @@ struct MeshBuilder {
|
||||
} *models;
|
||||
MeshRange *sequences;
|
||||
// procedured
|
||||
MeshRange shadowBlob, shadowBox;
|
||||
MeshRange shadowBlob;
|
||||
MeshRange quad, circle;
|
||||
MeshRange plane;
|
||||
|
||||
@@ -286,13 +265,6 @@ struct MeshBuilder {
|
||||
iCount += shadowBlob.iCount;
|
||||
vCount += 8 * 2 + 1;
|
||||
|
||||
// shadow box (for stencil shadow volumes with degenerate triangles)
|
||||
shadowBox.vStart = vCount;
|
||||
shadowBox.iStart = iCount;
|
||||
shadowBox.iCount = (3 * (2 + 4)) * 6;
|
||||
iCount += shadowBox.iCount;
|
||||
vCount += 4 * 6;
|
||||
|
||||
// quad (post effect filter)
|
||||
quad.vStart = vCount;
|
||||
quad.iStart = iCount;
|
||||
@@ -402,8 +374,9 @@ struct MeshBuilder {
|
||||
// build shadow blob
|
||||
for (int i = 0; i < 9; i++) {
|
||||
Vertex &v0 = vertices[vCount + i * 2 + 0];
|
||||
v0.normal = { 0, -1, 0, 1 };
|
||||
v0.texCoord = { 32688, 32688, 0, 0 };
|
||||
v0.normal = { 0, -1, 0, 0 };
|
||||
v0.texCoord = { 32688, 32688, 32767, 32767 };
|
||||
v0.param = { 0, 0, 0, 0 };
|
||||
v0.color = { 0, 0, 0, 0 };
|
||||
|
||||
if (i == 8) {
|
||||
@@ -443,59 +416,6 @@ struct MeshBuilder {
|
||||
iCount += shadowBlob.iCount;
|
||||
aCount++;
|
||||
|
||||
// build shadow box volume
|
||||
{
|
||||
static const Index tmpIndices[] = {
|
||||
0,1,2, 0,2,3, 0,7,1, 0,4,7,
|
||||
1,11,2, 1,8,11, 2,15,3, 2,12,15,
|
||||
3,19,0, 3,16,19, 21,6,5, 21,20,6,
|
||||
20,10,9, 20,23,10, 23,14,13, 23,22,14,
|
||||
22,18,17, 22,21,18, 20,21,22, 20,22,23,
|
||||
7,6,9, 7,9,8, 11,10,13, 11,13,12,
|
||||
15,14,17, 15,17,16, 19,5,4, 19,18,5,
|
||||
4,6,7, 4,5,6, 8,9,10, 8,10,11,
|
||||
12,14,15, 12,13,14, 16,18,19, 16,17,18
|
||||
};
|
||||
static const short4 tmpCoords[] = {
|
||||
{ -1, -1, -1, 0 }, { 1, -1, -1, 0 }, { 1, 1, -1, 0 }, { -1, 1, -1, 0 },
|
||||
{ -1, -1, -1, 0 }, { -1, -1, 1, 0 }, { 1, -1, 1, 0 }, { 1, -1, -1, 0 },
|
||||
{ 1, -1, -1, 0 }, { 1, -1, 1, 0 }, { 1, 1, 1, 0 }, { 1, 1, -1, 0 },
|
||||
{ 1, 1, -1, 0 }, { 1, 1, 1, 0 }, { -1, 1, 1, 0 }, { -1, 1, -1, 0 },
|
||||
{ -1, 1, -1, 0 }, { -1, 1, 1, 0 }, { -1, -1, 1, 0 }, { -1, -1, -1, 0 },
|
||||
{ 1, -1, 1, 0 }, { -1, -1, 1, 0 }, { -1, 1, 1, 0 }, { 1, 1, 1, 0 },
|
||||
};
|
||||
|
||||
const short n = 32767;
|
||||
static const short4 tmpNormals[] = {
|
||||
{ 0, 0, -n, 0 },
|
||||
{ 0, -n, 0, 0 },
|
||||
{ n, 0, 0, 0 },
|
||||
{ 0, n, 0, 0 },
|
||||
{ -n, 0, 0, 0 },
|
||||
{ 0, 0, n, 0 },
|
||||
};
|
||||
|
||||
static const ubyte4 tmpColors[] = {
|
||||
{ 255, 0, 0, 0 },
|
||||
{ 0, 255, 0, 0 },
|
||||
{ 0, 0, 255, 0 },
|
||||
{ 255, 0, 255, 0 },
|
||||
{ 255, 255, 0, 0 },
|
||||
{ 0, 255, 255, 0 },
|
||||
};
|
||||
|
||||
memcpy(&indices[iCount], &tmpIndices[0], shadowBox.iCount * sizeof(Index));
|
||||
memset(&vertices[vCount], 0, 4 * 6 * sizeof(Vertex));
|
||||
for (int i = 0; i < 4 * 6; i++) {
|
||||
vertices[vCount + i].coord = tmpCoords[i];
|
||||
vertices[vCount + i].normal = tmpNormals[i / 4];
|
||||
vertices[vCount + i].color = tmpColors[i / 4];
|
||||
}
|
||||
iCount += shadowBox.iCount;
|
||||
vCount += 4 * 6;
|
||||
aCount++;
|
||||
}
|
||||
|
||||
// quad
|
||||
addQuad(indices, iCount, vCount, quad.vStart, vertices, &whiteTile);
|
||||
vertices[vCount + 3].coord = { -1, -1, 0, 0 };
|
||||
@@ -507,7 +427,8 @@ struct MeshBuilder {
|
||||
Vertex &v = vertices[vCount + i];
|
||||
v.normal = { 0, 0, 0, 0 };
|
||||
v.color = { 255, 255, 255, 255 };
|
||||
v.texCoord = { 32688, 32688, 0, 0 };
|
||||
v.texCoord = { 32688, 32688, 32767, 32767 };
|
||||
v.param = { 0, 0, 0, 0 };
|
||||
}
|
||||
vCount += 4;
|
||||
aCount++;
|
||||
@@ -522,7 +443,8 @@ struct MeshBuilder {
|
||||
v.coord = { short(pos.x), short(pos.y), 0, 0 };
|
||||
v.normal = { 0, 0, 0, 0 };
|
||||
v.color = { 255, 255, 255, 255 };
|
||||
v.texCoord = { 32688, 32688, 0, 0 };
|
||||
v.texCoord = { 32688, 32688, 32767, 32767 };
|
||||
v.param = { 0, 0, 0, 0 };
|
||||
|
||||
indices[iCount++] = i;
|
||||
indices[iCount++] = (i + 1) % CIRCLE_SEGS;
|
||||
@@ -576,7 +498,6 @@ struct MeshBuilder {
|
||||
for (int i = 0; i < level.modelsCount; i++)
|
||||
mesh->initRange(models[i].geometry);
|
||||
mesh->initRange(shadowBlob);
|
||||
mesh->initRange(shadowBox);
|
||||
mesh->initRange(quad);
|
||||
mesh->initRange(circle);
|
||||
mesh->initRange(plane);
|
||||
@@ -700,8 +621,11 @@ struct MeshBuilder {
|
||||
|
||||
if (opaque != (t.attribute == 0))
|
||||
continue;
|
||||
|
||||
addQuad(indices, iCount, vCount, vStart, vertices, &t);
|
||||
addQuad(indices, iCount, vCount, vStart, vertices, &t,
|
||||
d.vertices[f.vertices[0]].vertex,
|
||||
d.vertices[f.vertices[1]].vertex,
|
||||
d.vertices[f.vertices[2]].vertex,
|
||||
d.vertices[f.vertices[3]].vertex);
|
||||
|
||||
TR::Vertex n;
|
||||
CHECK_ROOM_NORMAL(n);
|
||||
@@ -761,7 +685,11 @@ struct MeshBuilder {
|
||||
|
||||
TR::Color24 c = textured ? COLOR_WHITE : level.getColor(f.texture);
|
||||
|
||||
addQuad(indices, iCount, vCount, vStart, vertices, &t);
|
||||
addQuad(indices, iCount, vCount, vStart, vertices, &t,
|
||||
mesh.vertices[f.vertices[0]].coord,
|
||||
mesh.vertices[f.vertices[1]].coord,
|
||||
mesh.vertices[f.vertices[2]].coord,
|
||||
mesh.vertices[f.vertices[3]].coord);
|
||||
|
||||
for (int k = 0; k < 4; k++) {
|
||||
TR::Mesh::Vertex &v = mesh.vertices[f.vertices[k]];
|
||||
@@ -808,7 +736,7 @@ struct MeshBuilder {
|
||||
int tx = (tile % 4) * 256;
|
||||
int ty = (tile / 4) * 256;
|
||||
return vec2( (float)(((tx + tex.texCoord[0].x) << 5) + 16),
|
||||
(float)(((ty + tex.texCoord[0].y) << 5) + 16) );
|
||||
(float)(((ty + tex.texCoord[0].y) << 5) + 16) ) * (1.0f / 32767.0f);
|
||||
}
|
||||
|
||||
void initAnimTextures(TR::Level &level) {
|
||||
@@ -846,7 +774,7 @@ struct MeshBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
TR::ObjectTexture* getAnimTexture(TR::ObjectTexture *tex, int &range, int &frame) {
|
||||
TR::ObjectTexture* getAnimTexture(TR::ObjectTexture *tex, uint8 &range, uint8 &frame) {
|
||||
range = frame = 0;
|
||||
if (!level->animTexturesDataSize)
|
||||
return tex;
|
||||
@@ -869,24 +797,37 @@ struct MeshBuilder {
|
||||
}
|
||||
|
||||
void addTexCoord(Vertex *vertices, int vCount, TR::ObjectTexture *tex, bool triangle) {
|
||||
int range, frame;
|
||||
uint8 range, frame;
|
||||
tex = getAnimTexture(tex, range, frame);
|
||||
|
||||
int tile = tex->tile.index;
|
||||
int tx = (tile % 4) * 256;
|
||||
int ty = (tile / 4) * 256;
|
||||
|
||||
|
||||
int count = triangle ? 3 : 4;
|
||||
for (int i = 0; i < count; i++) {
|
||||
Vertex &v = vertices[vCount + i];
|
||||
v.texCoord.x = ((tx + tex->texCoord[i].x) << 5) + 16;
|
||||
v.texCoord.y = ((ty + tex->texCoord[i].y) << 5) + 16;
|
||||
v.texCoord.z = range;
|
||||
v.texCoord.w = frame;
|
||||
v.texCoord.z = 32767;
|
||||
v.texCoord.w = 32767;
|
||||
v.param = { range, frame, 0, 0 };
|
||||
}
|
||||
|
||||
if (level->version == TR::Level::VER_TR1_PSX && !triangle)
|
||||
swap(vertices[vCount + 2].texCoord, vertices[vCount + 3].texCoord);
|
||||
/*
|
||||
short2 uv[4] = {
|
||||
{0, 0}, {32767, 0}, {32767, 32767}, {0, 32767}
|
||||
};
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
Vertex &v = vertices[vCount + i];
|
||||
v.texCoord.x = uv[i].x;
|
||||
v.texCoord.y = uv[i].y;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void addTriangle(Index *indices, int &iCount, int vCount, int vStart, Vertex *vertices, TR::ObjectTexture *tex) {
|
||||
@@ -917,6 +858,43 @@ struct MeshBuilder {
|
||||
if (tex) addTexCoord(vertices, vCount, tex, false);
|
||||
}
|
||||
|
||||
void addQuad(Index *indices, int &iCount, int &vCount, int vStart, Vertex *vertices, TR::ObjectTexture *tex,
|
||||
const short3 &c0, const short3 &c1, const short3 &c2, const short3 &c3) {
|
||||
addQuad(indices, iCount, vCount, vStart, vertices, tex);
|
||||
|
||||
vec3 a = c0 - c1;
|
||||
vec3 b = c3 - c2;
|
||||
vec3 c = c0 - c3;
|
||||
vec3 d = c1 - c2;
|
||||
|
||||
float aL = a.length();
|
||||
float bL = b.length();
|
||||
float cL = c.length();
|
||||
float dL = d.length();
|
||||
|
||||
float ab = a.dot(b) / (aL * bL);
|
||||
float cd = c.dot(d) / (cL * dL);
|
||||
|
||||
int16 tx = abs(vertices[vCount + 0].texCoord.x - vertices[vCount + 3].texCoord.x);
|
||||
int16 ty = abs(vertices[vCount + 0].texCoord.y - vertices[vCount + 3].texCoord.y);
|
||||
|
||||
if (ab > cd) {
|
||||
int k = (tx > ty) ? 3 : 2;
|
||||
|
||||
if (aL > bL)
|
||||
vertices[vCount + 2].texCoord[k] = vertices[vCount + 3].texCoord[k] = int16(bL / aL * 32767.0f);
|
||||
else
|
||||
vertices[vCount + 0].texCoord[k] = vertices[vCount + 1].texCoord[k] = int16(aL / bL * 32767.0f);
|
||||
} else {
|
||||
int k = (tx > ty) ? 2 : 3;
|
||||
|
||||
if (cL > dL) {
|
||||
vertices[vCount + 1].texCoord[k] = vertices[vCount + 2].texCoord[k] = int16(dL / cL * 32767.0f);
|
||||
} else
|
||||
vertices[vCount + 0].texCoord[k] = vertices[vCount + 3].texCoord[k] = int16(cL / dL * 32767.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void addSprite(Index *indices, Vertex *vertices, int &iCount, int &vCount, int vStart, int16 x, int16 y, int16 z, const TR::SpriteTexture &sprite, uint8 intensity, bool expand = false) {
|
||||
addQuad(indices, iCount, vCount, vStart, NULL, NULL);
|
||||
|
||||
@@ -939,9 +917,9 @@ struct MeshBuilder {
|
||||
quad[2].coord = { x1, y1, z, 0 };
|
||||
quad[3].coord = { x0, y1, z, 0 };
|
||||
|
||||
|
||||
quad[0].normal = quad[1].normal = quad[2].normal = quad[3].normal = { 0, 0, 0, 0 };
|
||||
quad[0].color = quad[1].color = quad[2].color = quad[3].color = { 255, 255, 255, intensity };
|
||||
quad[0].param = quad[1].param = quad[2].param = quad[3].param = { 0, 0, 0, 0 };
|
||||
|
||||
int tx = (sprite.tile % 4) * 256;
|
||||
int ty = (sprite.tile / 4) * 256;
|
||||
@@ -992,7 +970,8 @@ struct MeshBuilder {
|
||||
s = int(s) * 32767 / 1024;
|
||||
t = int(t) * 32767 / 1024;
|
||||
|
||||
v.texCoord = { s, t, 0, 0 };
|
||||
v.texCoord = { s, t, 32767, 32767 };
|
||||
v.param = { 0, 0, 0, 0 };
|
||||
}
|
||||
|
||||
vCount += 4;
|
||||
@@ -1018,7 +997,7 @@ struct MeshBuilder {
|
||||
Vertex &v = vertices[vCount + i];
|
||||
v.normal = { 0, 0, 0, 0 };
|
||||
v.color = *((ubyte4*)&color1);
|
||||
v.texCoord = { 32688, 32688, 0, 0 };
|
||||
v.texCoord = { 32688, 32688, 32767, 32767 };
|
||||
}
|
||||
|
||||
addQuad(indices, iCount, vCount, 0, vertices, NULL); vCount += 4;
|
||||
@@ -1038,7 +1017,7 @@ struct MeshBuilder {
|
||||
Vertex &v = vertices[vCount + i];
|
||||
v.normal = { 0, 0, 0, 0 };
|
||||
v.color = *((ubyte4*)&color2);
|
||||
v.texCoord = { 32688, 32688, 0, 0 };
|
||||
v.texCoord = { 32688, 32688, 32767, 32767 };
|
||||
}
|
||||
|
||||
addQuad(indices, iCount, vCount, 0, vertices, NULL); vCount += 4;
|
||||
@@ -1082,10 +1061,6 @@ struct MeshBuilder {
|
||||
mesh->render(shadowBlob);
|
||||
}
|
||||
|
||||
void renderShadowBox() {
|
||||
mesh->render(shadowBox);
|
||||
}
|
||||
|
||||
void renderQuad() {
|
||||
mesh->render(quad);
|
||||
}
|
||||
|
@@ -5,8 +5,9 @@
|
||||
|
||||
#define SHADER_ATTRIBS(E) \
|
||||
E( aCoord ) \
|
||||
E( aTexCoord ) \
|
||||
E( aNormal ) \
|
||||
E( aTexCoord ) \
|
||||
E( aParam ) \
|
||||
E( aColor )
|
||||
|
||||
#define SHADER_SAMPLERS(E) \
|
||||
@@ -21,7 +22,6 @@
|
||||
E( uParam ) \
|
||||
E( uTexParam ) \
|
||||
E( uViewProj ) \
|
||||
E( uViewInv ) \
|
||||
E( uBasis ) \
|
||||
E( uLightProj ) \
|
||||
E( uMaterial ) \
|
||||
@@ -32,7 +32,8 @@
|
||||
E( uAnimTexRanges ) \
|
||||
E( uAnimTexOffsets ) \
|
||||
E( uRoomSize ) \
|
||||
E( uPosScale )
|
||||
E( uPosScale ) \
|
||||
E( uContacts )
|
||||
|
||||
enum AttribType { SHADER_ATTRIBS(DECL_ENUM) aMAX };
|
||||
enum SamplerType { SHADER_SAMPLERS(DECL_ENUM) sMAX };
|
||||
|
@@ -16,10 +16,8 @@ varying vec4 vColor;
|
||||
attribute vec4 aTexCoord;
|
||||
attribute vec4 aColor;
|
||||
|
||||
#define TEXCOORD_SCALE (1.0 / 32767.0)
|
||||
|
||||
void main() {
|
||||
vTexCoord = aTexCoord.xy * TEXCOORD_SCALE;
|
||||
vTexCoord = aTexCoord.xy;
|
||||
vColor = aColor * uMaterial;
|
||||
gl_Position = uViewProj * vec4(aCoord.xy * uPosScale.zw + uPosScale.xy, 0.0, 1.0);
|
||||
}
|
||||
|
@@ -4,37 +4,49 @@ R"====(
|
||||
precision highp float;
|
||||
#endif
|
||||
|
||||
varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
#ifdef OPT_CONTACT
|
||||
varying vec3 vCoord;
|
||||
#endif
|
||||
|
||||
varying vec4 vTexCoord; // xy - atlas coords, zw - trapezoidal correction
|
||||
|
||||
#if defined(OPT_WATER) && defined(UNDERWATER)
|
||||
varying vec2 vCausticsCoord; // - xy caustics texture coord
|
||||
#endif
|
||||
|
||||
//uniform vec4 data[MAX_RANGES + MAX_OFFSETS + 4 + 4 + 1 + 1 + MAX_LIGHTS + MAX_LIGHTS + 1 + 6 + 1 + 32 * 2];
|
||||
|
||||
uniform vec2 uAnimTexRanges[MAX_RANGES];
|
||||
uniform vec2 uAnimTexOffsets[MAX_OFFSETS];
|
||||
uniform mat4 uLightProj;
|
||||
uniform mat4 uViewProj;
|
||||
uniform vec3 uViewPos;
|
||||
uniform vec4 uParam; // x - time, y - water height, z - clip plane sign, w - clip plane height
|
||||
uniform vec3 uLightPos[MAX_LIGHTS];
|
||||
uniform vec4 uLightColor[MAX_LIGHTS]; // xyz - color, w - radius * intensity
|
||||
uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ
|
||||
uniform vec3 uAmbient[6];
|
||||
uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
||||
uniform vec4 uBasis[32 * 2];
|
||||
|
||||
#ifndef PASS_SHADOW
|
||||
varying vec4 vViewVec; // xyz - dir * dist, w - coord.y
|
||||
uniform vec3 uViewPos;
|
||||
|
||||
varying vec4 vDiffuse;
|
||||
|
||||
#ifndef TYPE_FLASH
|
||||
#ifdef PASS_COMPOSE
|
||||
varying vec4 vNormal; // xyz - normal dir, w - fog factor
|
||||
varying vec3 vNormal; // xyz - normal dir
|
||||
varying vec4 vLightProj;
|
||||
varying vec3 vLightVec;
|
||||
varying vec4 vLightVec; // xyz - dir, w - fog factor
|
||||
|
||||
#ifdef OPT_SHADOW
|
||||
varying vec3 vAmbient;
|
||||
#endif
|
||||
|
||||
uniform vec3 uLightPos[4];
|
||||
uniform vec4 uLightColor[4]; // xyz - color, w - radius * intensity
|
||||
#endif
|
||||
|
||||
varying vec4 vLight; // 4 lights intensity
|
||||
|
||||
#if defined(OPT_WATER) && defined(UNDERWATER)
|
||||
uniform vec4 uRoomSize; // xy - minXZ, zw - maxXZ
|
||||
#endif
|
||||
varying vec4 vLight; // lights intensity (MAX_LIGHTS == 4)
|
||||
|
||||
#if defined(OPT_AMBIENT) && defined(TYPE_ENTITY)
|
||||
uniform vec3 uAmbient[6];
|
||||
|
||||
vec3 calcAmbient(vec3 n) {
|
||||
vec3 sqr = n * n;
|
||||
vec3 pos = step(0.0, n);
|
||||
@@ -44,33 +56,12 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
uniform vec4 uParam; // x - time, y - water height, z - clip plane sign, w - clip plane height
|
||||
uniform vec4 uMaterial; // x - diffuse, y - ambient, z - specular, w - alpha
|
||||
#endif
|
||||
|
||||
#ifdef VERTEX
|
||||
uniform mat4 uViewProj;
|
||||
|
||||
uniform mat4 uViewInv;
|
||||
|
||||
#ifndef PASS_AMBIENT
|
||||
uniform mat4 uLightProj;
|
||||
#endif
|
||||
|
||||
#ifdef PASS_COMPOSE
|
||||
uniform vec2 uAnimTexRanges[MAX_RANGES];
|
||||
uniform vec2 uAnimTexOffsets[MAX_OFFSETS];
|
||||
#endif
|
||||
|
||||
#ifdef TYPE_ENTITY
|
||||
uniform vec4 uBasis[32 * 2];
|
||||
#else
|
||||
uniform vec4 uBasis[2];
|
||||
#endif
|
||||
|
||||
attribute vec4 aCoord;
|
||||
attribute vec4 aTexCoord;
|
||||
attribute vec4 aParam;
|
||||
|
||||
#ifndef PASS_AMBIENT
|
||||
attribute vec4 aNormal;
|
||||
@@ -80,8 +71,6 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
attribute vec4 aColor;
|
||||
#endif
|
||||
|
||||
#define TEXCOORD_SCALE (1.0 / 32767.0)
|
||||
|
||||
vec3 mulQuat(vec4 q, vec3 v) {
|
||||
return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + v * q.w);
|
||||
}
|
||||
@@ -100,10 +89,12 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
vec4 rBasisPos = uBasis[1];
|
||||
#endif
|
||||
|
||||
vec4 coord = vec4(mulBasis(rBasisRot, rBasisPos, aCoord.xyz), rBasisPos.w);
|
||||
|
||||
vec4 coord;
|
||||
coord.w = rBasisPos.w; // visible flag
|
||||
#ifdef TYPE_SPRITE
|
||||
coord.xyz += uViewInv[0].xyz * aTexCoord.z - uViewInv[1].xyz * aTexCoord.w;
|
||||
coord.xyz = mulBasis(rBasisRot, rBasisPos + aCoord.xyz, vec3(aTexCoord.z, -aTexCoord.w, 0.0) * 32767.0);
|
||||
#else
|
||||
coord.xyz = mulBasis(rBasisRot, rBasisPos, aCoord.xyz);
|
||||
#endif
|
||||
|
||||
#ifndef PASS_SHADOW
|
||||
@@ -129,9 +120,12 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
fog = length(vViewVec.xyz);
|
||||
#endif
|
||||
|
||||
vNormal.w = clamp(1.0 / exp(fog), 0.0, 1.0);
|
||||
vLightVec.w = clamp(1.0 / exp(fog), 0.0, 1.0);
|
||||
#endif
|
||||
|
||||
#ifdef OPT_CONTACT
|
||||
vCoord = coord.xyz;
|
||||
#endif
|
||||
return coord;
|
||||
}
|
||||
|
||||
@@ -161,13 +155,15 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
vec3 lv2 = (uLightPos[2].xyz - coord) * uLightColor[2].w;
|
||||
vec3 lv3 = (uLightPos[3].xyz - coord) * uLightColor[3].w;
|
||||
|
||||
vLightVec = lv0;
|
||||
vLightVec.xyz = lv0;
|
||||
|
||||
vec4 lum, att;
|
||||
#ifdef TYPE_ENTITY
|
||||
lum.x = dot(vNormal.xyz, normalize(lv0)); att.x = dot(lv0, lv0);
|
||||
lum.x = dot(vNormal.xyz, normalize(lv0));
|
||||
att.x = dot(lv0, lv0);
|
||||
#else
|
||||
lum.x = aColor.w; att.x = 0.0;
|
||||
lum.x = aColor.w;
|
||||
att.x = 0.0;
|
||||
|
||||
#ifdef TYPE_SPRITE
|
||||
lum.x *= uMaterial.y;
|
||||
@@ -219,20 +215,18 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
}
|
||||
|
||||
void _uv(vec3 coord) {
|
||||
vTexCoord = aTexCoord;
|
||||
#if defined(PASS_COMPOSE) && !defined(TYPE_SPRITE)
|
||||
// animated texture coordinates
|
||||
vec2 range = uAnimTexRanges[int(aTexCoord.z)]; // x - start index, y - count
|
||||
float frame = fract((aTexCoord.w + uParam.x * 4.0 - range.x) / range.y) * range.y;
|
||||
vec2 range = uAnimTexRanges[int(aParam.x)]; // x - start index, y - count
|
||||
float frame = fract((aParam.y + uParam.x * 4.0 - range.x) / range.y) * range.y;
|
||||
vec2 offset = uAnimTexOffsets[int(range.x + frame)]; // texCoord offset from first frame
|
||||
vTexCoord.xy = (aTexCoord.xy + offset) * TEXCOORD_SCALE;
|
||||
#else
|
||||
vTexCoord.xy = aTexCoord.xy * TEXCOORD_SCALE;
|
||||
vTexCoord.xy += offset;
|
||||
vTexCoord.xy *= vTexCoord.zw;
|
||||
#endif
|
||||
|
||||
#if defined(OPT_WATER) && defined(UNDERWATER)
|
||||
vTexCoord.zw = clamp((coord.xz - uRoomSize.xy) / (uRoomSize.zw - uRoomSize.xy), vec2(0.0), vec2(1.0));
|
||||
#else
|
||||
vTexCoord.zw = vec2(1.0);
|
||||
vCausticsCoord.xy = clamp((coord.xz - uRoomSize.xy) / (uRoomSize.zw - uRoomSize.xy), vec2(0.0), vec2(1.0));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -346,13 +340,13 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
} else
|
||||
rShadow /= 4.0;
|
||||
|
||||
float fade = clamp(dot(vLightVec, vLightVec), 0.0, 1.0);
|
||||
float fade = clamp(dot(vLightVec.xyz, vLightVec.xyz), 0.0, 1.0);
|
||||
return rShadow + (1.0 - rShadow) * fade;
|
||||
}
|
||||
|
||||
float getShadow() {
|
||||
#ifdef TYPE_ROOM
|
||||
float vis = min(dot(vNormal.xyz, vLightVec), vLightProj.w);
|
||||
float vis = min(dot(vNormal.xyz, vLightVec.xyz), vLightProj.w);
|
||||
#else
|
||||
float vis = vLightProj.w;
|
||||
#endif
|
||||
@@ -369,13 +363,29 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
|
||||
#if defined(OPT_WATER) && defined(UNDERWATER)
|
||||
float calcCaustics(vec3 n) {
|
||||
vec2 cc = vCausticsCoord.xy;
|
||||
vec2 border = vec2(256.0) / (uRoomSize.zw - uRoomSize.xy);
|
||||
vec2 fade = smoothstep(vec2(0.0), border, vTexCoord.zw) * (1.0 - smoothstep(vec2(1.0) - border, vec2(1.0), vTexCoord.zw));
|
||||
return texture2D(sReflect, vTexCoord.zw).g * max(0.0, -n.y) * fade.x * fade.y;
|
||||
vec2 fade = smoothstep(vec2(0.0), border, cc) * (1.0 - smoothstep(vec2(1.0) - border, vec2(1.0), cc));
|
||||
return texture2D(sReflect, cc).g * max(0.0, -n.y) * fade.x * fade.y;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef OPT_CONTACT
|
||||
uniform vec4 uContacts[MAX_CONTACTS];
|
||||
|
||||
float getContactAO(vec3 p, vec3 n) {
|
||||
float res = 1.0;
|
||||
for (int i = 0; i < MAX_CONTACTS; i++) {
|
||||
vec3 v = uContacts[i].xyz - p;
|
||||
float a = uContacts[i].w;
|
||||
float o = a * clamp(dot(n, v), 0.0, 1.0) / dot(v, v);
|
||||
res *= clamp(1.0 - o, 0.0, 1.0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
#ifdef PASS_COMPOSE
|
||||
#ifdef CLIP_PLANE
|
||||
@@ -390,9 +400,13 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
vec3 rv = reflect(-normalize(vViewVec.xyz), normalize(vNormal.xyz));
|
||||
color = textureCube(sEnvironment, normalize(rv));
|
||||
#endif
|
||||
#else
|
||||
#if defined(PASS_COMPOSE) && !defined(TYPE_SPRITE)
|
||||
color = texture2D(sDiffuse, vTexCoord.xy / vTexCoord.zw);
|
||||
#else
|
||||
color = texture2D(sDiffuse, vTexCoord.xy);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ALPHA_TEST
|
||||
if (color.w <= 0.8)
|
||||
@@ -429,10 +443,16 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
#endif
|
||||
|
||||
#ifdef TYPE_ROOM
|
||||
|
||||
light += mix(vAmbient.x, vLight.x, getShadow());
|
||||
#if defined(OPT_WATER) && defined(UNDERWATER)
|
||||
light += calcCaustics(n);
|
||||
#endif
|
||||
|
||||
#ifdef OPT_CONTACT
|
||||
light *= getContactAO(vCoord, n) * 0.5 + 0.5;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TYPE_SPRITE
|
||||
@@ -444,7 +464,7 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
#endif
|
||||
|
||||
#ifdef TYPE_ENTITY
|
||||
color.xyz += calcSpecular(n, vViewVec.xyz, vLightVec, uLightColor[0], uMaterial.z * rShadow + 0.03);
|
||||
color.xyz += calcSpecular(n, vViewVec.xyz, vLightVec.xyz, uLightColor[0], uMaterial.z * rShadow + 0.03);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -460,9 +480,9 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - caustics coords
|
||||
|
||||
#if defined(PASS_COMPOSE) && !defined(TYPE_FLASH)
|
||||
#ifdef UNDERWATER
|
||||
color.xyz = mix(UNDERWATER_COLOR * 0.2, color.xyz, vNormal.w);
|
||||
color.xyz = mix(UNDERWATER_COLOR * 0.2, color.xyz, vLightVec.w);
|
||||
#else
|
||||
color.xyz = mix(vec3(0.0), color.xyz, vNormal.w);
|
||||
color.xyz = mix(vec3(0.0), color.xyz, vLightVec.w);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@@ -103,6 +103,37 @@ uniform sampler2D sNormal;
|
||||
return v;
|
||||
}
|
||||
|
||||
vec3 hash33(vec3 p3) {
|
||||
p3 = fract(p3 * vec3(.1031,.11369,.13787));
|
||||
p3 += dot(p3, p3.yxz+19.19);
|
||||
return -1.0 + 2.0 * fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));
|
||||
}
|
||||
|
||||
float simplex_noise(vec3 p) { // https://www.shadertoy.com/view/4sc3z2
|
||||
const float K1 = 0.333333333;
|
||||
const float K2 = 0.166666667;
|
||||
|
||||
vec3 i = floor(p + (p.x + p.y + p.z) * K1);
|
||||
vec3 d0 = p - (i - (i.x + i.y + i.z) * K2);
|
||||
|
||||
vec3 e = step(vec3(0.0), d0 - d0.yzx);
|
||||
vec3 i1 = e * (1.0 - e.zxy);
|
||||
vec3 i2 = 1.0 - e.zxy * (1.0 - e);
|
||||
|
||||
vec3 d1 = d0 - (i1 - 1.0 * K2);
|
||||
vec3 d2 = d0 - (i2 - 2.0 * K2);
|
||||
vec3 d3 = d0 - (1.0 - 3.0 * K2);
|
||||
|
||||
vec4 h = max(0.6 - vec4(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), 0.0);
|
||||
vec4 n = h * h * h * h * vec4(dot(d0, hash33(i)), dot(d1, hash33(i + i1)), dot(d2, hash33(i + i2)), dot(d3, hash33(i + 1.0)));
|
||||
|
||||
return dot(vec4(31.316), n);
|
||||
}
|
||||
|
||||
float h(vec2 tc) {
|
||||
return simplex_noise(vec3(tc * 16.0, uParam.w)) * 0.001;
|
||||
}
|
||||
|
||||
vec4 calc() {
|
||||
vec2 tc = gl_FragCoord.xy * uTexParam.xy;
|
||||
|
||||
@@ -125,7 +156,7 @@ uniform sampler2D sNormal;
|
||||
|
||||
v.y += (average - v.x) * vel;
|
||||
v.y *= vis;
|
||||
v.x += v.y;
|
||||
v.x += v.y + h(tc);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
@@ -62,9 +62,7 @@ struct Sprite : Controller {
|
||||
}
|
||||
|
||||
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);
|
||||
Core::active.shader->setParam(uBasis, Basis(Core::mViewInv.getRot(), pos));
|
||||
mesh->renderSprite(-(getEntity().modelIndex + 1), frame);
|
||||
}
|
||||
};
|
||||
|
@@ -11,7 +11,7 @@ struct Texture {
|
||||
Format format;
|
||||
bool cube;
|
||||
|
||||
Texture(int width, int height, Format format, bool cube, void *data = NULL, bool filter = true) : cube(cube) {
|
||||
Texture(int width, int height, Format format, bool cube, void *data = NULL, bool filter = true, bool mips = false) : cube(cube) {
|
||||
if (!Core::support.texNPOT) {
|
||||
width = nextPow2(width);
|
||||
height = nextPow2(height);
|
||||
@@ -65,8 +65,9 @@ struct Texture {
|
||||
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, color);
|
||||
}
|
||||
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter ? (mips ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) : ( mips ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST ));
|
||||
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter ? GL_LINEAR : GL_NEAREST);
|
||||
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter ? GL_LINEAR : GL_NEAREST);
|
||||
|
||||
struct FormatDesc {
|
||||
GLuint ifmt, fmt;
|
||||
|
2
src/ui.h
2
src/ui.h
@@ -205,7 +205,7 @@ namespace UI {
|
||||
" SHIFT - Walk@"
|
||||
" SPACE - Draw Weapon@"
|
||||
" CTRL - Action@"
|
||||
" ALT - Jump@"
|
||||
" D - Jump@"
|
||||
" Z - Step Left@"
|
||||
" X - Step Right@"
|
||||
" A - Roll@"
|
||||
|
16
src/utils.h
16
src/utils.h
@@ -271,6 +271,9 @@ struct vec4 {
|
||||
vec4(const vec3 &xyz, float w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w) {}
|
||||
vec4(const vec2 &xy, const vec2 &zw) : x(xy.x), y(xy.y), z(zw.x), w(zw.y) {}
|
||||
|
||||
inline bool operator == (const vec4 &v) const { return x == v.x && y == v.y && z == v.z && w == v.w; }
|
||||
inline bool operator != (const vec4 &v) const { return !(*this == v); }
|
||||
|
||||
vec4 operator + (const vec4 &v) const { return vec4(x + v.x, y + v.y, z + v.z, w + v.w); }
|
||||
vec4 operator - (const vec4 &v) const { return vec4(x - v.x, y - v.y, z - v.z, w - v.w); }
|
||||
vec4 operator * (const vec4 &v) const { return vec4(x*v.x, y*v.y, z*v.z, w*v.w); }
|
||||
@@ -599,7 +602,7 @@ struct mat4 {
|
||||
quat getRot() const {
|
||||
float t, s;
|
||||
t = 1.0f + e00 + e11 + e22;
|
||||
if (t > EPS) {
|
||||
if (t > 0.0001f) {
|
||||
s = 0.5f / sqrtf(t);
|
||||
return quat((e21 - e12) * s, (e02 - e20) * s, (e10 - e01) * s, 0.25f / s);
|
||||
} else
|
||||
@@ -711,12 +714,23 @@ struct short2 {
|
||||
|
||||
struct short3 {
|
||||
int16 x, y, z;
|
||||
|
||||
short3() {}
|
||||
short3(int16 x, int16 y, int16 z) : x(x), y(y), z(z) {}
|
||||
|
||||
operator vec3() const { return vec3((float)x, (float)y, (float)z); };
|
||||
|
||||
short3 operator + (const short3 &v) const { return short3(x + v.x, y + v.y, z + v.z); }
|
||||
short3 operator - (const short3 &v) const { return short3(x - v.x, y - v.y, z - v.z); }
|
||||
};
|
||||
|
||||
struct short4 {
|
||||
int16 x, y, z, w;
|
||||
|
||||
operator vec3() const { return vec3((float)x, (float)y, (float)z); };
|
||||
operator short3() const { return *((short3*)this); }
|
||||
|
||||
inline int16& operator [] (int index) const { ASSERT(index >= 0 && index <= 3); return ((int16*)this)[index]; }
|
||||
};
|
||||
|
||||
quat rotYXZ(const vec3 &a) {
|
||||
|
Reference in New Issue
Block a user