📄 ddfade.htm
字号:
<!--Header-->
<HTML>
<HEAD>
<TITLE>GPMega - DirectX Section - DirectDraw Fading Mania</TITLE>
<META NAME="DESCRIPTION" CONTENT="The only tutorial you'll need to have awesome 16-bit fades with DirectDraw. Covers crossfading, fade to a surface, and fading to black. Covers theory, technique and gives implementation code. Includes complete demo with source code in C++.">
</HEAD>
<BODY BGCOLOR=#000000 TEXT=#FFFFFF LINK=#00FF00 VLINK=#00FF00 ALINK=#0000FF>
<!--End Header-->
<!--Advertiser-->
<CENTER>
<TABLE>
<TR>
<TD>
<A HREF="http://www.ugo.com/">
<IMG SRC="/GPMega/ugologo120.gif" BORDER=0 WIDTH=120 HEIGHT=60></A>
</TD>
<TD>
<IMG SRC="/GPMega/sponsored.gif" WIDTH=468 HEIGHT=10><br><br>
<SCRIPT LANGUAGE= "JavaScript">
<!--
var now = new Date();
var random_num = now.getSeconds();
document.write("<A HREF='http://www.ugo.net/RealMedia/ads/click_nx.cgi/www.perplexed.com/GPMega/directx/ddfade.htm/" + random_num + "/@Top'>");
document.write("<IMG SRC='http://www.ugo.net/RealMedia/ads/adstream_nx.cgi/www.perplexed.com/GPMega/directx/ddfade.htm/" + random_num + "/@Top' BORDER='0' WIDTH='468' HEIGHT='60'></A>");
//-->
</SCRIPT>
</TD>
</TR>
</TABLE>
</CENTER>
<!--End Advertiser-->
<!--Splitter-->
<BR>
<!--End Splitter-->
<!--Body-->
<FONT SIZE=2 FACE=Helvetica>
<STRONG>
<!--Top Navigation-->
<A NAME="top"></A>
<CENTER>
<TABLE WIDTH=75%>
<TR VALIGN=MIDDLE>
<TD ALIGN=LEFT>
<IMG SRC="gradsplit2.jpg" WIDTH=100% HEIGHT=1><BR><BR>
<A HREF="http://www.perplexed.com/GPMega/"><IMG SRC="logo.jpg" BORDER=0 ALT="Home" WIDTH=80 HEIGHT=47 ALIGN=CENTER></A>
<FONT COLOR=#666666 FACE=HELVETICA SIZE=-1><I>
This Article Is Taken From <A HREF="http://www.perplexed.com/GPMega/">The Game Programming MegaSite</A>, A Definitive Resource For Game Developers!
</I></FONT><BR>
<IMG SRC="gradsplit2.jpg" WIDTH=100% HEIGHT=1>
</TD>
</TR>
</TABLE>
</CENTER>
<BR><!--End Top Navigation-->
<!--Title-->
<H3 ALIGN=CENTER><font color="#FFF400">D</font><font color="#FFE900">i</font><font color="#FFDE00">r</font><font color="#FFD300">e</font><font color="#FFC800">c</font><font color="#FFBD00">t</font><font color="#FFB200">D</font><font color="#FFA700">r</font><font color="#FF9C00">a</font><font color="#FF9100">w</font><font color="#FF8600"> </font><font color="#FF7B00">F</font><font color="#FF7000">a</font><font color="#FF6500">d</font><font color="#FF5A00">i</font><font color="#FF4F00">n</font><font color="#FF4400">g</font><font color="#FF3900"> </font><font color="#FF2E00">M</font><font color="#FF2300">a</font><font color="#FF1800">n</font><font color="#FF0D00">i</font><font color="#FF0200">a</font><BR><FONT SIZE=-2>By: Matt Reiferson</FONT></H3>
<!--End Title-->
<P>Fades are an excellent way to cut to and from sections of your game. Fade into your intro screen, fade out after the player dies,
and cross-fade from screen-to-screen. Well, how do you do it? I'm going to cover fades in DirectDraw 16-bit modes, this seems
to be the most commonly used mode, and in subsequently is the most commonly asked mode to do fades in.
<P>NOTE: This article assumes you have a decent knowledge of DirectDraw, such as setting modes, creating surfaces, locking/unlocking, etc.
<H3><FONT COLOR=YELLOW><I>16-bit Pixel Formats</I></FONT></H3>
<P>Answer me this quick question, can you evenly divide 3 into 16? I hope you said no. My point is that in order to describe
a single pixel, you need three components, <i>red</i>, <i>green</i>, and <i>blue</i>. In other words if your in a 16-bit
mode each pixel is given 16 bits for it's RGB combo and since you can't evenly divide 3 (R,G,B) into 16 bits, your video card
determines how it's going to split things up. Video cards put in 16-bit modes come in two flavors, the 5,6,5 format or the
5,5,5 format (# of bits for r,g,b respectively). How does this affect fading? Well we're going to need the red, green, and
blue components of the pixels were going to be manipulating.
<P>After that background info on these two 16-bit pixel formats, the next obvious step is to throw some code at you that
demonstrates one technique of determining what the users video card format is in. The function is called <i>DDGetRGB16()</i>
and i'll throw that in below but first, the function fills up a structure called <i>RGB16</i> which holds information about
pixel masks and bit positions.
<BLOCKQUOTE>
<PRE><FONT SIZE=2 COLOR=RED>
// the structure which holds pixel RGB masks
typedef struct _RGBMASK
{
unsigned long rgbRed; // red component
unsigned long rgbGreen; // green component
unsigned long rgbBlue; // blue component
} RGBMASK;
// the structure which holds screen format info (5,6,5 or 5,5,5 and masking)
typedef struct _RGB16
{
RGBQUAD depth;
RGBQUAD amount;
RGBQUAD position;
RGBMASK mask;
} RGB16;
</FONT></PRE>
</BLOCKQUOTE>
<P>Then of course, we're also going to need a couple globals. One being the RGB16 structure, and the integers being a couple
of convienence variables so we don't constantly type out the entire structure. In case your wondering, the <i>'m'</i>
or <i>'p'</i> preceding the variables below stand for <i>mask</i> and <i>position</i> variables respectively.
<BLOCKQUOTE>
<PRE><FONT SIZE=2 COLOR=RED>
RGB16 rgb16; // Video Card RGB Information Structure
int mRed, mGreen, // Faster values of above structure
mBlue, pRed, // Faster values of above structure
pGreen, pBlue; // Faster values of above structure
</FONT></PRE>
</BLOCKQUOTE>
<P>Ok, now we're ready to go ahead and see that <i>DDGetRGB16()</i> function. What it does is simply manipulate information
returned from a query to <i>->GetSurfaceDesc()</i> on the primary surface.
<BLOCKQUOTE>
<PRE><FONT SIZE=2 COLOR=RED>
/*
* DDGetRGB16:
* Must run this function to fill the RGB16 struct with the information needed to plot a pixel
* To call this, you must have rgb16 defined as a global (unless you want to modify this) variable
* RGB16 rgb16;
*/
void DDGetRGB16(void)
{
DDSURFACEDESC ddsd; // DirectDraw Surface Description
BYTE shiftcount; // Shift Counter
// get a surface despriction
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_PIXELFORMAT;
lpDDSPrimary->GetSurfaceDesc(&ddsd);
// Fill in the masking values for extracting colors
rgb16.mask.rgbRed = ddsd.ddpfPixelFormat.dwRBitMask;
rgb16.mask.rgbGreen = ddsd.ddpfPixelFormat.dwGBitMask;
rgb16.mask.rgbBlue = ddsd.ddpfPixelFormat.dwBBitMask;
// get red surface information
shiftcount = 0;
while(!(ddsd.ddpfPixelFormat.dwRBitMask & 1))
{
ddsd.ddpfPixelFormat.dwRBitMask >>= 1;
shiftcount++;
}
rgb16.depth.rgbRed = (BYTE)ddsd.ddpfPixelFormat.dwRBitMask;
rgb16.position.rgbRed = shiftcount;
rgb16.amount.rgbRed = (ddsd.ddpfPixelFormat.dwRBitMask == 0x1f) ? 3 : 2;
// get green surface information
shiftcount = 0;
while(!(ddsd.ddpfPixelFormat.dwGBitMask & 1))
{
ddsd.ddpfPixelFormat.dwGBitMask >>= 1;
shiftcount++;
}
rgb16.depth.rgbGreen =(BYTE)ddsd.ddpfPixelFormat.dwGBitMask;
rgb16.position.rgbGreen = shiftcount;
rgb16.amount.rgbGreen = (ddsd.ddpfPixelFormat.dwGBitMask == 0x1f) ? 3 : 2;
// get Blue surface information
shiftcount = 0;
while(!(ddsd.ddpfPixelFormat.dwBBitMask & 1))
{
ddsd.ddpfPixelFormat.dwBBitMask >>= 1;
shiftcount++;
}
rgb16.depth.rgbBlue =(BYTE)ddsd.ddpfPixelFormat.dwBBitMask;
rgb16.position.rgbBlue = shiftcount;
rgb16.amount.rgbBlue = (ddsd.ddpfPixelFormat.dwBBitMask == 0x1f) ? 3 : 2;
// fill in variables so we dont' have to access the structure anymore
mRed = rgb16.mask.rgbRed; // Red Mask
mGreen = rgb16.mask.rgbGreen; // Green Mask
mBlue = rgb16.mask.rgbBlue; // Blue Mask
pRed = rgb16.position.rgbRed; // Red Position
pGreen = rgb16.position.rgbGreen; // Green Position
pBlue = rgb16.position.rgbBlue; // Blue Position
}
</FONT></PRE>
</BLOCKQUOTE>
<H3><FONT COLOR=YELLOW><I>Fading Technique</I></FONT></H3>
<P>Since the implementation of fading that we use at the end involves manipulating each pixel, how do we go about blending one
pixel into another? Well, let first establish an equation which will allow us to blend two pixel's color values for one of their RGB
components.
<BLOCKQUOTE>
<PRE><FONT SIZE=2 COLOR=RED>
// get pixels red,green,blue values
red_final = (red1 * transparency1) + (red2 * transparency2);
blue_final = (blue1 * transparency1) + (blue2 * transparency2);
green_final = (green1 * transparency1) + (green2 * transparency2);
// recombine red,green,blue to pixel value
</FONT></PRE>
</BLOCKQUOTE>
<P>Great, so Matt, how do we get the pixels red,green,blue values and then how to we create a pixel value from those new red,green,blue
values we've calculated? Glad you asked, here's where we put into use that information we've obtained from our <i>DDGetRGB16()</i>
function.
<P>What follows are four macros which do exactly what they say, find out that information we need...
<BLOCKQUOTE>
<PRE><FONT SIZE=2 COLOR=RED>
#define RED(p) (p >> pRed) // Extracts Red Component
#define GREEN(p) ((p & mGreen) >> pGreen) // Extracts Green Component
#define BLUE(p) (p & mBlue) // Extracts Blue Component
#define RGB16(r, g, b) ((r << pRed) | (g << pGreen) | b) // Creates RGB Pixel Value
</FONT></PRE>
</BLOCKQUOTE>
<P>If you didn't know already, we also want this cross-fade to occur fast, so I took the liberty of making an important
but commonly used optimization, a lookup table. I made the decision that for any given fade, 32 steps would be enough to
create a smooth enough effect. So the lookup table is simply a huge array of all the shades of any given color in 32 steps.
<BLOCKQUOTE>
<PRE><FONT SIZE=2 COLOR=RED>
WORD PixelShade[32][65536];
</FONT></PRE>
</BLOCKQUOTE>
<P>In our <i>PixelShade</i> initialization function, we're going to precompute the values for a given pixel in the given shade
level, 0-31. The function should be self explanatory, the only interesting note is the use of our above macros, and the use
of a constant array of the decimal percentage values for each shade level.
<BLOCKQUOTE>
<PRE><FONT SIZE=2 COLOR=RED>
/*
* InitPixelShade:
* Fills the PixelShade array with precomputed shades of every possible pixel (32 shades)
*/
void InitPixelShade(void)
{
int i, j;
int r,g,b;
int dr,dg,db;
const double alpha[32] = { 0.0, 0.03, 0.06, 0.09,
0.13, 0.17, 0.21, 0.24,
0.27, 0.31, 0.34, 0.37,
0.41, 0.44, 0.47, 0.49,
0.51, 0.53, 0.56, 0.59,
0.63, 0.66, 0.69, 0.73,
0.76, 0.79, 0.83, 0.87,
0.91, 0.94, 0.97, 1.0 };
for(i=0;i<32;i++)
{
for(j=0;j<65536;j++)
{
r = RED(j);
g = GREEN(j);
b = BLUE(j);
dr = (int)(r*alpha[i]);
dg = (int)(g*alpha[i]);
db = (int)(b*alpha[i]);
PixelShade[i][j] = RGB16(dr,dg,db);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -