Delphi Graphics and Game Programming Exposed! with DirectX For versions 5.0-7.0:Special Effects
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
Fire
The fire effect is a really cool trick that, when performed properly, can create a very convincing illusion of fire. This effect is well documented both on the Web and in various books on graphics programming, and has been around for quite some time. It is a very computationally intensive effect, but it can be highly optimized and runs quite fast when implemented in assembly code. There are numerous ways of implementing this effect, but well examine one that produces a nice effect at decent speeds.
Basic Theory
The first thing we need to accomplish is creating an appropriate palette. For an effective fire, well create a palette that ranges from white in the upper slots (255-192), through yellow and orange, to red, and finally to black in the lowest slots (63-0). We could adjust the palette range somewhat and put some blues in, to simulate a cooler flame, or perhaps add some grays at the end, which would effectively simulate smoke.
This effect involves moving pixels that already exist in a surface. Therefore, we need to create a new surface that will contain the image of the fire. Since well be reading values from this surface, well place it in system memory. This algorithm is a CPU hog, so even though well create a surface thats the same size as the screen, well only use a small part of it for the effect. In our example, weve defined a starting and ending vertical position as well as a starting and ending horizontal position, which will confine the effect to the rectangle defined by these coordinates.
Now for the real work. Starting at the first row of pixels (defined by our starting vertical position) in the fire effect surface, we begin iterating through each column (as defined by our starting and ending horizontal position). We retrieve the current value of this pixel, subtract a random amount from this number, and then place the new value in the row of pixels above our current row. In effect, this produces an animation of pixels moving upwards on the screen. Additionally, we add a random number between 1 and 1 to move the pixels left or right in a chaotic manner.
Figure 11-13: Flaming pixels
Relative to the colors we defined in our palette, the pixel colors will slowly move from white, through yellow and red, and finally to black as they move upward due to the subtraction of a random value from their current color. This produces a very effective illusion of flames. At each frame of the animation, well need to place some random pixel values on the bottom row of the effect to give the algorithm some starting values. Implementing this effect is very simple, as illustrated by the following example.
Listing 11-8: The flame effect
const
.
.
.
{define the rectangular area for the effect}
XSTART = 200;
XEND = 440;
YSTART = 100;
YEND = 400;
{define the random decay value}
DECAY = 6;
type
.
.
.
TBytePtr = array[0..0] of Byte;
PBytePtr = ^TBytePtr;
var
.
.
.
{the interfaces for the primary and backbuffer surfaces}
FPrimarySurface,
FBackBuffer,
FireSurface: IDirectDrawSurface4;
{the palette interface}
FPalette: IDirectDrawPalette;
implementation
.
.
.
procedure TfrmDXAppMain.FormActivate(Sender: TObject);
var
.
.
.
{hold the palette colors}
PalColors: TColorTable;
iCount: Integer;
{this procedure stuffs the RGB values into the appropriate color table entry}
procedure SetPalEntry(Idx, Red, Green, Blue: Integer);
begin
PalColors[Idx].R := Red;
PalColors[Idx].G := Green;
PalColors[Idx].B := Blue;
PalColors[Idx].A := 0;
end;
begin
.
.
.
{define the colors for the palette. this will produce a spread from white
to yellow/orange to red, fading to black}
for iCount := 0 to 63 do
begin
SetPalEntry(iCount, iCount shl 2, 0, 0);
SetPalEntry(64+iCount, 255, iCount shl 2, 0);
SetPalEntry(128+iCount, 255, 255, iCount shl 2);
SetPalEntry(192+iCount, 255, 255, 255);
end;
{create the actual palette}
FDirectDraw.CreatePalette(DDPCAPS_8BIT or DDPCAPS_ALLOW256, @PalColors,
FPalette, nil);
{attach the palette to the primary surface}
FPrimarySurface.SetPalette(FPalette);
{create the offscreen buffer for the fire. were going to be modifying this
constantly, so well place it in system memory}
FillChar(DDSurface, SizeOf(TDDSurfaceDesc2), 0);
DDSurface.dwSize := SizeOf(TDDSurfaceDesc2);
DDSurface.dwFlags := DDSD_CAPS or DDSD_HEIGHT or DDSD_WIDTH;
DDSurface.dwWidth := DXWIDTH;
DDSurface.dwHeight := DXHEIGHT;
DDSurface.ddsCaps.dwCaps := DDSCAPS_OFFSCREENPLAIN or
DDSCAPS_SYSTEMMEMORY;
{initialize the surface}
DXCheck( FDirectDraw.CreateSurface(DDSurface, FireSurface, nil) );
{initialize the offscreen buffer to all black}
ColorFill(FireSurface, 0, nil);
.
.
.
end;
.
.
.
procedure TfrmDXAppMain.DrawSurfaces;
var
SrcRect: TRect;
SrfcDesc: TDDSurfaceDesc2;
iCol, iRow: Integer;
FireSrfcPtr,
BottomLine: PBytePtr;
CurPixel: Byte;
begin
{begin by locking the fire surface buffer}
FillChar(SrfcDesc, SizeOf(TDDSurfaceDesc2), 0);
SrfcDesc.dwSize := SizeOf(TDDSurfaceDesc2);
FireSurface.Lock(nil, SrfcDesc, DDLOCK_WAIT, 0);
FireSrfcPtr := PBytePtr(Longint(SrfcDesc.lpSurface)+
(YSTART*SrfcDesc.lPitch));
{well also need a pointer to the bottom line of the rectangular
area for the effect}
BottomLine := PBytePtr(Longint(SrfcDesc.lpSurface)+(YEND*SrfcDesc.lPitch));
{initialize some new pixels in the fire}
for iCol := XSTART to XEND do
BottomLine^[iCol] := 255-Random(32);
{perform the actual flame calculations}
for iRow := YSTART to YEND do
begin
for iCol := XSTART to XEND do
begin
{retrieve the pixel from this column}
CurPixel := FireSrfcPtr^[iCol];
{if the pixel is less than the decay value or is at the far ends of
the effect area, blacken it out...}
If (CurPixel < Decay) or (iCol = XSTART) or (iCol = XEND) then
{draw a black pixel on the row above the current one}
PBytePtr(Longint(FireSrfcPtr)-SrfcDesc.lPitch)^[iCol] := 0
else
{...otherwise, draw a new pixel on the row above the current one,
either directly above or to either side of the current pixel, but
subtract a random value from its color. this causes the color of the
pixel to slowly move from white, through yellow and red, to black}
PBytePtr(Longint(FireSrfcPtr)-SrfcDesc.lPitch)^[iCol+Random(3)-1] :=
CurPixel - Random(DECAY);
end;
{move to the next row in the fire surface}
Inc(FireSrfcPtr, SrfcDesc.lPitch);
end;
{unlock the buffer}
FireSurface.Unlock(nil);
{finally, blit the fire surface to the back buffer to make it visible}
SrcRect := Rect(0, 0, DXWIDTH, DXHEIGHT);
FBackBuffer.BltFast(0, 0, FireSurface, SrcRect, DDBLTFAST_WAIT);
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:
Analiza Wykład 8 (25 11 10)5 11 10 18 07 26 47HIE 29 11 1011 10 Lift and Drag on Road Vehicles141 11 (10)11 10 Luty 1998 Polacy wolniwięcej podobnych podstron