Delphi Graphics and Game Programming Exposed! with DirectX For versions 5.0-7.0:Sprite Techniques
Search Tips
Advanced Search
Title
Author
Publisher
ISBN
Please Select
-----------
Artificial Intel
Business & Mgmt
Components
Content Mgmt
Certification
Databases
Enterprise Mgmt
Fun/Games
Groupware
Hardware
IBM Redbooks
Intranet Dev
Middleware
Multimedia
Networks
OS
Productivity Apps
Programming Langs
Security
Soft Engineering
UI
Web Services
Webmaster
Y2K
-----------
New Arrivals
Delphi Graphics and Game Programming Exposed with DirectX 7.0
by John Ayres
Wordware Publishing, Inc.
ISBN: 1556226373 Pub Date: 12/01/99
Search this book:
Previous
Table of Contents
Next
Pixel Checking
A somewhat more direct way of implementing transparency, this method draws the sprite image one pixel at a time. As it is drawing individual pixels, it checks the pixel it will be drawing to see if its color matches the specified transparent color. If so, it skips drawing that pixel entirely; otherwise it draws the pixel into the destination.
Implementing this method is a bit more involved than color keying. By its very nature, it is pointer intensive and requires some creative pointer manipulation. It also requires more intimate knowledge of the pixel format of both the source and destination surfaces. It is slower than color keying, but through clever optimization can be as fast as non-hardware assisted color keying. However, the biggest benefit that a developer will see from this method is that it allows the creation of incredible special effects, such as lighting and translucency.
Locking a Surface
This method requires direct access to the memory that contains both the source bitmap and the destination, which is usually the backbuffer surface. Using normal GDI functions, this would be impossible. This is one of the things that makes DirectDraw so attractive to game developers.
To retrieve a pointer to surface memory, we must use the Lock method of the IDirectDrawSurface4 object. Using this method, we can access the entire surface memory or provide the coordinates for accessing only a specific rectangular area of the memory. The Lock method is defined as:
function Lock (
lpDestRect: PRect; // the surface region to lock
out lpDDSurfaceDesc: TDDSurfaceDesc2; // a TDDSurfaceDesc2 structure
dwFlags: DWORD; // indicates locking behavior
hEvent: THandle // unused
): HResult; // returns a DirectX error code
The first parameter indicates the rectangular area of the surface to lock; specifying nil in this parameter locks the entire surface. The second parameter is a TDDSurfaceDesc2 structure that will be initialized with relevant details about the surface. In particular, the lpSurface member of this structure will contain a pointer to the upper left pixel of the surface memory. Other members of this structure will contain additional information about the surface, such as its height, width, and stride. The third parameter is a series of flags controlling access to the locked memory, such as read-only or write-only. The final parameter is unused and should be set to zero.
As an example, the code for retrieving a pointer to our backbuffer memory would look something like:
var
BackSurfaceDesc: TDDSurfaceDesc2;
begin
{initialize the size member}
BackSurfaceDesc.dwSize := SizeOf(TDDSurfaceDesc2);
{lock the backbuffer memory}
FBackBuffer.Lock(nil,BackSurfaceDesc,DDLOCK_WAIT or DDLOCK_SURFACEMEMORYPTR,0)
Note: It is very important to always set the size member of any record structure that has one before using it in any function call.
As with all DirectX functions, it is usually a good practice to check the return code from a call to the Lock method. The DDLOCK_WAIT flag will cause the Lock method to wait until the surface is available and no longer being accessed by the hardware blitter. However, if the surface is locked by another thread or process, this function will return immediately with a DDERR_SURFACEBUSY error regardless of the DDLOCK_WAIT flag.
Accessing the Memory
When the Lock method returns, the lpSurface member of the TDDSurfaceDesc2 structure will contain a pointer to the surface memory. Exactly how this is used depends entirely on the pixel format of the surface. Since all of our examples deal with 256-color palettized display modes, pixels will be stored as bytes. Therefore, if we typecast the lpSurface member as a pointer to a byte, writing a value at the location reference by this pointer will change one byte on the surface, and thus one pixel in the image the surface contains.
In practice, it is useful to access this pointer as a pointer to an array of bytes. This allows us to access horizontal bytes as if they were stored in a one-dimensional array. Although perhaps not immediately obvious, the process is simple. Well need to create a new data type that is declared as an array of byte with only one element, and another data type that is a pointer to this previous type, like so:
TBytePtr = array[0..0] of Byte;
PBytePtr = ^TBytePtr;
Then, if we set a variable of type PBytePtr to the value of the lpSurface member, we can easily reference the surface memory as an array of bytes:
var
BackMem: PBytePtr;
begin
BackMem := PBytePtr(BackSurfaceDesc.lpSurface);
Drawing the Sprite
We must lock both the backbuffer surface and the surface containing the sprite images. Once this is done, we iterate through each row of the sprite, and each pixel in the row. For each pixel in the current row being drawn, we check to see if it is equal to the specified transparent color. If it is not, we go ahead and set the appropriate pixel in the destination memory to the value of the pixel being checked. If it is indeed equal to the transparent color, we simply move on to the next pixel in the row. The following example demonstrates an implementation of this technique.
Listing 6-4: Drawing a sprite with transparent pixels
procedure TfrmDXAppMain.DrawSurfaces;
var
SourceRect: TRect
BackSurfaceDesc,
SpriteSurfaceDesc: TDDSurfaceDesc2;
BackMem, SpriteMem: PBytePtr;
Row, Col: Integer;
begin
{erase the last frame of animation}
SourceRect := Rect(0, 0, DXWIDTH, DXHEIGHT);
FBackBuffer.BltFast(0, 0, FBackground, SourceRect,
DDBLTFAST_NOCOLORKEY OR DDBLTFAST_WAIT);
{increment the frame number and update the sprites position}
with FSprite do
begin
Inc(FCurFrame);
{rollover the frame number as necessary}
if FCurFrame > FFrameNum then
FCurFrame := 0;
{add the velocities to the positions. our sprite will only move
horizontally, so we do not need to bother with the vertical values}
FXPos := FXPos + FXVel;
{see if the sprite is moving offscreen, and adjust
its position accordingly}
if FXPos < 0 then
FXPos := DXWIDTH - 90;
{begin blitting the current frame}
{we need to lock both the backbuffer surface and the sprite image
surface, so begin by locking the backbuffer}
BackSurfaceDesc.dwSize := SizeOf(TDDSurfaceDesc2);
{we re going to lock the entire surface}
DXCheck(FBackBuffer.Lock(nil, BackSurfaceDesc,
DDLOCK_WAIT or DDLOCK_SURFACEMEMORYPTR, 0));
{initialize the byte array pointer to point at the locked memory}
BackMem := PBytePtr(BackSurfaceDesc.lpSurface);
{increment this pointer to the position in the buffer at which the
sprite should be displayed (based on the sprites position)}
BackMem := Pointer(Longint(BackMem)+FXPos+(FYPos*BackSurfaceDesc.lPitch));
{now, lock the sprite surface}
SpriteSurfaceDesc.dwSize := SizeOf(TDDSurfaceDesc2);
{again, well lock the entire surface}
DXCheck(FImages.Lock(nil, SpriteSurfaceDesc,
DDLOCK_WAIT or DDLOCK_SURFACEMEMORYPTR, 0));
{initialize the byte array pointer to point at the locked memory}
SpriteMem := PBytePtr(SpriteSurfaceDesc.lpSurface);
{increment this pointer to the position of the current sprite frame}
SpriteMem := Pointer(Longint(SpriteMem)+(FCurFrame*90));
{iterate through each row of pixels in the sprite image (our sprite image is
90 X 50)}
for Row := 0 to 49 do
begin
{iterate through each pixel in the current row}
for Col := 0 to 89 do
{if the pixel in the sprite image is not 0 (the transparent color),
copy it into the destination surface}
if SpriteMem^[Col] <> 0 then
BackMem^[Col] := SpriteMem^[Col];
{move to the next row in the sprite and backbuffer surface memory}
Inc(BackMem, BackSurfaceDesc.lPitch);
Inc(SpriteMem, SpriteSurfaceDesc.lPitch);
end;
********************************************************************************
{we have now copied the sprite, so unlock the surface memory}
FBackBuffer.Unlock(nil);
FImages.Unlock(nil);
end;
end;
Previous
Table of Contents
Next
Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.
Wyszukiwarka
Podobne podstrony:
egzamin96 06 04WSM 06 04 pl06 04 Maria Wojtak Wybrane elementy staropolskiej etykiety jÄ™zykowej06 04ZL5 06 04Przedstawiciel władz Iraku podejrzany o malwersacje (06 04 2009)ZL1 06 04ZL2 06 04ZL4 06 04Plakat WEGLINIEC Odjazdy wazny od 14 04 27 do 14 06 14ZADANIE A1 2009 04 06TI 01 04 06 B plWSM 04 06 pl(1)więcej podobnych podstron