From c087e4d41147d1dfd4baad22a291a9347f480bca Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 18 Dec 2007 01:50:08 +0000 Subject: [PATCH] - New: When using the D3D9 framebuffer, palette blending is now applied only to the 3D area of the screen. This means the console and (the primary rectangular area of) the status bar are no longer blended. SVN r601 (trunk) --- docs/rh-log.txt | 5 ++ src/c_console.h | 1 + src/d_main.cpp | 17 +++++ src/r_plane.cpp | 3 +- src/v_video.h | 3 + src/win32/fb_d3d9.cpp | 155 +++++++++++++++++++++++++++++++++++++---- src/win32/win32iface.h | 4 ++ 7 files changed, 174 insertions(+), 14 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index e1935c28d8..97104f9c82 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,8 @@ +December 17, 2007 +- New: When using the D3D9 framebuffer, palette blending is now applied only + to the 3D area of the screen. This means the console and (the primary + rectangular area of) the status bar are no longer blended. + December 17, 2007 (Changes by Graf Zahl) - Fixed: When a skybox viewpoint is destroyed it should clear all sector references to itself. diff --git a/src/c_console.h b/src/c_console.h index 8f44ba5098..cc1e06c424 100644 --- a/src/c_console.h +++ b/src/c_console.h @@ -48,6 +48,7 @@ typedef enum cstate_t { c_up=0, c_down=1, c_falling=2, c_rising=3 } constate_e; extern constate_e ConsoleState; +extern int ConBottom; // Initialize the console void C_InitConsole (int width, int height, bool ingame); diff --git a/src/d_main.cpp b/src/d_main.cpp index 7dda98c82a..11217887a9 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -87,6 +87,7 @@ #include "version.h" #include "v_text.h" #include "st_start.h" +#include "templates.h" // MACROS ------------------------------------------------------------------ @@ -524,6 +525,7 @@ void D_Display (bool screenshot) switch (gamestate) { case GS_FULLCONSOLE: + screen->SetBlendingRect(0,0,0,0); C_DrawConsole (); M_Drawer (); if (!screenshot) @@ -535,6 +537,18 @@ void D_Display (bool screenshot) if (!gametic) break; + if (!menuactive) + { + screen->SetBlendingRect(viewwindowx, MAX(ConBottom,viewwindowy), + viewwindowx + realviewwidth, MAX(ConBottom,viewwindowy + realviewheight)); + } + else + { + // Don't chop the blending effect off at the status bar when the menu is + // active. Mostly, this is just to make Strife's dialogs with portrait + // images look okay when a blend is active. + screen->SetBlendingRect(0,0,0,0); + } R_RefreshViewBorder (); P_CheckPlayerSprites(); R_RenderActorView (players[consoleplayer].mo); @@ -559,16 +573,19 @@ void D_Display (bool screenshot) break; case GS_INTERMISSION: + screen->SetBlendingRect(0,0,0,0); WI_Drawer (); CT_Drawer (); break; case GS_FINALE: + screen->SetBlendingRect(0,0,0,0); F_Drawer (); CT_Drawer (); break; case GS_DEMOSCREEN: + screen->SetBlendingRect(0,0,0,0); D_PageDrawer (); CT_Drawer (); break; diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 6638b5f8c2..fe8ac2e348 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -50,6 +50,7 @@ #include "v_video.h" #include "vectors.h" #include "a_sharedglobal.h" +#include "c_console.h" //EXTERN_CVAR (Int, tx) //EXTERN_CVAR (Int, ty) @@ -452,8 +453,6 @@ void R_MapColoredPlane (int y, int x1) // //========================================================================== -extern int ConBottom; - void R_ClearPlanes (bool fullclear) { int i, max; diff --git a/src/v_video.h b/src/v_video.h index f97f138047..72093d53d7 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -264,6 +264,9 @@ public: // Changes the vsync setting, if supported by the device. virtual void SetVSync (bool vsync); + // Set the rect defining the area effected by blending. + virtual void SetBlendingRect (int x1, int y1, int x2, int y2) {} + #ifdef _WIN32 virtual void PaletteChanged () = 0; virtual int QueryNewPalette () = 0; diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index 2ef976c50b..dd969d89fb 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -67,6 +67,9 @@ // MACROS ------------------------------------------------------------------ +// The number of vertices the vertex buffer should hold. +#define NUM_VERTS 28 + // TYPES ------------------------------------------------------------------- IMPLEMENT_CLASS(D3DFB) @@ -194,6 +197,11 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) PalFormat = D3DFMT_UNKNOWN; VSync = vid_vsync; OffByOneAt = -1; + BlendingRect.left = 0; + BlendingRect.top = 0; + BlendingRect.right = FBWidth; + BlendingRect.bottom = FBHeight; + UseBlendingRect = false; Gamma = 1.0; memset (FlashConstants, 0, sizeof(FlashConstants)); @@ -621,32 +629,116 @@ bool D3DFB::CreatePaletteTexture () } bool D3DFB::CreateVertexes () +{ + if (FAILED(D3DDevice->CreateVertexBuffer (sizeof(FBVERTEX)*NUM_VERTS, D3DUSAGE_WRITEONLY, D3DFVF_FBVERTEX, D3DPOOL_DEFAULT, &VertexBuffer, NULL)) || + !UploadVertices()) + { + return false; + } + return true; +} + +bool D3DFB::UploadVertices() { float top = (TrueHeight - Height) * 0.5f - 0.5f; float right = float(Width) - 0.5f; float bot = float(Height) + top; float texright = float(Width) / float(FBWidth); float texbot = float(Height) / float(FBHeight); - FBVERTEX verts[4] = - { - { -0.5f, top, 0.5f, 1.f, 0.f, 0.f }, - { right, top, 0.5f, 1.f, texright, 0.f }, - { right, bot, 0.5f, 1.f, texright, texbot }, - { -0.5f, bot, 0.5f, 1.f, 0.f, texbot } - }; void *pverts; - if (FAILED(D3DDevice->CreateVertexBuffer (sizeof(verts), D3DUSAGE_WRITEONLY, D3DFVF_FBVERTEX, D3DPOOL_DEFAULT, &VertexBuffer, NULL)) || - FAILED(VertexBuffer->Lock (0, sizeof(verts), &pverts, 0))) + if ((BlendingRect.left <= 0 && BlendingRect.right >= FBWidth && + BlendingRect.top <= 0 && BlendingRect.bottom >= FBHeight) || + BlendingRect.left >= BlendingRect.right || + BlendingRect.top >= BlendingRect.bottom) { + // Blending rect covers the whole screen, so only need 4 verts. + FBVERTEX verts[4] = + { + { -0.5f, top, 0.5f, 1.f, 0.f, 0.f }, + { right, top, 0.5f, 1.f, texright, 0.f }, + { right, bot, 0.5f, 1.f, texright, texbot }, + { -0.5f, bot, 0.5f, 1.f, 0.f, texbot } + }; + if (SUCCEEDED(VertexBuffer->Lock(0, sizeof(verts), &pverts, 0))) + { + memcpy (pverts, verts, sizeof(verts)); + VertexBuffer->Unlock(); + return true; + } return false; } - else + // Only the 3D area of the screen is effected by palette flashes. + // So we create some boxes around it that can be drawn without the + // flash. These include the corners of the view area so I can be + // sure the texture interpolation is consistant. (Well, actually, + // since it's a 1-to-1 pixel mapping, it shouldn't matter.) + float mxl = float(BlendingRect.left) - 0.5f; + float mxr = float(BlendingRect.right) - 0.5f; + float myt = float(BlendingRect.top) + top; + float myb = float(BlendingRect.bottom) + top; + float tmxl = float(BlendingRect.left) / float(Width) * texright; + float tmxr = float(BlendingRect.right) / float(Width) * texright; + float tmyt = float(BlendingRect.top) / float(Height) * texbot; + float tmyb = float(BlendingRect.bottom) / float(Height) * texbot; + /* +-------------------+ + | | + +-----+-------+-----+ + | | | | + | | | | + | | | | + +-----+-------+-----+ + | | + +-------------------+ */ + FBVERTEX verts[28] = + { + // The whole screen, for when no blending is happening + { -0.5f, top, 0.5f, 1.f, 0.f, 0.f }, // 0 + { right, top, 0.5f, 1.f, texright, 0.f }, + { right, bot, 0.5f, 1.f, texright, texbot }, + { -0.5f, bot, 0.5f, 1.f, 0.f, texbot }, + + // Left area + { -0.5f, myt, 0.5f, 1.f, 0.f, tmyt }, // 4 + { mxl, myt, 0.5f, 1.f, tmxl, tmyt }, + { mxl, myb, 0.5f, 1.f, tmxl, tmyb }, + { -0.5f, myb, 0.5f, 1.f, 0.f, tmyb }, + + // Right area + { mxr, myt, 0.5f, 1.f, tmxr, tmyt }, // 8 + { right, myt, 0.5f, 1.f, texright, tmyt }, + { right, myb, 0.5f, 1.f, texright, tmyb }, + { mxr, myb, 0.5f, 1.f, tmxr, tmyb }, + + // Bottom area + { -0.5f, bot, 0.5f, 1.f, 0.f, texbot }, // 12 + { -0.5f, myb, 0.5f, 1.f, 0.f, tmyb }, + { mxl, myb, 0.5f, 1.f, tmxl, tmyb }, + { mxr, myb, 0.5f, 1.f, tmxr, tmyb }, + { right, myb, 0.5f, 1.f, texright, tmyb }, + { right, bot, 0.5f, 1.f, texright, texbot }, + + // Top area + { right, top, 0.5f, 1.f, texright, 0.f }, // 18 + { right, myt, 0.5f, 1.f, texright, tmyt }, + { mxr, myt, 0.5f, 1.f, tmxr, tmyt }, + { mxl, myt, 0.5f, 1.f, tmxl, tmyt }, + { -0.5f, myt, 0.5f, 1.f, 0.f, tmyt }, + { -0.5f, top, 0.5f, 1.f, 0.f, 0.f }, + + // Middle (blended) area + { mxl, myt, 0.5f, 1.f, tmxl, tmyt }, // 24 + { mxr, myt, 0.5f, 1.f, tmxr, tmyt }, + { mxr, myb, 0.5f, 1.f, tmxr, tmyb }, + { mxl, myb, 0.5f, 1.f, tmxl, tmyb } + }; + if (SUCCEEDED(VertexBuffer->Lock(0, sizeof(verts), &pverts, 0))) { memcpy (pverts, verts, sizeof(verts)); VertexBuffer->Unlock(); + return true; } - return true; + return false; } int D3DFB::GetPageCount () @@ -806,7 +898,25 @@ bool D3DFB::PaintToWindow () D3DDevice->SetFVF (D3DFVF_FBVERTEX); D3DDevice->SetPixelShader (PalTexShader); D3DDevice->SetPixelShaderConstantF (0, FlashConstants[0], 2); - D3DDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2); + if (!UseBlendingRect || FlashConstants[1][0] == 1) + { // The whole screen as a single quad. + D3DDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 0, 2); + } + else + { // The screen split up so that only the 3D view is blended. + D3DDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 24, 2); // middle + + // The rest is drawn unblended, so reset the shader constant. + static const float FlashZero[2][4] = + { { 0, 0, 0, 0 }, + { 1, 1, 1, 0 } }; + D3DDevice->SetPixelShaderConstantF (0, FlashZero[0], 2); + + D3DDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 4, 2); // left + D3DDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 8, 2); // right + D3DDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 12, 4); // bottom + D3DDevice->DrawPrimitive (D3DPT_TRIANGLEFAN, 18, 4); // top + } D3DDevice->EndScene(); return SUCCEEDED(D3DDevice->Present(NULL, NULL, NULL, NULL)); } @@ -934,3 +1044,24 @@ void D3DFB::Blank () { // Only used by movie player, which isn't working with D3D9 yet. } + +void D3DFB::SetBlendingRect(int x1, int y1, int x2, int y2) +{ + if (BlendingRect.left != x1 || + BlendingRect.top != y1 || + BlendingRect.right != x2 || + BlendingRect.bottom != y2) + { + BlendingRect.left = x1; + BlendingRect.top = y1; + BlendingRect.right = x2; + BlendingRect.bottom = y2; + + if (UploadVertices()) + { + UseBlendingRect = ((x1 > 0 || x2 < FBWidth || y1 > 0 || y2 < FBHeight) + && BlendingRect.left < BlendingRect.right + && BlendingRect.top < BlendingRect.bottom); + } + } +} diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index a037198eba..5d656e8b17 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -229,6 +229,7 @@ public: void Blank (); bool PaintToWindow (); void SetVSync (bool vsync); + void SetBlendingRect (int x1, int y1, int x2, int y2); HRESULT GetHR (); private: @@ -240,6 +241,7 @@ private: void DoOffByOneCheck(); void UploadPalette(); void FillPresentParameters (D3DPRESENT_PARAMETERS *pp, bool fullscreen, bool vsync); + bool UploadVertices(); bool Reset(); BYTE GammaTable[256]; @@ -257,6 +259,8 @@ private: int FBWidth, FBHeight; int OffByOneAt; bool VSync; + RECT BlendingRect; + bool UseBlendingRect; IDirect3DDevice9 *D3DDevice; IDirect3DVertexBuffer9 *VertexBuffer;