您的位置:首页 > 移动开发

Chapter 7. Advanced DirectDraw and Bitmapped Graphics

2006-08-07 03:15 295 查看
使用高彩模式

GameInit() 中 内联汇编

_asm
{
CLD                        ; clear direction of copy to forward
MOV EAX, color             ; color goes here
MOV ECX, (SCREEN_WIDTH/2)  ; number of DWORDS goes here
MOV EDI, video_buffer      ; address of line to move data
REP STOSD                  ; send the Pentium X on its way...
} // end asm

Basically, the preceding code implements the following C/C++ loop:
for (DWORD ecx = 0, DWORD *edi = video_buffer;
ecx < (SCREEN_WIDTH/2); ecx++)
edi[ecx] = color;


// this builds a 16 bit color value in 5.5.5 format (1-bit alpha mode)
#define _RGB16BIT555(r,g,b) ((b & 31) + ((g & 31) << 5) + ((r & 31) << 10))

// this builds a 16 bit color value in 5.6.5 format (green dominate mode)
#define _RGB16BIT565(r,g,b) ((b & 31) + ((g & 63) << 5) + ((r & 31) << 11))

// this builds a 32 bit color value in A.8.8.8 format (8-bit alpha mode)
#define _RGB32BIT(a,r,g,b) ((b) + ((g) << 8) + ((r) << 16) + ((a) << 24))

// this macro should be on one line
#define DDRAW_INIT_STRUCT(ddstruct)
{ memset(&ddstruct,0,sizeof(ddstruct));
ddstruct.dwSize=sizeof(ddstruct); }

在一个游戏循环中,基本原则是在进行所有处理操作之前只对表面加锁一次,然后完成操作后再解锁。

将二进制数右移1位相当于出一2,左移一位相当于乘以2。

int lpitch16 = (lpitch >> 1);

inline void Plot_Pixel_Faster16(int x, int y,
int red, int green, int blue,
USHORT *video_buffer, int lpitch16)
{
// this function plots a pixel in 16-bit color mode
// assuming that the caller already locked the surface
// and is sending a pointer and byte pitch to it

// first build up color WORD
USHORT pixel = _RGB16BIT565(red,green,blue);

// write the data
video_buffer[x + y*lpitch16] = pixel;

} // end Plot_Pixel_Faster16

1.Getting the Pixel Format

IDIRECTDRAWSURFACE7:GetPixelFormat()

HRESULT GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat);

DDPIXELFORMAT structure:
DWORD dwSize; // the size of the structure, must be set by you
DWORD dwFlags; // flags describing the surface, refer to Table 7.1
DWORD dwRGBBitCount; // number of bits for Red, Green, and Blue

ValueDescription
DDPF_ALPHA The pixel format describes an alpha-only surface.
DDPF_ALPHAPIXELS The surface has alpha channel information in the pixel format.
DDPF_LUMINANCE The pixel format describes a luminance-only or luminance-alpha surface.
DDPF_PALETTEINDEXED1 The surface is 1-bit color indexed.
DDPF_PALETTEINDEXED2 The surface is 2-bit color indexed.
DDPF_PALETTEINDEXED4 The surface is 4-bit color indexed.
DDPF_PALETTEINDEXED8The surface is 8-bit color indexed. Most common.
DDPF_PALETTEINDEXEDTO8 The surface is 1-, 2-, or 4-bit color indexed to an 8-bit palette.
DDPF_RGB The RGB data in the pixel format structure is valid.
DDPF_ZBUFFER The pixel format describes a z-buffer surface.
DDPF_ZPIXELS The surface contains z information in the pixels
// now perform tests
// check if this is an RGB mode or palettized
if (ddpixel.dwFlags & DDPF_RGB)
{
// RGB mode
// what's the RGB mode
switch(ddpixel.dwRGBBitCount)
{
case 15: // must be 5.5.5 mode
{
// use the _RGB16BIT555(r,g,b) macro
} break;

case 16: // must be 5.6.5 mode
{
// use the _RGB16BIT565(r,g,b) macro
} break;

case 24: // must be 8.8.8 mode
{
} break;

case 32: // must be alpha(8).8.8.8 mode
{
} break;

default: break;

} // end switch

} // end if
else
if (ddpixel.dwFlags & DDPF_PALETTEINDEXED8)
{
// 256 color palettized mode
} // end if
else
{
// something else??? more tests
} // end else

2.24/32位真彩
inline void Plot_Pixel_24(int x, int y,
int red, int green, int blue,
UCHAR *video_buffer, int lpitch)
{
// this function plots a pixel in 24-bit color mode
// assuming that the caller already locked the surface
// and is sending a pointer and byte pitch to it

// in byte or 8-bit math the proper address is: 3*x + y*lpitch
// this is the address of the low order byte which is the Blue channel
// since the data is in RGB order
DWORD pixel_addr = (x+x+x) + y*lpitch;

// write the data, first blue
video_buffer[pixel_addr] = blue;

// now red
video_buffer[pixel_addr+1] = green;

// finally green
video_buffer[pixel_addr+2] = red;

} // end Plot_Pixel_24

inline void Plot_Pixel_32(int x, int y,
int alpha,int red, int green, int blue,
UINT *video_buffer, int lpitch32)
{
// this function plots a pixel in 32-bit color mode
// assuming that the caller already locked the surface
// and is sending a pointer and DWORD aligned pitch to it

// first build up color WORD
UINT pixel = __RGB32BIT(alpha,red,green,blue);

// write the data
video_buffer[x + y*lpitch32] = pixel;

} // end Plot_Pixel_32
3.Surface Dynamics
创建后备缓冲的目的是用DirectDraw的方式实现对双缓冲功能的仿真,通常它在VRAM中,读写会非常快

First, you have to add DDSD_BACKBUFFERCOUNT to the dwFlags flag field to indicate to DirectDraw that the dwBackBufferCount field of the DDSURFACEDESC2 structure will be valid and contain the number of back buffers (one in this case).

Second, you must add the control flags DDSCAPS_COMPLEX and DDSCAPS_FLIP to the capabilities WORD of the DDSURFACEDESC2 structure contained in the ddsCaps.dwCaps field.

Finally, create the primary surface as usual. From it, request the attached back buffer with a call to IDIRECTDRAWSURFACE7::GetAttachedSurface(), shown below, and you're in business.

HRESULT GetAttachedSurface( LPDDSCAPS2 lpDDSCaps,
LPDIRECTDRAWSURFACE7 FAR *lplpDDAttachedSurface );
DDSCAPS2 ddscaps.dwCaps = DDSCAPS_BACKBUFFER;

// assume we already have the directdraw object etc...

DDSURFACEDESC2 ddsd; // directdraw surface description
LPDIRECTDRAWSURFACE7 lpddsprimary = NULL; // primary surface
LPDIRECTDRAWSURFACE7 lpddsback = NULL; // back buffer

// clear ddsd and set size
DDRAW_INIT_STRUCT(ddsd);

// enable valid fields
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;

// set the backbuffer count field to 1
ddsd.dwBackBufferCount = 1;

// request a complex, flippable
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_COMPLEX | DDSCAPS_FLIP;

// create the primary surface
if (FAILED(lpdd->CreateSurface(&ddsd, &lpddsprimary, NULL)))
return(0);

// now query for attached surface from the primary surface

// this line is needed by the call
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;

if (FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps, &lpddsback)))

return(0);

4.Page Flipping

Clear back buffer.

Render scene to back buffer.

Flip primary surface with back buffer surface.

Lock to frame rate (30 fps, for example).

Repeat step 1.

后备缓冲表面总是离屏的,而主表面总是可见的。所以,总是在后备缓冲中进行绘制,并且每frame与主表面做切换
IDIRECTDRAWSURFACE7::Flip()

HRESULT Flip( LPDIRECTDRAWSURFACE7 lpDDSurfaceTargetOverride, // override surface, set it to NULL here
DWORD dwFlags); // control flags

lpDDSurfaceTargetOverride is basically an advanced parameter used to override the flipping chain and flip to another surface other than the back buffer attached to the primary surface; just send NULL here.

三缓冲性能出奇的好, DirectDraw的好处是只需简单调用 Flip(),硬件以循环方式切换表面。不过对用户来说,仍然是只在一个后备缓冲中进行渲染。三缓冲对用户来说是透明的

Typically, you'll set the flags for DDFLIP_WAIT and that's it. Also, you must call Flip() as a method from the primary surface while (FAILED(lpddsprimary->Flip(NULL, DDFLIP_WAIT)));
int Game_Main(void *parms = NULL, int num_parms = 0)
{
// this is the main loop of the game, do all your processing
// here

// make sure this isn't executed again
if (window_closed)
return(0);

// for now test if user is hitting ESC and send WM_CLOSE
if (KEYDOWN(VK_ESCAPE))
{
PostMessage(main_window_handle,WM_CLOSE,0,0);
window_closed = 1;
} // end if

// lock the back buffer
DDRAW_INIT_STRUCT(ddsd);
lpddsback->Lock(NULL,&ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,NULL);

// alias pointer to back buffer surface
UCHAR *back_buffer = (UCHAR *)ddsd.lpSurface;

// now clear the back buffer out

// linear memory?
if (ddsd.lPitch == SCREEN_WIDTH)
memset(back_buffer,0,SCREEN_WIDTH*SCREEN_HEIGHT);
else
{
// non-linear memory

// make copy of video pointer
UCHAR *dest_ptr = back_buffer;

// clear out memory one line at a time
for (int y=0; y<SCREEN_HEIGHT; y++)
{
// clear next line
memset(dest_ptr,0,SCREEN_WIDTH);

// advance pointer to next line
dest_ptr+=ddsd.lPitch;

} // end for y

} // end else

// you would perform game logic...

// draw the next frame into the back buffer, notice that we
// must use the lpitch since it's a surface and may not be linear

// plot 5000 random pixels
for (int index=0; index < 5000; index++)
{
int x = rand()%SCREEN_WIDTH;
int y = rand()%SCREEN_HEIGHT;
UCHAR col = rand()%256;
back_buffer[x+y*ddsd.lPitch] = col;
} // end for index

// unlock the back buffer
if (FAILED(lpddsback->Unlock(NULL)))
return(0);

// perform the flip
while (FAILED(lpddsprimary->Flip(NULL, DDFLIP_WAIT)));

// wait a sec
Sleep(500);

// return success or failure or your own return code here
return(1);

} // end Game_Main

5. 使用Blitter
利用硬件Blitter,可以立即直接填充或者移动大块VRAM和DirectDraw表面.

Blt()内部调用剪裁器,BltFast()在使用HEL时大约比Blt()快10%。所以:需要剪裁的时候用Blt(),不需要是用BltFast()

在将任何一个 RECT 结构发送给DreictDraw函数时,一般它包含左上角,但不包含右下角。

IDIRECTDRAWSURFACE7:: Blt()
IDIRECTDRAWSURFACE7::BltFast(). Their prototypes are shown here:

HRESULT Blt(LPRECT lpDestRect, // dest RECT
LPDIRECTDRAWSURFACE7 lpDDSrcSurface, // dest surface
LPRECT lpSrcRect,  // source RECT
DWORD dwFlags,     // control flags
LPDDBLTFX lpDDBltFx); // special fx (very cool!)

DDBLT_COLORFILL Uses the dwFillColor member of the DDBLTFX structure as the RGB color that fills the destination rectangle on the destination surface.
DDBLT_DDFX Uses the dwDDFX member of the DDBLTFX structure to specify the effects to use for this blit.
DDBLT_DDROPS Uses the dwDDROP member of the DDBLTFX structure to specify the raster operations (ROPs) that are not part of the Win32 API.
DDBLT_DEPTHFILL Uses the dwFillDepth member of the DDBLTFX structure as the depth value with which to fill the destination rectangle on the destination z-buffer surface.
DDBLT_KEYDESTOVERRIDE Uses the ddckDestColorkey member of the DDBLTFX structure as the color key for the destination surface.
DDBLT_KEYSRCOVERRIDE Uses the ddckSrcColorkey member of the DDBLTFX structure as the color key for the source surface.
DDBLT_ROP Uses the dwROP member of the DDBLTFX structure for the ROP for this blit. These ROPs are the same as those defined in the Win32 API.
DDBLT_ROTATIONANGLE
Uses the dwRotationAngle member of the DDBLTFX structure as the rotation angle (specified in 1/100ths of a degree) for the surface. This only works with hardware support. The HEL (Hardware Emulation Layer) can't do rotation梑ummer!
Color Key Flags
DDBLT_KEYDEST Uses the color key associated with the destination surface.
DDBLT_KEYSRC Uses the color key associated with the source surface.
Behavior Flags
DDBLT_ASYNC Performs this blit asynchronously through the FIFO (First In, First Out) in the order received. If no room is available in the FIFO hardware, the call fails. Fast, but risky; error logic is needed to use this flag properly.
DDBLT_WAIT Waits until the blit can be performed and doesn't return the error DDERR_WASSTILLDRAWING if the blitter was busy.
typedef struct _DDBLTFX
{
DWORD dwSize; // the size of this structure in bytes
DWORD dwDDFX; // type of blitter fx
DWORD dwROP; // Win32 raster ops that are supported
DWORD dwDDROP; // DirectDraw raster ops that are supported

DWORD dwRotationAngle; // angle for rotations
DWORD dwZBufferOpCode; // z-buffer fields (advanced)
DWORD dwZBufferLow; // advanced..
DWORD dwZBufferHigh; // advanced..
DWORD dwZBufferBaseDest; // advanced..
DWORD dwZDestConstBitDepth; // advanced..
union
{
DWORD dwZDestConst; // advanced..
LPDIRECTDRAWSURFACE lpDDSZBufferDest; // advanced..
};
DWORD dwZSrcConstBitDepth; // advanced..
union
{
DWORD dwZSrcConst; // advanced..
LPDIRECTDRAWSURFACE lpDDSZBufferSrc; // advanced..
};
DWORD dwAlphaEdgeBlendBitDepth; // alpha stuff (advanced)
DWORD dwAlphaEdgeBlend; // advanced..
DWORD dwReserved; // advanced..
DWORD dwAlphaDestConstBitDepth; // advanced..
union
{
DWORD dwAlphaDestConst; // advanced..
LPDIRECTDRAWSURFACE lpDDSAlphaDest; // advanced..
};
DWORD dwAlphaSrcConstBitDepth; // advanced..
union
{
DWORD dwAlphaSrcConst; // advanced..
LPDIRECTDRAWSURFACE lpDDSAlphaSrc; // advanced..
};
union // these are very important
{
DWORD dwFillColor; // color word used for fill
DWORD dwFillDepth; // z filling (advanced)
DWORD dwFillPixel; // color fill word for RGB(alpha) fills

LPDIRECTDRAWSURFACE lpDDSPattern;
};
// these are very important
DDCOLORKEY ddckDestColorkey; // destination color key
DDCOLORKEY ddckSrcColorkey; // source color key
} DDBLTFX,FAR* LPDDBLTFX;

用Btl()函数填充表面:

Place the color index or RGB-encoded color you want to fill the surface with in the
dwFillColor field of a DDBLTFX structure.

Set up a
RECT structure with the area that you want to fill on your destination surface.

Make a call to Blt() from the destination surface's
IDIRECTDRAWSURFACE7 interface pointer with the control flags DDBLT_COLORFILL | DDBLT_WAIT. This is very important; Blt() and BltFast() are both called from the destination surface's interface, not the source!

ddbltfx.dwFillColor = __RGB16BIT565(0,255,0);

//...

// make the blitter call
if (FAILED(lpddsprimary->Blt(&dest_rect, // pointer to dest RECT
NULL, // pointer to source surface
NULL, // pointer to source RECT
DDBLT_COLORFILL | DDBLT_WAIT,
// do a color fill and wait if you have to
&ddbltfx))) // pointer to DDBLTFX holding info
return(0);

HRESULT BltFast(
DWORD dwX, // x-position of blit on destination
DWORD dwY, // y-position of blit on destination
LPDIRECTDRAWSURFACE7 lpDDSrcSurface, // source surface
LPRECT lpSrcRect, // source RECT to blit from
DWORD dwTrans); // type of transfer

DDBLTFAST_SRCCOLORKEY Specifies a transparent blit that uses the source's color key.
DDBLTFAST_DESTCOLORKEY Specifies a transparent blit that uses the destination's color key.
DDBLTFAST_NOCOLORKEY Specifies a normal copy blit with no transparency. Could be faster on some hardware; definitely faster in HEL.
DDBLTFAST_WAIT Forces the blitter to wait while busy and not send back the DDERR_WASSTILLDRAWING message. BltFast() returns as soon as the blit can be performed, or a serious error occurs.
Copying Bitmaps from Surface to Surface: 源和目标表面可以使同一个,但通常是不同的。后者是多数精灵引擎的基础(在屏幕上到处移动位图)。

lpddsprimary->Flip(NULL, DDFLIP_WAIT);

Warning:

Both the back buffer surface and the primary surface must be unlocked to perform the flip, so make sure you've unlocked them both before trying a call to Flip().
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: