From 67d89d1e1d845059e9870184ba1eff30a418cd60 Mon Sep 17 00:00:00 2001 From: XProger Date: Sun, 15 Apr 2018 02:20:09 +0300 Subject: [PATCH] #15 RT management rework; #23 per-object shadows (sm atlas) --- src/cache.h | 45 ++--- src/character.h | 3 +- src/controller.h | 33 +++- src/core.h | 79 ++++++--- src/debug.h | 3 +- src/inventory.h | 12 +- src/lara.h | 3 +- src/level.h | 164 +++++++++++++----- .../android/app/src/main/cpp/main.cpp | 2 +- 9 files changed, 226 insertions(+), 118 deletions(-) diff --git a/src/cache.h b/src/cache.h index 71d8aa0..346f8fd 100644 --- a/src/cache.h +++ b/src/cache.h @@ -8,8 +8,6 @@ #define NO_CLIP_PLANE 1000000.0f -#define SHADOW_TEX_SIZE 1024 - #define WATER_FOG_DIST (6 * 1024) //#define WATER_USE_GRID #define UNDERWATER_COLOR "#define UNDERWATER_COLOR vec3(0.6, 0.9, 0.9)\n" @@ -144,7 +142,7 @@ struct ShaderCache { src = SHADER; typ = typeNames[type]; - sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_CONTACTS %d\n#define WATER_FOG_DIST (1.0/%d.0)\n#define SHADOW_TEX_SIZE %d.0\n", ext, passNames[pass], typ, MAX_LIGHTS, MAX_CONTACTS, WATER_FOG_DIST, SHADOW_TEX_SIZE); + sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_CONTACTS %d\n#define WATER_FOG_DIST (1.0/%d.0)\n#define SHADOW_TEXEL vec3(1.0 / %d.0, 1.0 / %d.0, 0.0)\n#define SHADOW_OBJ_MAX %d\n", ext, passNames[pass], typ, MAX_LIGHTS, MAX_CONTACTS, WATER_FOG_DIST, SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, SHADOW_OBJ_MAX); #ifdef MERGE_SPRITES if (type == Shader::SPRITE) strcat(def, "#define ALIGN_SPRITES 1\n"); @@ -211,7 +209,7 @@ struct ShaderCache { shader->bind(); // TODO: bindable uniform block shader->setParam(uViewProj, Core::mViewProj); - shader->setParam(uLightProj, Core::mLightProj); + shader->setParam(uLightProj, Core::mLightProj[0], SHADOW_OBJ_MAX); shader->setParam(uViewPos, Core::viewPos); shader->setParam(uParam, Core::params); shader->setParam(uFogParams, Core::fogParams); @@ -306,7 +304,7 @@ struct AmbientCache { for (int j = 0; j < 6; j++) { Texture *src = textures[j * 4 + i - 1]; Texture *dst = textures[j * 4 + i]; - Core::setTarget(dst, CLEAR_ALL); + Core::setRenderTarget(dst, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR); src->bind(sDiffuse); game->getMesh()->renderQuad(); } @@ -314,7 +312,7 @@ struct AmbientCache { // get result color from 1x1 textures for (int j = 0; j < 6; j++) { - Core::setTarget(textures[j * 4 + 3]); + Core::setRenderTarget(textures[j * 4 + 3], RT_STORE_COLOR); colors[j] = Core::copyPixel(0, 0).xyz(); } @@ -462,25 +460,24 @@ struct WaterCache { m[(x - minX) + w * (z - minZ)] = hasWater ? 0xF800 : 0; } + mask = new Texture(w, h, Texture::RGB16, Texture::NEAREST, m); + delete[] m; size = vec3(float((maxX - minX) * 512), 1.0f, float((maxZ - minZ) * 512)); // half size pos = vec3(r.info.x + minX * 1024 + size.x, float(posY), r.info.z + minZ * 1024 + size.z); - data[0] = new Texture(w * 64, h * 64, Texture::RGBA_HALF); - data[1] = new Texture(w * 64, h * 64, Texture::RGBA_HALF); + int *mf = new int[4 * w * 64 * h * 64]; + memset(mf, 0, sizeof(int) * 4 * w * 64 * h * 64); + data[0] = new Texture(w * 64, h * 64, Texture::RGBA_HALF, 0, mf); + data[1] = new Texture(w * 64, h * 64, Texture::RGBA_HALF); + delete[] mf; + caustics = Core::settings.detail.water > Core::Settings::MEDIUM ? new Texture(512, 512, Texture::RGBA) : NULL; #ifdef BLUR_CAUSTICS caustics_tmp = Core::settings.detail.water > Core::Settings::MEDIUM ? new Texture(512, 512, Texture::RGBA) : NULL; #endif - mask = new Texture(w, h, Texture::RGB16, Texture::NEAREST, m); - delete[] m; blank = false; - - // texture may be initialized with trash, so... - Core::setTarget(data[0], CLEAR_ALL); - Core::validateRenderState(); // immediate clear - Core::invalidateTarget(false, true); } void deinit() { @@ -631,15 +628,15 @@ struct WaterCache { Core::active.shader->setParam(uParam, vec4(p.x, p.z, drop.radius * DETAIL, -drop.strength)); item.data[0]->bind(sDiffuse); - Core::setTarget(item.data[1], CLEAR_ALL); + Core::setRenderTarget(item.data[1], RT_STORE_COLOR); Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f)); game->getMesh()->renderQuad(); - Core::invalidateTarget(false, true); swap(item.data[0], item.data[1]); } } void step(Item &item) { + item.timer = SIMULATE_TIMESTEP; if (item.timer < SIMULATE_TIMESTEP) return; game->setShader(Core::passWater, Shader::WATER_STEP); @@ -649,10 +646,9 @@ struct WaterCache { while (item.timer >= SIMULATE_TIMESTEP) { // water step item.data[0]->bind(sDiffuse); - Core::setTarget(item.data[1], CLEAR_ALL); + Core::setRenderTarget(item.data[1], RT_STORE_COLOR); Core::setViewport(0, 0, int(item.size.x * DETAIL * 2.0f + 0.5f), int(item.size.z * DETAIL * 2.0f + 0.5f)); game->getMesh()->renderQuad(); - Core::invalidateTarget(false, true); swap(item.data[0], item.data[1]); item.timer -= SIMULATE_TIMESTEP; } @@ -669,9 +665,8 @@ struct WaterCache { Core::whiteTex->bind(sReflect); item.data[0]->bind(sNormal); - Core::setTarget(item.caustics, CLEAR_ALL); + Core::setRenderTarget(item.caustics, RT_STORE_COLOR); game->getMesh()->renderPlane(); - Core::invalidateTarget(false, true); #ifdef BLUR_CAUSTICS // v blur Core::setTarget(item.caustics_tmp, CLEAR_ALL); @@ -735,10 +730,6 @@ struct WaterCache { if (!refract || w != refract->origWidth || h != refract->origHeight) { delete refract; refract = new Texture(w, h, Texture::RGBA, false); - Core::setTarget(refract, CLEAR_ALL); - Core::validateRenderState(); // immediate clear - Core::invalidateTarget(false, true); - Core::setTarget(NULL); } Core::copyTarget(refract, 0, 0, int(Core::viewportDef.x), int(Core::viewportDef.y), w, h); // copy framebuffer into refraction texture } @@ -774,8 +765,7 @@ struct WaterCache { } // render mirror reflection - Core::setTarget(reflect, CLEAR_ALL); - Core::validateRenderState(); + Core::setRenderTarget(reflect, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR); Camera *camera = (Camera*)game->getCamera(); game->setupBinding(); @@ -829,7 +819,6 @@ struct WaterCache { game->renderView(TR::NO_ROOM, false, false, roomsCount, roomsList); } - Core::invalidateTarget(false, true); game->setClipParams(1.0f, NO_CLIP_PLANE); camera->reflectPlane = NULL; diff --git a/src/character.h b/src/character.h index 8c2cd7c..a266ba4 100644 --- a/src/character.h +++ b/src/character.h @@ -266,8 +266,7 @@ struct Character : Controller { void addSparks(uint32 mask) { Sphere spheres[MAX_SPHERES]; - int count; - getSpheres(spheres, count); + int count = getSpheres(spheres); for (int i = 0; i < count; i++) if (mask & (1 << i)) { vec3 sprPos = spheres[i].center + (vec3(randf(), randf(), randf()) * 2.0f - 1.0f) * spheres[i].radius; diff --git a/src/controller.h b/src/controller.h index bc3d15c..d3df251 100644 --- a/src/controller.h +++ b/src/controller.h @@ -699,21 +699,43 @@ struct Controller { return animation.getBoundingBox(vec3(0, 0, 0), oriented ? getEntity().rotation.value / 0x4000 : 0); } - void getSpheres(Sphere *spheres, int &count) { + int getSpheres(Sphere *spheres) { const TR::Model *m = getModel(); ASSERT(m->mCount <= MAX_SPHERES); updateJoints(); - count = 0; + int count = 0; for (int i = 0; i < m->mCount; i++) { TR::Mesh &aMesh = level->meshes[level->meshOffsets[m->mStart + i]]; if (aMesh.radius <= 0) continue; vec3 center = joints[i] * aMesh.center; spheres[count++] = Sphere(center, aMesh.radius); } + return count; } + Box getSpheresBox(bool local = false) { + Sphere spheres[MAX_SPHERES]; + int count = getSpheres(spheres); + if (count) { + + if (local) { + mat4 m = getMatrix().inverseOrtho(); + for (int i = 0; i < count; i++) + spheres[i].center = m * spheres[i].center; + } + + Box box(spheres[0].center - vec3(spheres[0].radius), spheres[0].center + vec3(spheres[0].radius)); + for (int i = 1; i < count; i++) + box += Box(spheres[i].center - vec3(spheres[i].radius), spheres[i].center + vec3(spheres[i].radius)); + + return box; + } else + return local ? getBoundingBoxLocal() : getBoundingBox(); + } + + int collide(Controller *controller, bool checkBoxes = true) { const TR::Model *a = getModel(); const TR::Model *b = controller->getModel(); @@ -728,10 +750,9 @@ struct Controller { Sphere aSpheres[MAX_SPHERES]; Sphere bSpheres[MAX_SPHERES]; - int aCount, bCount; - getSpheres(aSpheres, aCount); - controller->getSpheres(bSpheres, bCount); + int aCount = getSpheres(aSpheres); + int bCount = controller->getSpheres(bSpheres); int mask = 0; for (int i = 0; i < aCount; i++) @@ -1114,7 +1135,7 @@ struct Controller { if ((light.color.r | light.color.g | light.color.b) == 0) continue; vec3 dir = vec3(float(light.x), float(light.y), float(light.z)) - center; - float att = max(0.0f, 1.0f - dir.length2() / float(light.radius) / float(light.radius)) * ((light.color.r + light.color.g + light.color.b) / (3.0f * 255.0f)); + float att = max(0.0f, 1.0f - dir.length2() / SQR(light.radius)) * ((light.color.r + light.color.g + light.color.b) / (3.0f * 255.0f)); if (att > maxAtt) { maxAtt = att; diff --git a/src/core.h b/src/core.h index df935bb..18b0f9f 100644 --- a/src/core.h +++ b/src/core.h @@ -5,6 +5,10 @@ #define USE_INFLATE #endif +#ifdef _DEBUG + #define PROFILE +#endif + #include #define OS_FILEIO_CACHE @@ -182,6 +186,13 @@ #include "utils.h" +#define SHADOW_OBJ_COLS 4 +#define SHADOW_OBJ_ROWS 2 +#define SHADOW_TEX_TILE 128 +#define SHADOW_TEX_WIDTH (SHADOW_OBJ_COLS * SHADOW_TEX_TILE) +#define SHADOW_TEX_HEIGHT (SHADOW_OBJ_ROWS * SHADOW_TEX_TILE) +#define SHADOW_OBJ_MAX (SHADOW_OBJ_COLS * SHADOW_OBJ_ROWS) + extern void* osMutexInit (); extern void osMutexFree (void *obj); extern void osMutexLock (void *obj); @@ -276,6 +287,16 @@ struct KeySet { KeySet(InputKey key, JoyKey joy) : key(key), joy(joy) {} }; +enum RenderTargetOp { + RT_CLEAR_COLOR = 0x0001, + RT_LOAD_COLOR = 0x0002, + RT_STORE_COLOR = 0x0004, + + RT_CLEAR_DEPTH = 0x0008, + RT_LOAD_DEPTH = 0x0010, + RT_STORE_DEPTH = 0x0020, +}; + namespace Core { float deltaTime; int lastTime; @@ -616,7 +637,8 @@ enum BlendMode { bmNone, bmAlpha, bmAdd, bmMult, bmPremult }; namespace Core { float eye; vec4 viewport, viewportDef; - mat4 mModel, mView, mProj, mViewProj, mViewInv, mLightProj; + mat4 mModel, mView, mProj, mViewProj, mViewInv; + mat4 mLightProj[SHADOW_OBJ_MAX]; Basis basis; vec3 viewPos; vec4 lightPos[MAX_LIGHTS]; @@ -651,9 +673,10 @@ namespace Core { Shader *shader; Texture *textures[8]; Texture *target; + uint32 targetFace; + uint32 targetOp; vec4 viewport; vec4 material; - uint32 targetFace; #ifdef _PSP Index *iBuffer; VertexGPU *vBuffer; @@ -670,8 +693,8 @@ namespace Core { struct ReqTarget { Texture *texture; - uint8 clear; - uint8 face; + uint32 op; + uint32 face; } reqTarget; struct Stats { @@ -1191,8 +1214,19 @@ namespace Core { if (!mask) return; if (mask & RS_TARGET) { + #ifdef MOBILE + if (support.discardFrame) { + int count = 0; + GLenum discard[2]; + if (!(active.targetOp & RT_STORE_COLOR)) discard[count++] = active.target ? GL_COLOR_ATTACHMENT0 : GL_COLOR_EXT; + if (!(active.targetOp & RT_STORE_DEPTH)) discard[count++] = active.target ? GL_DEPTH_ATTACHMENT : GL_DEPTH_EXT; + if (count) + glDiscardFramebufferEXT(GL_FRAMEBUFFER, count, discard); + } + #endif + Texture *target = reqTarget.texture; - uint8 face = reqTarget.face; + uint32 face = reqTarget.face; if (target != active.target || face != active.targetFace) { #ifdef _PSP @@ -1221,6 +1255,7 @@ namespace Core { #endif active.target = target; + active.targetOp = reqTarget.op; active.targetFace = face; } } @@ -1334,16 +1369,16 @@ namespace Core { } #endif if (mask & RS_TARGET) { - if (reqTarget.clear) { + int clear = 0; #ifdef _PSP - sceGuClear(((reqTarget.clear & CLEAR_COLOR) ? GU_COLOR_BUFFER_BIT : 0) | - ((reqTarget.clear & CLEAR_DEPTH) ? GU_DEPTH_BUFFER_BIT : 0) | - GU_FAST_CLEAR_BIT); + if (reqTarget.op & RT_CLEAR_COLOR) clear |= GU_COLOR_BUFFER_BIT; + if (reqTarget.op & RT_CLEAR_DEPTH) clear |= GU_DEPTH_BUFFER_BIT; + if (clear) sceGuClear(clear | GU_FAST_CLEAR_BIT); #else - glClear(((reqTarget.clear & CLEAR_COLOR) ? GL_COLOR_BUFFER_BIT : 0) | - ((reqTarget.clear & CLEAR_DEPTH) ? GL_DEPTH_BUFFER_BIT : 0)); + if (reqTarget.op & RT_CLEAR_COLOR) clear |= GL_COLOR_BUFFER_BIT; + if (reqTarget.op & RT_CLEAR_DEPTH) clear |= GL_DEPTH_BUFFER_BIT; + if (clear) glClear(clear); #endif - } renderState &= ~RS_TARGET; } @@ -1367,6 +1402,10 @@ namespace Core { renderState |= RS_VIEWPORT; } + void setViewport(const vec4 &vp) { + setViewport(int(vp.x), int(vp.y), int(vp.z), int(vp.w)); + } + void setCulling(CullFace mode) { renderState &= ~RS_CULL; switch (mode) { @@ -1415,19 +1454,7 @@ namespace Core { renderState &= ~RS_DEPTH_TEST; } - void invalidateTarget(bool color, bool depth) { - #ifdef MOBILE - if (support.discardFrame && (color || depth)) { - int count = 0; - GLenum discard[2]; - if (color) discard[count++] = active.target ? GL_COLOR_ATTACHMENT0 : GL_COLOR_EXT; - if (depth) discard[count++] = active.target ? GL_DEPTH_ATTACHMENT : GL_DEPTH_EXT; - glDiscardFramebufferEXT(GL_FRAMEBUFFER, count, discard); - } - #endif - } - - void setTarget(Texture *target, uint8 clear = 0, uint8 face = 0) { + void setRenderTarget(Texture *target, int op, int face = 0) { if (!target) target = defaultTarget; @@ -1440,7 +1467,7 @@ namespace Core { setViewport(0, 0, target->width, target->height); reqTarget.texture = target; - reqTarget.clear = clear; + reqTarget.op = op; reqTarget.face = face; renderState |= RS_TARGET; } diff --git a/src/debug.h b/src/debug.h index 0364077..292dee8 100644 --- a/src/debug.h +++ b/src/debug.h @@ -617,8 +617,7 @@ namespace Debug { Debug::Draw::box(matrix, box.min, box.max, bboxIntersect ? vec4(1, 0, 0, 1): vec4(1)); Sphere spheres[MAX_SPHERES]; - int count; - controller->getSpheres(spheres, count); + int count = controller->getSpheres(spheres); for (int joint = 0; joint < count; joint++) { Sphere &sphere = spheres[joint]; diff --git a/src/inventory.h b/src/inventory.h index 69c031b..8598b12 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -1121,21 +1121,21 @@ struct Inventory { // #else // vertical blur - Core::setTarget(background[1], CLEAR_COLOR); + Core::setRenderTarget(background[1], RT_STORE_COLOR); game->setShader(Core::passFilter, Shader::FILTER_BLUR, false, false); Core::active.shader->setParam(uParam, vec4(0, 1, 1.0f / INVENTORY_BG_SIZE, 0));; background[0]->bind(sDiffuse); game->getMesh()->renderQuad(); // horizontal blur - Core::setTarget(background[0], CLEAR_COLOR); + Core::setRenderTarget(background[0], RT_STORE_COLOR); game->setShader(Core::passFilter, Shader::FILTER_BLUR, false, false); Core::active.shader->setParam(uParam, vec4(1, 0, 1.0f / INVENTORY_BG_SIZE, 0));; background[1]->bind(sDiffuse); game->getMesh()->renderQuad(); // grayscale - Core::setTarget(background[1], CLEAR_COLOR); + Core::setRenderTarget(background[1], RT_STORE_COLOR); game->setShader(Core::passFilter, Shader::FILTER_GRAYSCALE, false, false); Core::active.shader->setParam(uParam, vec4(1, 0, 0, 0)); background[0]->bind(sDiffuse); @@ -1144,8 +1144,6 @@ struct Inventory { swap(background[0], background[1]); #endif - Core::setTarget(NULL, CLEAR_ALL); // TODO: ??? - Core::setDepthTest(true); } @@ -1389,7 +1387,6 @@ struct Inventory { } void renderGameBG() { - Core::setTarget(NULL, CLEAR_DEPTH); #ifdef _PSP return; #endif @@ -1492,7 +1489,8 @@ struct Inventory { // items game->setupBinding(); - Core::mLightProj.identity(); + for (int i = 0; i < SHADOW_OBJ_MAX; i++) + Core::mLightProj[i].identity(); setupCamera(aspect); diff --git a/src/lara.h b/src/lara.h index c9805cf..3f1aacb 100644 --- a/src/lara.h +++ b/src/lara.h @@ -1376,8 +1376,7 @@ struct Lara : Character { t *= v.length(); v = v.normal(); Sphere spheres[MAX_SPHERES]; - int count; - target->getSpheres(spheres, count); + int count = target->getSpheres(spheres); for (int i = 0; i < count; i++) { float st; if (spheres[i].intersect(from, v, st)) { diff --git a/src/level.h b/src/level.h index 64b7a83..9851a53 100644 --- a/src/level.h +++ b/src/level.h @@ -261,7 +261,7 @@ struct Level : IGame { if (rebuildShadows) { delete shadow; - shadow = Core::settings.detail.shadows > Core::Settings::LOW ? new Texture(SHADOW_TEX_SIZE, SHADOW_TEX_SIZE, Texture::SHADOW, false) : NULL; + shadow = Core::settings.detail.shadows > Core::Settings::LOW ? new Texture(SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, Texture::SHADOW, false) : NULL; } if (rebuildWater) { @@ -422,9 +422,8 @@ struct Level : IGame { setupCubeCamera(pos, i); Core::pass = pass; Texture *target = (targets[0]->opt & Texture::CUBEMAP) ? targets[0] : targets[i * stride]; - Core::setTarget(target, CLEAR_ALL, i); + Core::setRenderTarget(target, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR, i); renderView(roomIndex, false, false); - Core::invalidateTarget(false, true); } Core::pass = tmpPass; } @@ -678,7 +677,7 @@ struct Level : IGame { zoneCache = new ZoneCache(this); ambientCache = Core::settings.detail.lighting > Core::Settings::MEDIUM ? new AmbientCache(this) : NULL; waterCache = Core::settings.detail.water > Core::Settings::LOW ? new WaterCache(this) : NULL; - shadow = Core::settings.detail.shadows > Core::Settings::LOW ? new Texture(SHADOW_TEX_SIZE, SHADOW_TEX_SIZE, Texture::SHADOW, false) : NULL; + shadow = Core::settings.detail.shadows > Core::Settings::LOW ? new Texture(SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, Texture::SHADOW, false) : NULL; initReflections(); @@ -714,9 +713,6 @@ struct Level : IGame { } */ - Core::setTarget(NULL); - Core::validateRenderState(); - Core::resetTime(); } @@ -1278,11 +1274,10 @@ struct Level : IGame { if (Core::settings.detail.shadows > Core::Settings::MEDIUM) { Sphere spheres[MAX_CONTACTS]; - int spheresCount; - player->getSpheres(spheres, spheresCount); + int count = player->getSpheres(spheres); for (int i = 0; i < MAX_CONTACTS; i++) - if (i < spheresCount) + if (i < count) Core::contacts[i] = vec4(spheres[i].center, PI * spheres[i].radius * spheres[i].radius * 0.25f); else Core::contacts[i] = vec4(0.0f); @@ -1874,10 +1869,7 @@ struct Level : IGame { } if (water) { - //bool clear = Core::settings.detail.stereo == Core::Settings::STEREO_VR; - //clear |= Core::settings.detail.stereo == Core::Settings::STEREO_OFF && players[1] == NULL; - bool clear = true; - Core::setTarget(NULL, clear ? CLEAR_ALL : 0); // render to back buffer + Core::setRenderTarget(NULL, RT_CLEAR_COLOR | RT_CLEAR_DEPTH | RT_STORE_COLOR); // render to back buffer setupBinding(); } @@ -1935,25 +1927,112 @@ struct Level : IGame { camera->setup(false); } - void setupLightCamera() { - vec3 pos = player->getBoundingBox().center(); + void renderEntityShadow(int index, Controller *controller, Controller *player) { + Box box = controller->getSpheresBox(true); + mat4 m = controller->getMatrix(); + vec3 pos = m * box.center(); Core::mViewInv = mat4(player->mainLightPos, pos, vec3(0, -1, 0)); Core::mView = Core::mViewInv.inverseOrtho(); - Core::mProj = mat4(90.0f, 1.0f, camera->znear, player->mainLightColor.w * 1.5f); + Core::mProj = mat4(90.0f, 1.0f, 1.0f, 2.0f); + + mat4 mLightProj = Core::mProj * Core::mView * m; + Box crop = box * (mLightProj); + crop.min.z = max(0.0f, crop.min.z); + + float sx = 2.0f / (crop.max.x - crop.min.x); + float sy = 2.0f / (crop.max.y - crop.min.y); + float sz = 2.0f / (crop.max.z - crop.min.z); + float ox = -0.5f * (crop.max.x + crop.min.x) * sx; + float oy = -0.5f * (crop.max.y + crop.min.y) * sy; + float oz = -0.5f * (crop.max.z + crop.min.z) * sz; + + Core::mProj = mat4(sx, 0, 0, 0, + 0, sy, 0, 0, + 0, 0, sz, 0, + ox, oy, oz, 1) * Core::mProj; + + Core::setViewProj(Core::mView, Core::mProj); mat4 bias; bias.identity(); - bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f; + bias.e00 = bias.e11 = bias.e22 = 0.5f; + bias.e03 = bias.e13 = bias.e23 = 0.5f; + Core::mLightProj[index] = bias * (Core::mProj * Core::mView); + + Core::setBlending(bmNone); - Core::mLightProj = bias * (Core::mProj * Core::mView); + mesh->transparent = 0; + if (mesh->models[controller->getEntity().modelIndex - 1].geometry[mesh->transparent].count) { + setShader(Core::pass, Shader::ENTITY, false, false); + controller->render(NULL, mesh, Shader::ENTITY, false); + } + mesh->transparent = 1; + if (mesh->models[controller->getEntity().modelIndex - 1].geometry[mesh->transparent].count) { + setShader(Core::pass, Shader::ENTITY, false, true); + controller->render(NULL, mesh, Shader::ENTITY, false); + } + mesh->transparent = 0; + } - camera->frustum->pos = Core::viewPos; - camera->frustum->calcPlanes(Core::mViewProj); + struct NearObj { + int player; + int index; + float dist; + NearObj() {} + NearObj(int player, int index, float dist) : player(player), index(index), dist(dist) {} + }; + + int getNearObjects(NearObj *nearObj, int maxCount) { + int count = 0; + + nearObj[count++] = NearObj(0, players[0]->entity, 0.0f); + if (players[1]) + nearObj[count++] = NearObj(1, players[1]->entity, 0.0f); + int base = count; + + for (int i = 0; i < level.entitiesCount; i++) { + TR::Entity &e = level.entities[i]; + Controller *controller = (Controller*)e.controller; + if (controller && controller->isActive() && e.isEnemy() && e.castShadow() && controller != players[0] && controller != players[1]) { + int pIndex = 0; + float dist = (players[0]->pos - controller->pos).length2(); + if (players[1]) { + float dist2 = (players[1]->pos - controller->pos).length2(); + if (dist2 < dist) { + dist = dist2; + pIndex = 1; + } + } + // get index to insert + int index = base; + while (index < count) { + if (dist < nearObj[index].dist) + break; + index++; + } + // insertion + if (index < maxCount) { + if (count < maxCount) + count++; + for (int j = count - 1; j > index; j--) + nearObj[j] = nearObj[j - 1]; + nearObj[index] = NearObj(pIndex, controller->entity, dist); + } + } + } + + return count; } void renderShadows(int roomIndex) { PROFILE_MARKER("PASS_SHADOW"); + + // get near objects + NearObj nearObj[SHADOW_OBJ_MAX]; + int nearCount = getNearObjects(nearObj, SHADOW_OBJ_MAX); + + // render to shadow map float oldEye = Core::eye; Core::eye = 0.0f; @@ -1962,14 +2041,19 @@ struct Level : IGame { bool colorShadow = shadow->format == Texture::RGBA ? true : false; if (colorShadow) Core::setClearColor(vec4(1.0f)); - Core::setTarget(shadow, CLEAR_ALL); - setupLightCamera(); + Core::setRenderTarget(shadow, RT_CLEAR_DEPTH | (colorShadow ? (RT_CLEAR_COLOR | RT_STORE_COLOR) : RT_STORE_DEPTH)); + Core::validateRenderState(); + Core::setCulling(cfBack); - setup(); - renderView(roomIndex, false, false); + for (int i = 0; i < nearCount; i++) { + Core::setViewport((i % SHADOW_OBJ_COLS) * SHADOW_TEX_TILE, (i / SHADOW_OBJ_COLS) * SHADOW_TEX_TILE, SHADOW_TEX_TILE, SHADOW_TEX_TILE); + renderEntityShadow(i, (Controller*)level.entities[nearObj[i].index].controller, players[nearObj[i].player]); + } + + for (int i = nearCount; i < SHADOW_OBJ_MAX; i++) + Core::mLightProj[i].identity(); - Core::invalidateTarget(!colorShadow, colorShadow); Core::setCulling(cfFront); if (colorShadow) Core::setClearColor(vec4(0.0f)); @@ -2032,8 +2116,8 @@ struct Level : IGame { glLoadIdentity(); glOrtho(0, Core::width, 0, Core::height, 0, 1); - if (waterCache && waterCache->count && waterCache->items[0].caustics) - waterCache->items[0].caustics->bind(sDiffuse); + if (shadow) + shadow->bind(sDiffuse); else atlas->bind(sDiffuse); glEnable(GL_TEXTURE_2D); @@ -2043,8 +2127,8 @@ struct Level : IGame { Core::validateRenderState(); glColor3f(10, 10, 10); - int w = Core::active.textures[sDiffuse]->width / 2; - int h = Core::active.textures[sDiffuse]->height / 2; + float w = float(Core::active.textures[sDiffuse]->width); + float h = float(Core::active.textures[sDiffuse]->height); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2f(0, 0); glTexCoord2f(1, 0); glVertex2f(w, 0); @@ -2060,7 +2144,7 @@ struct Level : IGame { glMatrixMode(GL_MODELVIEW); glPopMatrix(); */ - + /* Core::setDepthTest(false); glBegin(GL_LINES); @@ -2079,7 +2163,7 @@ struct Level : IGame { Core::setDepthTest(false); Core::validateRenderState(); // Debug::Level::rooms(level, lara->pos, lara->getEntity().room); - // Debug::Level::lights(level, lara->getRoomIndex(), lara); + // Debug::Level::lights(level, player->getRoomIndex(), player); // Debug::Level::sectors(this, lara->getRoomIndex(), (int)lara->pos.y); // Core::setDepthTest(false); // Debug::Level::portals(level); @@ -2222,16 +2306,11 @@ struct Level : IGame { } void renderPrepare() { - Core::invalidateTarget(true, true); - if (ambientCache) ambientCache->processQueue(); if (shadow) renderShadows(player->getRoomIndex()); - - Core::setTarget(NULL, CLEAR_ALL); - Core::validateRenderState(); } void renderGame(bool showUI) { @@ -2267,9 +2346,6 @@ struct Level : IGame { params->clipSign = 1.0f; params->waterHeight = params->clipHeight; - if (shadow && view == 1) - renderShadows(player->getRoomIndex()); - if (shadow) shadow->bind(sShadow); Core::pass = Core::passCompose; /* @@ -2401,8 +2477,8 @@ struct Level : IGame { UI::end(); } - void renderInventory(bool clear) { - Core::setTarget(NULL, clear ? CLEAR_ALL : 0); + void renderInventory() { + Core::setRenderTarget(NULL, RT_CLEAR_DEPTH | RT_STORE_COLOR); if (!(level.isTitle() || inventory.titleTimer > 0.0f)) inventory.renderBackground(); @@ -2425,7 +2501,7 @@ struct Level : IGame { lastTitle = title; if (isEnded) { - Core::setTarget(NULL, CLEAR_ALL); + Core::setRenderTarget(NULL, RT_CLEAR_COLOR); UI::begin(); UI::updateAspect(float(Core::width) / float(Core::height)); UI::textOut(vec2(0, 480 - 16), STR_LOADING, UI::aCenter, UI::width); @@ -2444,7 +2520,7 @@ struct Level : IGame { } } - renderInventory(title); + renderInventory(); } }; diff --git a/src/platform/android/app/src/main/cpp/main.cpp b/src/platform/android/app/src/main/cpp/main.cpp index 7d33b3b..ea0e0e1 100644 --- a/src/platform/android/app/src/main/cpp/main.cpp +++ b/src/platform/android/app/src/main/cpp/main.cpp @@ -66,7 +66,7 @@ JNI_METHOD(void, nativeInit)(JNIEnv* env, jobject obj, jstring contentDir, jstri env->ReleaseStringUTFChars(cacheDir, str); glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&Core::defaultFBO); - Game::init("level/1/LEVEL2.PSX"); + Game::init(); } JNI_METHOD(void, nativeFree)(JNIEnv* env) {