28. februar 2002 - 08:54
#3
DirectDraw eksisterer ikke længere i DirectX (siden 8.0), så med mindre du vil anvende et af de ældre interfaces, er det Direct3D du skal igang med.
Grunden hertil er, at de grafikkort der er på markedet idag faktisk er så hurtige, at man med fordel kan bruge 3D-funktionalitet til at generere 2D-grafik! (Det giver iøvrigt også nogle fordele som fx alpha blend, som de fleste kort understøtter i 3D, men ikke i 2D).
Altså kan du sagtens starte med 2D-grafik (hvis det er det du vil), ved at bruge Direct3D!
Den metode man anvender er mest kendt under navnet "bill boarding" (frit oversat: skiltning).
Tidligere blev metoden fraktisk brugt for at lette grafikken. Du har måske set det i fx Duke Nukem, hvor nogle objekter (skraldespande mv.) ikke var 3D-objekter, men bare en texture der altid vendte mod spilleren, altså den roterede når man gik rundt om den.
Nå, tilbage til DirectX...
DirectX (8.x) har et interface der hedder ID3DXSprite, der netop kan anvendes til 2D-grafik.
Jeg foreslår hele tiden 2D-grafik, det jeg mener det er bedst at starte med. Hvis du har helt styr på 3D-vektorgeometri og matrix-operationer kan du naturligvis gå lige til sagen...
Jeg har sammensat en lille wrapper-class, jeg selv bruger, for at forenkle brugen af 2D grafik. Jeg bruger det mest til menuer, toolbars osv.
Hvis du ønsker det, kan jeg poste den her...
gamedev.net er faktisk et af de bedste steder på nettet til at finde information om emnet, men nVidia har også nogle gode eksempler (af den lidt hårdere type)
http://developer.nvidia.com/view.asp?PAGE=directxOg du kan også finde noget på
http://www.codeproject.com/directx/
28. februar 2002 - 09:33
#7
Sprite.h
#include <D3dx8tex.h>
// Some D3DCOLOR shortcut macros:
#define DRGBA(r,g,b,a) ((D3DCOLOR)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff)))
#define DRGB(r,g,b) ((D3DCOLOR)(((0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff)))
#define GetB(rgb) ((BYTE)(rgb))
#define GetG(rgb) ((BYTE)(((WORD)(rgb)) >> 8))
#define GetR(rgb) ((BYTE)((rgb)>>16))
#define GetA(rgb) ((BYTE)((rgb)>>24))
// Flags Used by DrawRect()
#define DR3DLOOK 0x01
#define DR3DLOOK2 0x02
class CSprite
{
public:
CSprite::CSprite();
HRESULT Create(LPDIRECT3DDEVICE8 pd3dDevice, char* pFilename);
HRESULT InvalidateDeviceObjects();
HRESULT RestoreDeviceObjects(LPDIRECT3DDEVICE8 pd3dDevice);
HRESULT DeleteDeviceObjects();
HRESULT LoadTexture(char *filename);
HRESULT BltSprite(RECT *pDestRect, RECT *pSrcRect, DWORD dwFlags);
HRESULT BltSpriteEx(RECT *pDestRect, RECT *pSrcRect, DWORD dwFlags,
D3DCOLOR modulate = 0xFFFFFFFF, float rotation = 0, POINT *prcenter = NULL);
HRESULT DrawRect(RECT rc, DWORD fillstyle, D3DCOLOR fillcolor, int bordersize,
D3DCOLOR bordercolor, DWORD drflags);
LPDIRECT3DDEVICE8 m_pd3dDevice; // A D3DDevice used for rendering
LPDIRECT3DTEXTURE8 m_pd3dTexture;
LPD3DXSPRITE m_pd3dxSprite;
};
Sprite.cpp
#include "Sprite.h"
#include <ddraw.h>
#include "DXUtil.h"
CSprite::CSprite()
{
m_pd3dDevice = NULL;
m_pd3dTexture = NULL;
m_pd3dxSprite = NULL;
}
HRESULT CSprite::Create(LPDIRECT3DDEVICE8 pd3dDevice, char* pFilename)
{
m_pd3dDevice = pd3dDevice;
LoadTexture(pFilename);
if(FAILED(D3DXCreateSprite(m_pd3dDevice, &m_pd3dxSprite)))
return E_FAIL;
return S_OK;
}
HRESULT CSprite::InvalidateDeviceObjects()
{
SAFE_RELEASE(m_pd3dxSprite);
return S_OK;
}
HRESULT CSprite::RestoreDeviceObjects(LPDIRECT3DDEVICE8 pd3dDevice)
{
m_pd3dDevice = pd3dDevice;
if(FAILED(D3DXCreateSprite(m_pd3dDevice, &m_pd3dxSprite)))
return E_FAIL;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DeleteDeviceObjects()
// Desc: Destroys all device-dependent objects
//-----------------------------------------------------------------------------
HRESULT CSprite::DeleteDeviceObjects()
{
SAFE_RELEASE(m_pd3dTexture);
SAFE_RELEASE(m_pd3dxSprite);
m_pd3dDevice = NULL;
return S_OK;
}
//----------------------------------------------------------------------------
// LoadTexture() : Load a texture from a file, returns ptr to texture.
// D3DX8 supports BMP, PPM, DDS, JPG, PNG, TGA & DIB.
//----------------------------------------------------------------------------
HRESULT CSprite::LoadTexture(char* pFilename)
{
// Set black as our source color key. Use 0xFFFF00FF for magenta instead.
// Use 0x00000000 for no 'color key' substitution
D3DCOLOR colorkey = 0xFF000000;
// The D3DX function will fill in the following image info for us
D3DXIMAGE_INFO SrcInfo; // Optional
// Load image from file - maintain size of original file.
// It is also possible to specify a new height/width and ask D3DX to filter
// the image to the new size (stretch/shrink). See SDK docs for details.
return D3DXCreateTextureFromFileEx(m_pd3dDevice, pFilename, 0, 0, 1, 0,
D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_DEFAULT,
colorkey, &SrcInfo , NULL, &m_pd3dTexture);
}
//----------------------------------------------------------------------------
// BltSprite() : A replacement of the DirectDraw Blt() function for Direct3D8
// Supports DDBLTFX_MIRRORLEFTRIGHT and DDBLTFX_MIRRORUPDOWN
// If pDestRect is NULL, copies it to the same co-ord as src
// If pSrcRect is NULL, copies the entire texture
//----------------------------------------------------------------------------
HRESULT CSprite::BltSprite(RECT *pDestRect, RECT *pSrcRect, DWORD dwFlags)
{
D3DXVECTOR2 scaling(1,1), rcenter(0,0), trans(0,0);
// Set the parameters - translation (screen location)
if (pDestRect)
{
trans.x = (float) pDestRect->left;
trans.y = (float) pDestRect->top;
}
// Scaling - If Source & Destination are different size rects, then scale
if (pDestRect && pSrcRect)
{
scaling.x = ((float) (pDestRect->right - pDestRect->left)) /
((float) (pSrcRect->right - pSrcRect->left));
scaling.y = ((float) (pDestRect->bottom - pDestRect->top)) /
((float) (pSrcRect->bottom - pSrcRect->top));
}
// Handle the flags - need to change scaling & adjust translation
if (pSrcRect && dwFlags)
{
if (dwFlags&DDBLTFX_MIRRORLEFTRIGHT)
{
scaling.x = -scaling.x;
trans.x += (float) (pDestRect->right - pDestRect->left);
}
if (dwFlags&DDBLTFX_MIRRORUPDOWN)
{
scaling.y = -scaling.y;
trans.y += (float) (pDestRect->bottom - pDestRect->top);
}
}
// And here we go:
return m_pd3dxSprite->Draw(m_pd3dTexture, pSrcRect, &scaling,
&rcenter, 0, &trans, 0xFFFFFFFF);
}
//----------------------------------------------------------------------------
// BltSpriteEx() : A replacement of the DirectDraw Blt() function for Direct3D8
// Supports DDBLTFX_MIRRORLEFTRIGHT and DDBLTFX_MIRRORUPDOWN,
// modulate is color/alpha modifier
// rotation is value of rotation in RADIANS, counter-clockwise
// prcenter is the rotation centre point of the obj, or NULL
// If pDestRect is NULL, copies it to the same co-ord as src
// If pSrcRect is NULL, copies the entire texture
//----------------------------------------------------------------------------
HRESULT CSprite::BltSpriteEx(RECT *pDestRect, RECT *pSrcRect, DWORD dwFlags,
D3DCOLOR modulate, float rotation, POINT *prcenter)
{
D3DXVECTOR2 scaling(1,1), rcenter(0,0), trans(0,0);
// Set the parameters - translation (screen location)
if (pDestRect) {
trans.x = (float) pDestRect->left;
trans.y = (float) pDestRect->top;
}
// Rotation Center
if (prcenter) {
rcenter.x = (float) prcenter->x;
rcenter.y = (float) prcenter->y;
} else if (pSrcRect) {
// Set Rotation Center to be object center if none provided
rcenter.x = (float) (pSrcRect->right - pSrcRect->left) / 2;
rcenter.y = (float) (pSrcRect->bottom - pSrcRect->top) / 2;
}
// Scaling - If Source & Destination are different size rects, then scale
if (pDestRect && pSrcRect) {
scaling.x = ((float) (pDestRect->right - pDestRect->left)) /
((float) (pSrcRect->right - pSrcRect->left));
scaling.y = ((float) (pDestRect->bottom - pDestRect->top)) /
((float) (pSrcRect->bottom - pSrcRect->top));
}
// Handle the flags - need to change scaling & adjust translation
if (pSrcRect && dwFlags) {
if (dwFlags&DDBLTFX_MIRRORLEFTRIGHT) {
scaling.x = -scaling.x;
trans.x += (float) (pDestRect->right - pDestRect->left);
}
if (dwFlags&DDBLTFX_MIRRORUPDOWN) {
scaling.y = -scaling.y;
trans.y += (float) (pDestRect->bottom - pDestRect->top);
}
}
// And here we go:
return m_pd3dxSprite->Draw(m_pd3dTexture, pSrcRect, &scaling,
&rcenter, rotation, &trans, modulate);
}
//-----------------------------------------------------------------------------
// DrawRect() : Draws a rect on 'the viewport' using Clear, with some options
// This is not a Microsoft-endorsed use of the Clear command!
// Note that the Alpha values of colors are significant - 0xFF for opaque
// fillstyle: GDI values of BS_SOLID or BS_NULL (hollow)
// bordersize is -ve for internal to rectangle
// drflags are DR3DLOOK or DR3DLOOK2 for embossed shadow button effects
//-----------------------------------------------------------------------------
HRESULT CSprite::DrawRect(RECT rc, DWORD fillstyle, D3DCOLOR fillcolor, int bordersize,
D3DCOLOR bordercolor, DWORD drflags)
{
// Error if not a normal rectangle
if (rc.bottom-rc.top < 1) return DDERR_INVALIDPARAMS;
if (rc.right-rc.left < 1) return DDERR_INVALIDPARAMS;
// First, we do the inside (fill) part
switch (fillstyle) {
case BS_SOLID:
// Fill area is full size of rectangle
m_pd3dDevice->Clear( 1, (D3DRECT *)&rc, D3DCLEAR_TARGET,
fillcolor, 1.0f, 0);
break;
case BS_NULL:
default:
// No fill or unknown, no action
break;
}
// This handles drawing the borders (four sides)
if (bordersize != 0) {
D3DCOLOR topbord=bordercolor, botbord=bordercolor;
RECT brc;
// Adjust for border outside of rect if +ve border size:
if (bordersize > 0) {
rc.left -= bordersize;
rc.right += bordersize;
rc.top -= bordersize;
rc.bottom += bordersize;
bordersize = -bordersize;
}
// Embossed effect flags:
if (drflags & DR3DLOOK) {
topbord = DRGB( (GetR(bordercolor)+255)/2,
(GetG(bordercolor)+255)/2, (GetB(bordercolor)+255)/2 );
botbord = DRGB( (GetR(bordercolor))/2,
(GetG(bordercolor))/2, (GetB(bordercolor))/2 );
} else if (drflags & DR3DLOOK2) {
// Reversed shadow, for 'selected' look
topbord = DRGB( (GetR(bordercolor))/2,
(GetG(bordercolor))/2, (GetB(bordercolor))/2 );
botbord = DRGB( (GetR(bordercolor)+255)/2,
(GetG(bordercolor)+255)/2, (GetB(bordercolor)+255)/2 );
}
// Draw top and left
SetRect(&brc, rc.left, rc.top, rc.right, rc.top - bordersize);
m_pd3dDevice->Clear( 1, (D3DRECT *)&brc, D3DCLEAR_TARGET,
topbord, 1.0f, 0);
SetRect(&brc, rc.left, rc.top, rc.left-bordersize, rc.bottom);
m_pd3dDevice->Clear( 1, (D3DRECT *)&brc, D3DCLEAR_TARGET,
topbord, 1.0f, 0);
// Draw bottom and right
SetRect(&brc, rc.left, rc.bottom+bordersize, rc.right, rc.bottom);
m_pd3dDevice->Clear( 1, (D3DRECT *)&brc, D3DCLEAR_TARGET,
botbord, 1.0f, 0);
SetRect(&brc, rc.right+bordersize, rc.top, rc.right, rc.bottom);
m_pd3dDevice->Clear( 1, (D3DRECT *)&brc, D3DCLEAR_TARGET,
botbord, 1.0f, 0);
}
return S_OK;
}