1. Что Вам необходимо для использования DirectDraw
2. Инициализация DirectDraw
3. Создание первичной поверхности и установки для обеспечения смены страниц (flipping)
4. Загрузка изображений в видеопамять (bitmap)
5. Загрузка палитры
6. Настройка прозрачного цвета
7. Собрать все вместе и готово. Построение динамики.
8. Очистка по окончании использования
|
Пример инициализации поверхностей (первичной и вторичной) DirectDraw LPDIRECTDRAWSURFACE lpDDSPrimary; // указатель на первичную поверхность DirectDraw LPDIRECTDRAWSURFACE lpDDSBack; // указатель на вторичную поверхность DirectDraw BOOL CreatePrimarySurface() { DDSURFACEDESC ddsd; DDSCAPS ddscaps; HRESULT ddrval; // создадим первичную поверхность с одной вторичной memset( &ddsd, 0, sizeof(ddsd) ); ddsd.dwSize = sizeof( ddsd ); ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; // поле ddsCaps принимается в рассмотрение и в // нем имеет значение только количество вторичных //буферов(поверхностей) ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; ddsd.dwBackBufferCount = 1; ddrval = lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL ); if( ddrval != DD_OK ) { lpDD->Release(); return FALSE; } // Теперь получим вторичный буфер (поверхность) ddscaps.dwCaps = DDSCAPS_BACKBUFFER; ddrval = lpDDSPrimary->GetAttachedSurface(&ddscaps, &lpDDSBack); if( ddrval != DD_OK ) { lpDDSPrimary->Release(); lpDD->Release(); return FALSE; } return TRUE; } |
|
Пример кода загрузки изображений в DirectDraw /* * Функция DDLoadBitmap(IDirectDraw *pdd, LPCSTR szBitmap) создает поверхность * и загружает файл с диска. Параметр szBitmap имя файла изображения. */ IDirectDrawSurface * DDLoadBitmap(IDirectDraw *pdd, LPCSTR szBitmap) { HBITMAP hbm; BITMAP bm; IDirectDrawSurface *pdds; // загрузим с диска hbm = (HBITMAP)LoadImage(NULL, szBitmap, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION); if (hbm == NULL) return NULL; GetObject(hbm, sizeof(bm), &bm); // получим размер //создадим поверхность для данного изображения pdds = CreateOffScreenSurface(pdd, bm.bmWidth, bm.bmHeight); if (pdds) { DDCopyBitmap(pdds, hbm, bm.bmWidth, bm.bmHeight); } DeleteObject(hbm); return pdds; } /* * Функция создания поверхности для изображения заданного размера * Эта поверхность окажется в видеопамяти, если ее еще достаточно, * в противном случае - в системной памяти */ IDirectDrawSurface * CreateOffScreenSurface(IDirectDraw *pdd, int dx, int dy) { DDSURFACEDESC ddsd; IDirectDrawSurface *pdds; // // Создание поверхности // ZeroMemory(&ddsd, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH; // имеет значение высота и ширина ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; // это заэкранная поверхность ddsd.dwWidth = dx; ddsd.dwHeight = dy; if (pdd->CreateSurface(&ddsd, &pdds, NULL) != DD_OK) { return NULL; } else { return pdds; } } /* * Функция копирования ранее загруженного изображения в видео поверхность * (Используется обычный GDI интерфейс) * Это, конечно, не самый быстрый способ - но зато надежный * A в данный момент спешить некуда. Если у Вас происходит динамическая подгрузка * изображений в процессе то лучше эту функцию переписать аккуратнее */ HRESULT DDCopyBitmap(IDirectDrawSurface *pdds, HBITMAP hbm, int dx, int dy) { HDC hdcImage; HDC hdc; HRESULT hr; HBITMAP hbmOld; // // привяжем контекст изображения (DC) к загруженному изображению // hdcImage = CreateCompatibleDC(NULL); hbmOld = (HBITMAP)SelectObject(hdcImage, hbm); if ((hr = pdds->GetDC(&hdc)) == DD_OK) { BitBlt(hdc, 0, 0, dx, dy, hdcImage, 0, 0, SRCCOPY); pdds->ReleaseDC(hdc); } SelectObject(hdcImage, hbmOld); DeleteDC(hdcImage); return hr; } |
|
Пример кода создания палитры в DirectDraw /* * Создание палитры DirectDraw для файла загружаемого с диска * параметр szBitmap имя файла */ IDirectDrawPalette * LoadPaletteFromDibFile(IDirectDraw *pdd, LPCSTR szBitmap) { IDirectDrawPalette* ddpal; int i; int n; int fh; PALETTEENTRY ape[256]; if (szBitmap && (fh = _lopen(szBitmap, OF_READ)) != -1) { BITMAPFILEHEADER bf; BITMAPINFOHEADER bi; _lread(fh, &bf, sizeof(bf)); _lread(fh, &bi, sizeof(bi)); _lread(fh, ape, sizeof(ape)); _lclose(fh); if (bi.biSize != sizeof(BITMAPINFOHEADER)) n = 0; else if (bi.biBitCount > 8) n = 0; else if (bi.biClrUsed == 0) n = 1 << bi.biBitCount; else n = bi.biClrUsed; // // цветовая таблица DIB имеет BGR кодировку а не RGB // сделаем необходимую транспозицию. // for(i=0; i<N; (pdd- if } ape[i].peBlue = r; ape[i].peRed = ape[i].peBlue; r = ape[i].peRed; BYTE { ) i++CreatePalette(DDPCAPS_8BIT, ape, &ddpal, NULL) != DD_OK) { return NULL; } else { return ddpal; } } |
|
Пример кода загрузки палитры в DirectDraw ...................... lpDDPal = LoadPaletteFromDibFile(lpDD, szBitmap); // Создадим и Получим указатель на палитру if (lpDDPal) lpDDSPrimary->SetPalette(lpDDPal); // и установим эту палитру для первичной видео поверхности .................... |
|
Пример кода установки прозрачных цветов в DirectDraw // Установим прозрачный цвет для данного изображения . // DDCOLORKEY ddColorKey; ddColorKey.dwColorSpaceLowValue = 0xff; // весь диапазон прозрачности - 255 вход в палитру (обычно он черный) ddColorKey.dwColorSpaceHighValue = 0xff; // Далее необходимо сделать что-то типа для вех поверхностей (изображений ) для которых нужен эффект // прозрачности при выполнении операций копирования [Имя указателя на DirectDraw поверхность]->SetColorKey( DDCKEY_SRCBLT, &ddck ); |
|
Обновления экрана void UpdateScreen( void ) { HRESULT ddrval; RECT mRect; int xpos, ypos; // Выберем весь экран и скопируем на вторичную поверхность изображения фона // если Вы, конечно, его используете SetRect(&mRect, 0, 0, 640, 480); // lpDDBackgraund - здесь поверхность фонового изображения // кстати оно может быт больше экрана - тогда возможно копирование только его части - типа перемещения по карте ddrval = lpDDSBack->BltFast( 0, 0, lpDDBackgraund, &mRect, DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT); if( ddrval != DD_OK ) { // не смогли - вернемся return; } while ([цикл по всем изображениям, которые должны быть перенесены на экран]) { // Получить текущее изображение (указатель lpDDCurrentImage) из списка, массива - чего было задумано, // а также его размера mWidth, mHigh, и местоположения x и y ....................... // после получения указанных параметров SetRect(&mRect, 0, 0,mWidth , mHigh); ddrval = lpDDSBack->BltFast( x, y, lpDDCurrentImage, &mRect, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT ); if( ddrval != DD_OK ) { //не смогли - вернемся return; } } // Теперь все нарисовано - можно поменять экран ddrval = lpDDSPrimary->Flip( NULL, DDFLIP_WAIT ); } |
|
Очистка после себя void finiObjects( void ) { if( lpDD != NULL ) { if( lpDDSPrimary != NULL ) { lpDDSPrimary->Release(); lpDDSPrimary = NULL; } if( lpDDSOne != NULL ) { lpDDSOne->Release(); lpDDSOne = NULL; } if( lpDDPal != NULL ) { lpDDPal->Release(); lpDDPal = NULL; } lpDD->Release(); lpDD = NULL; } |