From 698b05ee699b9c5afbfa0d7835f8a7a791109c49 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 12 Oct 2016 07:34:07 +0200 Subject: [PATCH] Fix pixel center and letter box issues --- src/gl/system/gl_swframebuffer.cpp | 203 +++++++++++++---------------- src/gl/system/gl_swframebuffer.h | 7 +- src/gl/system/gl_swwipe.cpp | 32 ++--- 3 files changed, 105 insertions(+), 137 deletions(-) diff --git a/src/gl/system/gl_swframebuffer.cpp b/src/gl/system/gl_swframebuffer.cpp index 40d76aab17..252153b54d 100644 --- a/src/gl/system/gl_swframebuffer.cpp +++ b/src/gl/system/gl_swframebuffer.cpp @@ -153,8 +153,8 @@ OpenGLSWFrameBuffer::OpenGLSWFrameBuffer(void *hMonitor, int width, int height, VSync = vid_vsync; BlendingRect.left = 0; BlendingRect.top = 0; - BlendingRect.right = FBWidth; - BlendingRect.bottom = FBHeight; + BlendingRect.right = Width; + BlendingRect.bottom = Height; In2D = 0; Palettes = nullptr; Textures = nullptr; @@ -186,21 +186,6 @@ OpenGLSWFrameBuffer::OpenGLSWFrameBuffer(void *hMonitor, int width, int height, //Windowed = !(static_cast(Video)->GoFullscreen(fullscreen)); TrueHeight = height; - /*if (fullscreen) - { - for (Win32Video::ModeInfo *mode = static_cast(Video)->m_Modes; mode != nullptr; mode = mode->next) - { - if (mode->width == Width && mode->height == Height) - { - TrueHeight = mode->realheight; - PixelDoubling = mode->doubling; - break; - } - } - }*/ - // Offset from top of screen to top of letterboxed screen - LBOffsetI = (TrueHeight - Height) / 2; - LBOffset = float(LBOffsetI); CreateResources(); SetInitialState(); @@ -650,28 +635,39 @@ void OpenGLSWFrameBuffer::DrawTriangleList(int minIndex, int numVertices, int st void OpenGLSWFrameBuffer::Present() { - glBindFramebuffer(GL_FRAMEBUFFER, 0); + int clientWidth = GetClientWidth(); + int clientHeight = GetClientHeight(); + if (clientWidth > 0 && clientHeight > 0) + { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, clientWidth, clientHeight); - FBVERTEX verts[4]; + float scale = MIN(clientWidth / (float)Width, clientHeight / (float)Height); + int letterboxWidth = (int)round(Width * scale); + int letterboxHeight = (int)round(Height * scale); + int letterboxX = (clientWidth - letterboxWidth) / 2; + int letterboxY = (clientHeight - letterboxHeight) / 2; - CalcFullscreenCoords(verts, false, true, 0, 0xFFFFFFFF); - //for (int i = 0; i < 4; i++) - // verts[i].tv = 1.0f - verts[i].tv; - SetTexture(0, OutputFB->Texture); - SetPixelShader(Shaders[SHADER_GammaCorrection]); - SetAlphaBlend(0); - EnableAlphaTest(false); - DrawTriangleFans(2, verts); + DrawLetterbox(letterboxX, letterboxY, letterboxWidth, letterboxHeight); + glViewport(letterboxX, letterboxY, letterboxWidth, letterboxHeight); + + FBVERTEX verts[4]; + CalcFullscreenCoords(verts, false, 0, 0xFFFFFFFF); + SetTexture(0, OutputFB->Texture); + SetPixelShader(Shaders[SHADER_GammaCorrection]); + SetAlphaBlend(0); + EnableAlphaTest(false); + DrawTriangleFans(2, verts); + } SwapBuffers(); Debug->Update(); - glViewport(0, 0, GetClientWidth(), GetClientHeight()); - - float screensize[4] = { (float)GetClientWidth(), (float)GetClientHeight(), 1.0f, 1.0f }; + float screensize[4] = { (float)Width, (float)Height, 1.0f, 1.0f }; SetPixelShaderConstantF(PSCONST_ScreenSize, screensize, 1); glBindFramebuffer(GL_FRAMEBUFFER, OutputFB->Framebuffer); + glViewport(0, 0, Width, Height); } //========================================================================== @@ -707,7 +703,7 @@ void OpenGLSWFrameBuffer::SetInitialState() float weights[4] = { 77 / 256.f, 143 / 256.f, 37 / 256.f, 1 }; SetPixelShaderConstantF(PSCONST_Weights, weights, 1); - float screensize[4] = { (float)GetClientWidth(), (float)GetClientHeight(), 1.0f, 1.0f }; + float screensize[4] = { (float)Width, (float)Height, 1.0f, 1.0f }; SetPixelShaderConstantF(PSCONST_ScreenSize, screensize, 1); AlphaTestEnabled = false; @@ -846,14 +842,14 @@ bool OpenGLSWFrameBuffer::Reset() { ReleaseDefaultPoolItems(); - if (!CreateFrameBuffer("OutputFB", Width, Height, &OutputFB)) - return false; - glBindFramebuffer(GL_FRAMEBUFFER, OutputFB->Framebuffer); - - if (!CreateFBTexture() || !CreateVertexes()) + if (!CreateFrameBuffer("OutputFB", Width, Height, &OutputFB) || !CreateFBTexture() || !CreateVertexes()) { return false; } + + glBindFramebuffer(GL_FRAMEBUFFER, OutputFB->Framebuffer); + glViewport(0, 0, Width, Height); + SetInitialState(); return true; } @@ -892,10 +888,7 @@ void OpenGLSWFrameBuffer::KillNativeTexs() bool OpenGLSWFrameBuffer::CreateFBTexture() { - CreateTexture("FBTexture", Width, Height, 1, GL_R8, &FBTexture); - FBWidth = Width; - FBHeight = Height; - return true; + return CreateTexture("FBTexture", Width, Height, 1, GL_R8, &FBTexture); } //========================================================================== @@ -906,11 +899,7 @@ bool OpenGLSWFrameBuffer::CreateFBTexture() bool OpenGLSWFrameBuffer::CreatePaletteTexture() { - if (!CreateTexture("PaletteTexture", 256, 1, 1, GL_RGBA8, &PaletteTexture)) - { - return false; - } - return true; + return CreateTexture("PaletteTexture", 256, 1, 1, GL_RGBA8, &PaletteTexture); } //========================================================================== @@ -942,35 +931,31 @@ bool OpenGLSWFrameBuffer::CreateVertexes() // //========================================================================== -void OpenGLSWFrameBuffer::CalcFullscreenCoords(FBVERTEX verts[4], bool viewarea_only, bool can_double, uint32_t color0, uint32_t color1) const +void OpenGLSWFrameBuffer::CalcFullscreenCoords(FBVERTEX verts[4], bool viewarea_only, uint32_t color0, uint32_t color1) const { - float offset = LBOffset;//OldRenderTarget != nullptr ? 0 : LBOffset; - float top = offset - 0.5f; - float texright = float(Width) / float(FBWidth); - float texbot = float(Height) / float(FBHeight); float mxl, mxr, myt, myb, tmxl, tmxr, tmyt, tmyb; if (viewarea_only) { // Just calculate vertices for the viewarea/BlendingRect - mxl = float(BlendingRect.left) - 0.5f; - mxr = float(BlendingRect.right) - 0.5f; - myt = float(BlendingRect.top) + top; - myb = float(BlendingRect.bottom) + top; - tmxl = float(BlendingRect.left) / float(Width) * texright; - tmxr = float(BlendingRect.right) / float(Width) * texright; - tmyt = float(BlendingRect.top) / float(Height) * texbot; - tmyb = float(BlendingRect.bottom) / float(Height) * texbot; + mxl = float(BlendingRect.left); + mxr = float(BlendingRect.right); + myt = float(BlendingRect.top); + myb = float(BlendingRect.bottom); + tmxl = float(BlendingRect.left) / float(Width); + tmxr = float(BlendingRect.right) / float(Width); + tmyt = float(BlendingRect.top) / float(Height); + tmyb = float(BlendingRect.bottom) / float(Height); } else { // Calculate vertices for the whole screen - mxl = -0.5f; - mxr = float(Width << (can_double ? PixelDoubling : 0)) - 0.5f; - myt = top; - myb = float(Height << (can_double ? PixelDoubling : 0)) + top; + mxl = 0.0f; + mxr = float(Width); + myt = 0.0f; + myb = float(Height); tmxl = 0; - tmxr = texright; + tmxr = 1.0f; tmyt = 0; - tmyb = texbot; + tmyb = 1.0f; } //{ mxl, myt, 0, 1, 0, 0xFFFFFFFF, tmxl, tmyt }, @@ -1210,8 +1195,6 @@ void OpenGLSWFrameBuffer::Flip() { assert(InScene); - DrawLetterbox(); - Present(); InScene = false; @@ -1225,8 +1208,6 @@ void OpenGLSWFrameBuffer::Flip() TrueHeight = Height; PixelDoubling = 0; - LBOffsetI = 0; - LBOffset = 0.0f; Reset(); V_OutputResized(Width, Height); @@ -1338,7 +1319,7 @@ void OpenGLSWFrameBuffer::Draw3DPart(bool copy3d) color0 = FlashColor0; color1 = FlashColor1; } - CalcFullscreenCoords(verts, Accel2D, false, color0, color1); + CalcFullscreenCoords(verts, Accel2D, color0, color1); DrawTriangleFans(2, verts); } SetPixelShader(Shaders[SHADER_NormalColorPal]); @@ -1353,18 +1334,36 @@ void OpenGLSWFrameBuffer::Draw3DPart(bool copy3d) // //========================================================================== -void OpenGLSWFrameBuffer::DrawLetterbox() +void OpenGLSWFrameBuffer::DrawLetterbox(int x, int y, int width, int height) { - if (LBOffsetI != 0) + int clientWidth = GetClientWidth(); + int clientHeight = GetClientHeight(); + if (clientWidth == 0 || clientHeight == 0) + return; + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glEnable(GL_SCISSOR_TEST); + if (x > 0) { - glEnable(GL_SCISSOR_TEST); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glScissor(0, 0, Width, LBOffsetI); + glScissor(0, 0, clientWidth, x); glClear(GL_COLOR_BUFFER_BIT); - glScissor(0, Height + LBOffsetI, Width, TrueHeight - Height + LBOffsetI); - glClear(GL_COLOR_BUFFER_BIT); - glDisable(GL_SCISSOR_TEST); } + if (clientHeight - x - height > 0) + { + glScissor(0, x + height, clientWidth, clientHeight - x - height); + glClear(GL_COLOR_BUFFER_BIT); + } + if (y > 0) + { + glScissor(0, x, y, height); + glClear(GL_COLOR_BUFFER_BIT); + } + if (clientWidth - y - width > 0) + { + glScissor(y + width, x, clientWidth - y - width, height); + glClear(GL_COLOR_BUFFER_BIT); + } + glDisable(GL_SCISSOR_TEST); } void OpenGLSWFrameBuffer::UploadPalette() @@ -1604,7 +1603,7 @@ void OpenGLSWFrameBuffer::DrawPackedTextures(int packnum) continue; } - AddColorOnlyRect(x - 1, y - 1 - LBOffsetI, 258, 258, ColorXRGB(255, 255, 0)); + AddColorOnlyRect(x - 1, y - 1, 258, 258, ColorXRGB(255, 255, 0)); int back = 0; for (PackedTexture *box = pack->UsedList; box != nullptr; box = box->Next) { @@ -1638,8 +1637,8 @@ void OpenGLSWFrameBuffer::DrawPackedTextures(int packnum) quad->NumVerts = 4; quad->NumTris = 2; - float x0 = float(x) - 0.5f; - float y0 = float(y) - 0.5f; + float x0 = float(x); + float y0 = float(y); float x1 = x0 + 256.f; float y1 = y0 + 256.f; @@ -1695,7 +1694,7 @@ void OpenGLSWFrameBuffer::DrawPackedTextures(int packnum) { x = 8; y += 256 + 8; - if (y > TrueHeight - 256) + if (y > Height - 256) { return; } @@ -2457,7 +2456,7 @@ void OpenGLSWFrameBuffer::DrawLine(int x0, int y0, int x1, int y1, int palcolor, } // Add the endpoints to the vertex buffer. VertexData[VertexPos].x = float(x0); - VertexData[VertexPos].y = float(y0) + LBOffset; + VertexData[VertexPos].y = float(y0); VertexData[VertexPos].z = 0; VertexData[VertexPos].rhw = 1; VertexData[VertexPos].color0 = color; @@ -2466,7 +2465,7 @@ void OpenGLSWFrameBuffer::DrawLine(int x0, int y0, int x1, int y1, int palcolor, VertexData[VertexPos].tv = 0; VertexData[VertexPos + 1].x = float(x1); - VertexData[VertexPos + 1].y = float(y1) + LBOffset; + VertexData[VertexPos + 1].y = float(y1); VertexData[VertexPos + 1].z = 0; VertexData[VertexPos + 1].rhw = 1; VertexData[VertexPos + 1].color0 = color; @@ -2548,7 +2547,6 @@ void OpenGLSWFrameBuffer::DrawTextureParms(FTexture *img, DrawParms &parms) double uscale = 1.f / tex->Box->Owner->Width; bool scissoring = false; FBVERTEX *vert; - float yoffs; if (parms.flipX) { @@ -2598,7 +2596,7 @@ void OpenGLSWFrameBuffer::DrawTextureParms(FTexture *img, DrawParms &parms) BeginQuadBatch(); } glEnable(GL_SCISSOR_TEST); - glScissor(parms.lclip, parms.uclip + LBOffsetI, parms.rclip - parms.lclip, parms.dclip - parms.uclip); + glScissor(parms.lclip, parms.uclip, parms.rclip - parms.lclip, parms.dclip - parms.uclip); } #endif parms.bilinear = false; @@ -2619,23 +2617,6 @@ void OpenGLSWFrameBuffer::DrawTextureParms(FTexture *img, DrawParms &parms) quad->NumTris = 2; quad->NumVerts = 4; - yoffs = GatheringWipeScreen ? 0.5f : 0.5f - LBOffset; - -#if 0 - // Coordinates are truncated to integers, because that's effectively - // what the software renderer does. The hardware will instead round - // to nearest, it seems. - x0 = floorf(x0) - 0.5f; - y0 = floorf(y0) - yoffs; - x1 = floorf(x1) - 0.5f; - y1 = floorf(y1) - yoffs; -#else - x0 = x0 - 0.5f; - y0 = y0 - yoffs; - x1 = x1 - 0.5f; - y1 = y1 - yoffs; -#endif - vert = &VertexData[VertexPos]; // Fill the vertex buffer. @@ -2719,7 +2700,6 @@ void OpenGLSWFrameBuffer::FlatFill(int left, int top, int right, int bottom, FTe { return; } - float yoffs = GatheringWipeScreen ? 0.5f : 0.5f - LBOffset; float x0 = float(left); float y0 = float(top); float x1 = float(right); @@ -2732,10 +2712,6 @@ void OpenGLSWFrameBuffer::FlatFill(int left, int top, int right, int bottom, FTe float v0 = (y0 - yo) * ith; float u1 = (x1 - xo) * itw; float v1 = (y1 - yo) * ith; - x0 -= 0.5f; - y0 -= yoffs; - x1 -= 0.5f; - y1 -= yoffs; CheckQuadBatch(); @@ -2824,7 +2800,7 @@ void OpenGLSWFrameBuffer::FillSimplePoly(FTexture *texture, FVector2 *points, in BufferedTris *quad; FBVERTEX *verts; OpenGLTex *tex; - float yoffs, uscale, vscale; + float uscale, vscale; int i, ipos; uint32_t color0, color1; float ox, oy; @@ -2890,7 +2866,6 @@ void OpenGLSWFrameBuffer::FillSimplePoly(FTexture *texture, FVector2 *points, in quad->NumVerts = npoints; quad->NumTris = npoints - 2; - yoffs = GatheringWipeScreen ? 0 : LBOffset; uscale = float(1.f / (texture->GetScaledWidth() * scalex)); vscale = float(1.f / (texture->GetScaledHeight() * scaley)); ox = float(originx); @@ -2899,13 +2874,13 @@ void OpenGLSWFrameBuffer::FillSimplePoly(FTexture *texture, FVector2 *points, in for (i = 0; i < npoints; ++i) { verts[i].x = points[i].X; - verts[i].y = points[i].Y + yoffs; + verts[i].y = points[i].Y; verts[i].z = 0; verts[i].rhw = 1; verts[i].color0 = color0; verts[i].color1 = color1; - float u = points[i].X - 0.5f - ox; - float v = points[i].Y - 0.5f - oy; + float u = points[i].X - ox; + float v = points[i].Y - oy; if (dorotate) { float t = u; @@ -2944,8 +2919,8 @@ void OpenGLSWFrameBuffer::AddColorOnlyQuad(int left, int top, int width, int hei quad = &QuadExtra[QuadBatchPos]; verts = &VertexData[VertexPos]; - float x = float(left) - 0.5f; - float y = float(top) - 0.5f + (GatheringWipeScreen ? 0 : LBOffset); + float x = float(left); + float y = float(top); quad->ClearSetup(); quad->ShaderNum = BQS_ColorOnly; diff --git a/src/gl/system/gl_swframebuffer.h b/src/gl/system/gl_swframebuffer.h index 1cf0288ce3..5876c34c6d 100644 --- a/src/gl/system/gl_swframebuffer.h +++ b/src/gl/system/gl_swframebuffer.h @@ -382,7 +382,7 @@ private: bool CreatePaletteTexture(); bool CreateVertexes(); void UploadPalette(); - void CalcFullscreenCoords(FBVERTEX verts[4], bool viewarea_only, bool can_double, uint32_t color0, uint32_t color1) const; + void CalcFullscreenCoords(FBVERTEX verts[4], bool viewarea_only, uint32_t color0, uint32_t color1) const; bool Reset(); HWTexture *CopyCurrentScreen(); void ReleaseDefaultPoolItems(); @@ -390,7 +390,7 @@ private: void KillNativeTexs(); PackedTexture *AllocPackedTexture(int width, int height, bool wrapping, int format); void DrawPackedTextures(int packnum); - void DrawLetterbox(); + void DrawLetterbox(int x, int y, int width, int height); void Draw3DPart(bool copy3d); bool SetStyle(OpenGLTex *tex, DrawParms &parms, uint32_t &color0, uint32_t &color1, BufferedTris &quad); static int GetStyleAlpha(int type); @@ -442,13 +442,10 @@ private: int FlashAmount; int TrueHeight; int PixelDoubling; - int LBOffsetI; - float LBOffset; float Gamma; bool UpdatePending; bool NeedPalUpdate; bool NeedGammaUpdate; - int FBWidth, FBHeight; bool VSync; LTRBRect BlendingRect; int In2D; diff --git a/src/gl/system/gl_swwipe.cpp b/src/gl/system/gl_swwipe.cpp index 2f36272b6b..148a087c5a 100644 --- a/src/gl/system/gl_swwipe.cpp +++ b/src/gl/system/gl_swwipe.cpp @@ -232,7 +232,6 @@ bool OpenGLSWFrameBuffer::WipeDo(int ticks) EnableAlphaTest(false); bool done = ScreenWipe->Run(ticks, this); - DrawLetterbox(); return done; } @@ -284,7 +283,7 @@ void OpenGLSWFrameBuffer::Wiper::DrawScreen(OpenGLSWFrameBuffer *fb, HWTexture * { FBVERTEX verts[4]; - fb->CalcFullscreenCoords(verts, false, false, color0, color1); + fb->CalcFullscreenCoords(verts, false, color0, color1); fb->SetTexture(0, tex); fb->SetAlphaBlend(blendop, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); fb->SetPixelShader(fb->Shaders[SHADER_NormalColor]); @@ -410,15 +409,15 @@ bool OpenGLSWFrameBuffer::Wiper_Melt::Run(int ticks, OpenGLSWFrameBuffer *fb) quad->NumTris = 2; // Fill the vertex buffer. - float u0 = rect.left / float(fb->FBWidth); + float u0 = rect.left / float(fb->Width); float v0 = 0; - float u1 = rect.right / float(fb->FBWidth); - float v1 = (rect.bottom - rect.top) / float(fb->FBHeight); + float u1 = rect.right / float(fb->Width); + float v1 = (rect.bottom - rect.top) / float(fb->Height); - float x0 = float(rect.left) - 0.5f; - float x1 = float(rect.right) - 0.5f; - float y0 = float(dpt.y + fb->LBOffsetI) - 0.5f; - float y1 = float(fbheight + fb->LBOffsetI) - 0.5f; + float x0 = float(rect.left); + float x1 = float(rect.right); + float y0 = float(dpt.y); + float y1 = float(fbheight); vert[0].x = x0; vert[0].y = y0; @@ -562,18 +561,15 @@ bool OpenGLSWFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLSWFrameBuffer *fb) DrawScreen(fb, fb->InitialWipeScreen); // Burn the new screen on top of it. - float top = fb->LBOffset - 0.5f; - float right = float(fb->Width) - 0.5f; - float bot = float(fb->Height) + top; - float texright = float(fb->Width) / float(fb->FBWidth); - float texbot = float(fb->Height) / float(fb->FBHeight); + float right = float(fb->Width); + float bot = float(fb->Height); BURNVERTEX verts[4] = { - { -0.5f, top, 0.5f, 1.f, 0.f, 0.f, 0, 0 }, - { right, top, 0.5f, 1.f, texright, 0.f, 1, 0 }, - { right, bot, 0.5f, 1.f, texright, texbot, 1, 1 }, - { -0.5f, bot, 0.5f, 1.f, 0.f, texbot, 0, 1 } + { 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0, 0 }, + { right, 0.f, 0.f, 1.f, 1.f, 0.f, 1, 0 }, + { right, bot, 0.f, 1.f, 1.f, 1.f, 1, 1 }, + { 0.f, bot, 0.f, 1.f, 0.f, 1.f, 0, 1 } }; fb->SetTexture(0, fb->FinalWipeScreen);