Ir al contenido

publicidad

Foto

Curso MM: 4 Dibujando gráficos


Este tema ha sido archivado. Esto significa que no puedes responder en este tema.
No hay respuestas en este tema

#1

Escrito 05 agosto 2009 - 21:52

Dibujando gráficos

Desarrollando la clase Bitmap

Vamos a ampliar el motor con una clase para trabajar con Bitmaps.

La idea es desarrollar una clase Bitmap que cargue los bitmaps de archivos y los dibuje en contextos de dispositivo. Así podremos crear objetos Bitmap en los juegos que serán más fáciles de usar. La clase hará lo siguiente: cargar un bitmap de un archivo, cargarlo desde un recurso, crear un bitmap en blanco, dibujar un bitmap en un contexto de dispositivo, obtener el alto y ancho de un bitmap.

Win32 tiene varias estructuras de datos para trabajar con bitmaps. Una de ellas es BITMAPINFOHEADER, que almacena la cabecera del bitmap. Otra es RGBQUAD para almacenar los cuatro componentes de color de 8 bits de un color de 32 bits. Otra es BITMAPINFO_256 que almacena la cabecera y la tabla de colores de un bitmap con 256 colores:

[code:1]struct BITMAPINFO_256
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[256];
};[/code]

Definición de la clase bitmap:

[code:1]class Bitmap
{
protected:
// Member Variables
HBITMAP m_hBitmap;
int m_iWidth, m_iHeight;

// Helper Methods
void Free();

public:
// Constructor(s)/Destructor
Bitmap();
Bitmap(HDC hDC, LPTSTR szFileName);
Bitmap(HDC hDC, UINT uiResID, HINSTANCE hInstance);
Bitmap(HDC hDC, int iWidth, int iHeight, COLORREF crColor =
RGB(0, 0, 0));
virtual ~Bitmap();

// General Methods
BOOL Create(HDC hDC, LPTSTR szFileName);
BOOL Create(HDC hDC, UINT uiResID, HINSTANCE hInstance);
BOOL Create(HDC hDC, int iWidth, int iHeight, COLORREF crColor);
void Draw(HDC hDC, int x, int y);
int GetWidth() { return m_iWidth; };
int GetHeight() { return m_iHeight; };
};[/code]

La variable miembro m_hBitmap almacena el handle al bitmap. Hay tres constructores Bitmap() y cada uno tiene su método Create() asociado. El método Free() es para liberar memoria asociada con el bitmap. El método Draw() dibuja el bitmap en el contexto de dispositivo.

- Primer método para crear el Bitmap: el primer Create() carga un archivo de disco. Empieza llamando a Free() para asegurarnos que los datos del anterior Bitmap se eliminan. Se abre el archivo y se obtiene el handle. Se lee la cabecera y se hacen comprobaciones. Se lee la tabla de colores y luego los datos de la imagen. Hay que señalar el uso de CreateDIBSection() que se usa para obtener un handle a un objeto bitmap GDI de datos brutos de un bitmap.

- El segundo método Create(): hace lo mismo que el anterior pero leyéndolo desde un recurso. Se localiza el recurso en memoria, se carga en memoria y se prepara para poder acceder a su contenido.

- El último crea un bitmap en blanco. Utilizamos una función llamada CreateCompatibleBitmap().

- Dibujando el Bitmap: Draw() acepta un contexto de dispositivo y coordenadas x,y. Usamos la función BitBlt() que dibuja una imagen de un contexto de dispositivo a otro.

Programa de ejemplo

Como hemos añadido cosas habrá que ver todos los archivos (excepto GameEngine.h y .cpp que no han sido modificados).
Para verlo: Bitmap.h , Bitmap.cpp
- SlideShow.h
- SlideShow.cpp <- echar un vistazo al retraso en GameCycle() para hacer que vaya más despacio.
No os importe no entender la clase Bitmap o que os parezca muy complicado. Lo que hace falta es que sepáis trabajar con ella, no que entendáis cómo hace las cosas (aunque si lo estudiáis mejor). Los archivos que tenéis que entender son SlideShow.h y SlideShow.cpp.

Resource.h
[code:1]//-----------------------------------------------------------------
// Slideshow Resource Identifiers
// C++ Header - Resource.h
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// Icons Range : 1000 - 1999
//-----------------------------------------------------------------
#define IDI_SLIDESHOW 1000
#define IDI_SLIDESHOW_SM 1001

//-----------------------------------------------------------------
// Bitmaps Range : 2000 - 2999
//-----------------------------------------------------------------
#define IDB_IMAGE1 2000
#define IDB_IMAGE2 2001
#define IDB_IMAGE3 2002
#define IDB_IMAGE4 2003
#define IDB_IMAGE5 2004
#define IDB_IMAGE6 2005[/code]

Fijaos en que a los iconos los nombra como IDI y están en los rangos 1000-1999 y a los bitmaps los nombra como IDB y con rango 2000-2999.

SlideShow.rc
[code:1]//-----------------------------------------------------------------
// Slideshow Resources
// RC Source - Slideshow.rc
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include "Resource.h"

//-----------------------------------------------------------------
// Icons
//-----------------------------------------------------------------
IDI_SLIDESHOW ICON "Slideshow.ico"
IDI_SLIDESHOW_SM ICON "Slideshow_sm.ico"

//-----------------------------------------------------------------
// Bitmaps
//-----------------------------------------------------------------
IDB_IMAGE4 BITMAP "Image4.bmp"
IDB_IMAGE5 BITMAP "Image5.bmp"
IDB_IMAGE6 BITMAP "Image6.bmp"[/code]


Bitmap.h
[code:1]//-----------------------------------------------------------------
// Bitmap Object
// C++ Header - Bitmap.h
//-----------------------------------------------------------------

#pragma once

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include

//-----------------------------------------------------------------
// Custom Data Types
//-----------------------------------------------------------------
struct BITMAPINFO_256
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[256];
};

//-----------------------------------------------------------------
// Bitmap Class
//-----------------------------------------------------------------
class Bitmap
{
protected:
// Member Variables
HBITMAP m_hBitmap; //el manejador del bitmap.
int m_iWidth, m_iHeight;

// Helper Methods
void Free();

public:
// Constructor(s)/Destructor. Cada uno tiene su función Create() más abajo.
Bitmap();
Bitmap(HDC hDC, LPTSTR szFileName);
Bitmap(HDC hDC, UINT uiResID, HINSTANCE hInstance);
Bitmap(HDC hDC, int iWidth, int iHeight, COLORREF crColor = RGB(0, 0, 0));
virtual ~Bitmap();

// General Methods
BOOL Create(HDC hDC, LPTSTR szFileName);
BOOL Create(HDC hDC, UINT uiResID, HINSTANCE hInstance);
BOOL Create(HDC hDC, int iWidth, int iHeight, COLORREF crColor);
void Draw(HDC hDC, int x, int y);
int GetWidth() { return m_iWidth; };
int GetHeight() { return m_iHeight; };
};[/code]

Bitmap.cpp
[code:1]//-----------------------------------------------------------------
// Bitmap Object
// C++ Source - Bitmap.cpp
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include "Bitmap.h"

//-----------------------------------------------------------------
// Bitmap Constructor(s)/Destructor
//-----------------------------------------------------------------
Bitmap::Bitmap()
: m_hBitmap(NULL), m_iWidth(0), m_iHeight(0)
{
}

// Crear un Bitmap de un archivo.
Bitmap::Bitmap(HDC hDC, LPTSTR szFileName)
: m_hBitmap(NULL), m_iWidth(0), m_iHeight(0)
{
Create(hDC, szFileName);
}

// Crear un Bitmap desde un recurso.
Bitmap::Bitmap(HDC hDC, UINT uiResID, HINSTANCE hInstance)
: m_hBitmap(NULL), m_iWidth(0), m_iHeight(0)
{
Create(hDC, uiResID, hInstance);
}

// Crear un Bitmap en blanco.
Bitmap::Bitmap(HDC hDC, int iWidth, int iHeight, COLORREF crColor)
: m_hBitmap(NULL), m_iWidth(0), m_iHeight(0)
{
Create(hDC, iWidth, iHeight, crColor);
}

Bitmap::~Bitmap()
{
Free();
}

//-----------------------------------------------------------------
// Bitmap Helper Methods
//-----------------------------------------------------------------
void Bitmap::Free()
{
// Borrar el objeto gráfico del bitmap
if (m_hBitmap != NULL)
{
DeleteObject(m_hBitmap);
m_hBitmap = NULL;
}
}

//-----------------------------------------------------------------
// Bitmap General Methods
//-----------------------------------------------------------------
BOOL Bitmap::Create(HDC hDC, LPTSTR szFileName)
{
// Eliminar cualquier información del Bitmap anterior.
Free();

// Abrir el archivo del Bitmap.
HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;

// Leer la cabecera del archivo del Bitmap.
BITMAPFILEHEADER bmfHeader;
DWORD dwBytesRead;
BOOL bOK = ReadFile(hFile, &bmfHeader, sizeof(BITMAPFILEHEADER),
&dwBytesRead, NULL);
if ((!bOK) || (dwBytesRead != sizeof(BITMAPFILEHEADER)) ||
(bmfHeader.bfType != 0x4D42))
{
CloseHandle(hFile);
return FALSE;
}

BITMAPINFO* pBitmapInfo = (BITMAPINFO*)(new BITMAPINFO_256);
if (pBitmapInfo != NULL)
{
// Leer la cabecera de información del Bitmap.
bOK = ReadFile(hFile, pBitmapInfo, sizeof(BITMAPINFOHEADER),
&dwBytesRead, NULL);
if ((!bOK) || (dwBytesRead != sizeof(BITMAPINFOHEADER)))
{
CloseHandle(hFile);
Free();
return FALSE;
}

// Guardar el ancho y alto del Bitmap.
m_iWidth = (int)pBitmapInfo->bmiHeader.biWidth;
m_iHeight = (int)pBitmapInfo->bmiHeader.biHeight;

// Saltar (adelante o atrás) a la información del color, si es necesario.
if (pBitmapInfo->bmiHeader.biSize != sizeof(BITMAPINFOHEADER))
SetFilePointer(hFile, pBitmapInfo->bmiHeader.biSize - sizeof
(BITMAPINFOHEADER), NULL, FILE_CURRENT);

// Leer la información del color.
bOK = ReadFile(hFile, pBitmapInfo->bmiColors,
pBitmapInfo->bmiHeader.biClrUsed * sizeof(RGBQUAD), &dwBytesRead,
NULL);

// Obtener un handle al Bitmap y copiar los bits de la imagen.
PBYTE pBitmapBits;
m_hBitmap = CreateDIBSection(hDC, pBitmapInfo, DIB_RGB_COLORS,
(PVOID*)&pBitmapBits, NULL, 0);
if ((m_hBitmap != NULL) && (pBitmapBits != NULL))
{
SetFilePointer(hFile, bmfHeader.bfOffBits, NULL, FILE_BEGIN);
bOK = ReadFile(hFile, pBitmapBits, pBitmapInfo->bmiHeader.biSizeImage,
&dwBytesRead, NULL);
if (bOK)
return TRUE;
}
}

// Si llegamos aquí algo fue mal, así que borramos todo.
Free();
return FALSE;
}

BOOL Bitmap::Create(HDC hDC, UINT uiResID, HINSTANCE hInstance)
{
// Liberar cualquier información anterior del DIB (una imagen)
Free();

// Encontrar el recurso del Bitmap.
HRSRC hResInfo = FindResource(hInstance, MAKEINTRESOURCE(uiResID), RT_BITMAP);
if (hResInfo == NULL)
return FALSE;

// Cargar el recurso del Bitmap.
HGLOBAL hMemBitmap = LoadResource(hInstance, hResInfo);
if (hMemBitmap == NULL)
return FALSE;

// bloquear el recurso y acceder a la imagen completa.
PBYTE pBitmapImage = (BYTE*)LockResource(hMemBitmap);
if (pBitmapImage == NULL)
{
FreeResource(hMemBitmap);
return FALSE;
}

// Almacenar el alto y ancho del bitmap.
BITMAPINFO* pBitmapInfo = (BITMAPINFO*)pBitmapImage;
m_iWidth = (int)pBitmapInfo->bmiHeader.biWidth;
m_iHeight = (int)pBitmapInfo->bmiHeader.biHeight;

// Obtener un handle al Bitmap y copiar los bits de la imagen.
PBYTE pBitmapBits;
m_hBitmap = CreateDIBSection(hDC, pBitmapInfo, DIB_RGB_COLORS,
(PVOID*)&pBitmapBits, NULL, 0);
if ((m_hBitmap != NULL) && (pBitmapBits != NULL))
{
const PBYTE pTempBits = pBitmapImage + pBitmapInfo->bmiHeader.biSize +
pBitmapInfo->bmiHeader.biClrUsed * sizeof(RGBQUAD);
CopyMemory(pBitmapBits, pTempBits, pBitmapInfo->bmiHeader.biSizeImage);

// Desbloquear y liberar el objeto gráfico del Bitmap.
UnlockResource(hMemBitmap);
FreeResource(hMemBitmap);
return TRUE;
}

// Si hemos llegado hasta aquí algo fue mal, así que limpiamos todo.
UnlockResource(hMemBitmap);
FreeResource(hMemBitmap);
Free();
return FALSE;
}

BOOL Bitmap::Create(HDC hDC, int iWidth, int iHeight, COLORREF crColor)
{
// Crear un bitmap en blanco.
m_hBitmap = CreateCompatibleBitmap(hDC, iWidth, iHeight);
if (m_hBitmap == NULL)
return FALSE;

// guardar el alto y ancho.
m_iWidth = iWidth;
m_iHeight = iHeight;

// Crear un contexto de dispositivo en memoria para dibujar en él el bitmap.
HDC hMemDC = CreateCompatibleDC(hDC);

// crear un pincel sólido para rellenar el bitmap.
HBRUSH hBrush = CreateSolidBrush(crColor);

// Seleccionar el bitmap en el contexto de dispositivo.
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, m_hBitmap);

// Rellenar el bitmap con un color sólido.
RECT rcBitmap = { 0, 0, m_iWidth, m_iHeight };
FillRect(hMemDC, &rcBitmap, hBrush);

// Limpiar.
SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
DeleteObject(hBrush);

return TRUE;
}

void Bitmap::Draw(HDC hDC, int x, int y)
{
if (m_hBitmap != NULL)
{
// Crear un contexto de dispositivo en memoria para el Bitmap.
HDC hMemDC = CreateCompatibleDC(hDC);

// Seleccionar el bitmap en el contexto de dispositivo.
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, m_hBitmap);

// Dibujar el bitmap en el contexto de dispositivo de destino.
BitBlt(hDC, x, y, GetWidth(), GetHeight(), hMemDC, 0, 0, SRCCOPY);

// Restaurar el contexto de dispositivo y borrarlo.
SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
}
}[/code]

SlideShow.h
[code:1]//-----------------------------------------------------------------
// Slideshow Application
// C++ Header - Slideshow.h
//-----------------------------------------------------------------

#pragma once

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include
#include "Resource.h"
#include "GameEngine.h"
#include "Bitmap.h"

//-----------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------
HINSTANCE _hInstance; //el manejador (handle) de la instancia.
GameEngine* _pGame; //puntero al motor.
const int _iNUMSLIDES = 7; //número de imágenes.
Bitmap* _pSlides[_iNUMSLIDES]; //punteros a cada imagen.
int _iCurSlide; //índice de la imágen actual.[/code]

SlideShow.cpp
[code:1]//-----------------------------------------------------------------
// Slideshow Application
// C++ Source - Slideshow.cpp
//-----------------------------------------------------------------

//-----------------------------------------------------------------
// Include Files
//-----------------------------------------------------------------
#include "Slideshow.h"

//-----------------------------------------------------------------
// Game Engine Functions
//-----------------------------------------------------------------
BOOL GameInitialize(HINSTANCE hInstance)
{
// Create the game engine
_pGame = new GameEngine(hInstance, TEXT("Slideshow"),
TEXT("Slideshow"), IDI_SLIDESHOW, IDI_SLIDESHOW_SM);
if (_pGame == NULL)
return FALSE;

// Set the frame rate
_pGame->SetFrameRate(1);

// Store the instance handle
_hInstance = hInstance;

return TRUE;
}

void GameStart(HWND hWindow)
{
// Crear y cargar los bitmaps. Los ponemos en una tabla.
// 3 se cargan desde archivos.
// 3 se obtienen de los recursos y otro es un bitmap en blanco.
HDC hDC = GetDC(hWindow);
_pSlides[0] = new Bitmap(hDC, TEXT("Image1.bmp"));
_pSlides[1] = new Bitmap(hDC, TEXT("Image2.bmp"));
_pSlides[2] = new Bitmap(hDC, TEXT("Image3.bmp"));
_pSlides[3] = new Bitmap(hDC, IDB_IMAGE4, _hInstance);
_pSlides[4] = new Bitmap(hDC, IDB_IMAGE5, _hInstance);
_pSlides[5] = new Bitmap(hDC, IDB_IMAGE6, _hInstance);
_pSlides[6] = new Bitmap(hDC, 640, 480, RGB(128, 128, 64));

// Apuntamos el índice al primero.
_iCurSlide = 0;
}

void GameEnd()
{
// Eliminamos los bitmaps de la tabla.
for (int i = 0; i < _iNUMSLIDES; i++)
delete _pSlides[i];

// eliminamos el motor del juego.
delete _pGame;
}

void GameActivate(HWND hWindow)
{
}

void GameDeactivate(HWND hWindow)
{
}

void GamePaint(HDC hDC)
{
// Dibujamos el bitmap al que apunta el índice.
// Lo hacemos en la ventana del juego y en la posición 0,0.
_pSlides[_iCurSlide]->Draw(hDC, 0, 0);
}

void GameCycle()
{
static int iDelay = 0;

// Establecemos un retraso de 3 segundos antes de ir a la siguiente imagen.
if (++iDelay > 3)
{
// Si el retraso es 3 lo volvemos a poner a 0.
iDelay = 0;

// Apuntamos al siguiente bitmap de la tabla o al primero si estamos en el último.
if (++_iCurSlide == _iNUMSLIDES)
_iCurSlide = 0;

// forzamos un redibujado de la ventana para que se muestre la siguiente imagen.
InvalidateRect(_pGame->GetWindow(), NULL, FALSE);
}
}[/code]

Código fuente

Recordad que ahora hay que añadir al proyecto los siguientes archivos: bitmap.cpp, gameengine.cpp, resource.h, slideshow.cpp y slideshow.rc


Este tema ha sido archivado. Esto significa que no puedes responder en este tema.
publicidad