From 92a94d0ad6068d9c9c6a9dfe9b29dadc0946b26b Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 16 Jul 2026 11:00:35 -0500 Subject: [PATCH] Added tmdfs mode 4 for 2x 640x480 monitors --- .vscode/settings.json | 13 ++ .../CoreTech/Libraries/GameOS/VideoCard.cpp | 16 +++ .../CoreTech/Libraries/GameOS/WinMain.cpp | 22 +++ .../code/CoreTech/Libraries/GameOS/render.cpp | 128 +++++++++++++++++- .../code/CoreTech/Libraries/GameOS/render.hpp | 15 ++ Gameleap/code/mw4/Code/MW4/MW4Shell.cpp | 4 + .../Code/MW4Application/MW4Application.cpp | 2 +- 7 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..da1e4ab5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + // Legacy source files use CP949 (Korean Windows encoding, superset of EUC-KR). + // VS Code defaults to UTF-8, which silently corrupts the Korean comment bytes + // on save. Setting encoding to cp949 here preserves them exactly. + "files.encoding": "cp949", + + // Let VS Code try to detect encoding per-file, falling back to cp949 above. + "files.autoGuessEncoding": true, + + // Preserve the original Windows CRLF line endings (Git's * -text in + // .gitattributes also prevents conversion, but this keeps VS Code consistent). + "files.eol": "\r\n" +} diff --git a/Gameleap/code/CoreTech/Libraries/GameOS/VideoCard.cpp b/Gameleap/code/CoreTech/Libraries/GameOS/VideoCard.cpp index 76750d3b..170e144d 100644 --- a/Gameleap/code/CoreTech/Libraries/GameOS/VideoCard.cpp +++ b/Gameleap/code/CoreTech/Libraries/GameOS/VideoCard.cpp @@ -46,6 +46,8 @@ videoDevices BufferedDevices[8]; int g_nDualHead = -1; // jcem int g_nDualHead2 = -1; // jcem int g_nNonDualHead = -1; // jcem +int g_nMFD1 = -1; // mode 4: left 640x480 MFD monitor +int g_nMFD2 = -1; // mode 4: right 640x480 MFD monitor // MSL 5.03 Mechview int g_nMechViewType; // jcem : 0 - no mechview, 1 - on radar screen, 2 - on main screen @@ -380,6 +382,20 @@ void FindVideoCards() } } } + // Mode 4 (split dual 640x480): find two extra D3D devices beyond + // FullScreenDevice and g_nNonDualHead. These need no special resolution. + { + int found = 0; + for (int t0 = 0; t0 < NumDevices && found < 2; t0++) { + if (t0 == Environment.FullScreenDevice) continue; + if (t0 == g_nNonDualHead) continue; + if (DeviceArray[t0].D3DCaps.dwDevCaps & D3DDEVCAPS_HWRASTERIZATION) { + if (found == 0) g_nMFD1 = t0; + else g_nMFD2 = t0; + found++; + } + } + } // jcem // // Check any known video cards have up to date drivers (Only on Windows9x) diff --git a/Gameleap/code/CoreTech/Libraries/GameOS/WinMain.cpp b/Gameleap/code/CoreTech/Libraries/GameOS/WinMain.cpp index a3b6bb44..e710d2ac 100644 --- a/Gameleap/code/CoreTech/Libraries/GameOS/WinMain.cpp +++ b/Gameleap/code/CoreTech/Libraries/GameOS/WinMain.cpp @@ -940,6 +940,13 @@ void gos_UpdateDisplay( bool Everything ) radar_device.BeginScene(); } break; + case 4: + // Same 7-step cadence as mode 1: clear both MFD devices at step 0. + if(sh_step==0){ + radar_device.BeginScene(); + mfd_device.BeginScene(); // also clears mfd_device_right internally + } + break; } }else if(hsh_mrdev_initialized){ mr_device.BeginScene(); @@ -1106,6 +1113,21 @@ void gos_UpdateDisplay( bool Everything ) break; case 3: break; + case 4: + // Same 7-step cadence as mode 1. Flip all three: radar, left MFD, + // right MFD. mfd_device_right.pDDSFront is NULL if not initialised + // (e.g. g_nMFD2 = -1), so guard the flip. + sh_step++; + sh_step%=7; + if(sh_step==0) { + radar_device.EndScene(); + radar_device.pDDSFront->Flip(0,DDFLIP_DONOTWAIT|DDFLIP_NOVSYNC); + mfd_device.EndScene(); + mfd_device.pDDSFront->Flip(0,DDFLIP_DONOTWAIT|DDFLIP_NOVSYNC); + if (mfd_device_right.pDDSFront) + mfd_device_right.pDDSFront->Flip(0,DDFLIP_DONOTWAIT|DDFLIP_NOVSYNC); + } + break; } }else if(hsh_mrdev_initialized){ mr_device.EndScene(); diff --git a/Gameleap/code/CoreTech/Libraries/GameOS/render.cpp b/Gameleap/code/CoreTech/Libraries/GameOS/render.cpp index 9d1dd36f..5da8a4f7 100644 --- a/Gameleap/code/CoreTech/Libraries/GameOS/render.cpp +++ b/Gameleap/code/CoreTech/Libraries/GameOS/render.cpp @@ -945,6 +945,8 @@ void CHSH_Device::DrawTexture(float pt[4][2],DWORD dwColor,float tx1,float ty1,f extern int g_nDualHead; extern int g_nNonDualHead; +extern int g_nMFD1; // mode 4: left 640x480 MFD monitor +extern int g_nMFD2; // mode 4: right 640x480 MFD monitor // MSL 5.03 Mechview extern int g_nMechViewType; // jcem : 0 - no mechview, 1 - on radar screen, 2 - on main screen @@ -1066,6 +1068,23 @@ bool CMR_Device::LoadMRTargetTexture(const char *mechtexturename) CMR_Device mr_device; +// Mode 4: the right-hand 640x480 MFD device. Shares VRAM with mfd_device +// (same GPU), so mfd_device's pDDSTarget texture can be passed to this +// device's pD3DDevice->SetTexture without a copy. +CMFDRight_Device mfd_device_right; + +bool CMFDRight_Device::InitFirst() +{ + // Take over g_nMFD2 monitor at 640x480 fullscreen. + return CHSH_Device::InitFirst(g_nMFD2, 640, 480); +} + +bool CMFDRight_Device::InitSecond() +{ + // Create flip chain, D3D device and a render-target slot (1024x512). + return CHSH_Device::InitSecond(1024, 512); +} + /////////////////////////////////// CRadar_Device /////////////////////////////////// const char g_szRadarShutdown[] = "SHUT\nDOWN"; const char g_szRadarStartup[] = "START\nUP"; @@ -1349,7 +1368,7 @@ static DWORD channel_color[6]={ CMFD_Device::CMFD_Device() - : ch((DWORD)-1) + : ch((DWORD)-1), m_pRightDevice(NULL) { } @@ -1359,6 +1378,15 @@ CMFD_Device::~CMFD_Device() bool CMFD_Device::InitFirst() { + // Mode 4: use g_nMFD1 (640x480) for left panel; also start up the right + // device here so both displays are ready before InitSecond runs. + if (g_nTypeOfMFDs == 4) { + m_pRightDevice = &mfd_device_right; + CHSH_Device::InitFirst(g_nMFD1, 640, 480); // left device + mfd_device_right.InitFirst(); // right device display mode + return true; + } + m_pRightDevice = NULL; return CHSH_Device::InitFirst(g_nDualHead,1280,480); } @@ -1409,6 +1437,11 @@ bool CMFD_Device::InitSecond() pD3DDevice->SetMaterial( &mtrl ); pD3DDevice->SetRenderState( D3DRENDERSTATE_AMBIENT, 0xffffffff ); + // Mode 4: create flip chain + D3D device for the right 640x480 monitor. + if (g_nTypeOfMFDs == 4 && m_pRightDevice) { + mfd_device_right.InitSecond(); + } + return true; } @@ -1450,6 +1483,11 @@ bool CMFD_Device::BeginChannel(DWORD channel) return false; } break; + case 4: + // Same 7-step timing as mode 1: channels 0-4 map to sh_step 2-6. + if (sh_step != (int)(channel + 2)) + return false; + break; } ch=channel; @@ -1475,8 +1513,42 @@ bool CMFD_Device::EndChannel() gCaptureScreen = 0; } - SetRenderTargetBackbuffer(); - pD3DDevice->BeginScene(); + // Mode 4: route this channel's blit to the correct physical monitor. + // Handled here, before the modes 1-3 SetRenderTargetBackbuffer/BeginScene + // block, so each path has exactly one matched Begin/EndScene pair. + // Channels 0-2 go to the LEFT device (this, g_nMFD1). + // Channels 3-4 go to the RIGHT device (m_pRightDevice, g_nMFD2). + // pDDSTarget was created by this device's pDD; both devices are on the + // same GPU so VRAM textures are mutually accessible. + if (g_nTypeOfMFDs == 4 && m_pRightDevice) { + CHSH_Device* target = (ch >= 3) ? m_pRightDevice : static_cast(this); + target->SetRenderTargetBackbuffer(); + target->pD3DDevice->BeginScene(); + + target->pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); + target->pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); + target->pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE); + + target->pD3DDevice->SetTexture(0, pDDSTarget); + + DWORD color4 = channel_color[ch]; + float w4 = (float)target->size_back.cx; // 640 + float h4 = (float)target->size_back.cy; // 480 + float w2_4 = (float)size_target.cx; // 1024 + float h2_4 = (float)size_target.cy; // 512 + D3DTLVERTEX V4[4]; + V4[0]=D3DTLVERTEX(D3DVECTOR( -0.5f,h4-0.5f,0.9f),1.0f,color4,0, 0/w2_4,h4/h2_4); + V4[1]=D3DTLVERTEX(D3DVECTOR( -0.5f, -0.5f,0.9f),1.0f,color4,0, 0/w2_4, 0/h2_4); + V4[2]=D3DTLVERTEX(D3DVECTOR(w4-0.5f,h4-0.5f,0.9f),1.0f,color4,0,w4/w2_4,h4/h2_4); + V4[3]=D3DTLVERTEX(D3DVECTOR(w4-0.5f, -0.5f,0.9f),1.0f,color4,0,w4/w2_4, 0/h2_4); + target->pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,D3DFVF_TLVERTEX,V4,4,NULL); + + target->pD3DDevice->EndScene(); + ch = (DWORD)-1; + } else { + // Modes 1-3: blit to half of the single 1280-wide (or 640-wide) backbuffer. + SetRenderTargetBackbuffer(); + pD3DDevice->BeginScene(); pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE); pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE); @@ -1504,8 +1576,9 @@ bool CMFD_Device::EndChannel() pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX , Vertices, 4, NULL ); - pD3DDevice->EndScene(); - ch = (DWORD)-1; + pD3DDevice->EndScene(); + ch = (DWORD)-1; + } } return true; } @@ -1533,6 +1606,25 @@ bool CMFD_Device::BeginScene() pD3DDevice->Clear(1,&s_rc2,D3DCLEAR_TARGET ,0,1.0f,0); //pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET ,0,1.0f,0); }break; + case 4: + // Clear and draw background grid on the LEFT device. + SetRenderTargetBackbuffer(); + pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0); + pD3DDevice->BeginScene(); + if(sh_game_started) DrawMFDBackGrid(); + pD3DDevice->EndScene(); + // Clear and draw background grid on the RIGHT device. + if (m_pRightDevice) { + m_pRightDevice->SetRenderTargetBackbuffer(); + m_pRightDevice->pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0); + m_pRightDevice->pD3DDevice->BeginScene(); + if(sh_game_started) { + m_pRightDevice->pD3DDevice->SetTexture(0,0); + m_pRightDevice->DrawQuadList(8,rcs640_solo,0xFFFFFFFF); + } + m_pRightDevice->pD3DDevice->EndScene(); + } + return true; // skip the common BeginScene/DrawGrid/EndScene below } pD3DDevice->BeginScene(); if(sh_game_started) { @@ -1559,6 +1651,11 @@ bool CMFD_Device::Release() SAFE_RELEASE(pDDSDamageTexture); // MSL 5.03 Target Damage Display SAFE_RELEASE(pDDSTargetTexture); + // Mode 4: release the right device before releasing this (left) device. + if (g_nTypeOfMFDs == 4 && m_pRightDevice) { + m_pRightDevice->Release(); + m_pRightDevice = NULL; + } CHSH_Device::Release(); } return true; @@ -1700,6 +1797,19 @@ static RECT rcs640[8]={ {1120-1,440,1120+1,480}, }; +// Mode 4: same grid pattern as rcs640 but offset to x=0 for a standalone +// 640x480 surface (left half of rcs1280). +static RECT rcs640_solo[8]={ + {0,40,640,42}, + { 160-1,0, 160+1,40}, + { 320-1,0, 320+1,40}, + { 480-1,0, 480+1,40}, + {0,480-42,640,480-40}, + { 160-1,440, 160+1,480}, + { 320-1,440, 320+1,480}, + { 480-1,440, 480+1,480}, +}; + bool CMFD_Device::DrawMFDBackGrid() { pD3DDevice->SetTexture(0,0); @@ -1714,6 +1824,11 @@ bool CMFD_Device::DrawMFDBackGrid() case 2: DrawQuadList(8,rcs640,0xFFFFFFFF); break; + case 4: + // Left device uses the left-half grid (0..640). + // Right device grid is drawn separately in BeginScene. + DrawQuadList(8,rcs640_solo,0xFFFFFFFF); + break; } return true; @@ -2489,6 +2604,9 @@ bool IsMultimonitorAvaliable() if ((*g_pfnCTCL_GetType)()==_ECTCL_CameraShip) return false; } + // Mode 4 uses its own device slots ? g_nDualHead is not required. + if (g_nTypeOfMFDs == 4) + return (g_nMFD1 != -1 && g_nMFD2 != -1); if (g_nDualHead != -1) { // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual) switch(g_nTypeOfMFDs) diff --git a/Gameleap/code/CoreTech/Libraries/GameOS/render.hpp b/Gameleap/code/CoreTech/Libraries/GameOS/render.hpp index c54db34a..cd07b11d 100644 --- a/Gameleap/code/CoreTech/Libraries/GameOS/render.hpp +++ b/Gameleap/code/CoreTech/Libraries/GameOS/render.hpp @@ -169,6 +169,7 @@ public: LPDIRECTDRAWSURFACE7 pDDSTargetTexture;//¸ÞÅ© µ¥¹ÌÁö ÅØ½ºÃÄ.. DWORD ch; //current channel.... + CHSH_Device* m_pRightDevice; // mode 4: pointer to right 640x480 device (NULL in modes 1-3) public: CMFD_Device(); ~CMFD_Device(); @@ -189,6 +190,19 @@ public: bool DrawMFDDefaultBackAux1(int state); }; +// Mode 4 (split dual 640x480): right-side MFD device on its own 640x480 monitor. +// Same GPU as the left device (mfd_device), so VRAM textures are shared. +class CMFDRight_Device : public CHSH_Device +{ +public: + CMFDRight_Device() {} + bool InitFirst(); + bool InitSecond(); + virtual bool BeginScene() { return true; } + virtual bool EndScene() { return true; } + virtual bool Release() { return CHSH_Device::Release(); } +}; + class CMR_Device:public CHSH_Device { public: @@ -212,6 +226,7 @@ void HSH_DirectDrawRelease2(); extern CRadar_Device radar_device; extern CMFD_Device mfd_device; +extern CMFDRight_Device mfd_device_right; extern CMR_Device mr_device; extern bool use_shgui; extern int sh_step; diff --git a/Gameleap/code/mw4/Code/MW4/MW4Shell.cpp b/Gameleap/code/mw4/Code/MW4/MW4Shell.cpp index 620ddc41..ade612da 100644 --- a/Gameleap/code/mw4/Code/MW4/MW4Shell.cpp +++ b/Gameleap/code/mw4/Code/MW4/MW4Shell.cpp @@ -14820,6 +14820,10 @@ void __stdcall CTCL_UpdateMechView() mfd_device.BeginScene(); sh_step = 4; break; + case 4: + // Same 7-step cadence as mode 1. + sh_step = 6; + break; } } else diff --git a/Gameleap/code/mw4/Code/MW4Application/MW4Application.cpp b/Gameleap/code/mw4/Code/MW4Application/MW4Application.cpp index 8a19a1ec..c236875d 100644 --- a/Gameleap/code/mw4/Code/MW4Application/MW4Application.cpp +++ b/Gameleap/code/mw4/Code/MW4Application/MW4Application.cpp @@ -1440,7 +1440,7 @@ int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int n if (token && token[7]) { int n = atoi(&token[7]); - if ((0 <= n) && (n <= 3)) // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual) + if ((0 <= n) && (n <= 4)) // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual), 4 - split dual 640x480 g_nTypeOfMFDs = n; } token = strstr(all_lower, "-trio ");