From d6e1d42927d2769fad83cad2d07196f1bcb3a610 Mon Sep 17 00:00:00 2001 From: XProger Date: Sat, 19 May 2018 01:34:16 +0300 Subject: [PATCH] remove atlas shadows; add D3D9 shadows; fix water rat and crocodile bug --- src/cache.h | 10 ++-- src/camera.h | 5 +- src/core.h | 15 +---- src/enemy.h | 10 ++++ src/gapi_d3d9.h | 121 ++++++++++++++++++++++++---------------- src/gapi_gl.h | 16 ++++-- src/gapi_gu.h | 8 +++ src/inventory.h | 5 +- src/level.h | 31 +++++----- src/shader.h | 2 +- src/shaders/base.hlsl | 90 ++++++++++++++++++++++-------- src/shaders/common.hlsl | 56 +++++++++++++------ src/shaders/shader.glsl | 78 ++++++++++---------------- src/texture.h | 9 +-- src/ui.h | 4 +- src/utils.h | 31 ++++++++-- 16 files changed, 295 insertions(+), 196 deletions(-) diff --git a/src/cache.h b/src/cache.h index 9e506dd..513e5e5 100644 --- a/src/cache.h +++ b/src/cache.h @@ -33,6 +33,7 @@ struct ShaderCache { prepareFilter(FX_NONE); prepareGUI(FX_NONE); + Core::resetTime(); LOG("shader: cache is ready\n"); } @@ -148,12 +149,8 @@ struct ShaderCache { SD_ADD(CLIP_PLANE); if (Core::settings.detail.lighting > Core::Settings::MEDIUM && (type == Shader::ENTITY)) SD_ADD(OPT_AMBIENT); - if (Core::settings.detail.shadows > Core::Settings::LOW && (type == Shader::ENTITY || type == Shader::ROOM)) { + if (Core::settings.detail.shadows > Core::Settings::LOW && (type == Shader::ENTITY || type == Shader::ROOM)) SD_ADD(OPT_SHADOW); - - if (Core::settings.detail.shadows > Core::Settings::MEDIUM) - SD_ADD(OPT_SHADOW_HIGH); - } if (Core::settings.detail.shadows > Core::Settings::MEDIUM && (type == Shader::ROOM)) SD_ADD(OPT_CONTACT); if (Core::settings.detail.water > Core::Settings::MEDIUM && (type == Shader::ENTITY || type == Shader::ROOM) && (fx & FX_UNDERWATER)) @@ -715,11 +712,12 @@ struct WaterCache { if (!refract || w != refract->origWidth || h != refract->origHeight) { delete refract; refract = new Texture(w, h, FMT_RGBA); - + /* Core::setTarget(refract, RT_CLEAR_COLOR | RT_STORE_COLOR); Core::validateRenderState(); Core::setTarget(NULL, RT_STORE_COLOR); Core::validateRenderState(); + */ } Core::copyTarget(refract, 0, 0, int(Core::viewportDef.x), int(Core::viewportDef.y), w, h); // copy framebuffer into refraction texture } diff --git a/src/camera.h b/src/camera.h index 860b372..184d331 100644 --- a/src/camera.h +++ b/src/camera.h @@ -506,7 +506,7 @@ struct Camera : ICamera { if (Core::settings.detail.stereo == Core::Settings::STEREO_VR) Core::mProj = Input::hmd.proj[Core::eye == -1.0f ? 0 : 1]; else - Core::mProj = mat4(fov, aspect, znear, zfar); + Core::mProj = GAPI::perspective(fov, aspect, znear, zfar); } Core::setViewProj(Core::mView, Core::mProj); @@ -531,9 +531,6 @@ struct Camera : ICamera { fov = firstPerson ? 90.0f : 65.0f; znear = firstPerson ? 8.0f : 32.0f; - #ifdef _OS_PSP - znear = 256.0f; - #endif zfar = 45.0f * 1024.0f; } }; diff --git a/src/core.h b/src/core.h index e32b1ff..91cc811 100644 --- a/src/core.h +++ b/src/core.h @@ -85,14 +85,8 @@ #include "utils.h" // muse be equal with base shader -#define SHADOW_OBJ_COLS 4 -#define SHADOW_OBJ_ROWS 2 -#define SHADOW_TEX_TILE 128 -#define SHADOW_TEX_BIG_WIDTH 1024 -#define SHADOW_TEX_BIG_HEIGHT 1024 -#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) +#define SHADOW_TEX_WIDTH 1024 +#define SHADOW_TEX_HEIGHT 1024 extern void* osMutexInit (); extern void osMutexFree (void *obj); @@ -340,14 +334,12 @@ enum RenderState { // Texture image format enum TexFormat { - FMT_LUMINANCE, FMT_RGBA, FMT_RGB16, FMT_RGBA16, FMT_RGBA_FLOAT, FMT_RGBA_HALF, FMT_DEPTH, - FMT_DEPTH_STENCIL, FMT_SHADOW, FMT_MAX, }; @@ -453,7 +445,6 @@ struct MeshRange { E( CLIP_PLANE ) \ E( OPT_AMBIENT ) \ E( OPT_SHADOW ) \ - E( OPT_SHADOW_HIGH ) \ E( OPT_CONTACT ) \ E( OPT_CAUSTICS ) @@ -490,7 +481,7 @@ namespace Core { float eye; Viewport viewport, viewportDef; mat4 mModel, mView, mProj, mViewProj, mViewInv; - mat4 mLightProj[SHADOW_OBJ_MAX]; + mat4 mLightProj; Basis basis; vec4 viewPos; vec4 lightPos[MAX_LIGHTS]; diff --git a/src/enemy.h b/src/enemy.h index 38a57c5..55ae870 100644 --- a/src/enemy.h +++ b/src/enemy.h @@ -794,6 +794,11 @@ struct Rat : Enemy { bool water = getRoom().flags.water; int modelIndex = water ? modelWater : modelLand; + if (modelIndex == -1) { + water = modelWater != -1; + modelIndex = water ? modelWater : modelLand; + } + ASSERT(modelIndex > -1); const TR::Model *model = &level->models[modelIndex]; if (animation.model != model) { @@ -985,6 +990,11 @@ struct Crocodile : Enemy { bool water = getRoom().flags.water; int modelIndex = water ? modelWater : modelLand; + if (modelIndex == -1) { + water = modelWater != -1; + modelIndex = water ? modelWater : modelLand; + } + ASSERT(modelIndex > -1); const TR::Model *model = &level->models[modelIndex]; if (animation.model != model) { diff --git a/src/gapi_d3d9.h b/src/gapi_d3d9.h index c00a139..2ad28c1 100644 --- a/src/gapi_d3d9.h +++ b/src/gapi_d3d9.h @@ -70,7 +70,7 @@ namespace GAPI { int cullMode, blendMode; uint32 clearColor; - LPDIRECT3DSURFACE9 defBackBuffer; + LPDIRECT3DSURFACE9 defRT, defDS; LPDIRECT3DVERTEXDECLARATION9 vertexDecl; @@ -118,15 +118,15 @@ namespace GAPI { { 2, USAGE_VS | USAGE_PS }, // uViewProj { 6, USAGE_VS | USAGE_PS }, // uBasis { 70, USAGE_VS | USAGE_PS }, // uLightProj - { 102, USAGE_VS | USAGE_PS }, // uMaterial - { 103, USAGE_VS | USAGE_PS }, // uAmbient - { 109, USAGE_VS | USAGE_PS }, // uFogParams - { 110, USAGE_VS | USAGE_PS }, // uViewPos - { 111, USAGE_VS | USAGE_PS }, // uLightPos - { 115, USAGE_VS | USAGE_PS }, // uLightColor - { 119, USAGE_VS | USAGE_PS }, // uRoomSize - { 120, USAGE_VS | USAGE_PS }, // uPosScale - { 122, USAGE_VS | USAGE_PS }, // uContacts + { 74, USAGE_VS | USAGE_PS }, // uMaterial + { 75, USAGE_VS | USAGE_PS }, // uAmbient + { 81, USAGE_VS | USAGE_PS }, // uFogParams + { 82, USAGE_VS | USAGE_PS }, // uViewPos + { 83, USAGE_VS | USAGE_PS }, // uLightPos + { 87, USAGE_VS | USAGE_PS }, // uLightColor + { 91, USAGE_VS | USAGE_PS }, // uRoomSize + { 92, USAGE_VS | USAGE_PS }, // uPosScale + { 94, USAGE_VS | USAGE_PS }, // uContacts }; struct Shader { @@ -159,9 +159,8 @@ namespace GAPI { case SD_CLIP_PLANE : flags[ 7] = TRUE; break; case SD_OPT_AMBIENT : flags[ 8] = TRUE; break; case SD_OPT_SHADOW : flags[ 9] = TRUE; break; - case SD_OPT_SHADOW_HIGH : flags[10] = TRUE; break; - case SD_OPT_CONTACT : flags[11] = TRUE; break; - case SD_OPT_CAUSTICS : flags[12] = TRUE; break; + case SD_OPT_CONTACT : flags[10] = TRUE; break; + case SD_OPT_CAUSTICS : flags[11] = TRUE; break; } } @@ -218,28 +217,24 @@ namespace GAPI { void init(void *data) { ASSERT((opt & OPT_PROXY) == 0); - bool filter = (opt & OPT_NEAREST) == 0; + bool isDepth = fmt == FMT_DEPTH || fmt == FMT_SHADOW; bool mipmaps = (opt & OPT_MIPMAPS) != 0; bool cube = (opt & OPT_CUBEMAP) != 0; - bool isTarget = (opt & OPT_TARGET) != 0; - bool isShadow = fmt == FMT_SHADOW; - bool isDepth = fmt == FMT_DEPTH || fmt == FMT_DEPTH_STENCIL || fmt == FMT_SHADOW; + bool isTarget = (opt & OPT_TARGET) != 0 && !isDepth; static const struct FormatDesc { int bpp; D3DFORMAT format; } formats[FMT_MAX] = { - { 8, D3DFMT_L8 }, - { 32, D3DFMT_A8R8G8B8 }, - { 16, D3DFMT_R5G6B5 }, - { 16, D3DFMT_A1R5G5B5 }, - { 64, D3DFMT_A16B16G16R16 }, - { 64, D3DFMT_A16B16G16R16 }, - { 16, D3DFMT_D16 }, - { 32, D3DFMT_D24S8 }, - { 16, D3DFMT_D16 }, + { 32, D3DFMT_A8R8G8B8 }, + { 16, D3DFMT_R5G6B5 }, + { 16, D3DFMT_A1R5G5B5 }, + { 64, D3DFMT_A16B16G16R16F }, + {128, D3DFMT_A32B32G32R32F }, + { 16, D3DFMT_D16 }, + { 16, D3DFMT_D24X8 }, }; - + FormatDesc desc = formats[fmt]; uint32 usage = 0; @@ -247,7 +242,7 @@ namespace GAPI { if (isDepth) usage |= D3DUSAGE_DEPTHSTENCIL; if (isTarget) usage |= D3DUSAGE_RENDERTARGET; - D3DPOOL pool = isTarget ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED; + D3DPOOL pool = (isTarget || isDepth) ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED; if (cube) { D3DCHECK(device->CreateCubeTexture(width, 1, usage, desc.format, pool, &texCube, NULL)); @@ -291,8 +286,8 @@ namespace GAPI { bool mipmaps = (Core::settings.detail.filter > Core::Settings::MEDIUM) && (opt & OPT_MIPMAPS); bool aniso = filter && mipmaps && (Core::support.maxAniso > 0); - device->SetSamplerState(sampler, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - device->SetSamplerState(sampler, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + device->SetSamplerState(sampler, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + device->SetSamplerState(sampler, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); if (aniso) { device->SetSamplerState(sampler, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC); @@ -387,7 +382,7 @@ namespace GAPI { struct RenderTargetCache { int count; struct Item { -// GLuint ID; + LPDIRECT3DSURFACE9 surface; int width; int height; } items[MAX_RENDER_BUFFERS]; @@ -404,8 +399,8 @@ namespace GAPI { support.maxAniso = 8; support.maxVectors = 16; support.shaderBinary = false; - support.VAO = false; - support.depthTexture = false; + support.VAO = false; // SHADOW_COLOR + support.depthTexture = false; // SHADOW_DEPTH support.shadowSampler = false; support.discardFrame = false; support.texNPOT = false; @@ -440,6 +435,15 @@ namespace GAPI { } void resetDevice() { + // release dummy RTs + for (int i = 0; i < 2; i++) { + RenderTargetCache &cache = rtCache[i]; + for (int j = 0; j < cache.count; j++) + cache.items[j].surface->Release(); + cache.count = 0; + } + + // release texture RTs int tmpCount = resCount; Resource tmpList[256]; memcpy(tmpList, resList, sizeof(Resource) * tmpCount); @@ -454,6 +458,7 @@ namespace GAPI { D3DCHECK(device->Reset(&d3dpp)); + // reinit texture RTs for (int i = 0; i < tmpCount; i++) { Resource &res = tmpList[i]; if (res.mesh) @@ -464,6 +469,14 @@ namespace GAPI { } + mat4 ortho(float l, float r, float b, float t, float znear, float zfar) { + return mat4(mat4::PROJ_ZERO_POS, l, r, b, t, znear, zfar); + } + + mat4 perspective(float fov, float aspect, float znear, float zfar) { + return mat4(mat4::PROJ_ZERO_POS, fov, aspect, znear, zfar); + } + bool beginFrame() { switch (device->TestCooperativeLevel()) { case D3D_OK : @@ -480,14 +493,16 @@ namespace GAPI { return false; } - device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &defBackBuffer); + device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &defRT); + device->GetDepthStencilSurface(&defDS); device->BeginScene(); return true; } void endFrame() { device->EndScene(); - defBackBuffer->Release(); + defRT->Release(); + defDS->Release(); } void resetState() { @@ -509,34 +524,42 @@ namespace GAPI { RenderTargetCache::Item &item = cache.items[cache.count]; item.width = width; item.height = height; - /* - glGenRenderbuffers(1, &item.ID); - glBindRenderbuffer(GL_RENDERBUFFER, item.ID); - glRenderbufferStorage(GL_RENDERBUFFER, depth ? GL_RGB565 : GL_DEPTH_COMPONENT16, width, height); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - */ + + if (depth) + device->CreateDepthStencilSurface(width, height, D3DFMT_D16, D3DMULTISAMPLE_NONE, 0, true, &item.surface, NULL); + else + device->CreateRenderTarget(width, height, D3DFMT_R5G6B5, D3DMULTISAMPLE_NONE, 0, false, &item.surface, NULL); + return cache.count++; } void bindTarget(Texture *target, int face) { if (!target) { // may be a null - D3DCHECK(device->SetRenderTarget(0, defBackBuffer)); + D3DCHECK(device->SetRenderTarget(0, defRT)); + D3DCHECK(device->SetDepthStencilSurface(defDS)); } else { ASSERT(target->opt & OPT_TARGET); LPDIRECT3DSURFACE9 surface; - if (target->tex2D) + bool depth = target->fmt == FMT_DEPTH || target->fmt == FMT_SHADOW; + + if (target->tex2D) { D3DCHECK(target->tex2D->GetSurfaceLevel(0, &surface)); - else if (target->texCube) + } else if (target->texCube) D3DCHECK(target->texCube->GetCubeMapSurface(D3DCUBEMAP_FACES(D3DCUBEMAP_FACE_POSITIVE_X + face), 0, &surface)); - D3DCHECK(device->SetRenderTarget(0, surface)); + int rtIndex = cacheRenderTarget(!depth, target->width, target->height); + + if (depth) { + D3DCHECK(device->SetRenderTarget(0, rtCache[false].items[rtIndex].surface)); + D3DCHECK(device->SetDepthStencilSurface(surface)); + } else { + D3DCHECK(device->SetRenderTarget(0, surface)); + D3DCHECK(device->SetDepthStencilSurface(rtCache[true].items[rtIndex].surface)); + } surface->Release(); - - bool depth = target->fmt == FMT_DEPTH || target->fmt == FMT_SHADOW; - int rtIndex = cacheRenderTarget(depth, target->width, target->height); } } @@ -551,7 +574,7 @@ namespace GAPI { RECT srcRect = { x, y, x + width, y + height }, dstRect = { xOffset, yOffset, xOffset + width, yOffset + height }; - device->StretchRect(defBackBuffer, &srcRect, surface, &dstRect, D3DTEXF_POINT); + device->StretchRect(defRT, &srcRect, surface, &dstRect, D3DTEXF_POINT); surface->Release(); } diff --git a/src/gapi_gl.h b/src/gapi_gl.h index b4528b7..328d099 100644 --- a/src/gapi_gl.h +++ b/src/gapi_gl.h @@ -547,14 +547,12 @@ namespace GAPI { GLuint ifmt, fmt; GLenum type; } formats[FMT_MAX] = { - { GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE }, // LUMINANCE { GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE }, // RGBA { GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5 }, // RGB16 { GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1 }, // RGBA16 { GL_RGBA32F, GL_RGBA, GL_FLOAT }, // RGBA_FLOAT { GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT }, // RGBA_HALF { GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // DEPTH - { GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 }, // DEPTH_STENCIL { GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT }, // SHADOW }; @@ -978,6 +976,14 @@ namespace GAPI { glDeleteRenderbuffers(1, &rtCache[b].items[i].ID); } + mat4 ortho(float l, float r, float b, float t, float znear, float zfar) { + return mat4(mat4::PROJ_NEG_POS, l, r, b, t, znear, zfar); + } + + mat4 perspective(float fov, float aspect, float znear, float zfar) { + return mat4(mat4::PROJ_NEG_POS, fov, aspect, znear, zfar); + } + bool beginFrame() { return true; } @@ -1008,7 +1014,7 @@ namespace GAPI { glGenRenderbuffers(1, &item.ID); glBindRenderbuffer(GL_RENDERBUFFER, item.ID); - glRenderbufferStorage(GL_RENDERBUFFER, depth ? GL_RGB565 : GL_DEPTH_COMPONENT16, width, height); + glRenderbufferStorage(GL_RENDERBUFFER, depth ? GL_DEPTH_COMPONENT16 : GL_RGB565, width, height); glBindRenderbuffer(GL_RENDERBUFFER, 0); return cache.count++; } @@ -1023,11 +1029,11 @@ namespace GAPI { bool depth = target->fmt == FMT_DEPTH || target->fmt == FMT_SHADOW; - int rtIndex = cacheRenderTarget(depth, target->width, target->height); + 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); + glFramebufferRenderbuffer (GL_FRAMEBUFFER, depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rtCache[!depth].items[rtIndex].ID); } } diff --git a/src/gapi_gu.h b/src/gapi_gu.h index bb4f853..ac955de 100644 --- a/src/gapi_gu.h +++ b/src/gapi_gu.h @@ -289,6 +289,14 @@ namespace GAPI { delete[] cmdBuf; } + mat4 ortho(float l, float r, float b, float t, float znear, float zfar) { + return mat4(mat4::PROJ_ZERO_POS, l, r, b, t, znear, zfar); + } + + mat4 perspective(float fov, float aspect, float znear, float zfar) { + return mat4(mat4::PROJ_ZERO_POS, fov, aspect, znear, zfar); + } + bool beginFrame() { return true; } diff --git a/src/inventory.h b/src/inventory.h index b31d1cd..971c5a1 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -1496,7 +1496,7 @@ struct Inventory { if (Core::settings.detail.stereo == Core::Settings::STEREO_VR) Core::mProj = Input::hmd.proj[Core::eye == -1.0f ? 0 : 1]; else - Core::mProj = mat4(70.0f, aspect, 32.0f, 2048.0f); + Core::mProj = GAPI::perspective(70.0f, aspect, 32.0f, 2048.0f); Core::mView = Core::mViewInv.inverseOrtho(); Core::viewPos = Core::mViewInv.getPos(); @@ -1514,8 +1514,7 @@ struct Inventory { // items game->setupBinding(); - for (int i = 0; i < SHADOW_OBJ_MAX; i++) - Core::mLightProj[i].identity(); + Core::mLightProj.identity(); setupCamera(aspect); diff --git a/src/level.h b/src/level.h index d9f6d30..ac1f547 100644 --- a/src/level.h +++ b/src/level.h @@ -229,10 +229,8 @@ struct Level : IGame { void initShadow() { delete shadow; - if (Core::settings.detail.shadows > Core::Settings::MEDIUM) - shadow = new Texture(SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, FMT_SHADOW); - else if (Core::settings.detail.shadows > Core::Settings::LOW) - shadow = new Texture(SHADOW_TEX_BIG_WIDTH, SHADOW_TEX_BIG_HEIGHT, FMT_SHADOW); + if (Core::settings.detail.shadows > Core::Settings::LOW) + shadow = new Texture(SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, FMT_SHADOW, OPT_TARGET); else shadow = NULL; } @@ -1961,7 +1959,7 @@ struct Level : IGame { Core::mViewInv = mat4(pos, pos + dir, up); Core::mView = Core::mViewInv.inverseOrtho(); - Core::mProj = mat4(90, 1.0f, camera->znear, camera->zfar); + Core::mProj = GAPI::perspective(90, 1.0f, camera->znear, camera->zfar); Core::mViewProj = Core::mProj * Core::mView; Core::viewPos = Core::mViewInv.offset().xyz(); @@ -1971,15 +1969,17 @@ struct Level : IGame { void renderShadowView(int roomIndex) { vec3 pos = player->getBoundingBox().center(); + float znear = camera->znear; + float zfar = player->mainLightColor.w * 1.5f; + 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 = GAPI::perspective(90.0f, 1.0f, znear, zfar); mat4 bias; bias.identity(); - bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f; - - Core::mLightProj[0] = bias * (Core::mProj * Core::mView); + //bias.e03 = bias.e13 = bias.e23 = bias.e00 = bias.e11 = bias.e22 = 0.5f; + Core::mLightProj = bias * (Core::mProj * Core::mView); camera->frustum->pos = Core::viewPos.xyz(); camera->frustum->calcPlanes(Core::mViewProj); @@ -1987,7 +1987,7 @@ struct Level : IGame { setup(); renderView(roomIndex, false, false); } - +/* void renderShadowEntity(int index, Controller *controller, Controller *player) { Box box = controller->getSpheresBox(true); mat4 m = controller->getMatrix(); @@ -2086,7 +2086,7 @@ struct Level : IGame { return count; } - +*/ void renderShadows(int roomIndex) { PROFILE_MARKER("PASS_SHADOW"); @@ -2104,10 +2104,10 @@ struct Level : IGame { if (colorShadow) Core::setClearColor(vec4(1.0f)); Core::setTarget(shadow, RT_CLEAR_DEPTH | (colorShadow ? (RT_CLEAR_COLOR | RT_STORE_COLOR) : RT_STORE_DEPTH)); + //Core::setCullMode(cmBack); Core::validateRenderState(); - Core::setCullMode(cmBack); - + /* if (Core::settings.detail.shadows > Core::Settings::Quality::MEDIUM) { // per-object shadow map (atlas) NearObj nearObj[SHADOW_OBJ_MAX]; int nearCount = getNearObjects(nearObj, SHADOW_OBJ_MAX); @@ -2120,9 +2120,10 @@ struct Level : IGame { for (int i = nearCount; i < SHADOW_OBJ_MAX; i++) Core::mLightProj[i].identity(); } else // all-in-one shadow map - renderShadowView(roomIndex); + */ + renderShadowView(roomIndex); - Core::setCullMode(cmFront); + //Core::setCullMode(cmFront); if (colorShadow) Core::setClearColor(vec4(0.0f)); diff --git a/src/shader.h b/src/shader.h index 5f480e6..2a08be7 100644 --- a/src/shader.h +++ b/src/shader.h @@ -24,7 +24,7 @@ struct Shader : GAPI::Shader { void setup() { bind(); setParam(uViewProj, Core::mViewProj); - setParam(uLightProj, Core::mLightProj[0], Core::settings.detail.shadows > Core::Settings::Quality::MEDIUM ? SHADOW_OBJ_MAX : 1); + setParam(uLightProj, Core::mLightProj); setParam(uViewPos, Core::viewPos); setParam(uParam, Core::params); setParam(uFogParams, Core::fogParams); diff --git a/src/shaders/base.hlsl b/src/shaders/base.hlsl index d52ee8f..cebcc62 100644 --- a/src/shaders/base.hlsl +++ b/src/shaders/base.hlsl @@ -1,15 +1,16 @@ #include "common.hlsl" struct VS_OUTPUT { - float4 wpos : POSITION; - float3 coord : TEXCOORD0; - float4 texCoord : TEXCOORD1; - float4 viewVec : TEXCOORD2; - float4 normal : NORMAL; - float4 diffuse : COLOR0; - float3 ambient : COLOR1; - float4 lightMap : COLOR2; - float4 light : COLOR3; + float4 pos : POSITION; + float3 coord : TEXCOORD0; + float4 texCoord : TEXCOORD1; + float4 viewVec : TEXCOORD2; + float4 normal : NORMAL; + float4 diffuse : COLOR0; + float3 ambient : COLOR1; + float4 lightMap : COLOR2; + float4 light : COLOR3; + float4 hpos : TEXCOORD4; }; #ifdef VERTEX @@ -31,9 +32,9 @@ float3 calcAmbient(float3 n) { VS_OUTPUT main(VS_INPUT In) { VS_OUTPUT Out; - Out.ambient = 0.0; - Out.lightMap = 0.0; - Out.light = 0.0; + Out.ambient = 0.0; + Out.lightMap = 0.0; + Out.light = 0.0; int index = int(In.aCoord.w * 2.0); float4 rBasisRot = uBasis[index]; @@ -56,7 +57,6 @@ VS_OUTPUT main(VS_INPUT In) { Out.viewVec = float4((uViewPos.xyz - Out.coord) * uFogParams.w, Out.coord.y * uParam.z); #ifdef PASS_COMPOSE - if (TYPE_SPRITE) { Out.normal.xyz = normalize(Out.viewVec.xyz); } else { @@ -66,7 +66,6 @@ VS_OUTPUT main(VS_INPUT In) { float fog; if (!TYPE_FLASH) { - float3 lv0 = (uLightPos[0].xyz - Out.coord) * uLightColor[0].w; float3 lv1 = (uLightPos[1].xyz - Out.coord) * uLightColor[1].w; float3 lv2 = (uLightPos[2].xyz - Out.coord) * uLightColor[2].w; @@ -150,15 +149,58 @@ VS_OUTPUT main(VS_INPUT In) { } #endif - Out.wpos = mul(uViewProj, float4(Out.coord, rBasisPos.w)); - + Out.pos = mul(uViewProj, float4(Out.coord, rBasisPos.w)); + Out.hpos = Out.pos; + return Out; } #else // PIXEL -float getShadow(float3 lightVec) { - return 1.0; +float SHADOW(float2 p) { + #ifdef SHADOW_DEPTH + return tex2D(sShadow, p).x; + #else + return unpack(tex2D(sShadow, p)); + #endif +} + +float getShadow(float3 lightVec, float3 normal, float4 lightProj) { + float3 p = lightProj.xyz / lightProj.w; + + p.y = -p.y; + p.xy = p.xy * 0.5 + 0.5; + + p.z -= SHADOW_CONST_BIAS * SHADOW_TEXEL.x; + + float vis = lightProj.w; + if (TYPE_ROOM) { + vis = min(vis, dot(normal, lightVec)); + } + if (vis < 0.0 || p.x < 0.0 || p.y < 0.0 || p.x > 1.0 || p.y > 1.0) return 1.0; + + p.z = saturate(p.z); + + float4 samples = float4( + SHADOW(p.xy ), + SHADOW(p.xy + SHADOW_TEXEL.xz), + SHADOW(p.xy + SHADOW_TEXEL.zy), + SHADOW(p.xy + SHADOW_TEXEL.xy) + ); + samples = step(p.zzzz, samples); + + float2 f = frac(p.xy / SHADOW_TEXEL.xy); + samples.xy = lerp(samples.xz, samples.yw, f.xx); + float rShadow = lerp(samples.x, samples.y, f.y); + + float fade = saturate(dot(lightVec, lightVec)); + return rShadow + (1.0 - rShadow) * fade; +} + +float getShadow(float3 coord, float3 lightVec, float3 normal) { + float factor = clamp(1.0 - dot(normalize(lightVec), normal), 0.0, 1.0); + factor *= SHADOW_NORMAL_BIAS; + return getShadow(lightVec, normal, mul(uLightProj, float4(coord + normal * factor, 1.0))); } float getContactAO(float3 p, float3 n) { @@ -167,7 +209,7 @@ float getContactAO(float3 p, float3 n) { float3 v = uContacts[i].xyz - p; float a = uContacts[i].w; float o = a * saturate(dot(n, v)) / dot(v, v); - res *= clamp(1.0 - o, 0.0, 1.0); + res *= saturate(1.0 - o); } return res; } @@ -214,7 +256,11 @@ float4 main(VS_OUTPUT In) : COLOR0 { } #ifdef PASS_SHADOW - return 1.0; + #ifdef SHADOW_DEPTH + return 0.0; + #else // SHADOW_COLOR + return pack(In.hpos.z / In.hpos.w); + #endif #else color *= In.diffuse; @@ -241,11 +287,11 @@ float4 main(VS_OUTPUT In) : COLOR0 { light = uLightColor[1].xyz * In.light.y + uLightColor[2].xyz * In.light.z + uLightColor[3].xyz * In.light.w; if (TYPE_ENTITY) { - float rShadow = getShadow(lightVec); + float rShadow = getShadow(In.coord, lightVec, normal); rSpecular = (uMaterial.z + 0.03) * rShadow; light += In.ambient + uLightColor[0].xyz * (In.light.x * rShadow); } else if (TYPE_ROOM) { - float rShadow = getShadow(lightVec); + float rShadow = getShadow(In.coord, lightVec, normal); light += lerp(In.ambient.xyz, In.lightMap.xyz, rShadow); } else if (TYPE_SPRITE) { light += In.lightMap.xyz; diff --git a/src/shaders/common.hlsl b/src/shaders/common.hlsl index 50b9305..7132a91 100644 --- a/src/shaders/common.hlsl +++ b/src/shaders/common.hlsl @@ -3,6 +3,14 @@ #define WATER_FOG_DIST (1.0 / (6.0 * 1024.0)) #define UNDERWATER_COLOR float3(0.6, 0.9, 0.9) +static const float3 SHADOW_TEXEL = float3(1.0 / 1024.0, 1.0 / 1024.0, 0.0); + +#define SHADOW_NORMAL_BIAS 16.0 +#define SHADOW_CONST_BIAS 0.12 + +#define MAX_LIGHTS 4 +#define MAX_CONTACTS 15 + struct VS_INPUT { float4 aCoord : POSITION; float4 aNormal : NORMAL; @@ -20,21 +28,21 @@ struct VS_INPUT { sampler sMask : register(s5); #endif -bool uFlags[16] : register( b0 ); -float4 uParam : register( c0 ); -float4 uTexParam : register( c1 ); -float4x4 uViewProj : register( c2 ); -float4 uBasis[32 * 2] : register( c6 ); -float4x4 uLightProj : register( c70 ); -float4 uMaterial : register( c102 ); -float4 uAmbient[6] : register( c103 ); -float4 uFogParams : register( c109 ); -float4 uViewPos : register( c110 ); -float4 uLightPos[MAX_LIGHTS] : register( c111 ); -float4 uLightColor[MAX_LIGHTS] : register( c115 ); -float4 uRoomSize : register( c119 ); -float4 uPosScale[2] : register( c120 ); -float4 uContacts[MAX_CONTACTS] : register( c122 ); +bool uFlags[16] : register( b0 ); +float4 uParam : register( c0 ); +float4 uTexParam : register( c1 ); +float4x4 uViewProj : register( c2 ); +float4 uBasis[32 * 2] : register( c6 ); +float4x4 uLightProj : register( c70 ); +float4 uMaterial : register( c74 ); +float4 uAmbient[6] : register( c75 ); +float4 uFogParams : register( c81 ); +float4 uViewPos : register( c82 ); +float4 uLightPos[MAX_LIGHTS] : register( c83 ); +float4 uLightColor[MAX_LIGHTS] : register( c87 ); +float4 uRoomSize : register( c91 ); +float4 uPosScale[2] : register( c92 ); +float4 uContacts[MAX_CONTACTS] : register( c94 ); #define TYPE_SPRITE uFlags[0] #define TYPE_FLASH uFlags[1] @@ -60,6 +68,18 @@ float4 uContacts[MAX_CONTACTS] : register( c122 ); #define CLIP_PLANE uFlags[7] #define OPT_AMBIENT uFlags[8] #define OPT_SHADOW uFlags[9] -#define OPT_SHADOW_HIGH uFlags[10] -#define OPT_CONTACT uFlags[11] -#define OPT_CAUSTICS uFlags[12] \ No newline at end of file +#define OPT_CONTACT uFlags[10] +#define OPT_CAUSTICS uFlags[11] + +float4 pack(float value) { + float4 bitSh = float4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0); + float4 bitMsk = float4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0); + float4 res = frac(value * bitSh); + res -= res.xxyz * bitMsk; + return res; +} + +float unpack(float4 value) { + float4 bitSh = float4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0); + return dot(value, bitSh); +} \ No newline at end of file diff --git a/src/shaders/shader.glsl b/src/shaders/shader.glsl index 7665f1f..91ff2c2 100644 --- a/src/shaders/shader.glsl +++ b/src/shaders/shader.glsl @@ -20,14 +20,8 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - trapezoidal correction #endif #ifdef OPT_SHADOW - #ifdef OPT_SHADOW_HIGH - #define SHADOW_OBJ_MAX 8 - #define SHADOW_TEXEL vec3(1.0 / 512.0, 1.0 / 256.0, 0.0) - #else - #define SHADOW_OBJ_MAX 1 - #define SHADOW_TEXEL vec3(1.0 / 1024.0, 1.0 / 1024.0, 0.0) - #endif - uniform mat4 uLightProj[SHADOW_OBJ_MAX]; + #define SHADOW_TEXEL vec3(1.0 / 1024.0, 1.0 / 1024.0, 0.0) + uniform mat4 uLightProj; #endif uniform mat4 uViewProj; @@ -276,66 +270,55 @@ uniform vec4 uFogParams; #endif #else uniform sampler2D sShadow; - #define CMP(a,b) step(min(1.0, b), a) - #ifdef SHADOW_DEPTH - #define compare(p, z) CMP(texture2D(sShadow, (p)).x, (z)); - #elif defined(SHADOW_COLOR) - float unpack(vec4 value) { - vec4 bitSh = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0); - return dot(value, bitSh); - } - #define compare(p, z) CMP(unpack(texture2D(sShadow, (p))), (z)); - #endif + float unpack(vec4 value) { + vec4 bitSh = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0); + return dot(value, bitSh); + } - float SHADOW(vec3 p) { - return compare(p.xy, p.z); + float SHADOW(vec2 p) { + #ifdef SHADOW_DEPTH + return texture2D(sShadow, p).x; + #else + return unpack(texture2D(sShadow, p)); + #endif } #endif - float getShadow(vec3 lightVec, vec4 lightProj, vec2 tileOffset) { + float getShadow(vec3 lightVec, vec3 normal, vec4 lightProj) { vec3 p = lightProj.xyz / lightProj.w; + p.xyz = p.xyz * 0.5 + 0.5; + p.z -= 0.04 * SHADOW_TEXEL.x; float vis = lightProj.w; #ifdef TYPE_ROOM - vis = min(vis, dot(vNormal.xyz, lightVec)); + vis = min(vis, dot(normal, lightVec)); #endif if (vis < 0.0 || p.x < 0.0 || p.y < 0.0 || p.x > 1.0 || p.y > 1.0) return 1.0; - #ifdef OPT_SHADOW_HIGH - p.xy = p.xy * vec2(0.25, 0.5) + tileOffset; - #endif - #ifdef SHADOW_SAMPLER float rShadow = SHADOW(p); #else - vec4 samples = vec4(SHADOW(SHADOW_TEXEL * vec3(0.0, 0.0, 0.0) + p), - SHADOW(SHADOW_TEXEL * vec3(1.0, 0.0, 0.0) + p), - SHADOW(SHADOW_TEXEL * vec3(0.0, 1.0, 0.0) + p), - SHADOW(SHADOW_TEXEL * vec3(1.0, 1.0, 0.0) + p)); + vec4 samples = vec4(SHADOW( p.xy), + SHADOW(SHADOW_TEXEL.xz + p.xy), + SHADOW(SHADOW_TEXEL.zy + p.xy), + SHADOW(SHADOW_TEXEL.xy + p.xy)); + + samples = step(vec4(p.z), samples); + vec2 f = fract(p.xy / SHADOW_TEXEL.xy); - float rShadow = mix(mix(samples.x, samples.y, f.x), mix(samples.z, samples.w, f.x), f.y); + samples.xy = mix(samples.xz, samples.yw, f.x); + float rShadow = mix(samples.x, samples.y, f.y); #endif float fade = clamp(dot(lightVec, lightVec), 0.0, 1.0); return rShadow + (1.0 - rShadow) * fade; } - float getShadow(vec3 lightVec) { - vec4 c = vec4(vCoord, 1.0); - #ifdef OPT_SHADOW_HIGH - return min(min(min(min(min(min(min( // hardcoded for 4x2 shadow atlas - getShadow(lightVec, uLightProj[0] * c, vec2(0.00, 0.0)), - getShadow(lightVec, uLightProj[1] * c, vec2(0.25, 0.0))), - getShadow(lightVec, uLightProj[2] * c, vec2(0.50, 0.0))), - getShadow(lightVec, uLightProj[3] * c, vec2(0.75, 0.0))), - getShadow(lightVec, uLightProj[4] * c, vec2(0.00, 0.5))), - getShadow(lightVec, uLightProj[5] * c, vec2(0.25, 0.5))), - getShadow(lightVec, uLightProj[6] * c, vec2(0.50, 0.5))), - getShadow(lightVec, uLightProj[7] * c, vec2(0.75, 0.5))); - #else - return getShadow(lightVec, uLightProj[0] * c, vec2(0.0, 0.0)); - #endif + float getShadow(vec3 lightVec, vec3 normal) { + float factor = clamp(1.0 - dot(normalize(lightVec), normal), 0.0, 1.0); + factor *= 16.0; + return getShadow(lightVec, normal, uLightProj * vec4(vCoord + normal * factor, 1.0)); } #endif @@ -414,7 +397,6 @@ uniform vec4 uFogParams; #endif #ifdef PASS_COMPOSE - vec3 lightVec = (uLightPos[0].xyz - vCoord) * uLightColor[0].w; vec3 normal = normalize(vNormal.xyz); @@ -426,7 +408,7 @@ uniform vec4 uFogParams; vec3 light = uLightColor[1].xyz * vLight.y + uLightColor[2].xyz * vLight.z + uLightColor[3].xyz * vLight.w; #if defined(TYPE_ENTITY) || defined(TYPE_ROOM) - float rShadow = getShadow(lightVec); + float rShadow = getShadow(lightVec, normal); #endif #ifdef TYPE_ENTITY diff --git a/src/texture.h b/src/texture.h index fd46014..51fae44 100644 --- a/src/texture.h +++ b/src/texture.h @@ -66,16 +66,13 @@ struct Texture : GAPI::Texture { bool filter = (opt & OPT_NEAREST) == 0; bool mipmaps = (opt & OPT_MIPMAPS) != 0; - if (format == FMT_SHADOW && !Core::support.shadowSampler) { + if (format == FMT_SHADOW && !Core::support.shadowSampler) format = FMT_DEPTH; - filter = false; - } if (format == FMT_DEPTH) { - if (Core::support.depthTexture) - filter = false; - else + if (!Core::support.depthTexture) format = FMT_RGBA; + filter = false; } if (format == FMT_RGBA_HALF) { diff --git a/src/ui.h b/src/ui.h index 89a41f2..d445e53 100644 --- a/src/ui.h +++ b/src/ui.h @@ -280,7 +280,7 @@ namespace UI { void updateAspect(float aspect) { height = 480.0f; width = height * aspect; - Core::mProj = mat4(0.0f, width, height, 0.0f, 0.0f, 1.0f); + Core::mProj = GAPI::ortho(0.0f, width, height, 0.0f, 0.0f, 1.0f); Core::setViewProj(Core::mView, Core::mProj); Core::active.shader->setParam(uViewProj, Core::mViewProj); } @@ -493,7 +493,7 @@ namespace UI { Core::setBlendMode(bmAlpha); Core::setCullMode(cmNone); - Core::mViewProj = mat4(0.0f, float(Core::width), float(Core::height), 0.0f, 0.0f, 1.0f); + Core::mViewProj = GAPI::ortho(0.0f, float(Core::width), float(Core::height), 0.0f, 0.0f, 1.0f); game->setShader(Core::passGUI, Shader::DEFAULT); diff --git a/src/utils.h b/src/utils.h index c7f4e1f..497b41c 100644 --- a/src/utils.h +++ b/src/utils.h @@ -466,6 +466,12 @@ struct quat { }; struct mat4 { + + enum ProjRange { + PROJ_NEG_POS, + PROJ_ZERO_POS, + }; + float e00, e10, e20, e30, e01, e11, e21, e31, e02, e12, e22, e32, @@ -494,17 +500,24 @@ struct mat4 { e33 = 1.0f; } - mat4(float l, float r, float b, float t, float znear, float zfar) { + mat4(ProjRange range, float l, float r, float b, float t, float znear, float zfar) { identity(); e00 = 2.0f / (r - l); e11 = 2.0f / (t - b); e22 = 2.0f / (znear - zfar); e03 = (l + r) / (l - r); e13 = (t + b) / (b - t); - e23 = znear / (znear - zfar); + switch (range) { + case PROJ_NEG_POS : + e23 = (zfar + znear) / (znear - zfar); + break; + case PROJ_ZERO_POS : + e23 = znear / (znear - zfar); + break; + } } - mat4(float fov, float aspect, float znear, float zfar) { + mat4(ProjRange range, float fov, float aspect, float znear, float zfar) { float k = 1.0f / tanf(fov * 0.5f * DEG2RAD); identity(); if (aspect >= 1.0f) { @@ -514,10 +527,18 @@ struct mat4 { e00 = k; e11 = k * aspect; } - e22 = (znear + zfar) / (znear - zfar); e33 = 0.0f; e32 = -1.0f; - e23 = 2.0f * zfar * znear / (znear - zfar); + switch (range) { + case PROJ_NEG_POS : + e22 = (znear + zfar) / (znear - zfar); + e23 = 2.0f * zfar * znear / (znear - zfar); + break; + case PROJ_ZERO_POS : + e22 = zfar / (znear - zfar); + e23 = znear * e22; + break; + } } mat4(const vec3 &from, const vec3 &at, const vec3 &up) {