//////////////////////////////////////////////////////////////////////////// // AppCycle(). Do one iteration of the WT cycle. // void AppDoCycle(void) { wt_input(); wt_render(); HDC hdc = GetDC(hwndApp); //don't bother to realize the palette, because we've got AppActivate(). AppPaint(hwndApp, hdc); ReleaseDC(hwndApp, hdc); }
///////////////////////////////////////////////////////////////////////////// // GetFrameRate. Times the frame rate in one of four ways: WT only without // any WinG blitting, WinG only without any WT rendering, WT rendering with // WinG blitting with static rendering, WT rendering with WinG blitting with // dynamic rendering (player is rotating). // DWORD GetFrameRate(int reps, WPARAM what) { HDC hdc = GetDC(hwndApp); if (hpalApp) { SelectPalette(hdc, hpalApp, FALSE); RealizePalette(hdc); } if (what == ID_STUFF_FRAMERATE_DYNAMIC) { kbPressed[kbUpArrow] = 1; wt_input(); wt_input(); wt_input(); wt_input(); wt_input(); kbPressed[kbUpArrow] = 0; kbPressed[kbLeftArrow] = 1; } DWORD Time = timeGetTime(); for (int i=0; i<reps; i++) { if (what != ID_STUFF_FRAMERATE_RAW_WING) { if (what == ID_STUFF_FRAMERATE_DYNAMIC) wt_input(); wt_render(); } if (what != ID_STUFF_FRAMERATE_RAW_WT) AppPaint(hwndApp, hdc); } Time = timeGetTime() - Time; ReleaseDC(hwndApp, hdc); if (what == ID_STUFF_FRAMERATE_DYNAMIC) kbPressed[kbLeftArrow] = 0; return(Time); }
int main(int argc, char *argv[]) { int quit = False; if (argc != 2) { fprintf(stderr, "Usage: wt <world file>\n"); exit(EXIT_FAILURE); } if (wt_init(argv[1],320,200) == EXIT_FAILURE) { perror(argv[1]); exit(EXIT_FAILURE); } while (!quit) { wt_render(); quit = wt_input(); } wt_term(); return EXIT_SUCCESS; }
///////////////////////////////////////////////////////////////////////////// // AppWndProc( hwnd, uiMessage, wParam, lParam ) // // The window proc for the app's main (tiled) window. This processes all // of the parent window's messages. // LONG FAR PASCAL _export AppWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { PAINTSTRUCT ps; HDC hdc; BOOL f; //is it the registered message? (this proc is called after the creation //of the msgApp). if (msg == msgApp) { if (bShowRendering) { HDC hdc = GetDC(hwndApp); AppPaint(hwndApp, hdc); ReleaseDC(hwndApp, hdc); bShowRendering = (int)wParam; //sent a 0 to turn off bShowRendering. } return 0L; } //well, how about standard Windows messages? switch (msg) { case WM_CREATE: //let WM_SIZE do all the work. break; case WM_ACTIVATEAPP: bAppActive = (BOOL)wParam; wt_reset_input(); // *** Remap the system colors and deal with the palette AppActivate(bAppActive); if (hpalApp) { HDC hdc = GetDC(hwnd); UnrealizeObject(hpalApp); SelectPalette(hdc, hpalApp, FALSE); RealizePalette(hdc); ReleaseDC(hwnd, hdc); } break; case WM_SIZE: wt_reset_input(); nBitmapW = LOWORD(lParam); //new size. nBitmapH = HIWORD(lParam); nBitmapW /= StretchFactor; nBitmapH /= StretchFactor; //Windows DIBs, including WinG bitmaps, are always a multiple of //32-bits wide. For us, using the typical 8-bit per pixel bitmap, //that means we need to ensure the width is a multiple of 4. This //is important because the WT engine treats a bitmap's width and //pitch as one - there is no way for WT to draw into a bitmap //using a width different than the pitch. So we force the bitmap's //width to be a multiple of 4, to be both Windows and WT compatible. //Note we could have patched WT to deal with the concept of a //bitmap pitch, but that's too much change. nBitmapW = ((nBitmapW+3)/4)*4; if(Buffer) { //resizing, minimizing, maximizing. HBITMAP hbm; int Counter; //Create a new 8-bit WinGBitmap with the new size BufferHeader.Header.biWidth = nBitmapW; BufferHeader.Header.biHeight = nBitmapH * Orientation; //probably don't need to do this, but do it anyway. for(Counter = 0;Counter < 256;Counter++) { BufferHeader.aColors[Counter].rgbRed = ColorTable[Counter].rgbRed; BufferHeader.aColors[Counter].rgbGreen = ColorTable[Counter].rgbGreen; BufferHeader.aColors[Counter].rgbBlue = ColorTable[Counter].rgbBlue; BufferHeader.aColors[Counter].rgbReserved = 0; } hbm = WinG.pCreateBitmap(Buffer, (BITMAPINFO *)&BufferHeader, &pBuffer); // Select it in and delete the old one hbm = (HBITMAP)SelectObject(Buffer, hbm); DeleteObject(hbm); PatBlt(Buffer, 0,0,nBitmapW,nBitmapH, BLACKNESS); wt_set_fb_mem(pBuffer); //tell WT about new bitmap address. wt_reinit(nBitmapW,nBitmapH); //and about new bitmap size. wt_render(); //and have WT render a frame. } else //first time. { // Create a new WinGDC and 8-bit WinGBitmap HBITMAP hbm; int Counter; // Get WinG to recommend the fastest DIB format if(WinG.pRecommendDIBFormat((BITMAPINFO *)&BufferHeader)) { // make sure it's 8bpp and remember the orientation BufferHeader.Header.biBitCount = 8; BufferHeader.Header.biCompression = BI_RGB; Orientation = BufferHeader.Header.biHeight; if (Orientation > 0) { DebugMsg("WT requires a top-down bitmap!\nYou are about to hit a brick wall at 90 MPH!"); PostQuitMessage(1); //works but slams palette. bummer. } } else { // set it up ourselves BufferHeader.Header.biSize = sizeof(BITMAPINFOHEADER); BufferHeader.Header.biPlanes = 1; BufferHeader.Header.biBitCount = 8; BufferHeader.Header.biCompression = BI_RGB; BufferHeader.Header.biSizeImage = 0; BufferHeader.Header.biClrUsed = 0; BufferHeader.Header.biClrImportant = 0; } BufferHeader.Header.biWidth = nBitmapW; BufferHeader.Header.biHeight = nBitmapH * Orientation; //#define BAD_PALETTE_CODE #ifdef BAD_PALETTE_CODE //This code sets an incorrect palette, but at least you can still use //regular windows tools. Good for debugging. HDC Screen; RGBQUAD *pColorTable; // create an identity palette from the DIB's color table // get the 20 system colors as PALETTEENTRIES Screen = GetDC(0); GetSystemPaletteEntries(Screen,0,10,LogicalPalette.aEntries); GetSystemPaletteEntries(Screen,246,10, LogicalPalette.aEntries + 246); ReleaseDC(0,Screen); // initialize the logical palette and DIB color table for(Counter = 0;Counter < 10;Counter++) { // copy the system colors into the DIB header // WinG will do this in WinGRecommendDIBFormat, // but it may have failed above so do it here anyway BufferHeader.aColors[Counter].rgbRed = LogicalPalette.aEntries[Counter].peRed; BufferHeader.aColors[Counter].rgbGreen = LogicalPalette.aEntries[Counter].peGreen; BufferHeader.aColors[Counter].rgbBlue = LogicalPalette.aEntries[Counter].peBlue; BufferHeader.aColors[Counter].rgbReserved = 0; LogicalPalette.aEntries[Counter].peFlags = 0; BufferHeader.aColors[Counter + 246].rgbRed = LogicalPalette.aEntries[Counter + 246].peRed; BufferHeader.aColors[Counter + 246].rgbGreen = LogicalPalette.aEntries[Counter + 246].peGreen; BufferHeader.aColors[Counter + 246].rgbBlue = LogicalPalette.aEntries[Counter + 246].peBlue; BufferHeader.aColors[Counter + 246].rgbReserved = 0; LogicalPalette.aEntries[Counter + 246].peFlags = 0; } for (i=0; i<256; i++) { ColorTable[i].rgbRed = 0; ColorTable[i].rgbGreen = 0; ColorTable[i].rgbBlue = 0; } nColors = wt_load_palette(); for (i=0; i<nColors; i++) { int r,g,b; wt_get_palette_entry(i,&r,&g,&b); ColorTable[i].rgbRed = r; ColorTable[i].rgbGreen = g; ColorTable[i].rgbBlue = b; } pColorTable = &ColorTable[0]; for(Counter = 10;Counter < 246;Counter++) { // copy from the original color table to the WinGBitmap's // color table and the logical palette BufferHeader.aColors[Counter].rgbRed = LogicalPalette.aEntries[Counter].peRed = pColorTable[Counter].rgbRed; BufferHeader.aColors[Counter].rgbGreen = LogicalPalette.aEntries[Counter].peGreen = pColorTable[Counter].rgbGreen; BufferHeader.aColors[Counter].rgbBlue = LogicalPalette.aEntries[Counter].peBlue = pColorTable[Counter].rgbBlue; BufferHeader.aColors[Counter].rgbReserved = 0; LogicalPalette.aEntries[Counter].peFlags = PC_NOCOLLAPSE; } hpalApp = CreatePalette((LOGPALETTE *)&LogicalPalette); #else //GOOD_PALETTE_CODE //Working palette code. Has correct colors. And identity. Same frame //rate as bad palette code. This really hoses Windows colors, so //a GUI debugger's windows are really hard to read. I couldn't read the //Symantec IDDE's windows - so I #ifdef'd the bad palette code in for //debugging. //Anyway, this code works. Need 3 things for identity, as far as I can tell: //1. you have to be writing to your bitmap using a specific palette, //2. this palette has to be made into a Windows palette, and selected. //3. this palette has to be copied into the BitmapInfo header of the WinG // bitmap, before creating it (actually as a parameter to creating it). // ClearSystemPalette(); CreateWTPalette(); for(Counter = 0;Counter < 256;Counter++) { BufferHeader.aColors[Counter].rgbRed = ColorTable[Counter].rgbRed; BufferHeader.aColors[Counter].rgbGreen = ColorTable[Counter].rgbGreen; BufferHeader.aColors[Counter].rgbBlue = ColorTable[Counter].rgbBlue; BufferHeader.aColors[Counter].rgbReserved = 0; } #endif // Create a WinGDC and Bitmap, then select away Buffer = WinG.pCreateDC(); hbm = WinG.pCreateBitmap(Buffer, (BITMAPINFO *)&BufferHeader, &pBuffer); // Store the old hbitmap to select back in before deleting gbmOldMonoBitmap = (HBITMAP)SelectObject(Buffer, hbm); PatBlt(Buffer, 0,0,nBitmapW,nBitmapH, BLACKNESS); wt_set_fb_mem(pBuffer); //hack to get around WT's code. strcpy(szDefaultWorldFileName, szModulePath); strcat(szDefaultWorldFileName, DEFAULT_WORLD_FILEPATH); wt_init(szDefaultWorldFileName, nBitmapW,nBitmapH); AppSetCaption(DEFAULT_WORLD_FILETITLE); wt_render(); } bWTinitialized = TRUE; break; case WM_KEYDOWN: //set WT's keyboard array, then do a WT cycle. switch (wParam) { case VK_UP: kbPressed[kbUpArrow] = 1; break; case VK_DOWN: kbPressed[kbDownArrow] = 1; break; case VK_LEFT: kbPressed[kbLeftArrow] = 1; break; case VK_RIGHT: kbPressed[kbRightArrow] = 1; break; case VK_CONTROL: kbPressed[kbCtrl] = 1; break; case VK_ESCAPE: kbPressed[kbEsc] = 1; //DestroyWindow() here? let's check to ensure that func // will send the proper msgs to close stuff. break; case VK_SPACE: kbPressed[kbSpace] = 1; break; case VK_SHIFT: kbPressed[kbLeftShift] = 1; break; case VK_TAB: kbPressed[kbAlt] = 1; break; } //tried using wt_input/wt_render/InvalidateRect sequence //here, but was sometimes jerky (missed frames, actually), //if there was too much keyboard activity. //I think windows was collapsing queued/pending //WM_PAINT messages, so that the app got one instead of a //sudden stream. Anyhow now I draw immediately, and it works //great. Note that AppIdle() processing is required to //have acceleration/deceleration/monsters/events occur without //keyboard input. I guess a timer could also be used. //So I ended up using this helper routine to repaint. AppDoCycle(); break; case WM_KEYUP: //set WT's keyboard array, then do a WT cycle. switch (wParam) { case VK_UP: kbPressed[kbUpArrow] = 0; break; case VK_DOWN: kbPressed[kbDownArrow] = 0; break; case VK_LEFT: kbPressed[kbLeftArrow] = 0; break; case VK_RIGHT: kbPressed[kbRightArrow] = 0; break; case VK_CONTROL: kbPressed[kbCtrl] = 0; break; case VK_ESCAPE: kbPressed[kbEsc] = 0; break; case VK_SPACE: kbPressed[kbSpace] = 0; break; case VK_SHIFT: kbPressed[kbLeftShift] = 0; break; case VK_TAB: kbPressed[kbAlt] = 0; break; } AppDoCycle(); break; case WM_LBUTTONDOWN: break; case WM_RBUTTONDOWN: break; case WM_MOUSEMOVE: break; case WM_COMMAND: return AppCommand(hwnd,msg,wParam,lParam); case WM_DESTROY: PostQuitMessage(0); break; case WM_CLOSE: break; case WM_PALETTECHANGED: if ((HWND)wParam == hwnd) break; // fall through to WM_QUERYNEWPALETTE case WM_QUERYNEWPALETTE: hdc = GetDC(hwnd); if (hpalApp) SelectPalette(hdc, hpalApp, FALSE); f = RealizePalette(hdc); ReleaseDC(hwnd,hdc); if (f) InvalidateRect(hwnd,NULL,TRUE); return f; case WM_PAINT: hdc = BeginPaint(hwnd,&ps); SelectPalette(hdc, hpalApp, FALSE); RealizePalette(hdc); AppPaint (hwnd,hdc); EndPaint(hwnd,&ps); return 0L; } return DefWindowProc(hwnd,msg,wParam,lParam); }