1 // Support functions for blitters that use DirectX
2 #include "burner.h"
3
4 #if !defined BUILD_X64_EXE
5 #include "vid_directx_support.h"
6 #endif
7
8 #include <initguid.h>
9 #define DIRECT3D_VERSION 0x0700 // Use this Direct3D version
10
11 #if defined BUILD_X64_EXE
12 #include "vid_directx_support.h"
13 #endif
14
15 #include "ddraw_core.h"
16
17 // ---------------------------------------------------------------------------
18 // General
19
20 static IDirectDraw7* pDD = NULL;
21
VidSExit()22 void VidSExit()
23 {
24 pDD = NULL;
25 }
26
VidSInit(IDirectDraw7 * pDD7)27 int VidSInit(IDirectDraw7* pDD7)
28 {
29 pDD = pDD7;
30
31 if (pDD == NULL) {
32 return 1;
33 }
34
35 return 0;
36 }
37
38 // ---------------------------------------------------------------------------
39
40 // Get bit-depth of a surface (15/16/24/32)
41
VidSGetSurfaceDepth(IDirectDrawSurface7 * pSurf)42 int VidSGetSurfaceDepth(IDirectDrawSurface7* pSurf)
43 {
44 DDPIXELFORMAT ddpf;
45 if (pSurf == NULL) {
46 return 0;
47 }
48
49 // Find out the pixelformat of the screen surface
50 memset(&ddpf, 0, sizeof(ddpf));
51 ddpf.dwSize = sizeof(ddpf);
52
53 if (SUCCEEDED(pSurf->GetPixelFormat(&ddpf))) {
54 int nDepth = ddpf.dwRGBBitCount;
55 if (nDepth == 16 && ddpf.dwGBitMask == 0x03E0) {
56 nDepth = 15;
57 }
58
59 return nDepth;
60 }
61
62 return 0;
63 }
64
65 // Clear a surface to a specified colour
66
VidSClearSurface(IDirectDrawSurface7 * pSurf,unsigned int nColour,RECT * pRect)67 int VidSClearSurface(IDirectDrawSurface7* pSurf, unsigned int nColour, RECT* pRect)
68 {
69 DDBLTFX BltFx;
70
71 if (pSurf == NULL) {
72 return 1;
73 }
74
75 memset(&BltFx, 0, sizeof(BltFx));
76 BltFx.dwSize = sizeof(BltFx);
77 BltFx.dwFillColor = nColour;
78
79 if (FAILED(pSurf->Blt(NULL, NULL, pRect, DDBLT_COLORFILL, &BltFx))) {
80 return 1;
81 } else {
82 return 0;
83 }
84 }
85
86 // Clipper
87
VidSClipperInit(IDirectDrawSurface7 * pSurf)88 int VidSClipperInit(IDirectDrawSurface7* pSurf)
89 {
90 if (nVidFullscreen && bDrvOkay) {
91 return 0;
92 }
93
94 IDirectDrawClipper *pClipper = NULL;
95
96 if (SUCCEEDED(_DirectDrawCreateClipper(0, &pClipper, NULL))) {
97 if (SUCCEEDED(pClipper->SetHWnd(0, hVidWnd))) {
98 pSurf->SetClipper(pClipper);
99 RELEASE(pClipper);
100
101 return 0;
102 }
103 }
104
105 return 1;
106 }
107
108 // ---------------------------------------------------------------------------
109 // Gamma controls
110
111 static IDirectDrawGammaControl* pGammaControl;
112 static DDGAMMARAMP* pFBAGamma = NULL;
113 static DDGAMMARAMP* pSysGamma = NULL;
114
VidSRestoreGamma()115 void VidSRestoreGamma()
116 {
117 if (pGammaControl) {
118 if (pSysGamma) {
119 pGammaControl->SetGammaRamp(0, pSysGamma);
120 }
121
122 if (pSysGamma) {
123 free(pSysGamma);
124 pSysGamma = NULL;
125 }
126 if (pFBAGamma) {
127 free(pFBAGamma);
128 pFBAGamma = NULL;
129 }
130
131 RELEASE(pGammaControl);
132 }
133 }
134
VidSUpdateGamma()135 int VidSUpdateGamma()
136 {
137 if (pGammaControl) {
138 if (bDoGamma) {
139 for (int i = 0; i < 256; i++) {
140 int nValue = (int)(65535.0 * pow((i / 255.0), nGamma));
141 pFBAGamma->red[i] = nValue;
142 pFBAGamma->green[i] = nValue;
143 pFBAGamma->blue[i] = nValue;
144 }
145 pGammaControl->SetGammaRamp(0, pFBAGamma);
146 } else {
147 pGammaControl->SetGammaRamp(0, pSysGamma);
148 }
149 }
150
151 return 0;
152 }
153
VidSSetupGamma(IDirectDrawSurface7 * pSurf)154 int VidSSetupGamma(IDirectDrawSurface7* pSurf)
155 {
156 pGammaControl = NULL;
157
158 if (!bVidUseHardwareGamma || !nVidFullscreen) {
159 return 0;
160 }
161
162 if (FAILED(pSurf->QueryInterface(IID_IDirectDrawGammaControl, (void**)&pGammaControl))) {
163 pGammaControl = NULL;
164 #ifdef PRINT_DEBUG_INFO
165 dprintf(_T(" * Warning: Couldn't use hardware gamma controls.\n"));
166 #endif
167
168 return 1;
169 }
170
171 pSysGamma = (DDGAMMARAMP*)malloc(sizeof(DDGAMMARAMP));
172 if (pSysGamma == NULL) {
173 VidSRestoreGamma();
174 return 1;
175 }
176 pGammaControl->GetGammaRamp(0, pSysGamma);
177
178 pFBAGamma = (DDGAMMARAMP*)malloc(sizeof(DDGAMMARAMP));
179 if (pFBAGamma == NULL) {
180 VidSRestoreGamma();
181 return 1;
182 }
183
184 VidSUpdateGamma();
185
186 return 0;
187 }
188
189 // ---------------------------------------------------------------------------
190 // Fullscreen mode support routines
191
VidSScoreDisplayMode(VidSDisplayScoreInfo * pScoreInfo)192 int VidSScoreDisplayMode(VidSDisplayScoreInfo* pScoreInfo)
193 {
194 // Continue if the resolution is too low
195 if (pScoreInfo->nModeWidth < pScoreInfo->nRequestedWidth || pScoreInfo->nModeHeight < pScoreInfo->nRequestedHeight) {
196 return 0;
197 }
198
199 // Only test standard resolutions if below 512 x 384
200 if ((pScoreInfo->nModeWidth == 320 && pScoreInfo->nModeHeight == 240) || (pScoreInfo->nModeWidth == 400 && pScoreInfo->nModeHeight == 300) || (pScoreInfo->nModeWidth >= 512 && pScoreInfo->nModeHeight >= 384)) {
201
202 if (pScoreInfo->nRequestedWidth == 0 || pScoreInfo->nRequestedHeight == 0) {
203 RECT rect = {0, 0, 0, 0};
204 int nGameWidth = nVidImageWidth, nGameHeight = nVidImageHeight;
205 unsigned int nScore;
206
207 if (bDrvOkay) {
208 if ((BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) && (nVidRotationAdjust & 1)) {
209 BurnDrvGetVisibleSize(&nGameHeight, &nGameWidth);
210 } else {
211 BurnDrvGetVisibleSize(&nGameWidth, &nGameHeight);
212 }
213 }
214
215 nVidScrnWidth = rect.right = pScoreInfo->nModeWidth;
216 nVidScrnHeight = rect.bottom = pScoreInfo->nModeHeight;
217 VidImageSize(&rect, nGameWidth, nGameHeight);
218
219 // Continue if the resolution is too low
220 if (!bDrvOkay) {
221 if ((unsigned int)(rect.bottom - rect.top) < pScoreInfo->nRequestedHeight) {
222 return 0;
223 }
224 } else {
225 if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) {
226 if ((unsigned int)(rect.right - rect.left) < pScoreInfo->nRequestedWidth) {
227 return 0;
228 }
229 } else {
230 if ((unsigned int)(rect.bottom - rect.top) < pScoreInfo->nRequestedHeight) {
231 return 0;
232 }
233 }
234 }
235
236 // Score resolutions based on how many pixels are unused and the pixel aspect
237 nScore = 65536 * (pScoreInfo->nModeWidth - (unsigned)(rect.right - rect.left)) + (pScoreInfo->nModeHeight - (unsigned)(rect.bottom - rect.top));
238 nScore = (int)((double)nScore * ((double)pScoreInfo->nModeWidth * nVidScrnAspectY / pScoreInfo->nModeHeight / nVidScrnAspectX));
239 if (nScore < pScoreInfo->nBestScore) {
240 pScoreInfo->nBestScore = nScore;
241 pScoreInfo->nBestWidth = pScoreInfo->nModeWidth;
242 pScoreInfo->nBestHeight = pScoreInfo->nModeHeight;
243 }
244 } else {
245 // Select the lowest resolution that will fit the image
246 if (pScoreInfo->nModeWidth < pScoreInfo->nBestWidth && pScoreInfo->nModeHeight < pScoreInfo->nBestHeight) {
247 pScoreInfo->nBestWidth = pScoreInfo->nModeWidth;
248 pScoreInfo->nBestHeight = pScoreInfo->nModeHeight;
249 }
250 }
251 }
252
253 return 0;
254 }
255
VidSInitScoreInfo(VidSDisplayScoreInfo * pScoreInfo)256 int VidSInitScoreInfo(VidSDisplayScoreInfo* pScoreInfo)
257 {
258 int nGameWidth = nVidImageWidth, nGameHeight = nVidImageHeight;
259 int nGameAspectX = 4, nGameAspectY = 3;
260
261 pScoreInfo->nBestWidth = -1U;
262 pScoreInfo->nBestHeight = -1U;
263 pScoreInfo->nBestScore = -1U;
264
265 if (pScoreInfo->nRequestedZoom == 0) {
266 return 0;
267 }
268
269 pScoreInfo->nRequestedWidth = 0;
270 pScoreInfo->nRequestedHeight = 0;
271
272 if (bDrvOkay) {
273 if ((BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) && (nVidRotationAdjust & 1)) {
274 BurnDrvGetVisibleSize(&nGameHeight, &nGameWidth);
275 BurnDrvGetAspect(&nGameAspectY, &nGameAspectX);
276 } else {
277 BurnDrvGetVisibleSize(&nGameWidth, &nGameHeight);
278 BurnDrvGetAspect(&nGameAspectX, &nGameAspectY);
279 }
280 }
281
282 if (!bVidCorrectAspect || bVidFullStretch || (nVidSelect == 1 && (nVidBlitterOpt[1] & 0x07000000) == 0x07000000) || (nVidSelect == 2 && nVidBlitterOpt[2] & 0x00000100)) {
283 pScoreInfo->nRequestedWidth = nGameWidth * pScoreInfo->nRequestedZoom;
284 pScoreInfo->nRequestedHeight = nGameHeight * pScoreInfo->nRequestedZoom;
285 } else {
286 if (bDrvOkay) {
287 if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) {
288 pScoreInfo->nRequestedWidth = nGameWidth * pScoreInfo->nRequestedZoom;
289 } else {
290 pScoreInfo->nRequestedHeight = nGameHeight * pScoreInfo->nRequestedZoom;
291 }
292 }
293 }
294
295 return 0;
296 }
297
myEnumModesCallback(LPDDSURFACEDESC2 pSurfaceDesc,void * lpContext)298 static HRESULT WINAPI myEnumModesCallback(LPDDSURFACEDESC2 pSurfaceDesc, void* lpContext)
299 {
300 ((VidSDisplayScoreInfo*)lpContext)->nModeWidth = pSurfaceDesc->dwWidth;
301 ((VidSDisplayScoreInfo*)lpContext)->nModeHeight = pSurfaceDesc->dwHeight;
302
303 VidSScoreDisplayMode((VidSDisplayScoreInfo*)lpContext);
304
305 return DDENUMRET_OK;
306 }
307
VidSRestoreScreenMode()308 void VidSRestoreScreenMode()
309 {
310 if (pDD == NULL) {
311 return;
312 }
313
314 // Undo the changes we made to the display
315 pDD->SetCooperativeLevel(NULL, DDSCL_NORMAL);
316
317 nVidScrnWidth = 0;
318 nVidScrnHeight = 0;
319
320 return;
321 }
322
323 // Enter fullscreen mode, select optimal full-screen resolution
VidSEnterFullscreenMode(int nZoom,int nDepth)324 int VidSEnterFullscreenMode(int nZoom, int nDepth)
325 {
326 int nWidth, nHeight;
327
328 if (pDD == NULL) {
329 return 1;
330 }
331
332 if (nDepth == 0) {
333 nDepth = nVidDepth;
334 }
335 if (nDepth == 15) {
336 nDepth = 16;
337 }
338
339 if (FAILED(pDD->SetCooperativeLevel(hVidWnd, DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FPUPRESERVE | DDSCL_FULLSCREEN))) {
340 return 1;
341 }
342
343 if (bVidArcaderes) {
344 if (!VidSGetArcaderes(&nWidth, &nHeight)) {
345 return 1;
346 }
347 } else {
348 if (nZoom) {
349 DDSURFACEDESC2 ddsd;
350 VidSDisplayScoreInfo ScoreInfo;
351
352 memset(&ScoreInfo, 0, sizeof(VidSDisplayScoreInfo));
353 ScoreInfo.nRequestedZoom = nZoom;
354 VidSInitScoreInfo(&ScoreInfo);
355
356 memset(&ddsd, 0, sizeof(ddsd));
357 ddsd.dwSize = sizeof(ddsd);
358 ddsd.dwFlags = DDSD_PIXELFORMAT;
359
360 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
361 ddsd.ddpfPixelFormat.dwRGBBitCount = nDepth;
362
363 pDD->EnumDisplayModes(0, &ddsd, (void*)&ScoreInfo, myEnumModesCallback);
364
365 if (ScoreInfo.nBestWidth == -1U) {
366
367 VidSRestoreScreenMode();
368
369 FBAPopupAddText(PUF_TEXT_DEFAULT, MAKEINTRESOURCE(IDS_ERR_UI_FULL_NOMODE));
370 FBAPopupDisplay(PUF_TYPE_ERROR);
371
372 return 1;
373 }
374
375 nWidth = ScoreInfo.nBestWidth;
376 nHeight = ScoreInfo.nBestHeight;
377 } else {
378 nWidth = nVidWidth;
379 nHeight = nVidHeight;
380 }
381 }
382
383 if (!bDrvOkay && (nWidth < 640 || nHeight < 480)) {
384 return 1;
385 }
386
387 if (FAILED(pDD->SetDisplayMode(nWidth, nHeight, nDepth, nVidRefresh, 0))) {
388 VidSRestoreScreenMode();
389
390 FBAPopupAddText(PUF_TEXT_DEFAULT, MAKEINTRESOURCE(IDS_ERR_UI_FULL_PROBLEM));
391 if (bVidArcaderes && (nWidth != 320 && nHeight != 240)) {
392 FBAPopupAddText(PUF_TEXT_DEFAULT, MAKEINTRESOURCE(IDS_ERR_UI_FULL_CUSTRES));
393 }
394 FBAPopupDisplay(PUF_TYPE_ERROR);
395
396 nVidScrnWidth = 0;
397 nVidScrnHeight = 0;
398
399 return 1;
400 }
401
402 nVidScrnWidth = nWidth;
403 nVidScrnHeight = nHeight;
404
405 return 0;
406 }
407
408 // ---------------------------------------------------------------------------
409
410 // Compute the resolution needed to run a game without scaling and filling the screen
411 // (taking into account the aspect ratios of the game and monitor)
VidSGetArcaderes(int * pWidth,int * pHeight)412 bool VidSGetArcaderes(int* pWidth, int* pHeight)
413 {
414 int nGameWidth, nGameHeight;
415 int nGameAspectX, nGameAspectY;
416
417 if (bDrvOkay) {
418 if ((BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) && (nVidRotationAdjust & 1)) {
419 BurnDrvGetVisibleSize(&nGameHeight, &nGameWidth);
420 BurnDrvGetAspect(&nGameAspectY, &nGameAspectX);
421 } else {
422 BurnDrvGetVisibleSize(&nGameWidth, &nGameHeight);
423 BurnDrvGetAspect(&nGameAspectX, &nGameAspectY);
424 }
425
426 double dMonAspect = (double)nVidScrnAspectX / nVidScrnAspectY;
427 double dGameAspect = (double)nGameAspectX / nGameAspectY;
428
429 if (dMonAspect > dGameAspect) {
430 *pWidth = nGameHeight * nGameAspectY * nGameWidth * nVidScrnAspectX / (nGameHeight * nGameAspectX * nVidScrnAspectY);
431 *pHeight = nGameHeight;
432 } else {
433 *pWidth = nGameWidth;
434 *pHeight = nGameWidth * nGameAspectX * nGameHeight * nVidScrnAspectY / (nGameWidth * nGameAspectY * nVidScrnAspectX);
435 }
436
437 // Horizontal resolution must be a multiple of 8
438 if (*pWidth - nGameWidth < 8) {
439 *pWidth = (*pWidth + 7) & ~7;
440 } else {
441 *pWidth = (*pWidth + 4) & ~7;
442 }
443 } else {
444 return false;
445 }
446
447 return true;
448 }
449
450 // This function takes a rectangle and scales it to either:
451 // - The largest possible multiple of both X and Y;
452 // - The largest possible multiple of Y, modifying X to ensure the correct aspect ratio;
453 // - The window size
VidSScaleImage(RECT * pRect,int nGameWidth,int nGameHeight,bool bVertScanlines)454 int VidSScaleImage(RECT* pRect, int nGameWidth, int nGameHeight, bool bVertScanlines)
455 {
456 float xm, ym; // The multiple of nScrnWidth and nScrnHeight we can fit in
457 int nScrnWidth, nScrnHeight;
458 int nScrnAspectX, nScrnAspectY;
459
460 int nGameAspectX = 4, nGameAspectY = 3;
461 int nWidth = pRect->right - pRect->left;
462 int nHeight = pRect->bottom - pRect->top;
463
464 if (bVidFullStretch) { // Arbitrary stretch
465 return 0;
466 }
467
468 nScrnAspectX = nVidScrnAspectX;
469 nScrnAspectY = nVidScrnAspectY;
470
471 if (bDrvOkay) {
472 if ((BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) && (nVidRotationAdjust & 1)) {
473 BurnDrvGetAspect(&nGameAspectY, &nGameAspectX);
474 } else {
475 BurnDrvGetAspect(&nGameAspectX, &nGameAspectY);
476 }
477
478
479 if ((BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) && nVidFullscreen && !(nVidRotationAdjust & 1)) {
480 // Using vertically orientated monitor
481 nScrnAspectX = nVidVerScrnAspectX;
482 nScrnAspectY = nVidVerScrnAspectY;
483 }
484 }
485
486 //xm = (nWidth / nGameWidth) + (nWidth / nGameWidth) * 0.166666667;
487 //ym = (nHeight / nGameHeight) + (nWidth / nGameWidth) * 0.166666667;
488 xm = (float)nWidth / nGameWidth;
489 ym = (float)nHeight / nGameHeight;
490
491 if (nVidFullscreen) {
492 nScrnWidth = nVidScrnWidth;
493 nScrnHeight = nVidScrnHeight;
494 } else {
495 nScrnWidth = SystemWorkArea.right - SystemWorkArea.left;
496 nScrnHeight = SystemWorkArea.bottom - SystemWorkArea.top;
497 }
498
499 if (bVidCorrectAspect && bVidScanlines && ((ym >= 2 && xm) || (ym && xm >= 2 && bVertScanlines))) { // Correct aspect ratio with scanlines
500 float nWidthScratch, nHeightScratch;
501 if (nGameWidth < nGameHeight && bVertScanlines) {
502 float xmScratch = xm;
503 do {
504 nWidthScratch = nGameWidth * xmScratch;
505 nHeightScratch = (INT64)nWidthScratch * nScrnAspectX * nGameAspectY * nScrnHeight / (nScrnWidth * nScrnAspectY * nGameAspectX);
506 xmScratch--;
507 } while (nHeightScratch > nHeight && xmScratch >= 2);
508 if (nHeightScratch > nHeight) { // The image is too high
509 if (nGameWidth < nGameHeight) { // Vertical games
510 nWidth = (INT64)nHeight * nScrnAspectX * nGameAspectX * nScrnHeight / (nScrnWidth * nScrnAspectY * nGameAspectY);
511 } else { // Horizontal games
512 nWidth = (INT64)nHeight * nScrnAspectY * nGameAspectX * nScrnWidth / (nScrnHeight * nScrnAspectX * nGameAspectY);
513 }
514 } else {
515 nWidth = nWidthScratch;
516 nHeight = nHeightScratch;
517 }
518 } else {
519 float ymScratch = ym;
520 do {
521 nHeightScratch = nGameHeight * ymScratch;
522 nWidthScratch = (INT64)nHeightScratch * nScrnAspectY * nGameAspectX * nScrnWidth / (nScrnHeight * nScrnAspectX * nGameAspectY);
523 ymScratch--;
524 } while (nWidthScratch > nWidth && ymScratch >= 2);
525 if (nWidthScratch > nWidth) { // The image is too wide
526 if (nGameWidth < nGameHeight) { // Vertical games
527 nHeight = (INT64)nWidth * nScrnAspectY * nGameAspectY * nScrnWidth / (nScrnHeight * nScrnAspectX * nGameAspectX);
528 } else { // Horizontal games
529 nHeight = (INT64)nWidth * nScrnAspectX * nGameAspectY * nScrnHeight / (nScrnWidth * nScrnAspectY * nGameAspectX);
530 }
531 } else {
532 nWidth = nWidthScratch;
533 nHeight = nHeightScratch;
534 }
535 }
536 } else {
537 if (bVidCorrectAspect) { // Correct aspect ratio
538 float nWidthScratch;
539 nWidthScratch = (INT64)nHeight * nScrnAspectY * nGameAspectX * nScrnWidth / (nScrnHeight * nScrnAspectX * nGameAspectY);
540 if (nWidthScratch > nWidth) { // The image is too wide
541 if (nGameWidth < nGameHeight) { // Vertical games
542 nHeight = (INT64)nWidth * nScrnAspectY * nGameAspectY * nScrnWidth / (nScrnHeight * nScrnAspectX * nGameAspectX);
543 } else { // Horizontal games
544 nHeight = (INT64)nWidth * nScrnAspectX * nGameAspectY * nScrnHeight / (nScrnWidth * nScrnAspectY * nGameAspectX);
545 }
546 } else {
547 nWidth = nWidthScratch;
548 }
549 } else {
550 if (xm && ym) { // Don't correct aspect ratio
551 if (xm > ym) {
552 xm = ym;
553 } else {
554 ym = xm;
555 }
556 nWidth = nGameWidth * xm;
557 nHeight = nGameHeight * ym;
558 } else {
559 if (xm) {
560 nWidth = nGameWidth * xm * nHeight / nGameHeight;
561 } else {
562 if (ym) {
563 nHeight = nGameHeight * ym * nWidth / nGameWidth;
564 }
565 }
566 }
567 }
568 }
569
570 pRect->left = (pRect->right + pRect->left) / 2;
571 pRect->left -= nWidth / 2;
572 pRect->right = pRect->left + nWidth;
573
574 pRect->top = (pRect->top + pRect->bottom) / 2;
575 pRect->top -= nHeight / 2;
576 pRect->bottom = pRect->top + nHeight;
577
578 return 0;
579 }
580
581 // ---------------------------------------------------------------------------
582 // Text display routines
583
584 static struct { TCHAR pMsgText[32]; COLORREF nColour; int nPriority; unsigned int nTimer; } VidSShortMsg = { _T(""), 0, 0, 0,};
585 static HFONT ShortMsgFont = NULL;
586
587 static unsigned char nStatusSymbols[4] = {0x3B, 0xC2, 0x3D, 0x34}; //"pause", "record", "kaillera" and "play" in font Webdings, respectivelly
588 static HFONT StatusFont = NULL;
589 static HFONT StatusFontTiny = NULL;
590
591 #define CHAT_SIZE 11
592
593 static struct { TCHAR* pIDText; COLORREF nIDColour; TCHAR* pMainText; COLORREF nMainColour; } VidSChatMessage[CHAT_SIZE];
594 static bool bChatInitialised = false;
595
596 static HFONT ChatIDFont = NULL;
597 static HFONT ChatMainFont = NULL;
598 static unsigned int nChatTimer;
599 static int nChatFontSize;
600 static int nChatShadowOffset;
601 static int nChatOverFlow;
602 static bool bDrawChat;
603
604 static HFONT EditTextFont = NULL;
605 static HFONT EditCursorFont = NULL;
606 static DWORD nPrevStart, nPrevEnd;
607 static int nCursorTime;
608 static int nCursorState = 0;
609 static int nEditSize;
610 static int nEditShadowOffset;
611
612 static struct { TCHAR pMsgText[64]; COLORREF nColour; int nPriority; unsigned int nTimer; } VidSTinyMsg = {_T(""), 0, 0, 0};
613 static HFONT TinyMsgFont = NULL;
614
615 static struct { TCHAR pMsgText[64]; COLORREF nColour; int nLineNo; unsigned int nTimer; } VidSJoystickMsg = {_T(""), 0, 0, 0};
616 static HFONT JoystickMsgFont = NULL;
617
618 static IDirectDrawSurface7* pShortMsgSurf = NULL;
619 static IDirectDrawSurface7* pStatusSurf = NULL;
620 static IDirectDrawSurface7* pChatSurf = NULL;
621 static IDirectDrawSurface7* pEditSurf = NULL;
622 static IDirectDrawSurface7* pTinyMsgSurf = NULL;
623 static IDirectDrawSurface7* pJoystickMsgSurf = NULL;
624
625 static unsigned int nKeyColour = 0x000001;
626
627 static int nStatus = 0;
628 static int nPrevStatus = -1;
629
630 int nVidSDisplayStatus = 1; // 1 = display pause/record/replay/kaillera icons in the upper right corner of the display
631
632 int nMaxChatFontSize = 36; // Maximum size of the font used for the Kaillera chat function (1280x960 or higher)
633 int nMinChatFontSize = 12; // Minimum size of the font used for the Kaillera chat function (arcade resolution)
634
635 static int nZoom; // & 1: zoom X, & 2: zoom Y
636
637 static int nShortMsgFlags;
638 static int nStatusFlags;
639
640 bool bEditActive = false;
641 bool bEditTextChanged = false;
642 TCHAR EditText[MAX_CHAT_SIZE + 1] = _T("");
643
644 TCHAR OSDMsg[MAX_PATH] = _T("");
645 unsigned int nOSDTimer = 0;
646
MyTextOut(HDC hdc,int nXStart,int nYStart,LPCTSTR lpString,int cbString,int nShadowOffset,int nColour)647 static BOOL MyTextOut(HDC hdc, int nXStart, int nYStart, LPCTSTR lpString, int cbString, int nShadowOffset, int nColour)
648 {
649 // Print a black shadow
650 SetTextColor(hdc, 0);
651 if (nShadowOffset >= 2) {
652 TextOut(hdc, nXStart + nShadowOffset, nYStart + nShadowOffset, lpString, cbString);
653 }
654 // Print a black outline
655 TextOut(hdc, nXStart - 1, nYStart - 1, lpString, cbString);
656 TextOut(hdc, nXStart + 0, nYStart - 1, lpString, cbString);
657 TextOut(hdc, nXStart + 1, nYStart - 1, lpString, cbString);
658 TextOut(hdc, nXStart + 1, nYStart + 0, lpString, cbString);
659 TextOut(hdc, nXStart + 1, nYStart + 1, lpString, cbString);
660 TextOut(hdc, nXStart + 0, nYStart + 1, lpString, cbString);
661 TextOut(hdc, nXStart - 1, nYStart + 1, lpString, cbString);
662 TextOut(hdc, nXStart - 1, nYStart + 0, lpString, cbString);
663 // Print the text on top
664 SetTextColor(hdc, nColour);
665
666 return TextOut(hdc, nXStart, nYStart, lpString, cbString);
667 }
668
MyExtTextOut(HDC hdc,int X,int Y,UINT fuOptions,CONST RECT * lprc,LPCTSTR lpString,UINT cbCount,CONST INT * lpDx,int nShadowOffset,int nColour)669 static BOOL MyExtTextOut(HDC hdc, int X, int Y, UINT fuOptions, CONST RECT* lprc, LPCTSTR lpString, UINT cbCount, CONST INT* lpDx, int nShadowOffset, int nColour)
670 {
671 // Print a black shadow
672 SetTextColor(hdc, 0);
673 if (nShadowOffset >= 2) {
674 ExtTextOut(hdc, X + nShadowOffset, Y + nShadowOffset, fuOptions, lprc, lpString, cbCount, lpDx);
675 }
676 // Print a black outline
677 ExtTextOut(hdc, X - 1, Y - 1, fuOptions, lprc, lpString, cbCount, lpDx);
678 ExtTextOut(hdc, X + 0, Y - 1, fuOptions, lprc, lpString, cbCount, lpDx);
679 ExtTextOut(hdc, X + 1, Y - 1, fuOptions, lprc, lpString, cbCount, lpDx);
680 ExtTextOut(hdc, X + 1, Y + 0, fuOptions, lprc, lpString, cbCount, lpDx);
681 ExtTextOut(hdc, X + 1, Y + 1, fuOptions, lprc, lpString, cbCount, lpDx);
682 ExtTextOut(hdc, X + 0, Y + 1, fuOptions, lprc, lpString, cbCount, lpDx);
683 ExtTextOut(hdc, X - 1, Y + 1, fuOptions, lprc, lpString, cbCount, lpDx);
684 ExtTextOut(hdc, X - 1, Y + 0, fuOptions, lprc, lpString, cbCount, lpDx);
685 // Print the text on top
686 SetTextColor(hdc, nColour);
687
688 return ExtTextOut(hdc, X, Y, fuOptions, lprc, lpString, cbCount, lpDx);
689 }
690
VidSExitTinyMsg()691 static void VidSExitTinyMsg()
692 {
693 VidSTinyMsg.nTimer = 0;
694
695 if (TinyMsgFont) {
696 DeleteObject(TinyMsgFont);
697 TinyMsgFont = NULL;
698 }
699
700 RELEASE(pTinyMsgSurf);
701 }
702
VidSExitJoystickMsg()703 static void VidSExitJoystickMsg()
704 {
705 VidSJoystickMsg.nTimer = 0;
706
707 if (JoystickMsgFont) {
708 DeleteObject(JoystickMsgFont);
709 JoystickMsgFont = NULL;
710 }
711
712 RELEASE(pJoystickMsgSurf);
713 }
714
VidSExitShortMsg()715 static void VidSExitShortMsg()
716 {
717 VidSShortMsg.nTimer = 0;
718
719 if (ShortMsgFont) {
720 DeleteObject(ShortMsgFont);
721 ShortMsgFont = NULL;
722 }
723
724 RELEASE(pShortMsgSurf);
725 }
726
VidSExitStatus()727 static void VidSExitStatus()
728 {
729 if (StatusFont) {
730 DeleteObject(StatusFont);
731 StatusFont = NULL;
732 }
733
734 if (StatusFontTiny) {
735 DeleteObject(StatusFontTiny);
736 StatusFontTiny = NULL;
737 }
738
739 RELEASE(pStatusSurf);
740 }
741
VidSExitChat()742 void VidSExitChat()
743 {
744 nChatTimer = 0;
745
746 if (ChatIDFont) {
747 DeleteObject(ChatIDFont);
748 ChatIDFont = NULL;
749 }
750 if (ChatMainFont) {
751 DeleteObject(ChatMainFont);
752 ChatMainFont = NULL;
753 }
754
755 for (int i = 0; i < CHAT_SIZE; i++) {
756 if (VidSChatMessage[i].pIDText) {
757 free(VidSChatMessage[i].pIDText);
758 VidSChatMessage[i].pIDText = NULL;
759 }
760 if (VidSChatMessage[i].pMainText) {
761 free(VidSChatMessage[i].pMainText);
762 VidSChatMessage[i].pMainText = NULL;
763 }
764 }
765
766 RELEASE(pChatSurf);
767 }
768
VidSExitEdit()769 static void VidSExitEdit()
770 {
771 bEditActive = false;
772
773 if (EditTextFont) {
774 DeleteObject(EditTextFont);
775 EditTextFont = NULL;
776 }
777 if (EditCursorFont) {
778 DeleteObject(EditCursorFont);
779 EditCursorFont = NULL;
780 }
781
782 RELEASE(pEditSurf);
783 }
784
VidSExitOSD()785 void VidSExitOSD()
786 {
787 VidSExitTinyMsg();
788 VidSExitJoystickMsg();
789 if (kNetGame) {
790 VidSExitEdit();
791 }
792 VidSExitChat();
793 VidSExitShortMsg();
794 VidSExitStatus();
795 }
796
VidSInitTinyMsg(int)797 static int VidSInitTinyMsg(int /*nFlags*/)
798 {
799 DDSURFACEDESC2 ddsd;
800
801 VidSExitTinyMsg();
802
803 TinyMsgFont = CreateFont(12, 0, 0, 0, FW_SEMIBOLD, 0, 0, 0, 0, 0, 0, ANTIALIASED_QUALITY, FF_SWISS, _T("MS Sans Serif"));
804 VidSTinyMsg.nTimer = 0;
805
806 // create surface to display the text
807 memset(&ddsd, 0, sizeof(ddsd));
808 ddsd.dwSize = sizeof(ddsd);
809 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CKSRCBLT;
810
811 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
812
813 ddsd.dwWidth = 300;
814 ddsd.dwHeight = 20;
815
816 ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = nKeyColour;
817 ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = nKeyColour;
818
819 if (FAILED(pDD->CreateSurface(&ddsd, &pTinyMsgSurf, NULL))) {
820 #ifdef PRINT_DEBUG_INFO
821 printf(" * Error: Couldn't create OSD texture.\n");
822 #endif
823 return 1;
824 }
825
826 VidSClearSurface(pTinyMsgSurf, nKeyColour, NULL);
827
828 return 0;
829 }
830
VidSInitJoystickMsg(int)831 static int VidSInitJoystickMsg(int /*nFlags*/)
832 {
833 DDSURFACEDESC2 ddsd;
834
835 VidSExitJoystickMsg();
836
837 //JoystickMsgFont = CreateFont(12, 0, 0, 0, FW_DEMIBOLD, 0, 0, 0, 0, 0, 0, ANTIALIASED_QUALITY, FF_SWISS, _T("Courier New"));
838 JoystickMsgFont = CreateFont(8, 0, 0, 0, FW_THIN, 0, 0, 0, OUT_OUTLINE_PRECIS, 0, 0, NONANTIALIASED_QUALITY, FF_SWISS, _T("Courier New"));
839 VidSJoystickMsg.nTimer = 0;
840
841 // create surface to display the text
842 memset(&ddsd, 0, sizeof(ddsd));
843 ddsd.dwSize = sizeof(ddsd);
844 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CKSRCBLT;
845
846 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
847
848 ddsd.dwWidth = 300;
849 ddsd.dwHeight = 60;
850
851 ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = nKeyColour;
852 ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = nKeyColour;
853
854 if (FAILED(pDD->CreateSurface(&ddsd, &pJoystickMsgSurf, NULL))) {
855 #ifdef PRINT_DEBUG_INFO
856 printf(" * Error: Couldn't create OSD texture.\n");
857 #endif
858 return 1;
859 }
860
861 VidSClearSurface(pJoystickMsgSurf, nKeyColour, NULL);
862
863 return 0;
864 }
865
VidSInitShortMsg(int nFlags)866 static int VidSInitShortMsg(int nFlags)
867 {
868 DDSURFACEDESC2 ddsd;
869
870 VidSExitShortMsg();
871
872 nShortMsgFlags = nFlags;
873
874 ShortMsgFont = CreateFont(24, 0, 0, 0, FW_DEMIBOLD, 0, 0, 0, 0, 0, 0, ANTIALIASED_QUALITY, FF_SWISS, _T("Lucida"));
875 VidSShortMsg.nTimer = 0;
876
877 // create surface to display the text
878 memset(&ddsd, 0, sizeof(ddsd));
879 ddsd.dwSize = sizeof(ddsd);
880 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CKSRCBLT;
881
882 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
883
884 ddsd.dwWidth = 256;
885 ddsd.dwHeight = 32;
886
887 ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = nKeyColour;
888 ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = nKeyColour;
889
890 if (FAILED(pDD->CreateSurface(&ddsd, &pShortMsgSurf, NULL))) {
891 #ifdef PRINT_DEBUG_INFO
892 dprintf(_T(" * Error: Couldn't create OSD texture.\n"));
893 #endif
894 return 1;
895 }
896
897 VidSClearSurface(pShortMsgSurf, nKeyColour, NULL);
898
899 return 0;
900 }
901
VidSInitStatus(int nFlags)902 static int VidSInitStatus(int nFlags)
903 {
904 DDSURFACEDESC2 ddsd;
905
906 VidSExitStatus();
907
908 nStatusFlags = nFlags;
909
910 StatusFont = CreateFont(48, 0, 0, 0, FW_DEMIBOLD, 0, 0, 0, DEFAULT_CHARSET, 0, 0, ANTIALIASED_QUALITY, FF_SWISS, _T("Webdings"));
911 StatusFontTiny = CreateFont(20, 0, 0, 0, FW_DEMIBOLD, 0, 0, 0, DEFAULT_CHARSET, 0, 0, ANTIALIASED_QUALITY, FF_SWISS, _T("Webdings"));
912 nPrevStatus = -1;
913
914 // create surface to display the text
915 memset(&ddsd, 0, sizeof(ddsd));
916 ddsd.dwSize = sizeof(ddsd);
917 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CKSRCBLT;
918
919 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
920
921 ddsd.dwWidth = 192;
922 ddsd.dwHeight = 50;
923
924 ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = nKeyColour;
925 ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = nKeyColour;
926
927 if (FAILED(pDD->CreateSurface(&ddsd, &pStatusSurf, NULL))) {
928 #ifdef PRINT_DEBUG_INFO
929 dprintf(_T(" * Error: Couldn't create OSD texture.\n"));
930 #endif
931 return 1;
932 }
933
934 VidSClearSurface(pStatusSurf, nKeyColour, NULL);
935
936 return 0;
937 }
938
VidSInitChat(int)939 static int VidSInitChat(int /*nFlags*/)
940 {
941 DDSURFACEDESC2 ddsd;
942
943 if (bChatInitialised) {
944 VidSExitChat();
945 } else {
946 // for (int i = 0; i < CHAT_SIZE + (CHAT_SIZE >> 1); i++) {
947 for (int i = 0; i < CHAT_SIZE; i++) {
948 VidSChatMessage[i].pIDText = NULL;
949 VidSChatMessage[i].pMainText = NULL;
950 }
951 bChatInitialised = true;
952 }
953
954 //nChatFontSize = nMaxChatFontSize - ((nMaxChatFontSize - nMinChatFontSize) * nFlags) / 4;
955 nChatFontSize = 20; // used for cheat search only at the minute so only used in a window
956
957 ChatIDFont = CreateFont(nChatFontSize, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, ANTIALIASED_QUALITY, FF_SWISS, _T("Lucida"));
958 if (nChatFontSize > 20) {
959 ChatMainFont = CreateFont(nChatFontSize, 0, 0, 0, FW_NORMAL, 0, 0, 0, 0, 0, 0, ANTIALIASED_QUALITY, FF_SWISS, _T("Lucida"));
960 } else {
961 ChatMainFont = CreateFont(nChatFontSize, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, ANTIALIASED_QUALITY, FF_SWISS, _T("Lucida"));
962 }
963
964 nChatShadowOffset = (nChatFontSize / 16) + 1;
965 nChatOverFlow = 0;
966 bDrawChat = false;
967
968 // create surface to display the text
969 memset(&ddsd, 0, sizeof(ddsd));
970 ddsd.dwSize = sizeof(ddsd);
971 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CKSRCBLT;
972
973 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
974
975 if (nVidFullscreen) {
976 RECT rect;
977 GetClientScreenRect(hScrnWnd, &rect);
978 ddsd.dwWidth = rect.right - rect.left;
979 } else {
980 extern RECT SystemWorkArea;
981 ddsd.dwWidth = SystemWorkArea.right - SystemWorkArea.left;
982 }
983 ddsd.dwHeight = nChatFontSize * (CHAT_SIZE + (CHAT_SIZE >> 1));
984
985 ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = nKeyColour;
986 ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = nKeyColour;
987
988 if (FAILED(pDD->CreateSurface(&ddsd, &pChatSurf, NULL))) {
989 #ifdef PRINT_DEBUG_INFO
990 dprintf(_T(" * Error: Couldn't create Chat texture.\n"));
991 #endif
992 return 1;
993 }
994
995 VidSClearSurface(pChatSurf, nKeyColour, NULL);
996
997 bDrawChat = true;
998
999 return 0;
1000 }
1001
VidSInitEdit(int nFlags)1002 static int VidSInitEdit(int nFlags)
1003 {
1004 DDSURFACEDESC2 ddsd;
1005
1006 VidSExitEdit();
1007
1008 nEditSize = nMaxChatFontSize + 8 - ((nMaxChatFontSize - nMinChatFontSize) * nFlags) / 4;
1009
1010 EditTextFont = CreateFont(nEditSize - 8, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, ANTIALIASED_QUALITY, FF_SWISS, _T("Lucida"));
1011 EditCursorFont = CreateFont(nEditSize - 8, 0, 0, 0, FW_BOLD, 0, TRUE, 0, 0, 0, 0, ANTIALIASED_QUALITY, FF_SWISS, _T("Lucida"));
1012
1013 nEditShadowOffset = ((nEditSize - 8) / 16) + 1;
1014
1015 // create surface to display the text
1016 memset(&ddsd, 0, sizeof(ddsd));
1017 ddsd.dwSize = sizeof(ddsd);
1018 ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CKSRCBLT;
1019
1020 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
1021
1022 if (nVidFullscreen) {
1023 RECT rect;
1024 GetClientScreenRect(hScrnWnd, &rect);
1025 ddsd.dwWidth = rect.right - rect.left;
1026 } else {
1027 extern RECT SystemWorkArea;
1028 ddsd.dwWidth = SystemWorkArea.right - SystemWorkArea.left;
1029 }
1030 ddsd.dwHeight = nEditSize;
1031
1032 ddsd.ddckCKSrcBlt.dwColorSpaceLowValue = nKeyColour;
1033 ddsd.ddckCKSrcBlt.dwColorSpaceHighValue = nKeyColour;
1034
1035 if (FAILED(pDD->CreateSurface(&ddsd, &pEditSurf, NULL))) {
1036 #ifdef PRINT_DEBUG_INFO
1037 dprintf(_T(" * Error: Couldn't create OSD texture.\n"));
1038 #endif
1039 return 1;
1040 }
1041
1042 VidSClearSurface(pEditSurf, nKeyColour, NULL);
1043
1044 return 0;
1045 }
1046
VidSInitOSD(int nFlags)1047 int VidSInitOSD(int nFlags)
1048 {
1049 #ifdef PRINT_DEBUG_INFO
1050 // dprintf(_T(" ** OSD initialised.\n"));
1051 #endif
1052
1053 if (pDD == NULL) {
1054 return 1;
1055 }
1056
1057 if (VidSInitStatus(nFlags)) {
1058 return 1;
1059 }
1060 if (VidSInitShortMsg(nFlags)) {
1061 return 1;
1062 }
1063 if (VidSInitChat(nFlags)) {
1064 return 1;
1065 }
1066 if (kNetGame) {
1067 if (VidSInitEdit(nFlags)) {
1068 return 1;
1069 }
1070 }
1071 if (VidSInitTinyMsg(nFlags)) {
1072 return 1;
1073 }
1074 if (VidSInitJoystickMsg(nFlags)) {
1075 return 1;
1076 }
1077
1078 return 0;
1079 }
1080
VidSRestoreOSD()1081 int VidSRestoreOSD()
1082 {
1083 if (pShortMsgSurf) {
1084 if (FAILED(pShortMsgSurf->IsLost())) {
1085 if (FAILED(pShortMsgSurf->Restore())) {
1086 return 1;
1087 }
1088 VidSClearSurface(pShortMsgSurf, nKeyColour, NULL);
1089
1090 VidSShortMsg.nTimer = 0;
1091 }
1092 }
1093
1094 if (pTinyMsgSurf) {
1095 if (FAILED(pTinyMsgSurf->IsLost())) {
1096 if (FAILED(pTinyMsgSurf->Restore())) {
1097 return 1;
1098 }
1099 VidSClearSurface(pTinyMsgSurf, nKeyColour, NULL);
1100
1101 VidSTinyMsg.nTimer = 0;
1102 }
1103 }
1104
1105 if (pJoystickMsgSurf) {
1106 if (FAILED(pJoystickMsgSurf->IsLost())) {
1107 if (FAILED(pJoystickMsgSurf->Restore())) {
1108 return 1;
1109 }
1110 VidSClearSurface(pJoystickMsgSurf, nKeyColour, NULL);
1111
1112 VidSJoystickMsg.nTimer = 0;
1113 }
1114 }
1115
1116 if (pStatusSurf) {
1117 if (FAILED(pStatusSurf->IsLost())) {
1118 if (FAILED(pStatusSurf->Restore())) {
1119 return 1;
1120 }
1121 VidSClearSurface(pStatusSurf, nKeyColour, NULL);
1122
1123 nPrevStatus = -1;
1124 }
1125 }
1126
1127 if (pChatSurf) {
1128 if (FAILED(pChatSurf->IsLost())) {
1129 if (FAILED(pChatSurf->Restore())) {
1130 return 1;
1131 }
1132 VidSClearSurface(pChatSurf, nKeyColour, NULL);
1133 }
1134 }
1135
1136 if (kNetGame) {
1137 if (pEditSurf) {
1138 if (FAILED(pEditSurf->IsLost())) {
1139 if (FAILED(pEditSurf->Restore())) {
1140 return 1;
1141 }
1142 VidSClearSurface(pEditSurf, nKeyColour, NULL);
1143 }
1144 }
1145 }
1146
1147 return 0;
1148 }
1149
VidSDisplayTinyMsg(IDirectDrawSurface7 * pSurf,RECT * pRect)1150 static void VidSDisplayTinyMsg(IDirectDrawSurface7* pSurf, RECT* pRect)
1151 {
1152 if (VidSTinyMsg.nTimer) {
1153 RECT src = { 0, 0, 300, 20 };
1154 RECT dest = { pRect->right - 320, pRect->bottom - 24, pRect->right - 8, pRect->bottom - 4 };
1155
1156 // Switch off message display when the message has been displayed long enough
1157 if (nFramesEmulated > VidSTinyMsg.nTimer) {
1158 VidSTinyMsg.nTimer = 0;
1159 }
1160
1161 if (dest.left < pRect->left) {
1162 src.left = pRect->left - dest.left;
1163 dest.left = pRect->left;
1164 }
1165
1166 if (nZoom & 2) {
1167 dest.top <<= 1;
1168 dest.bottom <<= 1;
1169 }
1170
1171 if (nZoom & 1) {
1172 dest.left <<= 1;
1173 dest.right <<= 1;
1174 }
1175
1176 // Blit the message to the surface using a colourkey
1177 pSurf->Blt(&dest, pTinyMsgSurf, &src, DDBLT_ASYNC | DDBLT_KEYSRC, NULL);
1178 }
1179 }
1180
VidSDisplayJoystickMsg(IDirectDrawSurface7 * pSurf,RECT * pRect)1181 static void VidSDisplayJoystickMsg(IDirectDrawSurface7* pSurf, RECT* pRect)
1182 {
1183 if (VidSJoystickMsg.nTimer) {
1184 RECT src = { 0, 0, 300, 60 }; // left top right bottom
1185 RECT dest = { pRect->left, pRect->bottom - 60, pRect->left + 300, pRect->bottom };
1186
1187 // Switch off message display when the message has been displayed long enough
1188 if (nFramesEmulated > VidSJoystickMsg.nTimer) {
1189 VidSJoystickMsg.nTimer = 0;
1190 }
1191
1192 if (dest.left < pRect->left) {
1193 src.left = pRect->left - dest.left;
1194 dest.left = pRect->left;
1195 }
1196
1197 if (nZoom & 2) {
1198 dest.top <<= 1;
1199 dest.bottom <<= 1;
1200 }
1201
1202 if (nZoom & 1) {
1203 dest.left <<= 1;
1204 dest.right <<= 1;
1205 }
1206
1207 // Blit the message to the surface using a colourkey
1208 pSurf->Blt(&dest, pJoystickMsgSurf, &src, DDBLT_ASYNC | DDBLT_KEYSRC, NULL);
1209 }
1210 }
1211
VidSDisplayShortMsg(IDirectDrawSurface7 * pSurf,RECT * pRect)1212 static void VidSDisplayShortMsg(IDirectDrawSurface7* pSurf, RECT* pRect)
1213 {
1214 if (VidSShortMsg.nTimer) {
1215 RECT src = { 0, 0, 256, 32 };
1216 RECT dest = { 0, pRect->top + 4, pRect->right - 8, pRect->top + 36 };
1217
1218 // Switch off message display when the message has been displayed long enough
1219 if (nFramesEmulated > VidSShortMsg.nTimer) {
1220 VidSShortMsg.nTimer = 0;
1221 }
1222
1223 if (nStatus) {
1224 for (int x = 0; x < 4; x++) {
1225 if (nStatus & (1 << x)) {
1226 dest.right -= 48;
1227 }
1228 }
1229
1230 dest.top += 10;
1231 dest.bottom += 10;
1232 }
1233
1234 dest.left = dest.right - 256;
1235 if (dest.left < pRect->left) {
1236 src.left = pRect->left - dest.left;
1237 dest.left = pRect->left;
1238 }
1239
1240 if (nZoom & 2) {
1241 dest.top <<= 1;
1242 dest.bottom <<= 1;
1243 }
1244
1245 if (nZoom & 1) {
1246 dest.left <<= 1;
1247 dest.right <<= 1;
1248 }
1249
1250 // Blit the message to the surface using a colourkey
1251 pSurf->Blt(&dest, pShortMsgSurf, &src, DDBLT_ASYNC | DDBLT_KEYSRC, NULL);
1252 }
1253 }
1254
VidSDisplayStatus(IDirectDrawSurface7 * pSurf,RECT * pRect)1255 static void VidSDisplayStatus(IDirectDrawSurface7* pSurf, RECT* pRect)
1256 {
1257 nStatus = 0;
1258
1259 if (nVidSDisplayStatus == 0) {
1260 return;
1261 }
1262
1263 if (bRunPause) {
1264 nStatus |= 1;
1265 }
1266 if (kNetGame) {
1267 nStatus |= 2;
1268 }
1269 if (nReplayStatus == 1) {
1270 nStatus |= 4;
1271 }
1272 if (nReplayStatus == 2) {
1273 nStatus |= 8;
1274 }
1275
1276 if (nStatus != nPrevStatus) {
1277 nPrevStatus = nStatus;
1278 if (nStatus) {
1279 // Print the message
1280 HDC hDC;
1281 HFONT hFont;
1282 TCHAR szStatus[8];
1283
1284 // Clear the surface first
1285 VidSClearSurface(pStatusSurf, nKeyColour, NULL);
1286
1287 // Make the status string
1288 memset(szStatus, 0, sizeof(szStatus));
1289 for (int i = 0, j = 0; i < 4; i++) {
1290 if (nStatus & (1 << i)) {
1291 szStatus[j] = nStatusSymbols[i];
1292 j++;
1293 }
1294 }
1295
1296 pStatusSurf->GetDC(&hDC);
1297 SetBkMode(hDC, TRANSPARENT);
1298 hFont = (HFONT)SelectObject(hDC, (nReplayStatus == 1) ? StatusFontTiny : StatusFont);
1299 SetTextAlign(hDC, TA_TOP | TA_RIGHT);
1300
1301 MyTextOut(hDC, 192 - 2, 0, szStatus, _tcslen(szStatus), 2, RGB(0xFF, 0x3F, 0x3F));
1302
1303 // Clean up
1304 SelectObject(hDC, hFont);
1305 pStatusSurf->ReleaseDC(hDC);
1306 }
1307 }
1308
1309 if (nStatus) {
1310 RECT src = { 192, 0, 192, 48 };
1311 RECT dest = { 0, pRect->top + 4, pRect->right - 4, pRect->top + 52 };
1312 for (int x = 0; x < 4; x++) {
1313 if (nStatus & (1 << x)) {
1314 src.left -= 48;
1315 }
1316 }
1317 dest.left = dest.right - (src.right - src.left);
1318
1319 if (nZoom & 2) {
1320 dest.top <<= 1;
1321 dest.bottom <<= 1;
1322 }
1323
1324 if (nZoom & 1) {
1325 dest.left <<= 1;
1326 dest.right <<= 1;
1327 }
1328
1329 // Blit the message to the surface using a colourkey
1330 pSurf->Blt(&dest, pStatusSurf, &src, DDBLT_ASYNC | DDBLT_KEYSRC, NULL);
1331 }
1332 }
1333
VidSDrawChat(RECT * dest)1334 static int VidSDrawChat(RECT* dest)
1335 {
1336 bool bContent = false;
1337
1338 if (pChatSurf == NULL) {
1339 return 1;
1340 }
1341
1342 VidSClearSurface(pChatSurf, nKeyColour, NULL);
1343
1344 for (int i = 0; i < CHAT_SIZE; i++) {
1345 if (VidSChatMessage[i].pIDText || VidSChatMessage[i].pMainText) {
1346 bContent = true;
1347 break;
1348 }
1349 }
1350
1351 if (bContent) {
1352
1353 nChatTimer = nFramesEmulated + 300;
1354
1355 // Print the message
1356 HDC hDC;
1357 HFONT hFont;
1358 int nStringLength;
1359 int nFit = 0;
1360 SIZE sizeID, sizeMain;
1361
1362 // Clear the surface first
1363 VidSClearSurface(pChatSurf, nKeyColour, NULL);
1364
1365 pChatSurf->GetDC(&hDC);
1366 SetBkMode(hDC, TRANSPARENT);
1367
1368 hFont = (HFONT)SelectObject(hDC, ChatIDFont);
1369 SetTextAlign(hDC, TA_TOP | TA_LEFT);
1370
1371 nChatOverFlow = 0;
1372
1373 for (int i = 0; i < CHAT_SIZE; i++) {
1374
1375 // Exit when too many lines are displayed
1376 if (nChatOverFlow > (CHAT_SIZE >> 1)) {
1377 break;
1378 }
1379
1380 if (VidSChatMessage[i].pIDText) {
1381 SelectObject(hDC, ChatIDFont);
1382 nStringLength = _tcslen(VidSChatMessage[i].pIDText);
1383 MyExtTextOut(hDC, 0, (i + nChatOverFlow) * nChatFontSize, ETO_CLIPPED, dest, VidSChatMessage[i].pIDText, nStringLength, NULL, nChatShadowOffset, VidSChatMessage[i].nIDColour);
1384 GetTextExtentPoint32(hDC, VidSChatMessage[i].pIDText, nStringLength, &sizeID);
1385 } else {
1386 sizeID.cx = 0;
1387 }
1388
1389 if (VidSChatMessage[i].pMainText) {
1390 SelectObject(hDC, ChatMainFont);
1391 nStringLength = _tcslen(VidSChatMessage[i].pMainText);
1392 GetTextExtentExPoint(hDC, VidSChatMessage[i].pMainText, nStringLength, dest->right - sizeID.cx, &nFit, NULL, &sizeMain);
1393
1394 if (nFit < nStringLength) {
1395 // The string doesn't fit on the screen in one line, break the line on the last space that fits
1396 while (nFit > 0 && (VidSChatMessage[i].pMainText[nFit] != ' ')) {
1397 nFit--;
1398 }
1399
1400 nStringLength = nFit;
1401 MyExtTextOut(hDC, sizeID.cx, (i + nChatOverFlow) * nChatFontSize, ETO_CLIPPED, dest, VidSChatMessage[i].pMainText, nStringLength, NULL, nChatShadowOffset, VidSChatMessage[i].nMainColour);
1402
1403 nChatOverFlow++;
1404
1405 nStringLength = _tcslen(&(VidSChatMessage[i].pMainText[nFit + 1]));
1406 MyExtTextOut(hDC, sizeID.cx, (i + nChatOverFlow) * nChatFontSize, ETO_CLIPPED, dest, &(VidSChatMessage[i].pMainText[nFit + 1]), nStringLength, NULL, nChatShadowOffset, VidSChatMessage[i].nMainColour);
1407 } else {
1408 SelectObject(hDC, ChatMainFont);
1409 MyTextOut(hDC, sizeID.cx, (i + nChatOverFlow) * nChatFontSize, VidSChatMessage[i].pMainText, nStringLength, nChatShadowOffset, VidSChatMessage[i].nMainColour);
1410 }
1411 }
1412 }
1413
1414 // Clean up
1415 SelectObject(hDC, hFont);
1416 pChatSurf->ReleaseDC(hDC);
1417 } else {
1418 nChatTimer = 0;
1419 }
1420
1421 return 0;
1422 }
1423
VidSDisplayChat(IDirectDrawSurface7 * pSurf,RECT * pRect)1424 static void VidSDisplayChat(IDirectDrawSurface7* pSurf, RECT* pRect)
1425 {
1426 if (nChatTimer || bDrawChat) {
1427 // Blit the message to the surface using a colourkey
1428 RECT src = { 0, 0, pRect->right - pRect->left, nChatFontSize * (CHAT_SIZE + (CHAT_SIZE >> 1)) };
1429
1430 // Update the message if needed
1431 if (bDrawChat) {
1432 VidSDrawChat(&src);
1433 bDrawChat = false;
1434 }
1435
1436 if (nChatTimer) {
1437 RECT dest = { pRect->left, pRect->bottom - nChatFontSize * (CHAT_SIZE + nChatOverFlow), pRect->right, pRect->bottom };
1438 src.bottom = nChatFontSize * (CHAT_SIZE + nChatOverFlow);
1439
1440 if (bEditActive) {
1441 dest.top -= nEditSize;
1442 dest.bottom -= nEditSize;
1443 } else {
1444 dest.top -= 4;
1445 dest.bottom -= 4;
1446 }
1447
1448 if (nZoom & 2) {
1449 dest.top <<= 1;
1450 dest.bottom <<= 1;
1451 }
1452
1453 if (nZoom & 1) {
1454 dest.left <<= 1;
1455 dest.right <<= 1;
1456 }
1457
1458 pSurf->Blt(&dest, pChatSurf, &src, DDBLT_ASYNC | DDBLT_KEYSRC, NULL);
1459 }
1460
1461 // Scroll message if needed
1462 if (nFramesEmulated > nChatTimer) {
1463 nChatTimer = 0;
1464 VidSAddChatMsg(NULL, 0, NULL, 0);
1465 bDrawChat = true;
1466 }
1467 }
1468 }
1469
VidSDisplayEdit(IDirectDrawSurface7 * pSurf,RECT * pRect)1470 static void VidSDisplayEdit(IDirectDrawSurface7* pSurf, RECT* pRect)
1471 {
1472 if (bEditActive) {
1473 RECT src = { 0, 0, pRect->right - pRect->left, nEditSize };
1474 RECT dest = { pRect->left, pRect->bottom - nEditSize, pRect->right, pRect->bottom };
1475
1476 if (nZoom & 2) {
1477 dest.top <<= 1;
1478 dest.bottom <<= 1;
1479 }
1480
1481 if (nZoom & 1) {
1482 dest.left <<= 1;
1483 dest.right <<= 1;
1484 }
1485
1486 DWORD nStart, nEnd;
1487 SendMessage(hwndChat, EM_GETSEL, (WPARAM)&nStart, (WPARAM)&nEnd);
1488
1489 if (nStart != nPrevStart || nEnd != nPrevEnd) {
1490 nPrevStart = nStart;
1491 nPrevEnd = nEnd;
1492 bEditTextChanged = true;
1493 nCursorTime = nFramesEmulated + 30;
1494 nCursorState = 1;
1495 } else {
1496 if (GetCurrentFrame() > nCursorTime) {
1497 nCursorTime = nFramesEmulated + 30;
1498 nCursorState = !nCursorState;
1499 bEditTextChanged = true;
1500 }
1501 }
1502
1503 if (bEditTextChanged) {
1504 if (pEditSurf == NULL) {
1505 return;
1506 }
1507
1508 // Print the message
1509 HDC hDC;
1510 HFONT hFont;
1511 SIZE size;
1512 int pos;
1513
1514 TCHAR Space[] = _T(" ");
1515 unsigned int nFit = 0;
1516 TCHAR* pText = EditText;
1517
1518 // bool bDisplayCursor = false;
1519 // if (GetFocus()) {
1520 // bDisplayCursor = true;
1521 // }
1522
1523 // Clear the surface first
1524 VidSClearSurface(pEditSurf, nKeyColour, NULL);
1525
1526 pEditSurf->GetDC(&hDC);
1527 SetBkMode(hDC, TRANSPARENT);
1528 hFont = (HFONT)SelectObject(hDC, EditTextFont);
1529 SetTextAlign(hDC, TA_TOP | TA_LEFT);
1530
1531 // If the string is wider than the screen, shift the display to the right.
1532 pos = 0;
1533 do {
1534 GetTextExtentExPoint(hDC, pText, _tcslen(pText), src.right - pos - nEditSize, (int*)&nFit, NULL, &size);
1535 if (nFit < nStart) {
1536 pos -= src.right * 3 / 5;
1537 }
1538 } while (nFit < nStart);
1539
1540 if (nStart == _tcslen(pText)) {
1541 if (nStart) {
1542 MyExtTextOut(hDC, pos + 3, 3, ETO_CLIPPED, &src, pText, nStart, NULL, nEditShadowOffset, RGB(0xDF, 0xDF, 0xFF));
1543 }
1544
1545 GetTextExtentPoint32(hDC, pText, nStart, &size);
1546 pos += size.cx;
1547
1548 if (nCursorState) {
1549 SelectObject(hDC, EditCursorFont);
1550 }
1551 MyExtTextOut(hDC, pos + 3, 3, ETO_CLIPPED, &src, Space, 1, NULL, nEditShadowOffset, RGB(0xFF, 0xFF, 0xFF));
1552 } else {
1553 if (nStart) {
1554 MyExtTextOut(hDC, pos + 3, 3, ETO_CLIPPED, &src, pText, nStart, NULL, nEditShadowOffset, RGB(0xDF, 0xDF, 0xFF));
1555 }
1556
1557 GetTextExtentPoint32(hDC, pText, nStart, &size);
1558 pos += size.cx;
1559
1560 if (nEnd == nStart) {
1561 if (nCursorState) {
1562 SelectObject(hDC, EditCursorFont);
1563 }
1564 MyExtTextOut(hDC, pos + 3, 3, ETO_CLIPPED, &src, pText + nStart, 1, NULL, nEditShadowOffset, RGB(0xFF, 0xFF, 0xFF));
1565
1566 GetTextExtentPoint32(hDC, pText + nStart, 1, &size);
1567 pos += size.cx;
1568
1569 // We really printed one character past the end of the selection
1570 nEnd++;
1571 } else {
1572 // Highlight selected characters
1573 SelectObject(hDC, EditTextFont);
1574 // SetTextColor(hDC, RGB(0x7F, 0x1F, 0x1F));
1575 MyExtTextOut(hDC, pos + 3, 3, ETO_CLIPPED, &src, pText + nStart, nEnd - nStart, NULL, nEditShadowOffset, RGB(0xFF, 0xFF, 0xDF));
1576
1577 GetTextExtentPoint32(hDC, pText + nStart, nEnd - nStart, &size);
1578 pos += size.cx;
1579 }
1580
1581 if (nEnd < _tcslen(EditText)) {
1582 SelectObject(hDC, EditTextFont);
1583 MyExtTextOut(hDC, pos + 3, 3, ETO_CLIPPED, &src, pText + nEnd, _tcslen(pText) - nEnd, NULL, nEditShadowOffset, RGB(0xDF, 0xDF, 0xFF));
1584 }
1585 }
1586
1587 // Clean up
1588 SelectObject(hDC, hFont);
1589 pEditSurf->ReleaseDC(hDC);
1590
1591 bEditTextChanged = false;
1592 }
1593
1594 // Blit the message to the surface using a colourkey
1595 pSurf->Blt(&dest, pEditSurf, &src, DDBLT_ASYNC | DDBLT_KEYSRC, NULL);
1596 }
1597 }
1598
VidSDisplayOSD(IDirectDrawSurface7 * pSurf,RECT * pRect,int nFlags)1599 void VidSDisplayOSD(IDirectDrawSurface7* pSurf, RECT* pRect, int nFlags)
1600 {
1601 nZoom = nFlags & 3;
1602
1603 VidSDisplayStatus(pSurf, pRect);
1604 VidSDisplayTinyMsg(pSurf, pRect);
1605 VidSDisplayJoystickMsg(pSurf, pRect);
1606 VidSDisplayShortMsg(pSurf, pRect);
1607 VidSDisplayChat(pSurf, pRect);
1608 if (kNetGame) {
1609 VidSDisplayEdit(pSurf, pRect);
1610 }
1611 }
1612
VidSNewTinyMsg(const TCHAR * pText,int nRGB,int nDuration,int nPriority)1613 int VidSNewTinyMsg(const TCHAR* pText, int nRGB, int nDuration, int nPriority) // int nRGB = 0, int nDuration = 0, int nPriority = 5
1614 {
1615 // If a message with a higher priority is being displayed, exit.
1616 if (VidSTinyMsg.nTimer && VidSTinyMsg.nPriority > nPriority) {
1617 return 1;
1618 }
1619
1620 int nSize = _tcslen(pText);
1621 if (nSize > 63) {
1622 nSize = 63;
1623 }
1624 _tcsncpy(VidSTinyMsg.pMsgText, pText, nSize);
1625 VidSTinyMsg.pMsgText[nSize] = 0;
1626
1627 if (nRGB) {
1628 // Convert RGB value to COLORREF
1629 VidSTinyMsg.nColour = RGB((nRGB >> 16), ((nRGB >> 8) & 0xFF), (nRGB & 0xFF));
1630 } else {
1631 // Default message colour (yellow)
1632 VidSTinyMsg.nColour = RGB(0xFF, 0xFF, 0x7F);
1633 }
1634 if (nDuration) {
1635 VidSTinyMsg.nTimer = nFramesEmulated + nDuration;
1636 } else {
1637 VidSTinyMsg.nTimer = nFramesEmulated + 120;
1638 }
1639 VidSTinyMsg.nPriority = nPriority;
1640
1641 {
1642 if (pTinyMsgSurf == NULL) {
1643 return 1;
1644 }
1645
1646 // Print the message
1647 HDC hDC;
1648 HFONT hFont;
1649
1650 // Clear the surface first
1651 VidSClearSurface(pTinyMsgSurf, nKeyColour, NULL);
1652
1653 pTinyMsgSurf->GetDC(&hDC);
1654 SetBkMode(hDC, TRANSPARENT);
1655 hFont = (HFONT)SelectObject(hDC, TinyMsgFont);
1656 SetTextAlign(hDC, TA_BOTTOM | TA_RIGHT);
1657
1658 // Print a black shadow
1659 SetTextColor(hDC, 0);
1660 TextOut(hDC, 300, 20, VidSTinyMsg.pMsgText, _tcslen(VidSTinyMsg.pMsgText));
1661 // Print the text on top
1662 SetTextColor(hDC, VidSTinyMsg.nColour);
1663 TextOut(hDC, 300 - 1, 20 - 1, VidSTinyMsg.pMsgText, _tcslen(VidSTinyMsg.pMsgText));
1664
1665 // Clean up
1666 SelectObject(hDC, hFont);
1667 pTinyMsgSurf->ReleaseDC(hDC);
1668 }
1669
1670 return 0;
1671 }
1672
VidSNewJoystickMsg(const TCHAR * pText,int nRGB,int nDuration,int nLineNo)1673 int VidSNewJoystickMsg(const TCHAR* pText, int nRGB, int nDuration, int nLineNo) // int nRGB = 0, int nDuration = 0, int nLineNo = 0
1674 {
1675 if (!pText) { // NULL passed, clear surface
1676 VidSClearSurface(pJoystickMsgSurf, nKeyColour, NULL);
1677 return 0;
1678 }
1679
1680 int nSize = _tcslen(pText);
1681 if (nSize > 63) {
1682 nSize = 63;
1683 }
1684 _tcsncpy(VidSJoystickMsg.pMsgText, pText, nSize);
1685 VidSJoystickMsg.pMsgText[nSize] = 0;
1686
1687 if (nRGB) {
1688 // Convert RGB value to COLORREF
1689 VidSJoystickMsg.nColour = RGB((nRGB >> 16), ((nRGB >> 8) & 0xFF), (nRGB & 0xFF));
1690 } else {
1691 // Default message colour (yellow)
1692 VidSJoystickMsg.nColour = RGB(0xFF, 0xFF, 0x7F);
1693 }
1694 if (nDuration) {
1695 VidSJoystickMsg.nTimer = nFramesEmulated + nDuration;
1696 } else {
1697 VidSJoystickMsg.nTimer = nFramesEmulated + 120;
1698 }
1699 VidSJoystickMsg.nLineNo = nLineNo;
1700
1701 {
1702 if (pJoystickMsgSurf == NULL) {
1703 return 1;
1704 }
1705
1706 // Print the message
1707 HDC hDC;
1708 HFONT hFont;
1709
1710 pJoystickMsgSurf->GetDC(&hDC);
1711 SetBkMode(hDC, TRANSPARENT);
1712 hFont = (HFONT)SelectObject(hDC, JoystickMsgFont);
1713 SetTextAlign(hDC, TA_TOP | TA_LEFT);
1714
1715 MyTextOut(hDC, 40, 7+(nLineNo*8), VidSJoystickMsg.pMsgText, _tcslen(VidSJoystickMsg.pMsgText), 0, VidSJoystickMsg.nColour);
1716
1717 // Clean up
1718 SelectObject(hDC, hFont);
1719 pJoystickMsgSurf->ReleaseDC(hDC);
1720 }
1721
1722 return 0;
1723 }
1724
VidSNewShortMsg(const TCHAR * pText,int nRGB,int nDuration,int nPriority)1725 int VidSNewShortMsg(const TCHAR* pText, int nRGB, int nDuration, int nPriority) // int nRGB = 0, int nDuration = 0, int nPriority = 5
1726 {
1727 // If a message with a higher priority is being displayed, exit.
1728 if (VidSShortMsg.nTimer && VidSShortMsg.nPriority > nPriority) {
1729 return 1;
1730 }
1731
1732 int nSize = _tcslen(pText);
1733 if (nSize > 31) {
1734 nSize = 31;
1735 }
1736 _tcsncpy(VidSShortMsg.pMsgText, pText, nSize);
1737 VidSShortMsg.pMsgText[nSize] = 0;
1738
1739 // copy osd message
1740 memset(OSDMsg, '\0', MAX_PATH * sizeof(TCHAR));
1741 _tcsncpy(OSDMsg, pText, nSize);
1742
1743 if (nRGB) {
1744 // Convert RGB value to COLORREF
1745 VidSShortMsg.nColour = RGB((nRGB >> 16), ((nRGB >> 8) & 0xFF), (nRGB & 0xFF));
1746 } else {
1747 // Default message colour (yellow)
1748 VidSShortMsg.nColour = RGB(0xFF, 0xFF, 0x7F);
1749 }
1750 if (nDuration) {
1751 VidSShortMsg.nTimer = nFramesEmulated + nDuration;
1752 } else {
1753 VidSShortMsg.nTimer = nFramesEmulated + 120;
1754 }
1755 nOSDTimer = VidSShortMsg.nTimer;
1756 VidSShortMsg.nPriority = nPriority;
1757
1758 {
1759 if (pShortMsgSurf == NULL) {
1760 return 1;
1761 }
1762
1763 // Print the message
1764 HDC hDC;
1765 HFONT hFont;
1766
1767 // Clear the surface first
1768 VidSClearSurface(pShortMsgSurf, nKeyColour, NULL);
1769
1770 pShortMsgSurf->GetDC(&hDC);
1771 SetBkMode(hDC, TRANSPARENT);
1772 hFont = (HFONT)SelectObject(hDC, ShortMsgFont);
1773 SetTextAlign(hDC, TA_TOP | TA_RIGHT);
1774
1775 MyTextOut(hDC, 256 - 2, 0, VidSShortMsg.pMsgText, _tcslen(VidSShortMsg.pMsgText), 2, VidSShortMsg.nColour);
1776
1777 // Clean up
1778 SelectObject(hDC, hFont);
1779 pShortMsgSurf->ReleaseDC(hDC);
1780 }
1781
1782 return 0;
1783 }
1784
VidSKillShortMsg()1785 void VidSKillShortMsg()
1786 {
1787 VidSShortMsg.nTimer = 0;
1788 }
1789
VidSKillTinyMsg()1790 void VidSKillTinyMsg()
1791 {
1792 VidSTinyMsg.nTimer = 0;
1793 }
1794
VidSKillJoystickMsg()1795 void VidSKillJoystickMsg()
1796 {
1797 VidSTinyMsg.nTimer = 0;
1798 }
1799
VidSKillOSDMsg()1800 void VidSKillOSDMsg()
1801 {
1802 nOSDTimer = 0;
1803 }
1804
VidSAddChatMsg(const TCHAR * pID,int nIDRGB,const TCHAR * pMain,int nMainRGB)1805 int VidSAddChatMsg(const TCHAR* pID, int nIDRGB, const TCHAR* pMain, int nMainRGB)
1806 {
1807 if (pID || pMain) {
1808 // Scroll the text buffers up one entry
1809 if (VidSChatMessage[0].pIDText) {
1810 free(VidSChatMessage[0].pIDText);
1811 VidSChatMessage[0].pIDText = NULL;
1812 }
1813 if (VidSChatMessage[0].pMainText) {
1814 free(VidSChatMessage[0].pMainText);
1815 VidSChatMessage[0].pMainText = NULL;
1816 }
1817
1818 for (int i = 1; i < CHAT_SIZE; i++) {
1819 VidSChatMessage[i - 1].pIDText = VidSChatMessage[i].pIDText;
1820 VidSChatMessage[i - 1].nIDColour = VidSChatMessage[i].nIDColour;
1821 VidSChatMessage[i - 1].pMainText = VidSChatMessage[i].pMainText;
1822 VidSChatMessage[i - 1].nMainColour = VidSChatMessage[i].nMainColour;
1823 }
1824
1825 // Put the new entry in the last position
1826 if (pID) {
1827 int nSize = _tcslen(pID);
1828 VidSChatMessage[CHAT_SIZE - 1].pIDText = (TCHAR*)malloc((nSize + 1) * sizeof(TCHAR));
1829 _tcscpy(VidSChatMessage[CHAT_SIZE - 1].pIDText, pID);
1830 VidSChatMessage[CHAT_SIZE - 1].pIDText[nSize] = 0;
1831 VidSChatMessage[CHAT_SIZE - 1].nIDColour = RGB((nIDRGB >> 16), ((nIDRGB >> 8) & 0xFF), (nIDRGB & 0xFF));
1832 } else {
1833 VidSChatMessage[CHAT_SIZE - 1].pIDText = NULL;
1834 }
1835 if (pMain) {
1836 int nSize = _tcslen(pMain);
1837 VidSChatMessage[CHAT_SIZE - 1].pMainText = (TCHAR*)malloc((nSize + 1) * sizeof(TCHAR));
1838 _tcscpy(VidSChatMessage[CHAT_SIZE - 1].pMainText, pMain);
1839 VidSChatMessage[CHAT_SIZE - 1].pMainText[nSize] = 0;
1840 VidSChatMessage[CHAT_SIZE - 1].nMainColour = RGB((nMainRGB >> 16), ((nMainRGB >> 8) & 0xFF), (nMainRGB & 0xFF));
1841 } else {
1842 VidSChatMessage[CHAT_SIZE - 1].pMainText = NULL;
1843 }
1844 } else {
1845 for (int i = 0; i < CHAT_SIZE; i++) {
1846 if (VidSChatMessage[i].pIDText || VidSChatMessage[i].pMainText) {
1847 if (VidSChatMessage[i].pIDText) {
1848 free(VidSChatMessage[i].pIDText);
1849 VidSChatMessage[i].pIDText = NULL;
1850 }
1851 if (VidSChatMessage[i].pMainText) {
1852 free(VidSChatMessage[i].pMainText);
1853 VidSChatMessage[i].pMainText = NULL;
1854 }
1855
1856 break;
1857 }
1858 }
1859 }
1860
1861 bDrawChat = true;
1862
1863 return 0;
1864 }
1865