ref: 1b9c2d36629a7df8671f273c33bd68f33ddfe6e6
dir: /src/Draw.cpp/
// THIS IS DECOMPILED PROPRIETARY CODE - USE AT YOUR OWN RISK. // // The original code belongs to Daisuke "Pixel" Amaya. // // Modifications and custom code are under the MIT licence. // See LICENCE.txt for details. #include "Draw.h" #include <stddef.h> #include <stdio.h> #include <string.h> #include <ddraw.h> #include "WindowsWrapper.h" #include "CommonDefines.h" #include "Ending.h" #include "Generic.h" #include "Main.h" #include "MapName.h" #include "TextScr.h" typedef enum SurfaceType { SURFACE_SOURCE_NONE = 1, SURFACE_SOURCE_RESOURCE, SURFACE_SOURCE_FILE } SurfaceType; RECT grcGame = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; RECT grcFull = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; static int mag; static BOOL fullscreen; // TODO - Not the original variable name static LPDIRECTDRAW lpDD; // TODO - Not the original variable name static LPDIRECTDRAWSURFACE frontbuffer; // TODO - Not the original variable name static LPDIRECTDRAWSURFACE backbuffer; // TODO - Not the original variable name static LPDIRECTDRAWCLIPPER clipper; // TODO - Not the original variable name static LPDIRECTDRAWSURFACE surf[SURFACE_ID_MAX]; static RECT backbuffer_rect; // TODO - Not the original variable name static int scaled_window_width; // TODO - Not the original variable name static int scaled_window_height; // TODO - Not the original variable name static HFONT font; // TODO - Not the original variable name // This doesn't exist in the Linux port, so none of these symbol names are accurate static struct { char name[20]; unsigned int width; unsigned int height; SurfaceType type; BOOL bSystem; // Basically a 'do not regenerate' flag } surface_metadata[SURFACE_ID_MAX]; static int client_x; static int client_y; void SetClientOffset(int width, int height) { client_x = width; client_y = height; } BOOL Flip_SystemTask(HWND hWnd) { // TODO - Not the original variable names static DWORD timePrev; static DWORD timeNow; while (TRUE) { if (!SystemTask()) return FALSE; // Framerate limiter timeNow = GetTickCount(); if (timeNow >= timePrev + 20) break; Sleep(1); } if (timeNow >= timePrev + 100) timePrev = timeNow; // If the timer is freakishly out of sync, panic and reset it, instead of spamming frames for who-knows how long else timePrev += 20; static RECT dst_rect; // TODO - Not the original variable name GetWindowRect(hWnd, &dst_rect); dst_rect.left += client_x; dst_rect.top += client_y; dst_rect.right = dst_rect.left + scaled_window_width; dst_rect.bottom = dst_rect.top + scaled_window_height; frontbuffer->Blt(&dst_rect, backbuffer, &backbuffer_rect, DDBLT_WAIT, NULL); if (RestoreSurfaces()) { RestoreStripper(); RestoreMapName(); RestoreTextScript(); } return TRUE; } BOOL StartDirectDraw(HWND hWnd, int lMagnification, int lColourDepth) { DDSURFACEDESC ddsd; if (DirectDrawCreate(NULL, &lpDD, NULL) != DD_OK) return FALSE; memset(surface_metadata, 0, sizeof(surface_metadata)); switch (lMagnification) { case 0: mag = 1; fullscreen = FALSE; lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); break; case 1: mag = 2; fullscreen = FALSE; lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); break; case 2: mag = 2; fullscreen = TRUE; lpDD->SetCooperativeLevel(hWnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE); lpDD->SetDisplayMode(WINDOW_WIDTH * mag, WINDOW_HEIGHT * mag, lColourDepth); break; } backbuffer_rect.left = 0; backbuffer_rect.top = 0; backbuffer_rect.right = WINDOW_WIDTH * mag; backbuffer_rect.bottom = WINDOW_HEIGHT * mag; scaled_window_width = WINDOW_WIDTH * mag; scaled_window_height = WINDOW_HEIGHT * mag; memset(&ddsd, 0, sizeof(DDSURFACEDESC)); ddsd.dwSize = sizeof(DDSURFACEDESC); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; ddsd.dwBackBufferCount = 0; if (lpDD->CreateSurface(&ddsd, &frontbuffer, NULL) != DD_OK) return FALSE; memset(&ddsd, 0, sizeof(DDSURFACEDESC)); ddsd.dwSize = sizeof(DDSURFACEDESC); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; ddsd.dwWidth = WINDOW_WIDTH * mag; ddsd.dwHeight = WINDOW_HEIGHT * mag; if (lpDD->CreateSurface(&ddsd, &backbuffer, NULL) != DD_OK) return FALSE; lpDD->CreateClipper(0, &clipper, NULL); clipper->SetHWnd(0, hWnd); frontbuffer->SetClipper(clipper); return TRUE; } void EndDirectDraw(HWND hWnd) { int i; // Release all surfaces for (i = 0; i < SURFACE_ID_MAX; ++i) { if (surf[i] != NULL) { surf[i]->Release(); surf[i] = NULL; } } if (frontbuffer != NULL) { frontbuffer->Release(); frontbuffer = NULL; backbuffer = NULL; } if (fullscreen) lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); if (lpDD != NULL) { lpDD->Release(); lpDD = NULL; } memset(surface_metadata, 0, sizeof(surface_metadata)); } void ReleaseSurface(SurfaceID s) { // Release the surface we want to release if (surf[s] != NULL) { surf[s]->Release(); surf[s] = NULL; } memset(&surface_metadata[s], 0, sizeof(surface_metadata[0])); } // TODO - Inaccurate stack frame BOOL MakeSurface_Resource(const char *name, SurfaceID surf_no) { if (surf_no >= SURFACE_ID_MAX) return FALSE; if (surf[surf_no] != NULL) return FALSE; HANDLE handle = LoadImageA(GetModuleHandleA(NULL), name, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); if (handle == NULL) return FALSE; BITMAP bitmap; GetObjectA(handle, sizeof(BITMAP), &bitmap); DDSURFACEDESC ddsd; memset(&ddsd, 0, sizeof(DDSURFACEDESC)); ddsd.dwSize = sizeof(DDSURFACEDESC); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; ddsd.dwWidth = bitmap.bmWidth * mag; ddsd.dwHeight = bitmap.bmHeight * mag; if (lpDD->CreateSurface(&ddsd, &surf[surf_no], NULL) != DD_OK) return FALSE; int src_x = 0; int src_y = 0; int src_w = bitmap.bmWidth; int src_h = bitmap.bmHeight; int dst_x = 0; int dst_y = 0; int dst_w = bitmap.bmWidth * mag; int dst_h = bitmap.bmHeight * mag; HDC hdc = CreateCompatibleDC(NULL); HGDIOBJ hgdiobj = SelectObject(hdc, handle); HDC hdc2; surf[surf_no]->GetDC(&hdc2); StretchBlt(hdc2, dst_x, dst_y, dst_w, dst_h, hdc, src_x, src_y, src_w, src_h, SRCCOPY); surf[surf_no]->ReleaseDC(hdc2); SelectObject(hdc, hgdiobj); DeleteDC(hdc); DDCOLORKEY ddcolorkey; ddcolorkey.dwColorSpaceLowValue = 0; ddcolorkey.dwColorSpaceHighValue = 0; surf[surf_no]->SetColorKey(DDCKEY_SRCBLT, &ddcolorkey); surf[surf_no]->SetClipper(clipper); #ifdef FIX_MAJOR_BUGS DeleteObject(handle); #endif surface_metadata[surf_no].type = SURFACE_SOURCE_RESOURCE; surface_metadata[surf_no].width = bitmap.bmWidth; surface_metadata[surf_no].height = bitmap.bmHeight; surface_metadata[surf_no].bSystem = FALSE; strcpy(surface_metadata[surf_no].name, name); return TRUE; } // TODO - Inaccurate stack frame BOOL MakeSurface_File(const char *name, SurfaceID surf_no) { char path[MAX_PATH]; sprintf(path, "%s\\%s.pbm", gDataPath, name); if (!IsEnableBitmap(path)) { ErrorLog(path, 0); return FALSE; } #ifdef FIX_BUGS if (surf_no >= SURFACE_ID_MAX) #else if (surf_no > SURFACE_ID_MAX) #endif { ErrorLog("surface no", surf_no); return FALSE; } if (surf[surf_no] != NULL) { ErrorLog("existing", surf_no); return FALSE; } HANDLE handle = LoadImageA(GetModuleHandleA(NULL), path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); if (handle == NULL) { ErrorLog(path, 1); return FALSE; } BITMAP bitmap; GetObjectA(handle, sizeof(BITMAP), &bitmap); DDSURFACEDESC ddsd; memset(&ddsd, 0, sizeof(DDSURFACEDESC)); ddsd.dwSize = sizeof(DDSURFACEDESC); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; ddsd.dwWidth = bitmap.bmWidth * mag; ddsd.dwHeight = bitmap.bmHeight * mag; lpDD->CreateSurface(&ddsd, &surf[surf_no], NULL); int src_x = 0; int src_y = 0; int src_w = bitmap.bmWidth; int src_h = bitmap.bmHeight; int dst_x = 0; int dst_y = 0; int dst_w = bitmap.bmWidth * mag; int dst_h = bitmap.bmHeight * mag; HDC hdc = CreateCompatibleDC(NULL); HGDIOBJ hgdiobj = SelectObject(hdc, handle); HDC hdc2; surf[surf_no]->GetDC(&hdc2); StretchBlt(hdc2, dst_x, dst_y, dst_w, dst_h, hdc, src_x, src_y, src_w, src_h, SRCCOPY); surf[surf_no]->ReleaseDC(hdc2); SelectObject(hdc, hgdiobj); DeleteDC(hdc); DDCOLORKEY ddcolorkey; ddcolorkey.dwColorSpaceLowValue = 0; ddcolorkey.dwColorSpaceHighValue = 0; surf[surf_no]->SetColorKey(DDCKEY_SRCBLT, &ddcolorkey); surf[surf_no]->SetClipper(clipper); DeleteObject(handle); surface_metadata[surf_no].type = SURFACE_SOURCE_FILE; surface_metadata[surf_no].width = bitmap.bmWidth; surface_metadata[surf_no].height = bitmap.bmHeight; surface_metadata[surf_no].bSystem = FALSE; strcpy(surface_metadata[surf_no].name, name); return TRUE; } // TODO - Inaccurate stack frame BOOL ReloadBitmap_Resource(const char *name, SurfaceID surf_no) { if (surf_no >= SURFACE_ID_MAX) return FALSE; HANDLE handle = LoadImageA(GetModuleHandleA(NULL), name, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); if (handle == NULL) return FALSE; BITMAP bitmap; GetObjectA(handle, sizeof(BITMAP), &bitmap); int src_x = 0; int src_y = 0; int src_w = bitmap.bmWidth; int src_h = bitmap.bmHeight; int dst_x = 0; int dst_y = 0; int dst_w = bitmap.bmWidth * mag; int dst_h = bitmap.bmHeight * mag; HDC hdc = CreateCompatibleDC(NULL); HGDIOBJ hgdiobj = SelectObject(hdc, handle); HDC hdc2; surf[surf_no]->GetDC(&hdc2); StretchBlt(hdc2, dst_x, dst_y, dst_w, dst_h, hdc, src_x, src_y, src_w, src_h, SRCCOPY); surf[surf_no]->ReleaseDC(hdc2); SelectObject(hdc, hgdiobj); DeleteDC(hdc); DDCOLORKEY ddcolorkey; ddcolorkey.dwColorSpaceLowValue = 0; ddcolorkey.dwColorSpaceHighValue = 0; surf[surf_no]->SetColorKey(DDCKEY_SRCBLT, &ddcolorkey); surf[surf_no]->SetClipper(clipper); #ifdef FIX_MAJOR_BUGS DeleteObject(handle); #endif surface_metadata[surf_no].type = SURFACE_SOURCE_RESOURCE; strcpy(surface_metadata[surf_no].name, name); return TRUE; } // TODO - Inaccurate stack frame BOOL ReloadBitmap_File(const char *name, SurfaceID surf_no) { char path[MAX_PATH]; sprintf(path, "%s\\%s.pbm", gDataPath, name); if (!IsEnableBitmap(path)) { ErrorLog(path, 0); return FALSE; } #ifdef FIX_BUGS if (surf_no >= SURFACE_ID_MAX) #else if (surf_no > SURFACE_ID_MAX) #endif { ErrorLog("surface no", surf_no); return FALSE; } HANDLE handle = LoadImageA(GetModuleHandleA(NULL), path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); if (handle == NULL) { ErrorLog(path, 1); return FALSE; } BITMAP bitmap; GetObjectA(handle, sizeof(BITMAP), &bitmap); int src_x = 0; int src_y = 0; int src_w = bitmap.bmWidth; int src_h = bitmap.bmHeight; int dst_x = 0; int dst_y = 0; int dst_w = bitmap.bmWidth * mag; int dst_h = bitmap.bmHeight * mag; HDC hdc = CreateCompatibleDC(NULL); HGDIOBJ hgdiobj = SelectObject(hdc, handle); HDC hdc2; surf[surf_no]->GetDC(&hdc2); StretchBlt(hdc2, dst_x, dst_y, dst_w, dst_h, hdc, src_x, src_y, src_w, src_h, SRCCOPY); surf[surf_no]->ReleaseDC(hdc2); SelectObject(hdc, hgdiobj); DeleteDC(hdc); // No colour-keying DeleteObject(handle); surface_metadata[surf_no].type = SURFACE_SOURCE_FILE; strcpy(surface_metadata[surf_no].name, name); return TRUE; } // TODO - Inaccurate stack frame BOOL MakeSurface_Generic(int bxsize, int bysize, SurfaceID surf_no, BOOL bSystem) { #ifdef FIX_BUGS if (surf_no >= SURFACE_ID_MAX) #else if (surf_no > SURFACE_ID_MAX) // OOPS (should be '>=') #endif return FALSE; if (surf[surf_no] != NULL) return FALSE; DDSURFACEDESC ddsd; memset(&ddsd, 0, sizeof(DDSURFACEDESC)); ddsd.dwSize = sizeof(DDSURFACEDESC); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; if (bSystem) ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; else ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; ddsd.dwWidth = bxsize * mag; ddsd.dwHeight = bysize * mag; lpDD->CreateSurface(&ddsd, &surf[surf_no], NULL); DDCOLORKEY ddcolorkey; ddcolorkey.dwColorSpaceLowValue = 0; ddcolorkey.dwColorSpaceHighValue = 0; surf[surf_no]->SetColorKey(DDCKEY_SRCBLT, &ddcolorkey); surface_metadata[surf_no].type = SURFACE_SOURCE_NONE; surface_metadata[surf_no].width = ddsd.dwWidth / mag; surface_metadata[surf_no].height = ddsd.dwHeight / mag; if (bSystem) surface_metadata[surf_no].bSystem = TRUE; else surface_metadata[surf_no].bSystem = FALSE; strcpy(surface_metadata[surf_no].name, "generic"); return TRUE; } void BackupSurface(SurfaceID surf_no, const RECT *rect) { static DDBLTFX ddbltfx; // TODO - Not the original variable name memset(&ddbltfx, 0, sizeof(DDBLTFX)); ddbltfx.dwSize = sizeof(DDBLTFX); static RECT rcSet; // TODO - Not the original variable name rcSet.left = rect->left * mag; rcSet.top = rect->top * mag; rcSet.right = rect->right * mag; rcSet.bottom = rect->bottom * mag; surf[surf_no]->Blt(&rcSet, backbuffer, &rcSet, DDBLT_WAIT, &ddbltfx); } void PutBitmap3(const RECT *rcView, int x, int y, const RECT *rect, SurfaceID surf_no) // Transparency { static RECT rcWork; static RECT rcSet; rcWork = *rect; if (x + rect->right - rect->left > rcView->right) rcWork.right -= (x + rect->right - rect->left) - rcView->right; if (x < rcView->left) { rcWork.left += rcView->left - x; x = rcView->left; } if (y + rect->bottom - rect->top > rcView->bottom) rcWork.bottom -= (y + rect->bottom - rect->top) - rcView->bottom; if (y < rcView->top) { rcWork.top += rcView->top - y; y = rcView->top; } rcSet.left = x; rcSet.top = y; rcSet.right = x + rcWork.right - rcWork.left; rcSet.bottom = y + rcWork.bottom - rcWork.top; rcWork.left *= mag; rcWork.top *= mag; rcWork.right *= mag; rcWork.bottom *= mag; rcSet.left *= mag; rcSet.top *= mag; rcSet.right *= mag; rcSet.bottom *= mag; backbuffer->Blt(&rcSet, surf[surf_no], &rcWork, DDBLT_KEYSRC | DDBLT_WAIT, NULL); } void PutBitmap4(const RECT *rcView, int x, int y, const RECT *rect, SurfaceID surf_no) // No Transparency { static RECT rcWork; static RECT rcSet; rcWork = *rect; if (x + rect->right - rect->left > rcView->right) rcWork.right -= (x + rect->right - rect->left) - rcView->right; if (x < rcView->left) { rcWork.left += rcView->left - x; x = rcView->left; } if (y + rect->bottom - rect->top > rcView->bottom) rcWork.bottom -= (y + rect->bottom - rect->top) - rcView->bottom; if (y < rcView->top) { rcWork.top += rcView->top - y; y = rcView->top; } rcSet.left = x; rcSet.top = y; rcSet.right = x + rcWork.right - rcWork.left; rcSet.bottom = y + rcWork.bottom - rcWork.top; rcWork.left *= mag; rcWork.top *= mag; rcWork.right *= mag; rcWork.bottom *= mag; rcSet.left *= mag; rcSet.top *= mag; rcSet.right *= mag; rcSet.bottom *= mag; backbuffer->Blt(&rcSet, surf[surf_no], &rcWork, DDBLT_WAIT, NULL); } void Surface2Surface(int x, int y, const RECT *rect, SurfaceID to, SurfaceID from) { static RECT rcWork; static RECT rcSet; rcWork.left = rect->left * mag; rcWork.top = rect->top * mag; rcWork.right = rect->right * mag; rcWork.bottom = rect->bottom * mag; rcSet.left = x; rcSet.top = y; rcSet.right = x + rect->right - rect->left; rcSet.bottom = y + rect->bottom - rect->top; rcSet.left *= mag; rcSet.top *= mag; rcSet.right *= mag; rcSet.bottom *= mag; surf[to]->Blt(&rcSet, surf[from], &rcWork, DDBLT_KEYSRC | DDBLT_WAIT, NULL); } // This converts a colour to the 'native' format by writing it // straight to the framebuffer, and then reading it back unsigned long GetCortBoxColor(COLORREF col) { HDC hdc; if (backbuffer->GetDC(&hdc) != DD_OK) return 0xFFFFFFFF; COLORREF original_colour = GetPixel(hdc, 0, 0); SetPixel(hdc, 0, 0, col); backbuffer->ReleaseDC(hdc); DDSURFACEDESC ddsd; memset(&ddsd, 0, sizeof(DDSURFACEDESC)); ddsd.dwSize = sizeof(DDSURFACEDESC); if (backbuffer->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK) return 0xFFFFFFFF; DWORD native_colour = *(DWORD*)ddsd.lpSurface; if (ddsd.ddpfPixelFormat.dwRGBBitCount < 32) native_colour &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1; backbuffer->Unlock(0); if (backbuffer->GetDC(&hdc) != DD_OK) return 0xFFFFFFFF; SetPixel(hdc, 0, 0, original_colour); backbuffer->ReleaseDC(hdc); return native_colour; } void CortBox(const RECT *rect, unsigned long col) { static DDBLTFX ddbltfx; // TODO - Not the original variable name memset(&ddbltfx, 0, sizeof(DDBLTFX)); ddbltfx.dwSize = sizeof(DDBLTFX); ddbltfx.dwFillColor = col; static RECT rcSet; // TODO - Not the original variable name rcSet.left = rect->left * mag; rcSet.top = rect->top * mag; rcSet.right = rect->right * mag; rcSet.bottom = rect->bottom * mag; backbuffer->Blt(&rcSet, 0, 0, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); } void CortBox2(const RECT *rect, unsigned long col, SurfaceID surf_no) { static DDBLTFX ddbltfx; // TODO - Not the original variable name memset(&ddbltfx, 0, sizeof(DDBLTFX)); ddbltfx.dwSize = sizeof(DDBLTFX); ddbltfx.dwFillColor = col; static RECT rcSet; // TODO - Not the original variable name rcSet.left = rect->left * mag; rcSet.top = rect->top * mag; rcSet.right = rect->right * mag; rcSet.bottom = rect->bottom * mag; surface_metadata[surf_no].type = SURFACE_SOURCE_NONE; surf[surf_no]->Blt(&rcSet, 0, 0, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); } // Dummied-out log function // According to the Mac port, its name really is just "out". BOOL out(char surface_identifier) { // The actual name (and type) of these two variables are unknown char path[MAX_PATH]; FILE *fp; (void)surface_identifier; (void)path; (void)fp; // There may have been some kind of 'OutputDebugStringA' call here, // like the one in 'EnumDevices_Callback' in 'Input.cpp'. // Pixel may have kept them wrapped in '#ifdef DEBUG' blocks. return TRUE; } // TODO - Probably not the original function name (this is an educated guess) int RestoreSurfaces(void) { int s; RECT rect; int surfaces_regenerated = 0; if (frontbuffer == NULL) return surfaces_regenerated; if (backbuffer == NULL) return surfaces_regenerated; if (frontbuffer->IsLost() == DDERR_SURFACELOST) { ++surfaces_regenerated; frontbuffer->Restore(); out('f'); // 'f' for 'frontbuffer' } if (backbuffer->IsLost() == DDERR_SURFACELOST) { ++surfaces_regenerated; backbuffer->Restore(); out('b'); // 'b' for 'backbuffer' } for (s = 0; s < SURFACE_ID_MAX; ++s) { if (surf[s] != NULL) { if (surf[s]->IsLost() == DDERR_SURFACELOST) { ++surfaces_regenerated; surf[s]->Restore(); out('0' + s); // The number of the surface lost if (!surface_metadata[s].bSystem) { switch (surface_metadata[s].type) { case SURFACE_SOURCE_NONE: rect.left = 0; rect.top = 0; rect.right = surface_metadata[s].width; rect.bottom = surface_metadata[s].height; CortBox2(&rect, 0, (SurfaceID)s); break; case SURFACE_SOURCE_RESOURCE: ReloadBitmap_Resource(surface_metadata[s].name, (SurfaceID)s); break; case SURFACE_SOURCE_FILE: ReloadBitmap_File(surface_metadata[s].name, (SurfaceID)s); break; } } } } } return surfaces_regenerated; } // TODO - Inaccurate stack frame void InitTextObject(const char *name) { // Get font size unsigned int width, height; // Let me tell you why these font sizes are unfortunate... // 6x12 is a good font size - fonts use high-quality bitmaps at that // size, and it works with Cave Story's internal assumption that // characters are spaced 6 pixels apart. // The sad part is the 10x20 size: you might be wondering why Pixel // didn't use 12x24 instead. Well, that's because fonts don't use // bitmaps at that size - instead you get ugly low-res vector // renders. So, Pixel had to use 10x20 instead. But there's a // problem: this means the characters are spaced 5 pixels apart // instead. This normally isn't a problem because the game usually // hardcodes it, but this isn't the case when either <SAT is used, a // texture is regenerated, or when the game prints the name of the // map. This causes the font to render with incorrect spacing. // There's really not much of a solution to this, especially when // you consider that the English translation was specifically built // around the broken spacing. switch (mag) { case 1: height = 12; width = 6; break; case 2: height = 20; width = 10; break; } // The game uses DEFAULT_CHARSET when it should have used SHIFTJIS_CHARSET. // This breaks the Japanese text on English Windows installations. // Also, the game uses DEFAULT_QUALITY instead of NONANTIALIASED_QUALITY, // causing font antialiasing to blend with the colour-key, giving text an // ugly black outline. #ifdef FIX_BUGS #define QUALITY NONANTIALIASED_QUALITY #ifdef JAPANESE #define CHARSET SHIFTJIS_CHARSET #else #define CHARSET DEFAULT_CHARSET #endif #else #define QUALITY DEFAULT_QUALITY #define CHARSET DEFAULT_CHARSET #endif font = CreateFontA(height, width, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, QUALITY, FIXED_PITCH | FF_DONTCARE, name); if (font == NULL) font = CreateFontA(height, width, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, QUALITY, FIXED_PITCH | FF_DONTCARE, NULL); } void PutText(int x, int y, const char *text, unsigned long color) { HDC hdc; backbuffer->GetDC(&hdc); HGDIOBJ hgdiobj = SelectObject(hdc, font); SetBkMode(hdc, 1); SetTextColor(hdc, color); TextOutA(hdc, x * mag, y * mag, text, (int)strlen(text)); SelectObject(hdc, hgdiobj); backbuffer->ReleaseDC(hdc); } void PutText2(int x, int y, const char *text, unsigned long color, SurfaceID surf_no) { HDC hdc; surf[surf_no]->GetDC(&hdc); HGDIOBJ hgdiobj = SelectObject(hdc, font); SetBkMode(hdc, 1); SetTextColor(hdc, color); TextOutA(hdc, x * mag, y * mag, text, (int)strlen(text)); SelectObject(hdc, hgdiobj); surf[surf_no]->ReleaseDC(hdc); } void EndTextObject(void) { DeleteObject(font); }