/* dd.cpp - Don Yang (uguu.org) 12/31/00 */ #include"global.h" #include"bg.h" #include"dd.h" #include"main.h" #include"sprite.h" static clock_t LastFrameTime; static int LastFrameCount; static LPDIRECTDRAW DDObject; static LPDIRECTDRAWSURFACE DDPScreen; static LPDIRECTDRAWSURFACE DDScreen; static BOOL ClearScreen16(void); static BOOL ClearScreen24(void); static BOOL ClearScreen32(void); static BOOL RestoreSurfaces(void); /********************************************************************** Blit Copy off screen buffer to physical screen. */ BOOL Blit(void) { RECT src, dst; POINT offset; HRESULT result; if( !DDReady ) return TRUE; // Define source region src.left = src.top = 0; src.right = APP_WIDTH; src.bottom = APP_HEIGHT; // Set destination size and coordinates GetClientRect(AppWindow, &dst); offset.x = offset.y = 0; ClientToScreen(AppWindow, &offset); OffsetRect(&dst, offset.x, offset.y); // Wait for vsync DDObject->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL); FrameCount++; // Try blit repeatedly do { if( (result = DDPScreen->BltFast(dst.left, dst.top, DDScreen, &src, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT)) == DD_OK ) { // Success if( (clock() - LastFrameTime) > CLOCKS_PER_SEC ) { LastFrameTime = clock(); ActualFPS[ActualFPSindex] = FrameCount - LastFrameCount; ActualFPSindex = (ActualFPSindex + 1) & 3; LastFrameCount = FrameCount; } return TRUE; } if( result == DDERR_SURFACELOST ) if( !RestoreSurfaces() ) return Croak("Can not blit"); // (main.cpp) } while( result == DDERR_SURFACELOST ); return DDFailure("Can not blit.", result); } // Blit() /***************************************************************** DDFailure Display error message and cleanup DirectDraw. */ BOOL DDFailure(char *message, HRESULT code) { char text[256]; UninitDD(); ShowCursor(TRUE); sprintf(text, "Error %08x: %s", code, message); LogMessage(text); MessageBox(AppWindow, text, "Error", MB_OK | MB_ICONSTOP); return FALSE; } // DDFailure() /******************************************************************** InitDD Initialize DirectDraw. */ BOOL InitDD(void) { DDSURFACEDESC surface; HRESULT result; DDReady = FALSE; DDObject = NULL; DDPScreen = NULL; DDScreen = NULL; LastFrameCount = FrameCount = 0; LastFrameTime = clock(); // Initialize object if( (result = DirectDrawCreate(NULL, &DDObject, NULL)) != DD_OK ) return DDFailure("Can not create DirectDraw object.", result); if( (result = DDObject->SetCooperativeLevel( AppWindow, DDSCL_NORMAL)) != DD_OK ) return DDFailure("Can not set windowed mode.", result); // Create primary surface ZeroMemory(&surface, sizeof(DDSURFACEDESC)); surface.dwSize = sizeof(DDSURFACEDESC); surface.dwFlags = DDSD_CAPS; surface.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; if( (result = DDObject->CreateSurface( &surface, &DDPScreen, NULL)) != DD_OK ) return DDFailure("Can not create primary surface.", result); // Create off-screen buffer ZeroMemory(&surface, sizeof(DDSURFACEDESC)); surface.dwSize = sizeof(DDSURFACEDESC); surface.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; surface.dwWidth = APP_WIDTH; surface.dwHeight = APP_HEIGHT; surface.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; if( (result = DDObject->CreateSurface(&surface, &DDScreen, NULL)) != DD_OK ) return DDFailure("Can not create surface.", result); // Get screen information and select proper functions surface.dwSize = sizeof(DDSURFACEDESC); if( (result = DDScreen->GetSurfaceDesc(&surface)) != DD_OK ) return DDFailure("DDScreen->GetSurfaceDesc()", result); // !! if( !(surface.ddpfPixelFormat.dwFlags & DDPF_RGB) ) return Croak("Unsupported color model."); // (main.cpp) if( surface.ddpfPixelFormat.dwRBitMask == 0x7c00 && surface.ddpfPixelFormat.dwGBitMask == 0x03e0 && surface.ddpfPixelFormat.dwBBitMask == 0x001f && surface.ddpfPixelFormat.dwRGBBitCount == 16 ) { // 1:5:5:5 format PixelFormat = PIXEL_1555; ClearScreen = ClearScreen16; InitSprites = InitSprites15; // (sprite.cpp) InitBackground = InitBackground15; // (bg.cpp) } else if( surface.ddpfPixelFormat.dwRBitMask == 0xf800 && surface.ddpfPixelFormat.dwGBitMask == 0x07e0 && surface.ddpfPixelFormat.dwBBitMask == 0x001f && surface.ddpfPixelFormat.dwRGBBitCount == 16 ) { // 5:6:5 format PixelFormat = PIXEL_565; ClearScreen = ClearScreen16; InitSprites = InitSprites16; InitBackground = InitBackground16; } else if( surface.ddpfPixelFormat.dwRBitMask == 0xff0000 && surface.ddpfPixelFormat.dwGBitMask == 0x00ff00 && surface.ddpfPixelFormat.dwBBitMask == 0x0000ff && surface.ddpfPixelFormat.dwRGBBitCount == 24 ) { // 8:8:8 format PixelFormat = PIXEL_888; ClearScreen = ClearScreen24; InitSprites = InitSprites24; InitBackground = InitBackground24; } else if( surface.ddpfPixelFormat.dwRBitMask == 0xff0000 && surface.ddpfPixelFormat.dwGBitMask == 0x00ff00 && surface.ddpfPixelFormat.dwBBitMask == 0x0000ff && surface.ddpfPixelFormat.dwRGBBitCount == 32 ) { // 8:8:8:8 format PixelFormat = PIXEL_8888; ClearScreen = ClearScreen32; InitSprites = InitSprites32; InitBackground = InitBackground32; } else { return Croak( "Unsupported pixel format, need 16, 24, or 32 bits per pixel."); } DDPitch = surface.lPitch; InitBackground(); // (bg.cpp) RenderBackground(); // (bg.cpp) return DDReady = TRUE; } // InitDD() /**************************************************************** LockScreen Lock off screen buffer for writing. */ BOOL LockScreen(DDSURFACEDESC *surface) { HRESULT result; if( !DDReady ) return Croak("DirectDraw not initialized."); // (main.cpp) surface->dwSize = sizeof(DDSURFACEDESC); do { if( (result = DDScreen->Lock(NULL, surface, DDLOCK_WAIT, NULL)) == DD_OK ) return TRUE; if( result == DDERR_SURFACELOST ) { if( !RestoreSurfaces() ) return Croak("Can not lock screen"); } } while( result == DDERR_SURFACELOST ); return DDFailure("Can not lock screen.", result); } // LockScreen() /****************************************************************** UninitDD Release DirectDraw objects. */ void UninitDD(void) { DDReady = FALSE; if( DDObject != NULL ) { if( DDPScreen != NULL ) { DDPScreen->Release(); DDPScreen = NULL; } if( DDScreen != NULL ) { DDScreen->Release(); DDScreen = NULL; } DDObject->Release(); DDObject = NULL; } LogMessageN("%d frames rendered.", FrameCount); } // UninitDD() /************************************************************** UnlockScreen Unlock screen buffer. */ BOOL UnlockScreen(void) { HRESULT result; if( (result = DDScreen->Unlock(NULL)) != DD_OK ) return DDFailure("Can not unlock screen.", result); return TRUE; } // UnlockScreen() /************************************************************* ClearScreen16 Fill screen with black pixels. */ static BOOL ClearScreen16(void) { DDSURFACEDESC surface; DWORD screen; if( !LockScreen(&surface) ) return Croak("Can not clear screen"); // (main.cpp) screen = (DWORD)surface.lpSurface; __asm { pushf cld mov edi, screen xor eax, eax mov ebx, APP_HEIGHT mov edx, DDPitch sub edx, (APP_WIDTH * 2) ; EDX = delta between scanlines ClearScreen16_loop: mov ecx, (APP_WIDTH / 2) rep stosd add edi, edx dec ebx jnz ClearScreen16_loop popf } return UnlockScreen(); } // ClearScreen16() /************************************************************* ClearScreen24 Fill screen with black pixels. */ static BOOL ClearScreen24(void) { DDSURFACEDESC surface; DWORD screen; if( !LockScreen(&surface) ) return Croak("Can not clear screen"); // (main.cpp) screen = (DWORD)surface.lpSurface; __asm { pushf cld mov edi, screen xor eax, eax mov ebx, APP_HEIGHT mov edx, DDPitch sub edx, (APP_WIDTH * 3) ; EDX = delta between scanlines ClearScreen24_loop: mov ecx, (3 * APP_WIDTH / 4) rep stosd add edi, edx dec ebx jnz ClearScreen24_loop popf } return UnlockScreen(); } // ClearScreen24() /************************************************************* ClearScreen32 Fill screen with black pixels. */ static BOOL ClearScreen32(void) { DDSURFACEDESC surface; DWORD screen; if( !LockScreen(&surface) ) return Croak("Can not clear screen"); // (main.cpp) screen = (DWORD)surface.lpSurface; __asm { pushf cld mov edi, screen xor eax, eax mov ebx, APP_HEIGHT mov edx, DDPitch sub edx, (APP_WIDTH * 4) ; EDX = delta between scanlines ClearScreen32_loop: mov ecx, APP_WIDTH rep stosd add edi, edx dec ebx jnz ClearScreen32_loop popf } return UnlockScreen(); } // ClearScreen32() /*********************************************************** RestoreSurfaces Restore lost DirectDraw surfaces. */ static BOOL RestoreSurfaces(void) { HRESULT result; LogMessage("RestoreSurfaces()"); if( DDPScreen != NULL ) { if( (result = DDPScreen->Restore()) != DD_OK ) return DDFailure("Surfaces lost and can not be restored.", result); } if( DDScreen != NULL ) { if( (result = DDScreen->Restore()) != DD_OK ) return DDFailure("Surfaces lost and can not be restored.", result); } return TRUE; } // RestoreSurfaces() char *DdObjTime = __TIME__ " " __DATE__; int DdObjLines = __LINE__;