#include #include #include #include /* DirectDraw はアルファブレンドをサポートしません。 よって、アルファブレンドのコードは自力で書きました。 */ #define WINDOW_CLASS_NAME "WinClassName" #define FLIP_BLANK (1000/60) #define SCREEN_WIDTH 640 #define SCREEN_HEIGHT 480 static int screen_width, screen_height; static int g_bit = 0; static DWORD g_maskR = 0; DWORD wait_time; HWND g_hWnd = NULL; LPDIRECTDRAW lpDD = NULL; LPDIRECTDRAWSURFACE lpFront = NULL; LPDIRECTDRAWSURFACE lpBack = NULL; LPDIRECTDRAWCLIPPER lpClipper = NULL; /* * 色ビットと配置 * 8bit RRRGGGBB 16bit RRRRRGGG GGGBBBBB BBBBBGGG GGGRRRRR 0RRRRRGG GGGBBBBB  24bit RRRRRRRR GGGGGGGG BBBBBBBB BBBBBBBB GGGGGGGG RRRRRRRR 32bit 00000000 RRRRRRRR GGGGGGGG BBBBBBBB 00000000 BBBBBBBB GGGGGGGG RRRRRRRR */ DWORD getDwColor(BYTE r, BYTE g, BYTE b){ DWORD c; switch(g_bit){ case 16: switch(g_maskR){ case 0xF800: c = ((r << 8) & 0xF800) | ((g << 3) & 0x07E0) | (b >> 3); break; case 0x001F: c = (r >> 3) | ((g << 3) & 0x07E0) | ((r << 8) & 0xF800); break; case 0x7C00: c = ((r << 7) & 0x7C00) | ((g << 2) & 0x03E0) | (b >> 3); break; } break; case 32: switch(g_maskR){ case 0x00FF0000: c = (r << 16) | (g << 8) | b; break; case 0x000000FF: c = r | (g << 8) | (b << 16); break; } break; } return c; } DWORD blendAlpha(DWORD sou, DWORD dist, DWORD alpha){ DWORD r, g, b; switch(g_bit){ case 16: switch(g_maskR){ case 0xF800: r = (((((sou >> 11) * (255 - alpha)) + ((dist >> 11) * alpha)) >> 8) & 0x0000001F) << 11; g = ((((((sou >> 5) & 0x0000003F) * (255 - alpha)) + (((dist >> 5) & 0x0000003F) * alpha)) >> 8) & 0x0000003F) << 5; b = ((((sou & 0x0000001F) * (255 - alpha)) + ((dist & 0x0000001F) * alpha)) >> 8) & 0x0000001F; break; case 0x001F: r = ((((sou & 0x0000001F) * (255 - alpha)) + ((dist & 0x0000001F) * alpha)) >> 8) & 0x0000001F; g = ((((((sou >> 5) & 0x0000003F) * (255 - alpha)) + (((dist >> 5) & 0x0000003F) * alpha)) >> 8) & 0x0000003F) << 5; b = (((((sou >> 11) * (255 - alpha)) + ((dist >> 11) * alpha)) >> 8) & 0x0000001F) << 11; break; case 0x7C00: r = (((((sou >> 10) * (255 - alpha)) + ((dist >> 10) * alpha)) >> 8) & 0x0000001F) << 10; g = ((((((sou >> 5) & 0x0000001F) * (255 - alpha)) + (((dist >> 5) & 0x0000001F) * alpha)) >> 8) & 0x0000001F) << 5; b = ((((sou & 0x0000001F) * (255 - alpha)) + ((dist & 0x0000001F) * alpha)) >> 8) & 0x0000001F; break; } break; case 32: switch(g_maskR){ case 0x00FF0000: r = (((((sou >> 16) * (255 - alpha)) + ((dist >> 16) * alpha)) >> 8) & 0x000000FF) << 16; g = ((((((sou >> 8) & 0x000000FF) * (255 - alpha)) + (((dist >> 8) & 0x000000FF) * alpha)) >> 8) & 0x000000FF) << 8; b = ((((sou & 0x000000FF) * (255 - alpha)) + ((dist & 0x000000FF) * alpha)) >> 8) & 0x000000FF; break; case 0x000000FF: r = ((((sou & 0x000000FF) * (255 - alpha)) + ((dist & 0x000000FF) * alpha)) >> 8) & 0x000000FF; g = ((((((sou >> 8) & 0x000000FF) * (255 - alpha)) + (((dist >> 8) & 0x000000FF) * alpha)) >> 8) & 0x000000FF) << 8; b = (((((sou >> 16) * (255 - alpha)) + ((dist >> 16) * alpha)) >> 8) & 0x000000FF) << 16; break; } break; } return (r | g | b); } /* * DirectDraw */ int initDD(HWND hWnd, int w, int h){ DDSURFACEDESC ddsd; screen_width = w; screen_height = h; if(DirectDrawCreate(NULL, &lpDD, NULL) != DD_OK){ return 0; } if(lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL) != DD_OK){ return 0; } // プライマリサーフェスの作成 ZeroMemory(&ddsd, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; if(lpDD->CreateSurface(&ddsd, &lpFront, NULL) != DD_OK){ return 0; } if(lpDD->GetDisplayMode(&ddsd) != DD_OK){ return 0; } g_bit = ddsd.ddpfPixelFormat.dwRGBBitCount; g_maskR = ddsd.ddpfPixelFormat.dwRBitMask; if(g_bit != 16 && g_bit != 32){ MessageBox(hWnd, "Screen Mode is not 16bit or 32bit", "Error", MB_OK); return 0; } // サーフェスのクリップ lpDD->CreateClipper(0, &lpClipper, NULL); lpClipper->SetHWnd(0, hWnd); lpFront->SetClipper(lpClipper); ZeroMemory(&ddsd, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; ddsd.dwWidth = w; ddsd.dwHeight = h; if((lpDD->CreateSurface(&ddsd, &lpBack, NULL)) != DD_OK){ return 0; } return 1; } #define RELEASE(i) if(i){i->Release();i=NULL;} void deinitDD(void){ RELEASE(lpClipper); RELEASE(lpFront); RELEASE(lpBack); RELEASE(lpDD); } void drawPoint(LPDIRECTDRAWSURFACE lpsf, int x, int y, DWORD c){ DDSURFACEDESC desc; ZeroMemory(&desc, sizeof(DDSURFACEDESC)); desc.dwSize = sizeof(DDSURFACEDESC); lpsf->Lock(NULL, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL); switch(g_bit){ case 16: { WORD *p; p = (WORD *)desc.lpSurface; p[x + (y * desc.lPitch >> 1)] = (WORD)c; } break; case 32: { DWORD *p; p = (DWORD *)desc.lpSurface; p[x + ((y * desc.lPitch) >> 2)] = (DWORD)c; } break; } lpsf->Unlock(desc.lpSurface); } void fillBackSurface(BYTE r, BYTE g, BYTE b){ DDBLTFX ddbltfx; ZeroMemory(&ddbltfx, sizeof(DDBLTFX)); ddbltfx.dwSize=sizeof(DDBLTFX); ddbltfx.dwFillColor = getDwColor(r, g, b); lpBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); } void drawBackGround(BYTE r, BYTE g, BYTE b){ fillBackSurface(r, g, b); for(int t = 0; t < SCREEN_HEIGHT; t++){ for(int i = 0; i < SCREEN_WIDTH; i++){ if((t + 10) % 50 < 25){ if((i + 20) % 50 >= 25){ drawPoint(lpBack, i, t, getDwColor(0, 0, 0)); } } else{ if((i + 20) % 50 < 25){ drawPoint(lpBack, i, t, getDwColor(0, 0, 0)); } } } } } void drawRect32x32(LPDIRECTDRAWSURFACE lpsf, RECT *r, DWORD c){ static int f = 0; static RECT old_r = {0,0,32,32}; static DWORD buf[32 * 32]; DDSURFACEDESC desc; ZeroMemory(&desc, sizeof(DDSURFACEDESC)); desc.dwSize = sizeof(DDSURFACEDESC); if(f != 0){ lpsf->Lock(&old_r, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL); switch(g_bit){ case 16: { WORD *p; p = (WORD *)desc.lpSurface; for(int t = 0; t < 32; t++){ for(int i = 0; i < 32; i++){ p[i + (t * desc.lPitch >> 1)] = (WORD)buf[i + t * 32]; } } } break; case 32: { DWORD *p; p = (DWORD *)desc.lpSurface; for(int t = 0; t < 32; t++){ for(int i = 0; i < 32; i++){ p[i + (t * desc.lPitch >> 2)] = (DWORD)buf[i + t * 32]; } } } break; } lpsf->Unlock(desc.lpSurface); } lpsf->Lock(r, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL); switch(g_bit){ case 16: { WORD *p; p = (WORD *)desc.lpSurface; for(int t = 0; t < 32; t++){ for(int i = 0; i < 32; i++){ DWORD c2 = (DWORD)p[i + (t * desc.lPitch >> 1)]; buf[i + t * 32] = c2; p[i + (t * desc.lPitch >> 1)] = (WORD)blendAlpha(c2, c, 150); } } old_r = *r; f = 1; } break; case 32: { DWORD *p; p = (DWORD *)desc.lpSurface; for(int t = 0; t < 32; t++){ for(int i = 0; i < 32; i++){ DWORD c2 = (DWORD)p[i + (t * desc.lPitch >> 2)]; buf[i + t * 32] = c2; p[i + (t * desc.lPitch >> 2)] = (DWORD)blendAlpha(c2, c, 150); } } old_r = *r; f = 1; } break; } lpsf->Unlock(desc.lpSurface); } void CalcScreenRect(HWND hWnd, RECT *client_rect) { POINT client_point; client_point.x = client_point.y = 0; ClientToScreen(hWnd, &client_point); GetClientRect(hWnd, client_rect); OffsetRect(client_rect, client_point.x, client_point.y); } HRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ switch(message){ case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, message, wParam, lParam); } int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR, int nCmdShow){ MSG msg; WNDCLASS wc; if(!hPrevInst){ wc.lpszClassName = WINDOW_CLASS_NAME; wc.lpfnWndProc = WndProc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.hInstance = hInst; wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wc.lpszMenuName = NULL; wc.cbClsExtra = 0; wc.cbWndExtra = 0; if(RegisterClass(&wc) == 0){ return 0; } } HWND hWnd = CreateWindow( WINDOW_CLASS_NAME, "DirectDraw Test", WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInst, NULL); if(hWnd == NULL){ return 0; } g_hWnd = hWnd; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); if(!(initDD(hWnd, SCREEN_WIDTH, SCREEN_HEIGHT))){ MessageBox(hWnd, "Error", "Error", MB_OK); return 0; } drawBackGround(255, 255, 255); int px = 0, py = 0, dx = 7, dy = 7; while(1){ wait_time = timeGetTime(); px += dx; py += dy; if(px + 32 >= SCREEN_WIDTH){ px -= ((px + 32) - SCREEN_WIDTH) << 1; dx *= -1; } if(px < 0){ px *= -1; dx *= -1; } if(py + 32 >= SCREEN_HEIGHT){ py -= ((py + 32) - SCREEN_HEIGHT) << 1; dy *= -1; } if(py < 0){ py *= -1; dy *= -1; } RECT r = {px, py, px + 32, py + 32}; drawRect32x32(lpBack, &r, getDwColor(255, 0, 0)); RECT rectSrc = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT}; RECT rectDest; CalcScreenRect(hWnd, &rectDest); lpFront->Blt(&rectDest, lpBack, &rectSrc, DDBLT_WAIT /* | DDBLT_KEYSRC */, NULL); do{ while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){ if(msg.message == WM_QUIT){ goto fin; } TranslateMessage(&msg); DispatchMessage(&msg); } }while(timeGetTime() < wait_time + FLIP_BLANK); } fin: deinitDD(); return msg.wParam; }