// Программирование c использованием DirectDraw в среде C++ Builder // Автор Мальшаков Григорий Викторович, 2007 г. // www.malshakov.ru // Данный библиотечный файл позволяет упростить процесс программирования с использованием DirectDraw // Он содержит всего три элемента: картинку, персонаж и поверхность - что является достаточным для работы с графикой // При создании поверхности дополнительно необходимо передать адрес формы и панели для местоуказания вывода изображения // Используемые в программе .bmp изображения должны находится в текущей папке exe файла программы // Белый цвет в .bmp файлах, выступает в качестве прозрачного цвета // Чтобы все работало дополнительно необходимо добавить в проект файл ddraw.lib // [Project] -> [Add to Project ...] -> (C:\Program Files\Borland\CBuilder6\Lib\Psdk\ddraw.lib) -> ОК #include "ddraw.h" // Прототипы структур и классов class Surface; // Структура для хранения одного изображения персонажа struct Bmp{ AnsiString File; // картинки (кадры) int Width; // ширина int Height; // высота LPDIRECTDRAWSURFACE surf; // поверхности для каждой картинки LPDIRECTDRAWSURFACE back_surf; // задняя поверхности (фон) для каждой картинки }; // Класс для хранения персонажа (Character) class Character{ private: AnsiString StrBmp; // StrBmp - строка bmp файлов персонажа, разделенных пробелами Bmp _Bmp[20]; // картинки (кадры) int QuantityBmp; // Количество картинок (кадров) bool Put; // Выведена ли данный персонаж на экран, или нет ? bool Delete; // Удаленная или нет friend class Surface; public: int x, y; // координаты персонажа на экране int NumBmp; // № используемого bmp файла в текущий момент (№ активного изображения) int Number; // Порядковый номер вывода данного изображения - начинается с 1 - если нумерация одинаковая, то в порядке очереди bool Visible; // Видимость на экране: при true будет выводится на поверхность bool Transparent; // Прозрачность: true - да, false - нет (белый цвет на картинке становится прозрачным) Character(AnsiString _StrBmp) { StrBmp = _StrBmp; // Сохраняем строку с изображениями при создании персонажа Put = x = y = NumBmp = Number = QuantityBmp = 0; Visible = true; // видимая изначально Delete = false; // не удаленная Transparent = true; // прозрачный по умолчанию } }; // Поверхность на экране (куда все выводится) class Surface { private: TForm *SurfaceForm; TPanel *SurfacePanel; // Путь к EXE файлу программы AnsiString ExePath; Character *_Character[100]; int QuantityCharacter; // количество картинок на экране // Глобальные переменные long ScreenWidth, ScreenHeight; // Разрешение экрана long DisplayDepth; // Глубина пикселей // Поверхности LPDIRECTDRAWSURFACE primsurf; // Первичная поверхность LPDIRECTDRAWCLIPPER clipper; // Отсечение LPDIRECTDRAWSURFACE backsurf; // Вторичная поверхность (промежуточная буферная) // Интерфейс для взаимодействия с DirectDraw LPDIRECTDRAW idraw; //Интерфейс DirectDraw // Загрузка BMP картинки на поверхность void LoadBMPToSurface(Bmp *); // Формирование фона картинки void Set_back_surf(Bmp *); public: // Инициализация поверхности экрана (TForm * - указатель форму, TPanel * - указатель на панель) Surface(TForm *, TPanel *); // Закрытие (сворачивание) Direct-а ~Surface(); // Добавление персонажа на поверхность void AddCharacter(Character *p); // Удаление персонажа с поверхности void DelCharacter(Character *p); // Обновление поверхности экрана (еe перерисовка) void Update(void); // Смещение выводимой поверхности }; // Инициализация поверхности экрана (TForm *SurForm - указатель форму, TPanel *SurPanel - указатель на панель) Surface::Surface(TForm *SurForm, TPanel *SurPanel){ // Сохраняем местоположение формы и панели SurfaceForm = SurForm; SurfacePanel = SurPanel; // Определяем путь к текущему EXE файлу ExePath = ExtractFilePath(Application->ExeName); // Количество персонажей QuantityCharacter = 0; DDSURFACEDESC desc; // Дескриптор рабочего окна HWND MyHWnd; MyHWnd = SurfacePanel->Handle; LPDIRECTDRAW lpDD; // указатель на объект DirectDraw if(DirectDrawCreate( NULL, &lpDD, NULL )!= DD_OK) {Application->MessageBox("DirectDrawCreate","Ошибка",MB_OK); throw false;} // Получаем интерфейс для доступа к DirectDraw lpDD->QueryInterface(IID_IDirectDraw2, (void**)&idraw); lpDD->Release(), lpDD=0; // Устанавливаем уровень доступа к экрану (DDSCL_NORMAL - нормальный режим) // Первый параметр дескриптор главного окна приложения if (idraw->SetCooperativeLevel(MyHWnd, DDSCL_NORMAL)!= DD_OK) {Application->MessageBox("SetCooperativeLevel","Ошибка",MB_OK); throw false;} //Определение текущего режима монитора, инициализация переменных нач. ZeroMemory(&desc, sizeof(desc)); // обнуляем переменную desc desc.dwSize=sizeof(desc); // записываем корректный размер структуры // Определяем режим работы дисплея if (idraw->GetDisplayMode(&desc)!= DD_OK) {Application->MessageBox("GetDisplayMode","Ошибка",MB_OK); throw false;} // Разрешение экрана ScreenWidth =desc.dwWidth; // Ширина ScreenHeight =desc.dwHeight; // Высота // Глубина пикселей DisplayDepth = desc.ddpfPixelFormat.dwRGBBitCount; //Определение текущего режима монитора, инициализация переменных кон. // Создание поверхностей *************************** нач. // Создание первичной поверхности ZeroMemory(&desc, sizeof(desc)); // Обнуляем desc desc.dwSize = sizeof( desc ); // записываем ее величину desc.dwFlags = DDSD_CAPS; // в структуре находятся свойства поверхности desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; desc.ddpfPixelFormat.dwFlags = DDPF_RGB; if (idraw->CreateSurface( &desc, &primsurf, 0 )!= DD_OK) // Создаем главную поверхность {Application->MessageBox("FAILED to create 'primsurf'\n","Ошибка",MB_OK); throw false;} // Создание объекта отсечения - для ограничения области вывода приложения - областью главного окна if (idraw->CreateClipper( 0, &clipper, 0 )!= DD_OK) {Application->MessageBox("CreateClipper() failed\n","Ошибка",MB_OK); throw false;} if (clipper->SetHWnd( 0, MyHWnd )!= DD_OK) {Application->MessageBox("SetHWnd() failed\n","Ошибка",MB_OK); throw false;} if(primsurf->SetClipper(clipper) != DD_OK) // Устанавливаем объект отсечеия на первую поверхность {Application->MessageBox("primsurf->SetClipper() failed\n","Ошибка",MB_OK); throw false;} // Создание вторичной поверхности DDSURFACEDESC surdesc; ZeroMemory(&surdesc, sizeof(surdesc)); // Обнуляем desc surdesc.dwSize = sizeof( surdesc ); // записываем ее величину surdesc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; // в структуре находятся свойства поверхности surdesc.dwWidth = SurfacePanel->Width; surdesc.dwHeight = SurfacePanel->Height; surdesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; // Создание поверхности if (idraw->CreateSurface( &surdesc, &backsurf, 0 )!= DD_OK) {Application->MessageBox("FAILED to create backsurf\n","Ошибка",MB_OK);} // Создание поверхностей *************************** кон. } // Освобождение ресурсов Surface::~Surface(void){ // Уничтожаем поверхности всех картинок int ii, jj; for(ii=0; iiQuantityBmp; ++jj){ if (_Character[ii]->_Bmp[jj].surf) {_Character[ii]->_Bmp[jj].surf->Release();_Character[ii]->_Bmp[jj].surf=0;} if (_Character[ii]->_Bmp[jj].back_surf) {_Character[ii]->_Bmp[jj].back_surf->Release();_Character[ii]->_Bmp[jj].back_surf=0;} } } // Удаляем вторичную поверхность if (backsurf) {backsurf->Release();backsurf=0;} // Удаляем первичную поверхность if (primsurf) {primsurf->Release();primsurf=0;} // Удаляем интерфейс для взаимодействия с DirectDraw if (idraw) {idraw->Release();idraw=0;} } // Загрузка картинки на поверхность ************************************** void Surface::LoadBMPToSurface(Bmp *img){ //LPDIRECTDRAWSURFACE surf; HANDLE hBmp; BITMAP bm; char FileBmp[150]; int ii; for (ii=0;iiFile.Length();++ii){ FileBmp[ii] = img->File[ii+1]; } FileBmp[ii] = 0; // Загрузка картинки из файла hBmp = LoadImage(0, FileBmp, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); GetObject (hBmp, sizeof(bm), &bm); // Подготавливаем структуру для создания поверхности DDSURFACEDESC desc; ZeroMemory(&desc, sizeof(desc)); // Обнуляем desc desc.dwSize = sizeof( desc ); // записываем ее величину desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; // в структуре находятся свойства поверхности img->Width = desc.dwWidth = bm.bmWidth; img->Height = desc.dwHeight = bm.bmHeight; desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; // Создание поверхности if (idraw->CreateSurface( &desc, &(img->surf), 0 )!= DD_OK) {Application->MessageBox("FAILED to create bmpsurf\n","Ошибка",MB_OK);} if (idraw->CreateSurface( &desc, &(img->back_surf), 0 )!= DD_OK) {Application->MessageBox("FAILED to create bmp_back_surf\n","Ошибка",MB_OK);} // Копирование содержимого картинки на поверхность HDC hdcImage; hdcImage = CreateCompatibleDC(0); SelectObject(hdcImage, hBmp); HDC hdc; img->surf->GetDC(&hdc); StretchBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcImage, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); img->surf->ReleaseDC(hdc); // Копируем картинку на фоновую область img->back_surf->GetDC(&hdc); StretchBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcImage, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); img->back_surf->ReleaseDC(hdc); DeleteDC(hdcImage); DeleteObject(hBmp); // Устанавливаем фоновую поверхность Set_back_surf(img); } // Формирование фона картинки void Surface::Set_back_surf(Bmp *img){ // Получаем HDC фоновой поверхности HDC back_surf_HDC; // HDC вторичной повехности img->back_surf->GetDC(&back_surf_HDC); COLORREF Pixel; //Преобразование 1 в FFFFFFFF, не 1 в 0 int nXPos, nYPos; for (nXPos=0; nXPosWidth; ++nXPos){ for (nYPos=0; nYPosHeight; ++nYPos){ Pixel = GetPixel(back_surf_HDC,nXPos,nYPos); // 16777215 - белый цвет if (Pixel==16777215) Pixel=0; else Pixel=16777215; SetPixel(back_surf_HDC,nXPos,nYPos,Pixel); } } // Освобождаем HDC поверхности img->back_surf->ReleaseDC(back_surf_HDC); } // Добавление персонажа на поверхность void Surface::AddCharacter(Character *p){ // Загружаем изображения персонажа (в память - на поверхности) // Раскладываем строку на названия файлов int ii=1, len; len = p->StrBmp.Length(); AnsiString prom = ""; while(ii<=len){ if (p->StrBmp[ii]==' '){ if (prom.Length()>0){ // Загрузка изображения-кадра на поверхность p->_Bmp[p->QuantityBmp].File = ExePath + prom; LoadBMPToSurface(&(p->_Bmp[p->QuantityBmp])); if (p->_Bmp[p->QuantityBmp].surf!=NULL){ // Сохраняем кадр в массиве p->_Bmp[p->QuantityBmp].File = prom; ++(p->QuantityBmp); prom = ""; } } } else { prom += p->StrBmp[ii]; } ++ii; } // выбираем последнее слово if (prom.Length()>0){ // Загрузка изображения-кадра на поверхность p->_Bmp[p->QuantityBmp].File = ExePath + prom; LoadBMPToSurface(&(p->_Bmp[p->QuantityBmp])); if (p->_Bmp[p->QuantityBmp].surf!=NULL){ // Сохраняем кадр в массиве p->_Bmp[p->QuantityBmp].File = prom; ++(p->QuantityBmp); prom = ""; } } _Character[QuantityCharacter] = p; ++QuantityCharacter; } // Удаление персонажа с поверхности void Surface::DelCharacter(Character *p){ p->Delete = true; } // Обновление поверхности экрана (его перерисовка) void Surface::Update(void) { int ii; HDC backsurf_HDC; // HDC вторичной повехности HDC hdcImage; // HDC копируемого изображения HDC hdcBackImage; // HDC фона копируемого изображения // Получаем HDC вторичной поверхности backsurf->GetDC(&backsurf_HDC); // Подготавливаем вторичную поверхность (делаем ее белой) BitBlt(backsurf_HDC, 0, 0, SurfacePanel->Width, SurfacePanel->Height, 0, 0, 0, WHITENESS); // Переносим всех персонажей на вторичную поверхность for (ii=0;iiDelete==false && _Character[ii]->Visible==true){ // *********** ПЕРЕНОСИМ ФОН *********************************************** // Определяем HDC поверхности картинки _Character[ii]->_Bmp[_Character[ii]->NumBmp].back_surf->GetDC(&hdcBackImage); // Переносим изображение картинки BitBlt(backsurf_HDC, _Character[ii]->x, _Character[ii]->y, _Character[ii]->_Bmp[_Character[ii]->NumBmp].Width, _Character[ii]->_Bmp[_Character[ii]->NumBmp].Height, hdcBackImage, 0, 0, SRCPAINT); // Освобождаем HDC поверхности картинки _Character[ii]->_Bmp[_Character[ii]->NumBmp].back_surf->ReleaseDC(hdcBackImage); // *********** ПЕРЕНОСИМ КАРТИНКУ ****************************************** // Определяем HDC поверхности картинки _Character[ii]->_Bmp[_Character[ii]->NumBmp].surf->GetDC(&hdcImage); // Переносим изображение картинки if (_Character[ii]->Transparent) { BitBlt(backsurf_HDC, _Character[ii]->x, _Character[ii]->y, _Character[ii]->_Bmp[_Character[ii]->NumBmp].Width, _Character[ii]->_Bmp[_Character[ii]->NumBmp].Height, hdcImage, 0, 0, SRCAND); } else { BitBlt(backsurf_HDC, _Character[ii]->x, _Character[ii]->y, _Character[ii]->_Bmp[_Character[ii]->NumBmp].Width, _Character[ii]->_Bmp[_Character[ii]->NumBmp].Height, hdcImage, 0, 0, SRCCOPY); } // Освобождаем HDC поверхности картинки _Character[ii]->_Bmp[_Character[ii]->NumBmp].surf->ReleaseDC(hdcImage); } } // Освобождаем HDC вторичной поверхности backsurf->ReleaseDC(backsurf_HDC); // Переносим изображение со вторичной поверхности на первичную RECT dst; dst.left = 0 + SurfaceForm->Left + SurfacePanel->Left + 5; dst.top = 0 + SurfaceForm->Top + SurfacePanel->Top + 24; dst.right = dst.left + SurfacePanel->Width; dst.bottom = dst.top + SurfacePanel->Height; primsurf->Blt( &dst, backsurf, 0, DDBLT_WAIT , 0 ); }