From d875a66aaf980af08f4df342b082690545eaa402 Mon Sep 17 00:00:00 2001 From: XProger Date: Sun, 13 May 2018 05:52:23 +0300 Subject: [PATCH] #15 D3D9 WIP, port some shaders, handle device reset & lost --- src/cache.h | 8 +- src/core.h | 6 +- src/game.h | 22 ++- src/gapi_d3d9.h | 362 ++++++++++++++++++++++++++---------- src/gapi_gl.h | 8 +- src/gapi_gu.h | 4 +- src/lara.h | 2 +- src/platform/win/main.cpp | 36 +--- src/shader.h | 4 +- src/shaders/base.hlsl | 278 ++++++++++++++++++++++++--- src/shaders/common.hlsl | 73 ++++++-- src/shaders/compile_dx9.bat | 8 +- src/shaders/filter.glsl | 4 +- src/shaders/filter.hlsl | 68 ++++++- src/shaders/gui.hlsl | 2 - src/shaders/shader.glsl | 10 +- src/shaders/water.hlsl | 7 - src/trigger.h | 2 +- 18 files changed, 687 insertions(+), 217 deletions(-) diff --git a/src/cache.h b/src/cache.h index 20fd9d8..9e506dd 100644 --- a/src/cache.h +++ b/src/cache.h @@ -84,6 +84,7 @@ struct ShaderCache { void prepareShadows(int fx) { compile(Core::passShadow, Shader::ENTITY, fx, rsShadow); compile(Core::passShadow, Shader::ENTITY, fx, rsShadow | RS_DISCARD); + compile(Core::passShadow, Shader::MIRROR, fx, rsShadow); } void prepareWater(int fx) { @@ -169,7 +170,7 @@ struct ShaderCache { #undef SD_ADD LOG("shader: %s(%d) %s%s%s\n", Core::passNames[pass], type, (fx & FX_UNDERWATER) ? "u" : "", (fx & FX_ALPHA_TEST) ? "a" : "", (fx & FX_CLIP_PLANE) ? "c" : ""); - return shaders[pass][type][fx] = new Shader(pass, def, defCount); + return shaders[pass][type][fx] = new Shader(pass, type, def, defCount); #else return NULL; #endif @@ -233,7 +234,7 @@ struct AmbientCache { // init downsample textures for (int j = 0; j < 6; j++) for (int i = 0; i < 4; i++) - textures[j * 4 + i] = new Texture(64 >> (i << 1), 64 >> (i << 1), FMT_RGBA, false); + textures[j * 4 + i] = new Texture(64 >> (i << 1), 64 >> (i << 1), FMT_RGBA, OPT_TARGET | OPT_NEAREST); } ~AmbientCache() { @@ -277,7 +278,7 @@ struct AmbientCache { for (int i = 1; i < 4; i++) { int size = 64 >> (i << 1); - Core::active.shader->setParam(uParam, vec4(float(size << 2), 0.0f, 0.0f, 0.0f)); + Core::active.shader->setParam(uParam, vec4(1.0f / (size << 2), 0.0f, 0.0f, 0.0f)); for (int j = 0; j < 6; j++) { Texture *src = textures[j * 4 + i - 1]; @@ -300,6 +301,7 @@ struct AmbientCache { void processQueue() { game->setupBinding(); + for (int i = 0; i < tasksCount; i++) { Task &task = tasks[i]; diff --git a/src/core.h b/src/core.h index 67ddfbb..e32b1ff 100644 --- a/src/core.h +++ b/src/core.h @@ -122,6 +122,7 @@ struct Lock { #define OS_LOCK(mutex) Lock _lock(mutex) +/* extern void* osRWLockInit (); extern void osRWLockFree (void *obj); extern void osRWLockRead (void *obj); @@ -156,6 +157,7 @@ struct LockWrite { #define OS_LOCK_READ(rwLock) LockRead _rLock(rwLock) #define OS_LOCK_WRITE(rwLock) LockWrite _wLock(rwLock) +*/ enum InputKey { ikNone, // keyboard @@ -926,9 +928,9 @@ namespace Core { validateRenderState(); } - void beginFrame() { + bool beginFrame() { Core::stats.start(); - GAPI::beginFrame(); + return GAPI::beginFrame(); } void endFrame() { diff --git a/src/game.h b/src/game.h index a0bc1c8..3fbe7e0 100644 --- a/src/game.h +++ b/src/game.h @@ -169,11 +169,14 @@ namespace Game { return true; } - void frameBegin() { - if (Core::settings.version == SETTINGS_READING) return; + bool frameBegin() { + if (Core::settings.version == SETTINGS_READING) return false; Core::reset(); - Core::beginFrame(); - level->renderPrepare(); + if (Core::beginFrame()) { + level->renderPrepare(); + return true; + } + return false; } void frameRender() { @@ -195,10 +198,13 @@ namespace Game { Core::endFrame(); } - void render() { - frameBegin(); - frameRender(); - frameEnd(); + bool render() { + if (frameBegin()) { + frameRender(); + frameEnd(); + return true; + } + return false; } } diff --git a/src/gapi_d3d9.h b/src/gapi_d3d9.h index fd3c09e..c00a139 100644 --- a/src/gapi_d3d9.h +++ b/src/gapi_d3d9.h @@ -8,12 +8,54 @@ #define PROFILE_LABEL(id, name, label) #define PROFILE_TIMING(time) -extern LPDIRECT3D9 D3D; -extern LPDIRECT3DDEVICE9 device; +extern LPDIRECT3D9 D3D; +extern LPDIRECT3DDEVICE9 device; +extern D3DPRESENT_PARAMETERS d3dpp; + +#ifdef _DEBUG +void D3DCHECK(HRESULT res) { + if (res == D3D_OK) return; + + LOG("! "); + switch (res) { + case D3DERR_WRONGTEXTUREFORMAT : LOG("D3DERR_WRONGTEXTUREFORMAT"); break; + case D3DERR_UNSUPPORTEDCOLOROPERATION : LOG("D3DERR_UNSUPPORTEDCOLOROPERATION"); break; + case D3DERR_UNSUPPORTEDCOLORARG : LOG("D3DERR_UNSUPPORTEDCOLORARG"); break; + case D3DERR_UNSUPPORTEDALPHAOPERATION : LOG("D3DERR_UNSUPPORTEDALPHAOPERATION"); break; + case D3DERR_UNSUPPORTEDALPHAARG : LOG("D3DERR_UNSUPPORTEDALPHAARG"); break; + case D3DERR_TOOMANYOPERATIONS : LOG("D3DERR_TOOMANYOPERATIONS"); break; + case D3DERR_CONFLICTINGTEXTUREFILTER : LOG("D3DERR_CONFLICTINGTEXTUREFILTER"); break; + case D3DERR_UNSUPPORTEDFACTORVALUE : LOG("D3DERR_UNSUPPORTEDFACTORVALUE"); break; + case D3DERR_CONFLICTINGRENDERSTATE : LOG("D3DERR_CONFLICTINGRENDERSTATE"); break; + case D3DERR_UNSUPPORTEDTEXTUREFILTER : LOG("D3DERR_UNSUPPORTEDTEXTUREFILTER"); break; + case D3DERR_CONFLICTINGTEXTUREPALETTE : LOG("D3DERR_CONFLICTINGTEXTUREPALETTE"); break; + case D3DERR_DRIVERINTERNALERROR : LOG("D3DERR_DRIVERINTERNALERROR"); break; + case D3DERR_NOTFOUND : LOG("D3DERR_NOTFOUND"); break; + case D3DERR_MOREDATA : LOG("D3DERR_MOREDATA"); break; + case D3DERR_DEVICELOST : LOG("D3DERR_DEVICELOST"); break; + case D3DERR_DEVICENOTRESET : LOG("D3DERR_DEVICENOTRESET"); break; + case D3DERR_NOTAVAILABLE : LOG("D3DERR_NOTAVAILABLE"); break; + case D3DERR_OUTOFVIDEOMEMORY : LOG("D3DERR_OUTOFVIDEOMEMORY"); break; + case D3DERR_INVALIDDEVICE : LOG("D3DERR_INVALIDDEVICE"); break; + case D3DERR_INVALIDCALL : LOG("D3DERR_INVALIDCALL"); break; + case D3DERR_DRIVERINVALIDCALL : LOG("D3DERR_DRIVERINVALIDCALL"); break; + case D3DERR_WASSTILLDRAWING : LOG("D3DERR_WASSTILLDRAWING"); break; + default : LOG("D3DERR_UNKNOWN"); break; + } + LOG("\n"); + ASSERT(false); +} +#else + #define D3DCHECK(res) res +#endif namespace GAPI { - #include "shaders/base_vs.h" - #include "shaders/base_ps.h" + #include "shaders/compose_vs.h" + #include "shaders/compose_ps.h" + #include "shaders/shadow_vs.h" + #include "shaders/shadow_ps.h" + #include "shaders/ambient_vs.h" + #include "shaders/ambient_ps.h" #include "shaders/water_vs.h" #include "shaders/water_ps.h" #include "shaders/filter_vs.h" @@ -28,8 +70,39 @@ namespace GAPI { int cullMode, blendMode; uint32 clearColor; + LPDIRECT3DSURFACE9 defBackBuffer; LPDIRECT3DVERTEXDECLARATION9 vertexDecl; + + struct Texture; + struct Mesh; + + struct Resource { + Texture *texture; + Mesh *mesh; + } resList[256]; + int resCount; + + void registerResource(Mesh *mesh) { + resList[resCount].mesh = mesh; + resList[resCount].texture = NULL; + resCount++; + } + + void registerResource(Texture *texture) { + resList[resCount].mesh = NULL; + resList[resCount].texture = texture; + resCount++; + } + + void unregisterResource(void *res) { + for (int i = 0; i < resCount; i++) + if (resList[i].mesh == res || resList[i].texture == res) { + resList[i] = resList[--resCount]; + break; + } + } + // Shader enum { USAGE_VS, @@ -40,40 +113,58 @@ namespace GAPI { int reg; int usage; } bindings[uMAX] = { - { 1, USAGE_VS | USAGE_PS }, // uParam - { 2, USAGE_VS | USAGE_PS }, // uTexParam - { 3, USAGE_VS | USAGE_PS }, // uViewProj - { 7, USAGE_VS | USAGE_PS }, // uBasis - { 71, USAGE_VS | USAGE_PS }, // uLightProj - { 103, USAGE_VS | USAGE_PS }, // uMaterial - { 104, USAGE_VS | USAGE_PS }, // uAmbient - { 110, USAGE_VS | USAGE_PS }, // uFogParams - { 111, USAGE_VS | USAGE_PS }, // uViewPos - { 112, USAGE_VS | USAGE_PS }, // uLightPos - { 116, USAGE_VS | USAGE_PS }, // uLightColor - { 120, USAGE_VS | USAGE_PS }, // uRoomSize - { 121, USAGE_VS | USAGE_PS }, // uPosScale - { 123, USAGE_VS | USAGE_PS }, // uContacts + { 0, USAGE_VS | USAGE_PS }, // uParam + { 1, USAGE_VS | USAGE_PS }, // uTexParam + { 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 }; struct Shader { LPDIRECT3DVERTEXSHADER9 VS; LPDIRECT3DPIXELSHADER9 PS; + BOOL flags[16]; + Shader() : VS(NULL), PS(NULL) {} - void init(Core::Pass pass, int *def, int defCount) { + void init(Core::Pass pass, int type, int *def, int defCount) { const BYTE *vSrc, *pSrc; switch (pass) { - case Core::passCompose : - case Core::passShadow : - case Core::passAmbient : vSrc = BASE_VS; pSrc = BASE_PS; break; - case Core::passWater : vSrc = WATER_VS; pSrc = WATER_PS; break; - case Core::passFilter : vSrc = FILTER_VS; pSrc = FILTER_PS; break; - case Core::passGUI : vSrc = GUI_VS; pSrc = GUI_PS; break; + case Core::passCompose : vSrc = COMPOSE_VS; pSrc = COMPOSE_PS; break; + case Core::passShadow : vSrc = SHADOW_VS; pSrc = SHADOW_PS; break; + case Core::passAmbient : vSrc = AMBIENT_VS; pSrc = AMBIENT_PS; break; + case Core::passWater : vSrc = WATER_VS; pSrc = WATER_PS; break; + case Core::passFilter : vSrc = FILTER_VS; pSrc = FILTER_PS; break; + case Core::passGUI : vSrc = GUI_VS; pSrc = GUI_PS; break; default : ASSERT(false); LOG("! wrong pass id\n"); return; } + memset(flags, 0, sizeof(flags)); + flags[type] = TRUE; + + for (int i = 0; i < defCount; i++) { + switch (def[i]) { + case SD_UNDERWATER : flags[ 5] = TRUE; break; + case SD_ALPHA_TEST : flags[ 6] = TRUE; break; + 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; + } + } + device->CreateVertexShader ((DWORD*)vSrc, &VS); device->CreatePixelShader ((DWORD*)pSrc, &PS); } @@ -88,6 +179,9 @@ namespace GAPI { Core::active.shader = this; device->SetVertexShader(VS); device->SetPixelShader(PS); + + device->SetVertexShaderConstantB (0, flags, COUNT(flags)); + device->SetPixelShaderConstantB (0, flags, COUNT(flags)); } } @@ -127,7 +221,9 @@ namespace GAPI { bool filter = (opt & OPT_NEAREST) == 0; 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; static const struct FormatDesc { int bpp; @@ -146,26 +242,38 @@ namespace GAPI { FormatDesc desc = formats[fmt]; + uint32 usage = 0; + if (mipmaps) usage |= D3DUSAGE_AUTOGENMIPMAP; + if (isDepth) usage |= D3DUSAGE_DEPTHSTENCIL; + if (isTarget) usage |= D3DUSAGE_RENDERTARGET; + + D3DPOOL pool = isTarget ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED; + if (cube) { - device->CreateCubeTexture(width, 1, 0, desc.format, D3DPOOL_MANAGED, &texCube, NULL); + D3DCHECK(device->CreateCubeTexture(width, 1, usage, desc.format, pool, &texCube, NULL)); } else { - device->CreateTexture(width, height, 1, 0, desc.format, D3DPOOL_MANAGED, &tex2D, NULL); - if (data) { + D3DCHECK(device->CreateTexture(width, height, 1, usage, desc.format, pool, &tex2D, NULL)); + if (data && !isTarget) { D3DLOCKED_RECT rect; - tex2D->LockRect(0, &rect, NULL, 0); + D3DCHECK(tex2D->LockRect(0, &rect, NULL, 0)); memcpy(rect.pBits, data, width * height * (desc.bpp / 8)); - tex2D->UnlockRect(0); + D3DCHECK(tex2D->UnlockRect(0)); } } + + if (pool != D3DPOOL_MANAGED) + registerResource(this); } void deinit() { + unregisterResource(this); if (tex2D) tex2D->Release(); if (texCube) texCube->Release(); } void generateMipMap() { - // TODO + if (texCube) texCube->GenerateMipSubLevels(); + if (tex2D) tex2D->GenerateMipSubLevels(); } void bind(int sampler) { @@ -178,6 +286,25 @@ namespace GAPI { device->SetTexture(sampler, tex2D); else if (texCube) device->SetTexture(sampler, texCube); + + bool filter = (Core::settings.detail.filter > Core::Settings::LOW) && !(opt & OPT_NEAREST); + 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); + + if (aniso) { + device->SetSamplerState(sampler, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC); + device->SetSamplerState(sampler, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); + device->SetSamplerState(sampler, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + device->SetSamplerState(sampler, D3DSAMP_MAXANISOTROPY, support.maxAniso); + } else { + device->SetSamplerState(sampler, D3DSAMP_MINFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); + device->SetSamplerState(sampler, D3DSAMP_MAGFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); + device->SetSamplerState(sampler, D3DSAMP_MIPFILTER, mipmaps ? (filter ? D3DTEXF_LINEAR : D3DTEXF_POINT) : D3DTEXF_NONE); + device->SetSamplerState(sampler, D3DSAMP_MAXANISOTROPY, 1); + } } } @@ -188,18 +315,7 @@ namespace GAPI { } } - void setFilterQuality(int value) { - bool filter = value > Core::Settings::LOW; - bool mipmaps = value > Core::Settings::MEDIUM; - - for (int i = 0; i < sMAX; i++) { - device->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); - device->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); - device->SetSamplerState(i, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP); - device->SetSamplerState(i, D3DSAMP_MAGFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); - device->SetSamplerState(i, D3DSAMP_MINFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); - } - } + void setFilterQuality(int value) {} }; // Mesh @@ -216,15 +332,22 @@ namespace GAPI { void init(Index *indices, int iCount, ::Vertex *vertices, int vCount, int aCount) { this->iCount = iCount; this->vCount = vCount; - ASSERT(sizeof(GAPI::Vertex) == sizeof(::Vertex)); - device->CreateIndexBuffer (iCount * sizeof(indices[0]), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &IB, NULL); - device->CreateVertexBuffer (vCount * sizeof(vertices[0]), D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &VB, NULL); + uint32 usage = D3DUSAGE_WRITEONLY | (dynamic ? D3DUSAGE_DYNAMIC : 0); + D3DPOOL pool = dynamic ? D3DPOOL_DEFAULT : D3DPOOL_MANAGED; + + D3DCHECK(device->CreateIndexBuffer (iCount * sizeof(Index), usage, D3DFMT_INDEX16, pool, &IB, NULL)); + D3DCHECK(device->CreateVertexBuffer (vCount * sizeof(Vertex), usage, D3DFMT_UNKNOWN, pool, &VB, NULL)); + update(indices, iCount, vertices, vCount); + + if (pool != D3DPOOL_MANAGED) + registerResource(this); } void deinit() { + unregisterResource(this); IB->Release(); VB->Release(); } @@ -236,15 +359,17 @@ namespace GAPI { int size; if (indices && iCount) { - IB->Lock(0, size = iCount * sizeof(indices[0]), &ptr, 0); + size = iCount * sizeof(indices[0]); + D3DCHECK(IB->Lock(0, 0, &ptr, dynamic ? D3DLOCK_DISCARD : 0)); memcpy(ptr, indices, size); - IB->Unlock(); + D3DCHECK(IB->Unlock()); } if (vertices && vCount) { - VB->Lock(0, size = vCount * sizeof(vertices[0]), &ptr, 0); + size = vCount * sizeof(vertices[0]); + D3DCHECK(VB->Lock(0, 0, &ptr, dynamic ? D3DLOCK_DISCARD: 0)); memcpy(ptr, vertices, size); - VB->Unlock(); + D3DCHECK(VB->Unlock()); } } @@ -276,7 +401,7 @@ namespace GAPI { LOG("Vendor : %s\n", adapterInfo.Description); LOG("Renderer : Direct3D 9.0c\n"); - support.maxAniso = 16; + support.maxAniso = 8; support.maxVectors = 16; support.shaderBinary = false; support.VAO = false; @@ -308,40 +433,61 @@ namespace GAPI { }; device->CreateVertexDeclaration(VERTEX_DECL, &vertexDecl); -/* - if (support.maxAniso) - glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &support.maxAniso); - #ifdef _GAPI_GLES - glGetIntegerv(GL_MAX_VARYING_VECTORS, &support.maxVectors); - #else - support.maxVectors = 16; - #endif - glEnable(GL_SCISSOR_TEST); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&defaultFBO); - glGenFramebuffers(1, &FBO); -*/ } void deinit() { - /* - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glDeleteFramebuffers(1, &FBO); - - glBindRenderbuffer(GL_RENDERBUFFER, 0); - for (int b = 0; b < 2; b++) - for (int i = 0; i < rtCache[b].count; i++) - glDeleteRenderbuffers(1, &rtCache[b].items[i].ID); - */ + vertexDecl->Release(); } - void beginFrame() { + void resetDevice() { + int tmpCount = resCount; + Resource tmpList[256]; + memcpy(tmpList, resList, sizeof(Resource) * tmpCount); + + for (int i = 0; i < tmpCount; i++) { + Resource &res = tmpList[i]; + if (res.mesh) + res.mesh->deinit(); + else + res.texture->deinit(); + } + + D3DCHECK(device->Reset(&d3dpp)); + + for (int i = 0; i < tmpCount; i++) { + Resource &res = tmpList[i]; + if (res.mesh) + res.mesh->init(NULL, res.mesh->iCount, NULL, res.mesh->vCount, 0); + else + res.texture->init(NULL); + } + + } + + bool beginFrame() { + switch (device->TestCooperativeLevel()) { + case D3D_OK : + break; + case D3DERR_DEVICELOST : + return false; + case D3DERR_DEVICENOTRESET : + switch (device->Reset(&d3dpp)) { + case D3D_OK : break; + default : return false; + } + case D3DERR_DRIVERINTERNALERROR : + Core::quit(); + return false; + } + + device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &defBackBuffer); device->BeginScene(); + return true; } void endFrame() { device->EndScene(); + defBackBuffer->Release(); } void resetState() { @@ -373,39 +519,46 @@ namespace GAPI { } void bindTarget(Texture *target, int face) { - /* if (!target) { // may be a null - glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + D3DCHECK(device->SetRenderTarget(0, defBackBuffer)); } else { - GLenum texTarget = GL_TEXTURE_2D; - if (target->opt & OPT_CUBEMAP) - texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + ASSERT(target->opt & OPT_TARGET); + + LPDIRECT3DSURFACE9 surface; + + if (target->tex2D) + D3DCHECK(target->tex2D->GetSurfaceLevel(0, &surface)); + else if (target->texCube) + D3DCHECK(target->texCube->GetCubeMapSurface(D3DCUBEMAP_FACES(D3DCUBEMAP_FACE_POSITIVE_X + face), 0, &surface)); + + D3DCHECK(device->SetRenderTarget(0, surface)); + + surface->Release(); bool depth = target->fmt == FMT_DEPTH || target->fmt == FMT_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); } - */ } void discardTarget(bool color, bool depth) {} void copyTarget(Texture *dst, int xOffset, int yOffset, int x, int y, int width, int height) { - Core::active.textures[0] = NULL; - /* - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, dst->ID); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height); - glBindTexture(GL_TEXTURE_2D, 0); - */ + ASSERT(dst && dst->tex2D); + + LPDIRECT3DSURFACE9 surface; + dst->tex2D->GetSurfaceLevel(0, &surface); + + RECT srcRect = { x, y, x + width, y + height }, + dstRect = { xOffset, yOffset, xOffset + width, yOffset + height }; + + device->StretchRect(defBackBuffer, &srcRect, surface, &dstRect, D3DTEXF_POINT); + + surface->Release(); } void setVSync(bool enable) { - // + d3dpp.PresentationInterval = enable ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; + GAPI::resetDevice(); } void waitVBlank() {} @@ -502,9 +655,24 @@ namespace GAPI { } vec4 copyPixel(int x, int y) { - 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); + GAPI::Texture *t = Core::active.target; + ASSERT(t && t->tex2D); + + LPDIRECT3DSURFACE9 surface, texSurface; + D3DCHECK(t->tex2D->GetSurfaceLevel(0, &texSurface)); + D3DCHECK(device->CreateOffscreenPlainSurface(t->width, t->height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, NULL)); + D3DCHECK(device->GetRenderTargetData(texSurface, surface)); + + RECT r = { x, y, x + 1, y + 1 }; + D3DLOCKED_RECT rect; + surface->LockRect(&rect, &r, D3DLOCK_READONLY); + ubyte4 c = *((ubyte4*)rect.pBits); + surface->UnlockRect(); + + texSurface->Release(); + surface->Release(); + + return vec4(float(c.z), float(c.y), float(c.x), float(c.w)) * (1.0f / 255.0f); } void initPSO(PSO *pso) { diff --git a/src/gapi_gl.h b/src/gapi_gl.h index 9a331ae..fb1c29f 100644 --- a/src/gapi_gl.h +++ b/src/gapi_gl.h @@ -335,7 +335,7 @@ namespace GAPI { struct Shader { #ifdef FFP - void init(Core::Pass pass, int *def, int defCount) {} + void init(Core::Pass pass, int type, int *def, int defCount) {} void deinit() {} void bind() {} void setParam(UniformType uType, const vec4 &value, int count = 1) {} @@ -345,7 +345,7 @@ namespace GAPI { uint32 ID; int32 uID[uMAX]; - void init(Core::Pass pass, int *def, int defCount) { + void init(Core::Pass pass, int type, int *def, int defCount) { const char *source; switch (pass) { case Core::passCompose : @@ -977,7 +977,9 @@ namespace GAPI { glDeleteRenderbuffers(1, &rtCache[b].items[i].ID); } - void beginFrame() {} + bool beginFrame() { + return true; + } void endFrame() {} diff --git a/src/gapi_gu.h b/src/gapi_gu.h index 4fd635c..bb4f853 100644 --- a/src/gapi_gu.h +++ b/src/gapi_gu.h @@ -289,7 +289,9 @@ namespace GAPI { delete[] cmdBuf; } - void beginFrame() {} + bool beginFrame() { + return true; + } void endFrame() {} diff --git a/src/lara.h b/src/lara.h index 28ed026..22470b3 100644 --- a/src/lara.h +++ b/src/lara.h @@ -1443,7 +1443,7 @@ struct Lara : Character { void bakeEnvironment() { flags.invisible = true; if (!environment) - environment = new Texture(256, 256, FMT_RGBA, OPT_CUBEMAP | OPT_MIPMAPS); + environment = new Texture(256, 256, FMT_RGBA, OPT_CUBEMAP | OPT_MIPMAPS | OPT_TARGET); game->renderEnvironment(getRoomIndex(), pos - vec3(0.0f, 384.0f, 0.0f), &environment, 0, Core::passCompose); environment->generateMipMap(); flags.invisible = false; diff --git a/src/platform/win/main.cpp b/src/platform/win/main.cpp index 2ff64d6..d21dadd 100644 --- a/src/platform/win/main.cpp +++ b/src/platform/win/main.cpp @@ -50,26 +50,6 @@ void osMutexUnlock(void *obj) { } /* -void* osMutexInit() { - HANDLE *mutex = new HANDLE(); - *mutex = CreateMutex(NULL, FALSE, NULL); - return mutex; -} - -void osMutexFree(void *obj) { - CloseHandle(*(HANDLE*)obj); - delete (HANDLE*)obj; -} - -void osMutexLock(void *obj) { - WaitForSingleObject(*(HANDLE*)obj, INFINITE); -} - -void osMutexUnlock(void *obj) { - ReleaseMutex(*(HANDLE*)obj); -} -*/ - void* osRWLockInit() { SRWLOCK *lock = new SRWLOCK(); InitializeSRWLock(lock); @@ -95,7 +75,7 @@ void osRWLockWrite(void *obj) { void osRWUnlockWrite(void *obj) { ReleaseSRWLockExclusive((SRWLOCK*)obj); } - +*/ // timing int osStartTime = 0; @@ -441,16 +421,14 @@ HWND hWnd; SwapBuffers(hDC); } #else - D3DPRESENT_PARAMETERS d3dpp; LPDIRECT3D9 D3D; LPDIRECT3DDEVICE9 device; + D3DPRESENT_PARAMETERS d3dpp; void ContextCreate() { memset(&d3dpp, 0, sizeof(d3dpp)); d3dpp.Windowed = TRUE; d3dpp.BackBufferCount = 1; - d3dpp.BackBufferWidth = 1; - d3dpp.BackBufferHeight = 1; d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.hDeviceWindow = hWnd; @@ -474,14 +452,16 @@ HWND hWnd; } void ContextResize() { - d3dpp.BackBufferWidth = Core::width; - d3dpp.BackBufferHeight = Core::height; - device->Reset(&d3dpp); + if (Core::width <= 0 || Core::height <= 0) + return; + d3dpp.BackBufferWidth = Core::width; + d3dpp.BackBufferHeight = Core::height; + GAPI::resetDevice(); } void ContextSwap() { if (device->Present(NULL, NULL, NULL, NULL) == D3DERR_DEVICELOST) - ContextResize(); + GAPI::resetDevice(); } #endif diff --git a/src/shader.h b/src/shader.h index fe0ac53..5f480e6 100644 --- a/src/shader.h +++ b/src/shader.h @@ -13,8 +13,8 @@ struct Shader : GAPI::Shader { MAX = 6 }; - Shader(Core::Pass pass, int *def, int defCount) : GAPI::Shader() { - init(pass, def, defCount); + Shader(Core::Pass pass, Type type, int *def, int defCount) : GAPI::Shader() { + init(pass, type, def, defCount); } virtual ~Shader() { diff --git a/src/shaders/base.hlsl b/src/shaders/base.hlsl index 0b61566..d52ee8f 100644 --- a/src/shaders/base.hlsl +++ b/src/shaders/base.hlsl @@ -1,15 +1,15 @@ #include "common.hlsl" struct VS_OUTPUT { - float4 wPos : POSITION; - float3 vCoord : TEXCOORD2; - float4 vTexCoord : TEXCOORD0; - float4 vDiffuse : COLOR0; - float4 vNormal : NORMAL; - float4 vViewVec : TEXCOORD1; - float3 vAmbient : COLOR1; - float4 vLightMap : COLOR2; - float4 vLight : COLOR3; + 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; }; #ifdef VERTEX @@ -20,38 +20,262 @@ float3 mulQuat(float4 q, float3 v) { float3 mulBasis(float4 rot, float3 pos, float3 v) { return mulQuat(rot, v) + pos; } - + +float3 calcAmbient(float3 n) { + float3 sqr = n * n; + float3 pos = step(0.0, n); + return sqr.x * lerp(uAmbient[1].xyz, uAmbient[0].xyz, pos.x) + + sqr.y * lerp(uAmbient[3].xyz, uAmbient[2].xyz, pos.y) + + sqr.z * lerp(uAmbient[5].xyz, uAmbient[4].xyz, pos.z); +} + VS_OUTPUT main(VS_INPUT In) { VS_OUTPUT Out; + Out.ambient = 0.0; + Out.lightMap = 0.0; + Out.light = 0.0; int index = int(In.aCoord.w * 2.0); float4 rBasisRot = uBasis[index]; float4 rBasisPos = uBasis[index + 1]; - Out.vCoord = mulBasis(rBasisRot, rBasisPos.xyz, In.aCoord.xyz); - Out.wPos = mul(uViewProj, float4(Out.vCoord, rBasisPos.w)); - Out.vTexCoord = In.aTexCoord * (1.0 / 32767.0); - Out.vTexCoord.xy *= Out.vTexCoord.zw; + Out.texCoord = In.aTexCoord * (1.0 / 32767.0); + + if (TYPE_SPRITE) { + Out.coord = mulBasis(rBasisRot, rBasisPos.xyz + In.aCoord.xyz, float3(In.aTexCoord.z, In.aTexCoord.w, 0.0)); + } else { + Out.coord = mulBasis(rBasisRot, rBasisPos.xyz, In.aCoord.xyz); + Out.texCoord.xy *= Out.texCoord.zw; + } + + #ifdef PASS_SHADOW + Out.viewVec = 0.0; + Out.normal = 0.0; + Out.diffuse = 0.0; + #else + 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 { + Out.normal.xyz = mulQuat(rBasisRot, normalize(In.aNormal.xyz)); + } + + 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; + float3 lv3 = (uLightPos[3].xyz - Out.coord) * uLightColor[3].w; + + float4 lum, att; + if (TYPE_ENTITY) { + lum.x = dot(Out.normal.xyz, normalize(lv0)); + att.x = dot(lv0, lv0); + if (OPT_AMBIENT) { + Out.ambient = calcAmbient(Out.normal.xyz); + } else { + Out.ambient = min(uMaterial.yyy, In.aLight.xyz); + } + } else { + if (TYPE_SPRITE) { + lum.x = uMaterial.y; + } else { + lum.x = 1.0; + } + att.x = 0.0; + + Out.ambient = min(uMaterial.yyy, In.aLight.zyx); + } + + float4 light; + lum.y = dot(Out.normal.xyz, normalize(lv1)); att.y = dot(lv1, lv1); + lum.z = dot(Out.normal.xyz, normalize(lv2)); att.z = dot(lv2, lv2); + lum.w = dot(Out.normal.xyz, normalize(lv3)); att.w = dot(lv3, lv3); + light = max(0.0, lum) * max(0.0, 1.0 - att); + + if (UNDERWATER) { + light.x *= abs(sin(dot(Out.coord.xyz, 1.0 / 512.0) + uParam.x)) * 1.5 + 0.5; + + float d; + if (uViewPos.y < uParam.y) { + d = abs((Out.coord.y - uParam.y) / normalize(Out.viewVec.xyz).y); + } else { + d = length(uViewPos.xyz - Out.coord.xyz); + } + + fog = d * WATER_FOG_DIST; + } else { + fog = length(Out.viewVec.xyz); + } + Out.normal.w = saturate(1.0 / exp(fog)); + + if (OPT_SHADOW) { + Out.light = light; + Out.lightMap = In.aLight.zyxw * light.x; + } else { + Out.light.xyz = uLightColor[1].xyz * light.y + uLightColor[2].xyz * light.z + uLightColor[3].xyz * light.w; + Out.light.w = 0.0; + + if (TYPE_ENTITY) { + Out.light.xyz += Out.ambient + uLightColor[0].xyz * light.x; + } else { + Out.light.xyz += In.aLight.xyz * light.x; + } + } + } else + Out.normal.w = 1.0; + + #else + Out.normal = In.aNormal; + Out.light = float4(In.aLight.xyz, 1.0); + #endif + + if (TYPE_MIRROR) { + Out.diffuse = uMaterial; + } else { + Out.diffuse = float4(In.aColor.zyx * (uMaterial.x * 1.8), uMaterial.w); + + if (UNDERWATER) { + Out.diffuse.xyz *= UNDERWATER_COLOR; + } + + if (TYPE_FLASH) { + Out.diffuse.xyz += uMaterial.w; + } + } + #endif + + Out.wpos = mul(uViewProj, float4(Out.coord, rBasisPos.w)); - Out.vDiffuse = float4(In.aColor.xyz * (uMaterial.x), uMaterial.w); - Out.vNormal = In.aNormal; - Out.vViewVec = float4(uViewPos.xyz - Out.vCoord, 0.0); - Out.vAmbient = float3(0.2, 0.2, 0.2); - Out.vLightMap = In.aLight; - Out.vLight = float4(0.5, 0.5, 0.5, 0.5); return Out; } #else // PIXEL -sampler sDiffuse : register(s0); -sampler sNormal : register(s1); -sampler sReflect : register(s2); -sampler sShadow : register(s3); -sampler sEnvironment : register(s4); -sampler sMask : register(s5); +float getShadow(float3 lightVec) { + return 1.0; +} + +float getContactAO(float3 p, float3 n) { + float res = 1.0; + for (int i = 0; i < MAX_CONTACTS; i++) { + 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); + } + return res; +} + +float calcCaustics(float3 coord, float3 n) { + float2 cc = saturate((coord.xz - uRoomSize.xy) / uRoomSize.zw); + return tex2D(sReflect, cc).x * max(0.0, -n.y); +} + +float calcSpecular(float3 normal, float3 viewVec, float3 lightVec, float4 color, float intensity) { + float3 vv = normalize(viewVec); + float3 rv = reflect(-vv, normal); + float3 lv = normalize(lightVec); + return pow(max(0.0, dot(rv, lv)), 8.0) * intensity; +} float4 main(VS_OUTPUT In) : COLOR0 { - return (In.vDiffuse * In.vLightMap * tex2D(sDiffuse, In.vTexCoord.xy / In.vTexCoord.zw)).bgra; + float2 uv = In.texCoord.xy; + + #ifdef PASS_COMPOSE + if (CLIP_PLANE) { + if (In.viewVec.w > uParam.w) { + discard; + } + } + + if (!TYPE_SPRITE) { + uv /= In.texCoord.zw; + } + #endif + + float4 color; + + if (TYPE_MIRROR) { + float3 rv = reflect(-normalize(In.viewVec.xyz), normalize(In.normal.xyz)); + color = texCUBE(sEnvironment, normalize(rv)); + } else { + color = tex2D(sDiffuse, uv).bgra; + + if (ALPHA_TEST) { + if (color.w <= 0.5) + discard; + } + } + + #ifdef PASS_SHADOW + return 1.0; + #else + color *= In.diffuse; + + if (TYPE_FLASH) { + return color; + } + + if (TYPE_MIRROR) { + return color; + } + + #ifdef PASS_AMBIENT + color.xyz *= In.light.xyz; + #endif + + #ifdef PASS_COMPOSE + float3 lightVec = (uLightPos[0].xyz - In.coord) * uLightColor[0].w; + float3 normal = normalize(In.normal.xyz); + + float rSpecular = 0.0; + + float3 light; + if (OPT_SHADOW) { + 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); + rSpecular = (uMaterial.z + 0.03) * rShadow; + light += In.ambient + uLightColor[0].xyz * (In.light.x * rShadow); + } else if (TYPE_ROOM) { + float rShadow = getShadow(lightVec); + light += lerp(In.ambient.xyz, In.lightMap.xyz, rShadow); + } else if (TYPE_SPRITE) { + light += In.lightMap.xyz; + } + } else { + light = In.light.xyz; + } + + if (OPT_CAUSTICS) { + light += calcCaustics(In.coord, normal); + } + + if (OPT_CONTACT) { + light *= getContactAO(In.coord, normal) * 0.5 + 0.5; + } + + color.xyz *= light; + + if (TYPE_ENTITY) { + color.xyz += calcSpecular(normal, In.viewVec.xyz, lightVec, uLightColor[0], rSpecular); + } + + if (UNDERWATER) { + color.xyz = lerp(UNDERWATER_COLOR * 0.2, color.xyz, In.normal.w); + } else { + color.xyz = lerp(uFogParams.xyz, color.xyz, In.normal.w); + } + #endif + #endif + + return color; } #endif \ No newline at end of file diff --git a/src/shaders/common.hlsl b/src/shaders/common.hlsl index 5813e44..50b9305 100644 --- a/src/shaders/common.hlsl +++ b/src/shaders/common.hlsl @@ -1,5 +1,7 @@ -#define MAX_LIGHTS 4 -#define MAX_CONTACTS 15 +#define MAX_LIGHTS 4 +#define MAX_CONTACTS 15 +#define WATER_FOG_DIST (1.0 / (6.0 * 1024.0)) +#define UNDERWATER_COLOR float3(0.6, 0.9, 0.9) struct VS_INPUT { float4 aCoord : POSITION; @@ -9,18 +11,55 @@ struct VS_INPUT { float4 aLight : COLOR1; }; -int4 uInfo : register( c0 ); -float4 uParam : register( c1 ); -float4 uTexParam : register( c2 ); -float4x4 uViewProj : register( c3 ); -float4 uBasis[32 * 2] : register( c7 ); -float4x4 uLightProj : register( c71 ); -float4 uMaterial : register( c103 ); -float4 uAmbient[6] : register( c104 ); -float4 uFogParams : register( c110 ); -float4 uViewPos : register( c111 ); -float4 uLightPos[MAX_LIGHTS] : register( c112 ); -float4 uLightColor[MAX_LIGHTS] : register( c116 ); -float4 uRoomSize : register( c120 ); -float4 uPosScale[2] : register( c121 ); -float4 uContacts[MAX_CONTACTS] : register( c123 ); \ No newline at end of file +#ifdef PIXEL + sampler sDiffuse : register(s0); + sampler sNormal : register(s1); + sampler sReflect : register(s2); + sampler sShadow : register(s3); + sampler sEnvironment : register(s4); + 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 ); + +#define TYPE_SPRITE uFlags[0] +#define TYPE_FLASH uFlags[1] +#define TYPE_ROOM uFlags[2] +#define TYPE_ENTITY uFlags[3] +#define TYPE_MIRROR uFlags[4] + +#define FILTER_DEFAULT uFlags[0] +#define FILTER_DOWNSAMPLE uFlags[1] +#define FILTER_GRAYSCALE uFlags[2] +#define FILTER_BLUR uFlags[3] +#define FILTER_EQUIRECTANGULAR uFlags[4] + +#define WATER_DROP uFlags[0] +#define WATER_STEP uFlags[1] +#define WATER_CAUSTICS uFlags[2] +#define WATER_MASK uFlags[3] +#define WATER_COMPOSE uFlags[4] + +// options for compose, shadow, ambient passes +#define UNDERWATER uFlags[5] +#define ALPHA_TEST uFlags[6] +#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 diff --git a/src/shaders/compile_dx9.bat b/src/shaders/compile_dx9.bat index b4d26ba..a604f90 100644 --- a/src/shaders/compile_dx9.bat +++ b/src/shaders/compile_dx9.bat @@ -1,6 +1,10 @@ @echo off -fxc /nologo /T vs_3_0 /O3 /Vn BASE_VS /Fh base_vs.h base.hlsl /DVERTEX -fxc /nologo /T ps_3_0 /O3 /Vn BASE_PS /Fh base_ps.h base.hlsl /DPIXEL +fxc /nologo /T vs_3_0 /O3 /Vn COMPOSE_VS /Fh compose_vs.h base.hlsl /DPASS_COMPOSE /DVERTEX +fxc /nologo /T ps_3_0 /O3 /Vn COMPOSE_PS /Fh compose_ps.h base.hlsl /DPASS_COMPOSE /DPIXEL +fxc /nologo /T vs_3_0 /O3 /Vn SHADOW_VS /Fh shadow_vs.h base.hlsl /DPASS_SHADOW /DVERTEX +fxc /nologo /T ps_3_0 /O3 /Vn SHADOW_PS /Fh shadow_ps.h base.hlsl /DPASS_SHADOW /DPIXEL +fxc /nologo /T vs_3_0 /O3 /Vn AMBIENT_VS /Fh ambient_vs.h base.hlsl /DPASS_AMBIENT /DVERTEX +fxc /nologo /T ps_3_0 /O3 /Vn AMBIENT_PS /Fh ambient_ps.h base.hlsl /DPASS_AMBIENT /DPIXEL fxc /nologo /T vs_3_0 /O3 /Vn WATER_VS /Fh water_vs.h water.hlsl /DVERTEX fxc /nologo /T ps_3_0 /O3 /Vn WATER_PS /Fh water_ps.h water.hlsl /DPIXEL fxc /nologo /T vs_3_0 /O3 /Vn FILTER_VS /Fh filter_vs.h filter.hlsl /DVERTEX diff --git a/src/shaders/filter.glsl b/src/shaders/filter.glsl index fdc972b..ebb1e62 100644 --- a/src/shaders/filter.glsl +++ b/src/shaders/filter.glsl @@ -23,13 +23,11 @@ uniform vec4 uParam; uniform sampler2D sNormal; vec4 downsample() { // uParam (textureSize, unused, unused, unused) - float k = 1.0 / uParam.x; // inverted texture size - vec4 color = vec4(0.0); for (float y = -1.5; y < 2.0; y++) for (float x = -1.5; x < 2.0; x++) { vec4 p; - p.xyz = texture2D(sDiffuse, vTexCoord + vec2(x, y) * k).xyz; + p.xyz = texture2D(sDiffuse, vTexCoord + vec2(x, y) * uParam.x).xyz; p.w = dot(p.xyz, vec3(0.299, 0.587, 0.114)); p.xyz *= p.w; color += p; diff --git a/src/shaders/filter.hlsl b/src/shaders/filter.hlsl index 4d8d14a..de20637 100644 --- a/src/shaders/filter.hlsl +++ b/src/shaders/filter.hlsl @@ -1,25 +1,77 @@ #include "common.hlsl" struct VS_OUTPUT { - float4 wPos : POSITION; - float2 vTexCoord : TEXCOORD0; - float4 vDiffuse : COLOR0; + float4 wpos : POSITION; + float2 texCoord : TEXCOORD0; + float4 diffuse : COLOR0; }; #ifdef VERTEX VS_OUTPUT main(VS_INPUT In) { VS_OUTPUT Out; - Out.wPos = float4(In.aCoord.xy * (1.0 / 32767.0), 0.0, 1.0); - Out.vTexCoord = In.aTexCoord.xy * (1.0 / 32767.0); - Out.vDiffuse = In.aLight; + Out.wpos = float4(In.aCoord.xy * (1.0 / 32767.0), 0.0, 1.0); + Out.texCoord = In.aTexCoord.xy * (1.0 / 32767.0); + Out.diffuse = In.aLight; + +// D3D9 specific + if (FILTER_DOWNSAMPLE) { + Out.texCoord += float2(2.0, -2.0) * uParam.x; + } else if (FILTER_BLUR) { + Out.texCoord += float2(1.0, -1.0) * uParam.z; + } + return Out; } #else // PIXEL -sampler sDiffuse : register(s0); +float4 downsample(float2 uv) { // uParam (1 / textureSize, unused, unused, unused) + float4 color = 0.0; + [unroll] + for (float y = -1.5; y < 2.0; y++) { + [unroll] + for (float x = -1.5; x < 2.0; x++) { + float4 p; + p.xyz = tex2D(sDiffuse, uv + float2(x, y) * uParam.x).xyz; + p.w = dot(p.xyz, float3(0.299, 0.587, 0.114)); + p.xyz *= p.w; + color += p; + } + } + + return float4(color.xyz / color.w, 1.0); +} + +float4 grayscale(float2 uv) { // uParam (factor, unused, unused, unused) + float4 color = tex2D(sDiffuse, uv); + float3 gray = dot(color, float4(0.299, 0.587, 0.114, 0.0)); + return float4(lerp(color.xyz, gray, uParam.x), color.w); +} + +float4 blur(float2 uv) { // uParam (dirX, dirY, 1 / textureSize, unused) + const float3 offset = float3( 0.0, 1.3846153846, 3.2307692308); + const float3 weight = float3(0.2270270270, 0.3162162162, 0.0702702703); + + float2 dir = uParam.xy * uParam.z; + float4 color = tex2D(sDiffuse, uv) * weight[0]; + color += tex2D(sDiffuse, uv + dir * offset[1]) * weight[1]; + color += tex2D(sDiffuse, uv - dir * offset[1]) * weight[1]; + color += tex2D(sDiffuse, uv + dir * offset[2]) * weight[2]; + color += tex2D(sDiffuse, uv - dir * offset[2]) * weight[2]; + return color; +} float4 main(VS_OUTPUT In) : COLOR0 { - return (In.vDiffuse * tex2D(sDiffuse, In.vTexCoord.xy)).bgra; + + if (FILTER_DOWNSAMPLE) + return downsample(In.texCoord.xy); + + if (FILTER_GRAYSCALE) + return grayscale(In.texCoord.xy); + + if (FILTER_BLUR) + return blur(In.texCoord.xy); + + return (tex2D(sDiffuse, In.texCoord.xy) * In.diffuse).bgra; } #endif \ No newline at end of file diff --git a/src/shaders/gui.hlsl b/src/shaders/gui.hlsl index 7f2f280..e58f284 100644 --- a/src/shaders/gui.hlsl +++ b/src/shaders/gui.hlsl @@ -17,8 +17,6 @@ VS_OUTPUT main(VS_INPUT In) { #else // PIXEL -sampler sDiffuse : register(s0); - float4 main(VS_OUTPUT In) : COLOR0 { return (In.vDiffuse * tex2D(sDiffuse, In.vTexCoord.xy)).bgra; } diff --git a/src/shaders/shader.glsl b/src/shaders/shader.glsl index 40f8885..c7c4904 100644 --- a/src/shaders/shader.glsl +++ b/src/shaders/shader.glsl @@ -402,7 +402,6 @@ uniform vec4 uFogParams; color *= vDiffuse; #if !defined(TYPE_FLASH) && !defined(TYPE_MIRROR) - vec3 lightVec = (uLightPos[0].xyz - vCoord) * uLightColor[0].w; #ifdef PASS_AMBIENT color.xyz *= vLight.xyz; @@ -410,7 +409,8 @@ uniform vec4 uFogParams; #ifdef PASS_COMPOSE - vec3 n = normalize(vNormal.xyz); + vec3 lightVec = (uLightPos[0].xyz - vCoord) * uLightColor[0].w; + vec3 normal = normalize(vNormal.xyz); #ifdef TYPE_ENTITY float rSpecular = uMaterial.z + 0.03; @@ -441,17 +441,17 @@ uniform vec4 uFogParams; #endif #ifdef OPT_CAUSTICS - light += calcCaustics(n); + light += calcCaustics(normal); #endif #ifdef OPT_CONTACT - light *= getContactAO(vCoord, n) * 0.5 + 0.5; + light *= getContactAO(vCoord, normal) * 0.5 + 0.5; #endif color.xyz *= light; #ifdef TYPE_ENTITY - color.xyz += calcSpecular(n, vViewVec.xyz, lightVec.xyz, uLightColor[0], rSpecular); + color.xyz += calcSpecular(normal, vViewVec.xyz, lightVec, uLightColor[0], rSpecular); #endif #ifdef UNDERWATER diff --git a/src/shaders/water.hlsl b/src/shaders/water.hlsl index 1341dec..2d50ed5 100644 --- a/src/shaders/water.hlsl +++ b/src/shaders/water.hlsl @@ -44,13 +44,6 @@ VS_OUTPUT main(VS_INPUT In) { #else // PIXEL -sampler sDiffuse : register(s0); -sampler sNormal : register(s1); -sampler sReflect : register(s2); -sampler sShadow : register(s3); -sampler sEnvironment : register(s4); -sampler sMask : register(s5); - float4 main(VS_OUTPUT In) : COLOR0 { return (In.vDiffuse * tex2D(sDiffuse, In.vTexCoord.xy / In.vTexCoord.zw)).bgra; } diff --git a/src/trigger.h b/src/trigger.h index 680d2e7..7188a9e 100644 --- a/src/trigger.h +++ b/src/trigger.h @@ -762,7 +762,7 @@ struct Crystal : Controller { Texture *environment; Crystal(IGame *game, int entity) : Controller(game, entity) { - environment = new Texture(64, 64, FMT_RGBA, OPT_CUBEMAP | OPT_MIPMAPS); + environment = new Texture(64, 64, FMT_RGBA, OPT_CUBEMAP | OPT_MIPMAPS | OPT_TARGET); activate(); }