/*========================================================================== * * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved. * * File: donut.cpp * * This sample takes the ddraw donut sample from the DirectX SDK and * adds two animating text strings to it using DirectX Animation. * * It shows how one can add DXA animation to an existing direct draw * application. Since DXA can render to a direct draw surface, this sample * creates an offscreen surface and hands it to DXA. Two DXA views are * created, one with a rotating text string (view1), the other with a * text string moving up and down (view2). * On every frame, four things are performed: * 1) view1 is asked to render (to the offscreen surface) * 2) blt donut to the same offscreen surface * 3) view2 is asked to render (to the offscreen surface) * 4) blt from the offscreen surface to the primary. * * Creating multiple views allows DXA animation to be both under and * above the donut. * ***************************************************************************/ #define NAME "Donut" #define TITLE "Donut" #define WIN32_LEAN_AND_MEAN #include #include #include #include "ddutil.h" #include "dxa.h" #include "resource.h" char szBitmap[] = "DONUT"; BOOL gExclusive = FALSE; BOOL bPaused = FALSE; HWND hWndMain; IDirectDrawFactory *lpDDF; LPDIRECTDRAW lpDD; // DirectDraw object LPDIRECTDRAWSURFACE lpDDSPrimary; // DirectDraw primary surface LPDIRECTDRAWSURFACE lpDDSDA; // Offscreen surface for DA LPDIRECTDRAWSURFACE lpDDSDonut; // Offscreen surface for donut LPDIRECTDRAWPALETTE lpDDPal; // DirectDraw palette LPDIRECTDRAWCLIPPER lpClipper; // Clipper for the primary surface BOOL bActive; // is application active? RECT windowRect; // windows' client rectangle PALETTEENTRY ape[256]; // palette entry array for palette LPDIRECTDRAWPALETTE pDDPalette; // Palette Object /* * releaseSurfaces * * Release the global surfaces and clipper. */ void releaseSurfaces( void ) { if( lpDDSPrimary != NULL ) { lpDDSPrimary->Release(); lpDDSPrimary = NULL; } if( lpDDSDA != NULL ) { lpDDSDA->Release(); lpDDSDA = NULL; } if( lpDDSDonut != NULL ) { lpDDSDonut->Release(); lpDDSDonut = NULL; } if( lpClipper != NULL ) { lpClipper->Release(); lpClipper = NULL; } if( lpDDPal != NULL ) { lpDDPal->Release(); lpDDPal = NULL; } } /* * finiObjects * * Finish with all objects we use; release them */ static void finiObjects( void ) { if( lpDD != NULL ) { releaseSurfaces(); if( lpDDPal != NULL ) { lpDDPal->Release(); lpDDPal = NULL; } lpDD->Release(); lpDD = NULL; } // Clean up the screen on exit RedrawWindow( NULL, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN ); } /* finiObjects */ /* * initFail * * This function is called if the initialization function fails */ BOOL initFail( HWND hWnd, LPCTSTR msg ) { finiObjects(); MessageBox( hWnd, msg, TITLE, MB_OK ); DestroyWindow( hWnd ); return FALSE; } /* initFail */ /* * createSurfaces * * Create the front and back buffers. */ BOOL createSurfaces( void ) { HRESULT ddrval; DDSURFACEDESC ddsd; // Create the primary surface ddsd.dwSize = sizeof( ddsd ); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; ddrval = lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL ); if( ddrval != DD_OK ) return FALSE; if(!gExclusive) { // // now create a DirectDrawClipper object. // ddrval = lpDD->CreateClipper(0, &lpClipper, NULL); if( ddrval == DD_OK ) { ddrval = lpClipper->SetHWnd(0, hWndMain); if( ddrval == DD_OK ) { ddrval = lpDDSPrimary->SetClipper(lpClipper); } } if( ddrval != DD_OK ) return FALSE; } // // Create a DirectDrawSurface to hand to Direct Animation. // ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; ddsd.dwWidth = WINDOW_WIDTH; ddsd.dwHeight = WINDOW_HEIGHT; ddrval = lpDD->CreateSurface(&ddsd, &lpDDSDA, NULL); if (ddrval != DD_OK) return FALSE; lpDDSDonut = DDLoadBitmap(lpDD, szBitmap, 0, 0); if( lpDDSDonut == NULL ) { return FALSE; } // set color key to black DDSetColorKey(lpDDSDonut, RGB(0,0,0)); HDC destDC = NULL; destDC = GetDC(hWndMain); if((GetDeviceCaps(destDC, BITSPIXEL) * GetDeviceCaps(destDC, PLANES))<=8) { ddrval = lpDD->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE | DDPCAPS_ALLOW256,ape,&pDDPalette, NULL); if (ddrval != DD_OK) return FALSE; ddrval = lpDDSDA->SetPalette(pDDPalette); if (ddrval != DD_OK) return FALSE; lpDDPal = DDLoadPalette(lpDD, szBitmap); ddrval = lpDDSPrimary->SetPalette(lpDDPal); if (ddrval != DD_OK) return FALSE; } ReleaseDC(hWndMain, destDC); destDC = NULL; return TRUE; } /* createSurfaces */ /* * recreateSurfaces * * The screen resolution or bitdepth has changed, re-create * all surfaces. */ BOOL recreateSurfaces( void ) { releaseSurfaces(); if (createSurfaces()) { destroyDXAViewObj(); return initDXAViewObj(lpDDSDA); } return FALSE; } /* recreateSurfaces */ /* * restoreAll * * Restore all lost objects */ BOOL restoreAll( void ) { HRESULT ddrval; ddrval = lpDDSPrimary->Restore(); if (ddrval == DDERR_WRONGMODE) { if (recreateSurfaces()) { return TRUE; } } else if (ddrval == DD_OK) { ddrval = lpDDSDA->Restore(); if( ddrval == DD_OK ) { ddrval = lpDDSDonut->Restore(); if( ddrval == DD_OK ) { DDReLoadBitmap(lpDDSDonut, szBitmap); return TRUE; } } } return initFail(hWndMain, "DirectDraw: Can't Recreate Surfaces"); } /* restoreAll */ /* * updateFrame * * Decide what needs to be blitted next, wait for flip to complete, * then flip the buffers. */ void updateFrame( void ) { static DWORD lastTickCount = 0; static int currentFrame = 0; static BOOL haveBackground = FALSE; DWORD thisTickCount; DWORD delay = 17; HRESULT ddrval; thisTickCount = GetTickCount(); if((thisTickCount - lastTickCount) <= delay) { return; } thisTickCount = GetTickCount(); if((thisTickCount - lastTickCount) > delay) { // Move to next frame; lastTickCount = thisTickCount; currentFrame++; if(currentFrame > 59) { currentFrame = 0; } } // DA doesn't like lost surface. We should restore lost surface // before asking DA to render. if (lpDDSDA && lpDDSDA->IsLost() == DDERR_SURFACELOST) { // This function will destroy the window if failed. if (!restoreAll()) return; } if (lpDDSDA && lpDDSDA->GetBltStatus(DDGBS_CANBLT) == DDERR_SURFACEBUSY) { // This function will destroy the window if failed. if (!restoreAll()) return; } // Ask DA to render to the DA surface the next image/sound for view1. tick(view1); // The image in the DA model (defined in dxa.cpp) has a background // image, so we don't need to clear the background before we draw here. RECT donutSrcRect; donutSrcRect.left = currentFrame%10*64; donutSrcRect.top = currentFrame/10*64; donutSrcRect.right = currentFrame%10*64 + 64; donutSrcRect.bottom = currentFrame/10*64 + 64; // Blt the donut to the center of the DDSDonut surface. RECT donutDestRect; donutDestRect.left = WINDOW_WIDTH/2-32; donutDestRect.top = WINDOW_HEIGHT/2-32; donutDestRect.right = donutDestRect.left + 64; donutDestRect.bottom = donutDestRect.top + 64; // Blit the donut for the next frame to the DA surface. while( 1 ) { ddrval = lpDDSDA->Blt(&donutDestRect, lpDDSDonut, &donutSrcRect, DDBLT_WAIT|DDBLT_KEYSRC, NULL); if( ddrval == DD_OK ) { break; } if( ddrval == DDERR_SURFACELOST ) { ddrval = restoreAll(); if( ddrval != DD_OK ) { return; } } if( ddrval != DDERR_WASSTILLDRAWING ) { return; } } // Ask DA to render to the DA surface the next image/sound for view2. tick(view2); // Blit from the DA surface to the screen. RECT daRect; daRect.left = 0; daRect.top = 0; daRect.right = WINDOW_WIDTH; daRect.bottom = WINDOW_HEIGHT; RECT screenRect; screenRect.left = windowRect.left; screenRect.top = windowRect.top; screenRect.right = windowRect.left + WINDOW_WIDTH; screenRect.bottom = windowRect.top + WINDOW_HEIGHT; while( 1 ) { ddrval = lpDDSPrimary->Blt(&screenRect, lpDDSDA, &daRect, DDBLT_WAIT, NULL); if( ddrval == DD_OK ) { break; } if( ddrval == DDERR_SURFACELOST ) { ddrval = restoreAll(); if( ddrval != DD_OK ) { return; } } if( ddrval != DDERR_WASSTILLDRAWING ) { return; } } } /* updateFrame */ long FAR PASCAL WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { switch( message ) { case WM_SIZE: case WM_MOVE: if (IsIconic(hWnd)) { bPaused = true; } if (!gExclusive) { GetClientRect(hWnd, &windowRect); ClientToScreen(hWnd, (LPPOINT)&windowRect); ClientToScreen(hWnd, (LPPOINT)&windowRect+1); } else { SetRect(&windowRect, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); } break; case WM_ACTIVATEAPP: bActive = wParam && GetForegroundWindow() == hWnd; // Unpause when we're no longer iconic. if (bPaused && bActive) { bPaused = false; } break; case WM_SETCURSOR: if (gExclusive && bActive) { SetCursor(NULL); return TRUE; } break; case WM_PALETTECHANGED: if ((HWND)wParam == hWnd) break; // fall through to WM_QUERYNEWPALETTE case WM_QUERYNEWPALETTE: // install our palette here if (lpDDPal) { lpDDSPrimary->SetPalette(lpDDPal); } DDReLoadBitmap(lpDDSDonut, szBitmap); break; case WM_CREATE: break; case WM_KEYDOWN: switch( wParam ) { case VK_ESCAPE: case VK_F12: PostMessage(hWnd,WM_CLOSE,0,0); break; } break; case WM_DESTROY: destroyDXAViewObj(); finiObjects(); PostQuitMessage( 0 ); break; } return DefWindowProc(hWnd, message, wParam, lParam); } /* WindowProc */ /* * doInit - do work required for every instance of the application: * create the window, initialize data */ static BOOL doInit( HINSTANCE hInstance, int nCmdShow ) { WNDCLASS wc; HRESULT ddrval; /* * set up and register window class */ wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wc.lpszMenuName = NAME; wc.lpszClassName = NAME; RegisterClass( &wc ); /* * create a window */ DWORD wndStyle = WS_OVERLAPPEDWINDOW; if( gExclusive) wndStyle = WS_POPUP; hWndMain = CreateWindowEx( WS_EX_APPWINDOW, NAME, TITLE, wndStyle, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL ); if( !hWndMain ) { return FALSE; } ShowWindow( hWndMain, nCmdShow ); UpdateWindow( hWndMain ); /* * create the main DirectDraw object */ ddrval = CoCreateInstance(CLSID_DirectDrawFactory, NULL, CLSCTX_INPROC_SERVER, IID_IDirectDrawFactory, (void **) & lpDDF); char strDDFailed[] = "DirectDraw Init Failed"; if( ddrval != DD_OK ) { return initFail(hWndMain, strDDFailed); } ddrval = lpDDF->CreateDirectDraw(NULL, hWndMain, DDSCL_NORMAL, 0, NULL, &lpDD); if( ddrval != DD_OK ) { return initFail(hWndMain, strDDFailed); } // Get exclusive mode if requested if(gExclusive) { ddrval = lpDD->SetCooperativeLevel( hWndMain, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ); } else { ddrval = lpDD->SetCooperativeLevel( hWndMain, DDSCL_NORMAL ); } if( ddrval != DD_OK ) { return initFail(hWndMain, strDDFailed); } if (!createSurfaces()) { return initFail(hWndMain, strDDFailed); } // Create a DAView object and construct the model. if (!initDXAViewObj(lpDDSDA)) { return initFail(hWndMain, "DirectX Animation Init FAILED"); } return TRUE; } /* doInit */ /* * WinMain - initialization, message loop */ int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; LPSTR c; for(c=lpCmdLine; *c != '\0'; c++) { switch( *c ) { case 'X': gExclusive = TRUE; break; } } if( !doInit( hInstance, nCmdShow ) ) { return FALSE; } while( 1 ) { if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) { if( !GetMessage( &msg, NULL, 0, 0 ) ) return msg.wParam; TranslateMessage(&msg); DispatchMessage(&msg); } else if (!bPaused && (bActive || !gExclusive)) { updateFrame(); } else { WaitMessage(); } } } /* WinMain */