mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2026-03-28 15:59:40 -06:00
570 lines
12 KiB
C++
570 lines
12 KiB
C++
#include "..\ht.h"
|
|
|
|
#define kidmScale1 100
|
|
#define kidmScale2 101
|
|
#define kidmScale3 102
|
|
#define kidmScale4 103
|
|
#define kidmScaleDefault 104
|
|
|
|
HWND Display::m_hwnd;
|
|
HMENU Display::m_hmenuPopup;
|
|
RECT g_rcOldWindowPos;
|
|
|
|
RECT g_arcSilkscreen[] = {
|
|
{ 27 , 206 , (27+18) , (206+14) }, // abc area
|
|
{ 115 , 206 , (115+18) , (206+14) }, // 123 area
|
|
{ 0 , 164 , (0+27) , (164+28) }, // launch button
|
|
|
|
// WARNING: host.cpp code assumes the rectangle for the menu button
|
|
// is at index 3 (from 0) in this list
|
|
{ 0 , 192 , (0+27) , (192+28) }, // menu button
|
|
|
|
// WARNING: host.cpp code assumes the rectangle for the calc button
|
|
// is at index 4 (from 0) in this list
|
|
{ 133 , 164 , (133+27) , (164+28) }, // calculator button
|
|
|
|
// WARNING: host.cpp code assumes the rectangle for the find button
|
|
// is at index 5 (from 0) in this list
|
|
{ 133 , 192 , (133+27) , (192+28) }, // find button
|
|
|
|
// WARNING: HostGetSilkRect() assumes all these indexes
|
|
{ 0, 0, 160 , 160 }, // screen
|
|
{ 27 , 164 , (27+62) , (164+56) }, // alpha rect
|
|
{ 89 , 164 , (89+44) , (164+56) }, // number rect
|
|
};
|
|
|
|
Display *HostCreateDisplay()
|
|
{
|
|
// Make sure the Hostile Takeover window isn't underlaying the taskbar if
|
|
// it happens to be along the left side of the desktop.
|
|
|
|
if (g_rcOldWindowPos.left == 0 && g_rcOldWindowPos.top == 0) {
|
|
POINT ptT = { 0, 0 };
|
|
HMONITOR hmon = MonitorFromPoint(ptT, MONITOR_DEFAULTTOPRIMARY);
|
|
|
|
MONITORINFOEX mi;
|
|
mi.cbSize = sizeof(mi);
|
|
GetMonitorInfo(hmon, &mi);
|
|
g_rcOldWindowPos.left = mi.rcWork.left;
|
|
g_rcOldWindowPos.top = mi.rcWork.top;
|
|
}
|
|
|
|
// Create a display
|
|
|
|
Display *pdisp = new Display();
|
|
if (pdisp == NULL)
|
|
return NULL;
|
|
if (!pdisp->Init()) {
|
|
delete pdisp;
|
|
return NULL;
|
|
}
|
|
return pdisp;
|
|
}
|
|
|
|
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp)
|
|
{
|
|
switch (wm) {
|
|
case WM_CLOSE:
|
|
PostMessage(NULL, WM_GAMEEVENT, appStopEvent, knAppExit);
|
|
return 0;
|
|
|
|
case WM_PAINT:
|
|
if (gpmfrmm != NULL)
|
|
gpmfrmm->InvalidateRect(NULL);
|
|
PostMessage(NULL, WM_GAMEEVENT, gamePaintEvent, 0);
|
|
break;
|
|
|
|
case WM_RBUTTONDOWN:
|
|
{
|
|
POINT pt;
|
|
pt.x = LOWORD(lp);
|
|
pt.y = HIWORD(lp);
|
|
MapWindowPoints(Display::m_hwnd, NULL, &pt, 1);
|
|
int idm = TrackPopupMenu(Display::m_hmenuPopup,
|
|
TPM_CENTERALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_LEFTBUTTON,
|
|
pt.x, pt.y, 0, Display::m_hwnd, NULL);
|
|
switch (idm) {
|
|
case kidmScale1:
|
|
gpdisp->SetScale(1);
|
|
break;
|
|
|
|
case kidmScale2:
|
|
gpdisp->SetScale(2);
|
|
break;
|
|
|
|
case kidmScale3:
|
|
gpdisp->SetScale(3);
|
|
break;
|
|
|
|
case kidmScale4:
|
|
gpdisp->SetScale(4);
|
|
break;
|
|
|
|
case kidmScaleDefault:
|
|
gpdisp->SetScale(-1);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_ERASEBKGND:
|
|
if (gpdisp != NULL) {
|
|
ModeInfo mode;
|
|
gpdisp->GetMode(&mode);
|
|
if (mode.cyGraffiti != 0) {
|
|
DefWindowProc(hwnd, wm, wp, lp);
|
|
HDC hdc = (HDC)wp;
|
|
HBRUSH hbrT = (HBRUSH)GetStockObject(WHITE_BRUSH);
|
|
ModeInfo mode;
|
|
gpdisp->GetMode(&mode);
|
|
int nScale = gpdisp->GetScale() * mode.cx / 160;
|
|
RECT *prcT = g_arcSilkscreen;
|
|
for (int i = 0; i < sizeof(g_arcSilkscreen) / sizeof(RECT); i++, prcT++) {
|
|
RECT rcT = *prcT;
|
|
rcT.left = rcT.left * nScale;
|
|
rcT.top = rcT.top * nScale;
|
|
rcT.right = rcT.right * nScale;
|
|
rcT.bottom = rcT.bottom * nScale;
|
|
FrameRect(hdc, &rcT, hbrT);
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return DefWindowProc(hwnd, wm, wp, lp);
|
|
}
|
|
|
|
Display::Display()
|
|
{
|
|
m_hwnd = NULL;
|
|
m_hbm = NULL;
|
|
m_hbmSav = NULL;
|
|
m_hdc = NULL;
|
|
m_hdcMem = NULL;
|
|
m_imode = -1;
|
|
m_cmodes = 0;
|
|
m_pbmClip = NULL;
|
|
m_pbmFront = NULL;
|
|
m_pbmBack = NULL;
|
|
m_nScale = 1;
|
|
m_hmenuPopup = NULL;
|
|
}
|
|
|
|
Display::~Display()
|
|
{
|
|
if (m_hdc != NULL) {
|
|
ReleaseDC(m_hwnd, m_hdc);
|
|
m_hdc = NULL;
|
|
}
|
|
if (m_hwnd != NULL) {
|
|
GetWindowRect(m_hwnd, &g_rcOldWindowPos);
|
|
DestroyWindow(m_hwnd);
|
|
m_hwnd = NULL;
|
|
}
|
|
if (m_hbm != NULL) {
|
|
if (m_hdcMem != NULL)
|
|
SelectObject(m_hdcMem, (HGDIOBJ)m_hbmSav);
|
|
DeleteObject(m_hbm);
|
|
m_hbm = NULL;
|
|
}
|
|
if (m_hdcMem != NULL) {
|
|
DeleteDC(m_hdcMem);
|
|
m_hdcMem = NULL;
|
|
}
|
|
if (m_hmenuPopup != NULL) {
|
|
DestroyMenu(m_hmenuPopup);
|
|
m_hmenuPopup = NULL;
|
|
}
|
|
delete m_pbmBack;
|
|
m_pbmBack = NULL;
|
|
delete m_pbmFront;
|
|
m_pbmFront = NULL;
|
|
delete m_pbmClip;
|
|
m_pbmClip = NULL;
|
|
}
|
|
|
|
bool Display::Init()
|
|
{
|
|
WNDCLASS wc;
|
|
memset(&wc, 0, sizeof(wc));
|
|
wc.lpfnWndProc = MainWndProc;
|
|
wc.hInstance = ghInst;
|
|
wc.hIcon = LoadIcon(ghInst, MAKEINTRESOURCE(kidiMain));
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
|
|
wc.lpszClassName = kszWindowClass;
|
|
RegisterClass(&wc);
|
|
|
|
// Adjust so the client area is the size we want
|
|
|
|
dword dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN;
|
|
RECT rc;
|
|
SetRect(&rc, 0, 0, 320, 320 + (60 * 2 /* Graffiti area */));
|
|
AdjustWindowRect(&rc, dwStyle, false);
|
|
|
|
m_hwnd = CreateWindowEx(0, kszWindowClass, kszWindowTitle,
|
|
dwStyle, g_rcOldWindowPos.left, g_rcOldWindowPos.top, // CW_USEDEFAULT, CW_USEDEFAULT,
|
|
rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, ghInst, 0);
|
|
if (m_hwnd == NULL)
|
|
return false;
|
|
m_hdc = GetDC(m_hwnd);
|
|
if (m_hdc == NULL)
|
|
return false;
|
|
m_hdcMem = CreateCompatibleDC(m_hdc);
|
|
if (m_hdcMem == NULL)
|
|
return false;
|
|
|
|
// Create popup menu
|
|
|
|
m_hmenuPopup = CreatePopupMenu();
|
|
AppendMenu(m_hmenuPopup, MF_STRING, kidmScale1, "1x scale");
|
|
AppendMenu(m_hmenuPopup, MF_STRING, kidmScale2, "2x scale");
|
|
AppendMenu(m_hmenuPopup, MF_STRING, kidmScale3, "3x scale");
|
|
AppendMenu(m_hmenuPopup, MF_STRING, kidmScale4, "4x scale");
|
|
AppendMenu(m_hmenuPopup, MF_SEPARATOR, 0, NULL);
|
|
AppendMenu(m_hmenuPopup, MF_STRING, kidmScaleDefault, "Default scale");
|
|
|
|
// Set up mode list
|
|
|
|
ModeInfo *pmode = m_amodeInfo;
|
|
|
|
pmode->cx = 160;
|
|
pmode->cy = 160;
|
|
pmode->nDepth = 4;
|
|
pmode->fNative = false;
|
|
pmode->cyGraffiti = 60;
|
|
pmode->nScale = 2;
|
|
pmode->nDegreeOrientation = 0;
|
|
pmode++;
|
|
|
|
pmode->cx = 160;
|
|
pmode->cy = 240;
|
|
pmode->nDepth = 4;
|
|
pmode->fNative = false;
|
|
pmode->cyGraffiti = 0;
|
|
pmode->nScale = 2;
|
|
pmode->nDegreeOrientation = 0;
|
|
pmode++;
|
|
|
|
pmode->cx = 160;
|
|
pmode->cy = 160;
|
|
pmode->nDepth = 8;
|
|
pmode->fNative = false;
|
|
pmode->cyGraffiti = 60;
|
|
pmode->nScale = 2;
|
|
pmode->nDegreeOrientation = 0;
|
|
pmode++;
|
|
|
|
pmode->cx = 160;
|
|
pmode->cy = 240;
|
|
pmode->nDepth = 8;
|
|
pmode->fNative = false;
|
|
pmode->cyGraffiti = 0;
|
|
pmode->nScale = 2;
|
|
pmode->nDegreeOrientation = 0;
|
|
pmode++;
|
|
|
|
pmode->cx = 240;
|
|
pmode->cy = 320;
|
|
pmode->nDepth = 8;
|
|
pmode->fNative = false;
|
|
pmode->cyGraffiti = 0;
|
|
pmode->nScale = 1;
|
|
pmode->nDegreeOrientation = 0;
|
|
pmode++;
|
|
|
|
pmode->cx = 320;
|
|
pmode->cy = 320;
|
|
pmode->nDepth = 4;
|
|
pmode->fNative = false;
|
|
pmode->cyGraffiti = 120;
|
|
pmode->nScale = 1;
|
|
pmode->nDegreeOrientation = 0;
|
|
pmode++;
|
|
|
|
pmode->cx = 320;
|
|
pmode->cy = 480;
|
|
pmode->nDepth = 4;
|
|
pmode->fNative = false;
|
|
pmode->cyGraffiti = 0;
|
|
pmode->nScale = 1;
|
|
pmode->nDegreeOrientation = 0;
|
|
pmode++;
|
|
|
|
pmode->cx = 320;
|
|
pmode->cy = 320;
|
|
pmode->nDepth = 8;
|
|
pmode->fNative = false;
|
|
pmode->cyGraffiti = 120;
|
|
pmode->nScale = 1;
|
|
pmode->nDegreeOrientation = 0;
|
|
pmode++;
|
|
|
|
pmode->cx = 320;
|
|
pmode->cy = 480;
|
|
pmode->nDepth = 8;
|
|
pmode->fNative = false;
|
|
pmode->cyGraffiti = 0;
|
|
pmode->nScale = 1;
|
|
pmode->nDegreeOrientation = 0;
|
|
pmode++;
|
|
|
|
pmode->cx = 480;
|
|
pmode->cy = 320;
|
|
pmode->nDepth = 8;
|
|
pmode->fNative = false;
|
|
pmode->cyGraffiti = 0;
|
|
pmode->nScale = 1;
|
|
pmode->nDegreeOrientation = 0;
|
|
pmode++;
|
|
|
|
pmode->cx = 320;
|
|
pmode->cy = 240;
|
|
pmode->nDepth = 8;
|
|
pmode->fNative = false;
|
|
pmode->cyGraffiti = 0;
|
|
pmode->nScale = 1;
|
|
pmode->nDegreeOrientation = 0;
|
|
pmode++;
|
|
|
|
pmode->cx = 640;
|
|
pmode->cy = 480;
|
|
pmode->nDepth = 8;
|
|
pmode->fNative = false;
|
|
pmode->cyGraffiti = 0;
|
|
pmode->nScale = 1;
|
|
pmode->nDegreeOrientation = 0;
|
|
pmode++;
|
|
|
|
m_cmodes = pmode - m_amodeInfo;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Display::SetMode(int imode, int nScale)
|
|
{
|
|
ModeInfo *pmode = &m_amodeInfo[imode];
|
|
|
|
// Create dib bitmap
|
|
|
|
DibBitmap *pbmBack = CreateDibBitmap(NULL, pmode->cx, pmode->cy);
|
|
if (pbmBack == NULL)
|
|
return false;
|
|
|
|
// Create display surface with default palm palette
|
|
|
|
struct BitmapInfo // bi
|
|
{
|
|
BITMAPINFOHEADER bmiHeader;
|
|
RGBQUAD bmiColors[256];
|
|
};
|
|
BitmapInfo bi;
|
|
memset(&bi, 0, sizeof(bi));
|
|
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
|
|
bi.bmiHeader.biWidth = pmode->cx;
|
|
bi.bmiHeader.biHeight = -pmode->cy;
|
|
bi.bmiHeader.biPlanes = 1;
|
|
bi.bmiHeader.biBitCount = 8;
|
|
bi.bmiHeader.biCompression = BI_RGB;
|
|
switch (pmode->nDepth) {
|
|
case 4:
|
|
bi.bmiHeader.biClrUsed = 16;
|
|
break;
|
|
|
|
case 8:
|
|
bi.bmiHeader.biClrUsed = 256;
|
|
break;
|
|
}
|
|
|
|
byte *pbScreen;
|
|
HBITMAP hbm = CreateDIBSection(m_hdcMem, (BITMAPINFO *)&bi, DIB_RGB_COLORS, (void **)&pbScreen, NULL, 0);
|
|
if (hbm == NULL) {
|
|
delete pbmBack;
|
|
return false;
|
|
}
|
|
|
|
// Success
|
|
|
|
if (m_hbm != NULL) {
|
|
SelectObject(m_hdcMem, (HGDIOBJ)m_hbmSav);
|
|
DeleteObject(m_hbm);
|
|
m_hbm = NULL;
|
|
delete m_pbmBack;
|
|
m_pbmBack = NULL;
|
|
delete m_pbmFront;
|
|
m_pbmFront = NULL;
|
|
}
|
|
|
|
DibBitmap *pbmFront = CreateDibBitmap(pbScreen, pmode->cx, pmode->cy);
|
|
if (pbmFront == NULL) {
|
|
delete pbmBack;
|
|
return false;
|
|
}
|
|
|
|
m_hbm = hbm;
|
|
m_hbmSav = (HBITMAP)SelectObject(m_hdcMem, (HGDIOBJ)m_hbm);
|
|
m_imode = imode;
|
|
m_pbmBack = pbmBack;
|
|
m_pbmFront = pbmFront;
|
|
|
|
// Scale the window
|
|
|
|
if (nScale <= 0)
|
|
nScale = m_amodeInfo[imode].nScale;
|
|
SetScale(nScale);
|
|
return true;
|
|
}
|
|
|
|
void Display::SetScale(int nScale)
|
|
{
|
|
if (nScale <= 0)
|
|
nScale = m_amodeInfo[m_imode].nScale;
|
|
m_nScale = nScale;
|
|
ResizeWindow(nScale);
|
|
}
|
|
|
|
void Display::ResizeWindow(int nScale)
|
|
{
|
|
// Size window to the requested size
|
|
|
|
ModeInfo *pmode = &m_amodeInfo[m_imode];
|
|
int cx = pmode->cx * nScale;
|
|
int cy = (pmode->cy + pmode->cyGraffiti) * nScale;
|
|
dword dwStyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPCHILDREN;
|
|
RECT rc;
|
|
SetRect(&rc, 0, 0, cx, cy);
|
|
AdjustWindowRect(&rc, dwStyle, false);
|
|
|
|
// Hack: If we're running in multiplayer test mode, position this window according to side represented
|
|
|
|
int x = g_rcOldWindowPos.left;
|
|
int y = g_rcOldWindowPos.top;
|
|
#ifdef MP_STRESS
|
|
if (gnMPPos != 0)
|
|
x += (rc.right - rc.left) * gnMPPos;
|
|
#endif
|
|
|
|
SetWindowPos(m_hwnd, NULL, x, y, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_SHOWWINDOW);
|
|
InvalidateRect(m_hwnd, NULL, TRUE);
|
|
}
|
|
|
|
int Display::GetMode(ModeInfo *pmode)
|
|
{
|
|
if (pmode != NULL) {
|
|
if (m_imode == -1) {
|
|
memset(pmode, 0, sizeof(*pmode));
|
|
} else {
|
|
*pmode = m_amodeInfo[m_imode];
|
|
}
|
|
}
|
|
return m_imode;
|
|
}
|
|
|
|
int Display::GetModeCount()
|
|
{
|
|
return m_cmodes;
|
|
}
|
|
|
|
void Display::GetModeInfo(int imode, ModeInfo *pmode)
|
|
{
|
|
memset(pmode, 0, sizeof(*pmode));
|
|
if (imode >= 0 && imode < m_cmodes)
|
|
*pmode = m_amodeInfo[imode];
|
|
}
|
|
|
|
DibBitmap *Display::GetBackDib()
|
|
{
|
|
return m_pbmBack;
|
|
}
|
|
|
|
DibBitmap *Display::GetFrontDib()
|
|
{
|
|
return m_pbmFront;
|
|
}
|
|
|
|
DibBitmap *Display::GetClippingDib()
|
|
{
|
|
if (m_pbmClip != NULL)
|
|
return m_pbmClip;
|
|
DibBitmap *pbm = CreateDibBitmap(NULL, kcCopyBy4Procs * 4, kcCopyBy4Procs * 4);
|
|
if (pbm == NULL)
|
|
return NULL;
|
|
m_pbmClip = pbm;
|
|
return pbm;
|
|
}
|
|
|
|
void Display::FrameStart()
|
|
{
|
|
}
|
|
|
|
void Display::FrameComplete()
|
|
{
|
|
// Update screen
|
|
|
|
int cx = m_amodeInfo[m_imode].cx;
|
|
int cy = m_amodeInfo[m_imode].cy;
|
|
StretchBlt(m_hdc, 0, 0, cx * m_nScale, cy * m_nScale, m_hdcMem, 0, 0, cx, cy, SRCCOPY);
|
|
|
|
#ifdef DEBUG_HELPERS
|
|
extern void paint();
|
|
paint();
|
|
#endif
|
|
}
|
|
|
|
void Display::SetPalette(Palette *ppal)
|
|
{
|
|
RGBQUAD *prgbq = new RGBQUAD[BigWord(ppal->cEntries)];
|
|
for (int n = 0; n < BigWord(ppal->cEntries); n++) {
|
|
prgbq[n].rgbRed = ppal->argb[n][0];
|
|
prgbq[n].rgbGreen = ppal->argb[n][1];
|
|
prgbq[n].rgbBlue = ppal->argb[n][2];
|
|
prgbq[n].rgbReserved = 0;
|
|
}
|
|
SetDIBColorTable(m_hdcMem, 0, BigWord(ppal->cEntries), prgbq);
|
|
delete prgbq;
|
|
}
|
|
|
|
void Display::GetWindowsPalette(RGBQUAD *pargbq)
|
|
{
|
|
GetDIBColorTable(m_hdcMem, 0, 256, pargbq);
|
|
}
|
|
|
|
void Display::DrawText(const char *psz, int x, int y, word wf)
|
|
{
|
|
if (y == -1)
|
|
y = m_amodeInfo[m_imode].cy * m_nScale - 16;
|
|
|
|
RECT rc;
|
|
rc.left = 0;
|
|
rc.top = y;
|
|
if (wf & kfDtClearLine) {
|
|
rc.right = m_amodeInfo[m_imode].cx * m_nScale;
|
|
rc.bottom = rc.top + 16;
|
|
HBRUSH hbrT = CreateSolidBrush(RGB(0, 0, 0));
|
|
FillRect(m_hdc, &rc, hbrT);
|
|
DeleteObject(hbrT);
|
|
}
|
|
SetTextColor(m_hdc, RGB(255, 255, 255));
|
|
SetBkColor(m_hdc, RGB(0, 0, 0));
|
|
TextOut(m_hdc, rc.left, rc.top, psz, strlen(psz));
|
|
GdiFlush();
|
|
}
|
|
|
|
void Display::DrawFrameInclusive(Rect *prc)
|
|
{
|
|
RECT rcT;
|
|
SetRect(&rcT, prc->left * m_nScale, prc->top * m_nScale, prc->right * m_nScale, prc->bottom * m_nScale);
|
|
HBRUSH hbr = CreateSolidBrush(RGB(255, 255, 0));
|
|
FrameRect(m_hdc, &rcT, hbr);
|
|
DeleteObject((HGDIOBJ)hbr);
|
|
GdiFlush();
|
|
}
|
|
|
|
void Display::GetHslAdjustments(short *pnHueOffset, short *pnSatMultiplier, short *pnLumOffset)
|
|
{
|
|
*pnHueOffset = 0;
|
|
*pnSatMultiplier = 0;
|
|
*pnLumOffset = 0;
|
|
}
|