diff --git a/docs/rh-log.txt b/docs/rh-log.txt index e1935c28d..97104f9c8 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 8f44ba509..cc1e06c42 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 7dda98c82..11217887a 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 6638b5f8c..fe8ac2e34 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 f97f13804..72093d53d 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 2ef976c50..dd969d89f 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 a037198eb..5d656e8b1 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;