diff --git a/src/cache.h b/src/cache.h index b1f14b0..0cbe479 100644 --- a/src/cache.h +++ b/src/cache.h @@ -794,8 +794,8 @@ struct WaterCache { Texture* getScreenTex() { - int w = Core::viewportDef.width; - int h = Core::viewportDef.height; + int w = Core::viewportDef.z; + int h = Core::viewportDef.w; // get refraction texture if (!refract || w != refract->origWidth || h != refract->origHeight) { PROFILE_MARKER("WATER_REFRACT_INIT"); @@ -829,7 +829,7 @@ struct WaterCache { blitTexture(screen, flip); Core::setTarget(screen, NULL, RT_LOAD_COLOR | RT_LOAD_DEPTH | RT_STORE_COLOR); } else { - Core::copyTarget(refract, 0, 0, x, y, Core::viewportDef.width, Core::viewportDef.height); // copy framebuffer into refraction texture + Core::copyTarget(refract, 0, 0, x, y, Core::viewportDef.z, Core::viewportDef.w); // copy framebuffer into refraction texture } } diff --git a/src/core.h b/src/core.h index 9402167..17d6447 100644 --- a/src/core.h +++ b/src/core.h @@ -398,22 +398,23 @@ namespace GAPI { enum RenderState { RS_TARGET = 1 << 0, RS_VIEWPORT = 1 << 1, - RS_DEPTH_TEST = 1 << 2, - RS_DEPTH_WRITE = 1 << 3, - RS_COLOR_WRITE_R = 1 << 4, - RS_COLOR_WRITE_G = 1 << 5, - RS_COLOR_WRITE_B = 1 << 6, - RS_COLOR_WRITE_A = 1 << 7, + RS_SCISSOR = 1 << 2, + RS_DEPTH_TEST = 1 << 3, + RS_DEPTH_WRITE = 1 << 4, + RS_COLOR_WRITE_R = 1 << 5, + RS_COLOR_WRITE_G = 1 << 6, + RS_COLOR_WRITE_B = 1 << 7, + RS_COLOR_WRITE_A = 1 << 8, RS_COLOR_WRITE = RS_COLOR_WRITE_R | RS_COLOR_WRITE_G | RS_COLOR_WRITE_B | RS_COLOR_WRITE_A, - RS_CULL_BACK = 1 << 8, - RS_CULL_FRONT = 1 << 9, + RS_CULL_BACK = 1 << 9, + RS_CULL_FRONT = 1 << 10, RS_CULL = RS_CULL_BACK | RS_CULL_FRONT, - RS_BLEND_ALPHA = 1 << 10, - RS_BLEND_ADD = 1 << 11, - RS_BLEND_MULT = 1 << 12, - RS_BLEND_PREMULT = 1 << 13, + RS_BLEND_ALPHA = 1 << 11, + RS_BLEND_ADD = 1 << 12, + RS_BLEND_MULT = 1 << 13, + RS_BLEND_PREMULT = 1 << 14, RS_BLEND = RS_BLEND_ALPHA | RS_BLEND_ADD | RS_BLEND_MULT | RS_BLEND_PREMULT, - RS_DISCARD = 1 << 14, + RS_DISCARD = 1 << 15, }; // Texture image format @@ -571,20 +572,10 @@ const char *UniformName[uMAX] = { SHADER_UNIFORMS(DECL_STR) }; enum CullMode { cmNone, cmBack, cmFront, cmMAX }; enum BlendMode { bmNone, bmAlpha, bmAdd, bmMult, bmPremult, bmMAX }; -struct Viewport { - int x, y, width, height; - - Viewport() : x(0), y(0), width(0), height(0) {} - Viewport(int x, int y, int width, int height) : x(x), y(y), width(width), height(height) {} - - inline bool operator == (const Viewport &vp) const { return x == vp.x && y == vp.y && width == vp.width && height == vp.height; } - inline bool operator != (const Viewport &vp) const { return !(*this == vp); } -}; - namespace Core { float eye; Texture *eyeTex[2]; - Viewport viewport, viewportDef; + short4 viewport, viewportDef, scissor; mat4 mModel, mView, mProj, mViewProj, mViewInv; mat4 mLightProj; Basis basis; @@ -617,7 +608,8 @@ namespace Core { int32 renderState; uint32 targetFace; uint32 targetOp; - Viewport viewport; // TODO: ivec4 + short4 viewport; // x, y, width, height + short4 scissor; // x, y, width, height vec4 material; #ifdef _GAPI_GL @@ -1008,6 +1000,14 @@ namespace Core { renderState &= ~RS_VIEWPORT; } + if (mask & RS_SCISSOR) { + if (scissor != active.scissor) { + active.scissor = scissor; + GAPI::setScissor(scissor); + } + renderState &= ~RS_SCISSOR; + } + if (mask & RS_DEPTH_TEST) GAPI::setDepthTest((renderState & RS_DEPTH_TEST) != 0); @@ -1038,19 +1038,18 @@ namespace Core { GAPI::setClearColor(color); } - void setViewport(const Viewport &vp) { - viewport = vp; + void setViewport(const short4 &v) { + viewport = v; renderState |= RS_VIEWPORT; } void setViewport(int x, int y, int width, int height) { - setViewport(Viewport(x, y, width, height)); + setViewport(short4(x, y, width, height)); } - void setViewport(const vec4 &vp, int width, int height) { - vec4 s = vec4(vp.x, -vp.w, vp.z, -vp.y); - s = (s * 0.5 + 0.5) * vec4(float(width), float(height), float(width), float(height)); - setViewport(int(s.x), int(s.y), int(s.z) - int(s.x), int(s.w) - int(s.y)); + void setScissor(const short4 &s) { + scissor = s; + renderState |= RS_SCISSOR; } void setCullMode(CullMode mode) { @@ -1113,6 +1112,8 @@ namespace Core { else setViewport(0, 0, color->origWidth, color->origHeight); + setScissor(viewport); + reqTarget.texture = color; reqTarget.op = op; reqTarget.face = face; @@ -1177,6 +1178,7 @@ namespace Core { setViewport(Core::x, Core::y, Core::width, Core::height); viewportDef = viewport; + scissor = viewport; setCullMode(cmFront); setBlendMode(bmAlpha); diff --git a/src/gapi/d3d11.h b/src/gapi/d3d11.h index 125e91f..894ae1e 100644 --- a/src/gapi/d3d11.h +++ b/src/gapi/d3d11.h @@ -649,6 +649,7 @@ namespace GAPI { { D3D11_RASTERIZER_DESC desc; memset(&desc, 0, sizeof(desc)); + desc.ScissorEnable = TRUE; desc.FrontCounterClockwise = TRUE; desc.FillMode = D3D11_FILL_SOLID; desc.CullMode = D3D11_CULL_NONE; @@ -873,7 +874,7 @@ namespace GAPI { deviceContext->OMSetRenderTargets(1, &RTV, DSV); - Core::active.viewport = Viewport(0, 0, 0, 0); // forcing viewport reset + Core::active.viewport = short4(0, 0, 0, 0); // forcing viewport reset } void discardTarget(bool color, bool depth) {} @@ -925,7 +926,7 @@ namespace GAPI { clearColor = color; } - void setViewport(const Viewport &vp) { + void setViewport(const short4 &v) { D3D11_VIEWPORT viewport; viewport.TopLeftX = (FLOAT)x; viewport.TopLeftY = (FLOAT)y; @@ -933,9 +934,20 @@ namespace GAPI { viewport.Height = (FLOAT)height; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; + deviceContext->RSSetViewports(1, &viewport); } + void setScissor(const short4 &s) { + D3D11_RECT scissor; + scissor.left = s.x; + scissor.top = active.viewport.w - (s.y + s.w); + scissor.right = s.x + s.z; + scissor.bottom = active.viewport.w - s.y; + + deviceContext->RSSetScissorRects(1, &scissor); + } + void setDepthTest(bool enable) { depthTest = enable; dirtyDepthState = true; diff --git a/src/gapi/d3d9.h b/src/gapi/d3d9.h index 07338ca..db04cc1 100644 --- a/src/gapi/d3d9.h +++ b/src/gapi/d3d9.h @@ -646,7 +646,8 @@ namespace GAPI { surface->Release(); } - Core::active.viewport = Viewport(0, 0, 0, 0); // forcing viewport reset + Core::active.viewport = short4(0, 0, 0, 0); // forcing viewport reset + Core::active.scissor = short4(0, 0, 0, 0); } void discardTarget(bool color, bool depth) {} @@ -684,23 +685,26 @@ namespace GAPI { (int(color.w * 255) << 24); } - void setViewport(const Viewport &vp) { - D3DVIEWPORT9 dv; - dv.X = vp.x; - dv.Y = vp.y; - dv.Width = vp.width; - dv.Height = vp.height; - dv.MinZ = 0.0f; - dv.MaxZ = 1.0f; + void setViewport(const short4 &v) { + D3DVIEWPORT9 viewport; + viewport.X = v.x; + viewport.Y = v.y; + viewport.Width = v.z; + viewport.Height = v.w; + viewport.MinZ = 0.0f; + viewport.MaxZ = 1.0f; - RECT ds; - ds.left = vp.x; - ds.top = vp.y; - ds.right = vp.x + vp.width; - ds.bottom = vp.y + vp.height; + device->SetViewport(&viewport); + } - device->SetViewport(&dv); - device->SetScissorRect(&ds); + void setScissor(const short4 &s) { + RECT scissor; + scissor.left = s.x; + scissor.top = active.viewport.w - (s.y + s.w); + scissor.right = s.x + s.z; + scissor.bottom = active.viewport.w - s.y; + + device->SetScissorRect(&scissor); } void setDepthTest(bool enable) { diff --git a/src/gapi/gl.h b/src/gapi/gl.h index 7e2c064..3a340a4 100644 --- a/src/gapi/gl.h +++ b/src/gapi/gl.h @@ -1474,9 +1474,12 @@ namespace GAPI { glClearColor(color.x, color.y, color.z, color.w); } - void setViewport(const Viewport &vp) { - glViewport(vp.x, vp.y, vp.width, vp.height); - glScissor(vp.x, vp.y, vp.width, vp.height); + void setViewport(const short4 &v) { + glViewport(v.x, v.y, v.z, v.w); + } + + void setScissor(const short4 &s) { + glScissor(s.x, s.y, s.z, s.w); } void setDepthTest(bool enable) { diff --git a/src/gapi/sw.h b/src/gapi/sw.h index d70fdaa..df17a59 100644 --- a/src/gapi/sw.h +++ b/src/gapi/sw.h @@ -287,11 +287,13 @@ namespace GAPI { void setClearColor(const vec4 &color) {} - void setViewport(const Viewport &vp) { - swClipRect.x = vp.x; - swClipRect.y = vp.y; - swClipRect.z = vp.x + vp.width; - swClipRect.w = vp.y + vp.height; + void setViewport(const short4 &v) {} + + void setScissor(const short4 &s) { + swClipRect.x = s.x; + swClipRect.y = Core::active.viewport.w - (s.y + s.w); + swClipRect.z = s.x + s.z; + swClipRect.w = Core::active.viewport.w - s.y; } void setDepthTest(bool enable) {} @@ -365,7 +367,7 @@ namespace GAPI { x1 = swClipRect.x - x1; S.z += dS.z * x1; step(S, dS, x1); - x1 = Core::viewport.x; + x1 = swClipRect.x; } if (x2 > swClipRect.z) x2 = swClipRect.z; diff --git a/src/level.h b/src/level.h index 3739511..bd8b568 100644 --- a/src/level.h +++ b/src/level.h @@ -1846,6 +1846,19 @@ struct Level : IGame { setMainLight(player); } + short4 getPortalRect(const vec4 &v, int width, int height) { + //vec4 s = vec4(v.x, -v.w, v.z, -v.y); + vec4 s = v; + s = (s * 0.5 + 0.5) * vec4(float(width), float(height), float(width), float(height)); + s.z -= s.x; + s.w -= s.y; + s.x = clamp(s.x, -16383.0f, 16383.0f); + s.y = clamp(s.y, -16383.0f, 16383.0f); + s.z = clamp(s.z, -16383.0f, 16383.0f); + s.w = clamp(s.w, -16383.0f, 16383.0f); + return short4(short(s.x), short(s.y), short(s.z), short(s.w)); + } + void renderRooms(RoomDesc *roomsList, int roomsCount, int transp) { PROFILE_MARKER("ROOMS"); @@ -1875,7 +1888,7 @@ struct Level : IGame { atlasRooms->bind(sDiffuse); - Viewport vp = Core::viewport; + short4 vp = Core::scissor; while (i != end) { int roomIndex = roomsList[i].index; @@ -1886,9 +1899,7 @@ struct Level : IGame { continue; } - #ifdef _GAPI_SW - Core::setViewport(roomsList[i].portal, vp.width, vp.height); - #endif + Core::setScissor(getPortalRect(roomsList[i].portal, vp.z, vp.w)); const TR::Room &room = level.rooms[roomIndex]; @@ -1930,9 +1941,7 @@ struct Level : IGame { if (!range.sprites.iCount) continue; - #ifdef _GAPI_SW - Core::setViewport(roomsList[i].portal, vp.width, vp.height); - #endif + Core::setScissor(getPortalRect(roomsList[i].portal, vp.z, vp.w)); setRoomParams(roomIndex, Shader::SPRITE, 1.0f, 1.0f, 0.0f, 1.0f, true); @@ -1943,7 +1952,7 @@ struct Level : IGame { } } - Core::setViewport(vp); + Core::setScissor(vp); Core::setBlendMode(bmNone); } @@ -2387,13 +2396,11 @@ struct Level : IGame { TR::Room &room = level.rooms[to]; - if (!room.flags.visible) { - if (Core::pass == Core::passCompose && water && waterCache && from != TR::NO_ROOM && (level.rooms[from].flags.water ^ level.rooms[to].flags.water)) - waterCache->setVisible(from, to); + if (Core::pass == Core::passCompose && water && waterCache && from != TR::NO_ROOM && (level.rooms[from].flags.water ^ level.rooms[to].flags.water)) + waterCache->setVisible(from, to); - room.flags.visible = true; - roomsList[roomsCount++] = RoomDesc(to, viewPort); - } + room.flags.visible = true; + roomsList[roomsCount++] = RoomDesc(to, viewPort); vec4 clipPort; for (int i = 0; i < room.portalsCount; i++) { @@ -2947,11 +2954,11 @@ struct Level : IGame { vH = Core::defaultTarget->height; } - Viewport &vp = Core::viewportDef; - vp = Viewport(vX, vY, vW, vH); + short4 &vp = Core::viewportDef; + vp = short4(vX, vY, vW, vH); if (players[1] != NULL && view >= 0) { - vp = Viewport(vX + vW / 2 * view, vY, vW / 2, vH); + vp = short4(vX + vW / 2 * view, vY, vW / 2, vH); if (Core::settings.detail.stereo != Core::Settings::STEREO_SPLIT) { aspect *= 0.5f; @@ -2960,12 +2967,12 @@ struct Level : IGame { if (Core::settings.detail.stereo == Core::Settings::STEREO_SBS) { switch (eye) { - case -1 : vp = Viewport(vX + vp.x - vp.x / 2, vY + vp.y, vp.width / 2, vp.height); break; - case +1 : vp = Viewport(vX + vW / 2 + vp.x / 2, vY + vp.y, vp.width / 2, vp.height); break; + case -1 : vp = short4(vX + vp.x - vp.x / 2, vY + vp.y, vp.z / 2, vp.w); break; + case +1 : vp = short4(vX + vW / 2 + vp.x / 2, vY + vp.y, vp.z / 2, vp.w); break; } } - Core::setViewport(vp.x, vp.y, vp.width, vp.height); + Core::setViewport(vp.x, vp.y, vp.z, vp.w); return aspect; } @@ -3056,7 +3063,7 @@ struct Level : IGame { void renderEye(int eye, bool showUI, bool invBG) { float oldEye = Core::eye; - Viewport oldViewport = Core::viewportDef; + short4 oldViewport = Core::viewportDef; GAPI::Texture *oldTarget = Core::defaultTarget; Core::eye = float(eye); @@ -3104,7 +3111,7 @@ struct Level : IGame { } void renderGame(bool showUI, bool invBG) { - Viewport oldViewport = Core::viewportDef; + short4 oldViewport = Core::viewportDef; GAPI::Texture *oldTarget = Core::defaultTarget; bool upscale = !invBG && Core::settings.detail.scale != Core::Settings::SCALE_100; @@ -3118,7 +3125,7 @@ struct Level : IGame { scaleTex = new Texture(w, h, 1, FMT_RGBA, OPT_TARGET); } Core::defaultTarget = scaleTex; - Core::viewportDef = Viewport(0, 0, w, h); + Core::viewportDef = short4(0, 0, w, h); } if (Core::eye == 0.0f && Core::settings.detail.isStereo()) {