|
|
|
|
|
Welcome
to Tutorial 20. The bitmap image format is supported on just about every
computer, and just about every operating system. Not only is it easy to
work with, it's very easy to load and use as a texture. Up until now, we've
been using blending to place text and other images onto the screen without
erasing what's underneath the text or image. This is effective, but the
results are not always pretty.
Most the time a blended
texture blends in too much or not enough. When making a game using sprites,
you don't want the scene behind your character shining through the characters
body. When writing text to the screen you want the text to be solid and
easy to read.
That's where masking comes
in handy. Masking is a two step process. First we place a black and white
image of our texture on top of the scene. The white represents the transparent
part of our texture. The black represents the solid part of our texture.
Because of the type of blending we use, only the black will appear on the
scene. Almost like a cookie cutter effect. Then we switch blending modes,
and map our texture on top of the black cut out. Again, because of the
blending mode we use, the only parts of our texture that will be copied
to the screen are the parts that land on top of the black mask.
I'll rewrite the entire
program in this tutorial aside from the sections that haven't changed.
So if you're ready to learn something new, let's begin! |
|
|
|
|
#include <windows.h> // Header File For Windows
#include <math.h> // Header File For Windows Math Library
#include <stdio.h> // Header File For Standard Input/Output
#include <gl\gl.h> // Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library
#include <gl\glaux.h> // Header File For The Glaux Library
HDC hDC=NULL; // Private GDI Device Context
HGLRC hRC=NULL; // Permanent Rendering Context
HWND hWnd=NULL; // Holds Our Window Handle
HINSTANCE hInstance; // Holds The Instance Of The Application
|
|
|
|
|
We'll
be using 7 global variables in this program. masking is a boolean
variable (TRUE / FALSE) that will keep track of whether or not masking
is turned on of off. mp is used to make sure that the 'M' key isn't
being held down. sp is used to make sure that the 'Spacebar' isn't
being held down and the variable scene will keep track of whether
or not we're drawing the first or second scene.
We set up storage space
for 5 textures using the variable texture[5]. loop is our
generic counter variable, we'll use it a few times in our program to set
up textures, etc. Finally we have the variable roll. We'll use roll
to roll the textures across the screen. Creates a neat effect! We'll also
use it to spin the object in scene 2. |
|
|
|
|
bool keys[256]; // Array Used For The Keyboard Routine
bool active=TRUE; // Window Active Flag Set To TRUE By Default
bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default
bool masking=TRUE; // Masking On/Off
bool mp; // M Pressed?
bool sp; // Space Pressed?
bool scene; // Which Scene To Draw
GLuint texture[5]; // Storage For Our Five Textures
GLuint loop; // Generic Loop Variable
GLfloat roll; // Rolling Texture
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc
|
|
|
|
|
The
load bitmap code hasn't changed. It's the same as it was in lesson 6, etc.
In the code below we create
storage space for 5 images. We clear the space and load in all 5 bitmaps.
We loop through each image and convert it into a texture for use in our
program. The textures are stored in texture[0-4]. |
|
|
|
|
int LoadGLTextures() // Load Bitmaps And Convert To Textures
{
int Status=FALSE; // Status Indicator
AUX_RGBImageRec *TextureImage[5]; // Create Storage Space For The Texture Data
memset(TextureImage,0,sizeof(void *)*5); // Set The Pointer To NULL
if ((TextureImage[0]=LoadBMP("Data/logo.bmp")) && // Logo Texture
(TextureImage[1]=LoadBMP("Data/mask1.bmp")) && // First Mask
(TextureImage[2]=LoadBMP("Data/image1.bmp")) && // First Image
(TextureImage[3]=LoadBMP("Data/mask2.bmp")) && // Second Mask
(TextureImage[4]=LoadBMP("Data/image2.bmp"))) // Second Image
{
Status=TRUE; // Set The Status To TRUE
glGenTextures(5, &texture[0]); // Create Five Textures
for (loop=0; loop<5; loop++) // Loop Through All 5 Textures
{
glBindTexture(GL_TEXTURE_2D, texture[loop]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop]->sizeX, TextureImage[loop]->sizeY,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop]->data);
}
}
for (loop=0; loop<5; loop++) // Loop Through All 5 Textures
{
if (TextureImage[loop]) // If Texture Exists
{
if (TextureImage[loop]->data) // If Texture Image Exists
{
free(TextureImage[loop]->data); // Free The Texture Image Memory
}
free(TextureImage[loop]); // Free The Image Structure
}
}
return Status; // Return The Status
}
|
|
|
|
|
The
ReSizeGLScene() code hasn't changed so we'll skip over it.
The Init code is fairly
bare bones. We load in our textures, set the clear color, set and enable
depth testing, turn on smooth shading, and enable texture mapping. Simple
program so no need for a complex init :) |
|
|
|
|
int InitGL(GLvoid) // All Setup For OpenGL Goes Here
{
if (!LoadGLTextures()) // Jump To Texture Loading Routine
{
return FALSE; // If Texture Didn't Load Return FALSE
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Clear The Background Color To Black
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glEnable(GL_DEPTH_TEST); // Enable Depth Testing
glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading
glEnable(GL_TEXTURE_2D); // Enable 2D Texture Mapping
return TRUE; // Initialization Went OK
}
|
|
|
|
|
Now
for the fun stuff. Our drawing code! We start off the same as usual. We
clear the background color and the depth buffer. Then we reset the modelview
matrix, and translate into the screen 2 units so that we can see our scene. |
|
|
|
|
int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The Modelview Matrix
glTranslatef(0.0f,0.0f,-2.0f); // Move Into The Screen 5 Units
|
|
|
|
|
The
first line below select the 'logo' texture. We'll map the texture to the
screen using a quad. we specify our 4 texture coordinates along with our
4 vertices.
You'll notice that the
texture coordinates may look weird. Instead of using 1.0 and 0.0 I'm using
3.0 and 0.0. I'll explain what this does. By using 3.0 as a texture coordinate
instead of 1.0, we are telling OpenGL to draw our texture 3 times. Normally
our one texture is mapped across the entire face of our quad. This time
OpenGL will squish 3 of our textures onto the quad. I'm also using 3.0
for the up and down value, meaning we'll have three textures wide, and
3 textures up and down. Mapping 9 images of the selected texture to the
front of our quad.

You will also notice that I've added the variable -roll to our verticle
texture coordinates. This cause the texture to roll up the screen as the
value of roll increases. roll tells OpenGL what part of our
image to start texturing from. The image to the left is how our texture
would look if roll was equal to 0.0. From 0.0 to 1.0 would be the
first texture drawn up and down. From 1.0 to 2.0 would be our second texture,
and from 2.0 to 3.0 would be our third texture. The image on the right
shows how our texture would look if roll was equal to 0.5. Our first
texure would be drawn from -0.5 to 0.5 (notice that because we started
drawing halfway through the texture that the 'N' and 'e' have been cut
off). The second texture would be from 0.5 to 1.5, and the third texture
would be from 1.5 to 2.5. Again notice that only the 'N' and 'e' have been
drawn at the bottom. We never quite made it to 3.0 (the bottom of a complete
texture) so the 'H' and 'e' were not drawn. Rolling textures can be used
to create great effects such as moving clouds. Words spinning around an
object, etc. If you don't understand what I mean about rolling textures,
let me know. If you have a better way to explain let me know. It's easy
to understand how rolling textures work once you've used them, but trying
to explain it in words isn't very easy.
One last explanation to
hopefully clear things up. Imagine you had an endless amount of marbles
up and down, left and right. Every marble was identicle (imagine each marble
is a texture). The marble in the center of your infinate number of marbles
is your main marble (texture). It's left side is 0.0, it's right side is
1.0, the values up and down are also 0.0 to 1.0. Now if you move left half
a marble (-0.5), and you can only see 1.0 marbles wide you would only see
the right half of the marble to the left of your original marble and the
left half of your original marble. If you moved left another half (-0.5...
a total of -1.0) you would see an entire marble (texture) but it wouldn't
be your original marble, it would be the marble to the left of it. Because
all the marbles look exactly the same you would think you were seeing your
entire original marble (texture). {grin}. Hopefully that doesn't confuse
you even more. I know how some of you hate my little stories. |
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture[0]); // Select Our Logo Texture
glBegin(GL_QUADS); // Start Drawing A Textured Quad
glTexCoord2f(0.0f, -roll+0.0f); glVertex3f(-1.1f, -1.1f, 0.0f); // Bottom Left
glTexCoord2f(3.0f, -roll+0.0f); glVertex3f( 1.1f, -1.1f, 0.0f); // Bottom Right
glTexCoord2f(3.0f, -roll+3.0f); glVertex3f( 1.1f, 1.1f, 0.0f); // Top Right
glTexCoord2f(0.0f, -roll+3.0f); glVertex3f(-1.1f, 1.1f, 0.0f); // Top Left
glEnd(); // Done Drawing The Quad
|
|
|
|
|
Anyways...
back to reality. Now we enable blending. In order for this effect to work
we also have to disable depth testing. It's very important that you do
this! If you do not disable depth testing you probably wont see anything.
Your entire image will vanish! |
|
|
|
|
glEnable(GL_BLEND); // Enable Blending
glDisable(GL_DEPTH_TEST); // Disable Depth Testing
|
|
|
|
|
The
first thing we do after we enable blending and disable depth testing is
check to see if we're going to mask our image or blend it the old fashioned
way. The line of code below checks to see if masking is TRUE. If
it is we'll set up blending so that our mask gets drawn to the screen properly. |
|
|
|
|
if (masking) // Is Masking Enabled?
{
|
|
|
|
|
If
masking is TRUE the line below will set up blending for our mask.
A mask is just a copy of the texture we want to draw to the screen but
in black and white. Any section of the mask that is white will be transparent.
Any sections of the mask that is black will be SOLID.
The blend command below
does the following: The Destination color (screen color) will be set to
black if the section of our mask that is being copied to the screen is
black. This means that sections of the screen that the black portion of
our mask covers will turn black. Anything that was on the screen under
the mask will be cleared to black. The section of the screen covered by
the white mask will not change. |
|
|
|
|
glBlendFunc(GL_DST_COLOR,GL_ZERO); // Blend Screen Color With Zero (Black)
}
|
|
|
|
|
Now
we check to see what scene to draw. If scene is TRUE we will draw
the second scene. If scene is FALSE we will draw the first scene. |
|
|
|
|
if (scene) // Are We Drawing The Second Scene?
{
|
|
|
|
|
We
don't want things to be too big so we translate one more unit into the
screen. This reduces the size of our objects.
After we translate into
the screen, we rotate from 0-360 degrees depending on the value of
roll.
If roll is 0.0 we will be rotating 0 degrees. If roll is
1.0 we will be rotating 360 degrees. Fairly fast rotation, but I didn't
feel like creating another variable just to rotate the image in the center
of the screen. :) |
|
|
|
|
glTranslatef(0.0f,0.0f,-1.0f); // Translate Into The Screen One Unit
glRotatef(roll*360,0.0f,0.0f,1.0f); // Rotate On The Z Axis 360 Degrees
|
|
|
|
|
We
already have the rolling logo on the screen and we've rotated the scene
on the Z axis causing any objects we draw to be rotated counter-clockwise,
now all we have to do is check to see if masking is on. If it is we'll
draw our mask then our object. If masking is off we'll just draw our object. |
|
|
|
|
if (masking) // Is Masking On?
{
|
|
|
|
|
If
masking is TRUE the code below will draw our mask to the screen.
Our blend mode should be set up properly because we had checked for masking
once already while setting up the blending. Now all we have to do is draw
the mask to the screen. We select mask 2 (because this is the second scene).
After we have selected the mask texture we texture map it onto a quad.
The quad is 1.1 units to the left and right so that it fills the screen
up a little more. We only want one texture to show up so our texture coordinates
only go from 0.0 to 1.0.
after drawing our mask
to the screen a solid black copy of our final texture will appear on the
screen. The final result will look as if someone took a cookie cutter and
cut the shape of our final texture out of the screen, leaving an empty
black space. |
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture[3]); // Select The Second Mask Texture
glBegin(GL_QUADS); // Start Drawing A Textured Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.1f, -1.1f, 0.0f); // Bottom Left
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.1f, -1.1f, 0.0f); // Bottom Right
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.1f, 1.1f, 0.0f); // Top Right
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.1f, 1.1f, 0.0f); // Top Left
glEnd(); // Done Drawing The Quad
}
|
|
|
|
|
Now
that we have drawn our mask to the screen it's time to change blending
modes again. This time we're going to tell OpenGL to copy any part of our
colored texture that is NOT black to the screen. Because the final texture
is an exact copy of the mask but with color, the only parts of our texture
that get drawn to the screen are parts that land on top of the black portion
of the mask. Because the mask is black, nothing from the screen will shine
through our texture. This leaves us with a very solid looking texture floating
on top of the screen.
Notice that we select
the second image after selecting the final blending mode. This selects
our colored image (the image that our second mask is based on). Also notice
that we draw this image right on top of the mask. Same texture coordinates,
same vertices.
If we don't lay down a
mask, our image will still be copied to the screen, but it will blend with
whatever was on the screen. |
|
|
|
|
glBlendFunc(GL_ONE, GL_ONE); // Copy Image 2 Color To The Screen
glBindTexture(GL_TEXTURE_2D, texture[4]); // Select The Second Image Texture
glBegin(GL_QUADS); // Start Drawing A Textured Quad
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.1f, -1.1f, 0.0f); // Bottom Left
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.1f, -1.1f, 0.0f); // Bottom Right
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.1f, 1.1f, 0.0f); // Top Right
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.1f, 1.1f, 0.0f); // Top Left
glEnd(); // Done Drawing The Quad
}
|
|
|
|
|
If
scene was FALSE, we will draw the first scene (my favorite). |
|
|
|
|
else // Otherwise
{
|
|
|
|
|
We
start off by checking to see if masking is TRUE of FALSE, just like
in the code above. |
|
|
|
|
if (masking) // Is Masking On?
{
|
|
|
|
|
If
masking is TRUE we draw our mask 1 to the screen (the mask for scene
1). Notice that the texture is rolling from right to left (roll
is added to the horizontal texture coordinate). We want this texture to
fill the entire screen that is why we never translated further into the
screen. |
|
|
|
|
glBindTexture(GL_TEXTURE_2D, texture[1]); // Select The First Mask Texture
glBegin(GL_QUADS); // Start Drawing A Textured Quad
glTexCoord2f(roll+0.0f, 0.0f); glVertex3f(-1.1f, -1.1f, 0.0f); // Bottom Left
glTexCoord2f(roll+4.0f, 0.0f); glVertex3f( 1.1f, -1.1f, 0.0f); // Bottom Right
glTexCoord2f(roll+4.0f, 4.0f); glVertex3f( 1.1f, 1.1f, 0.0f); // Top Right
glTexCoord2f(roll+0.0f, 4.0f); glVertex3f(-1.1f, 1.1f, 0.0f); // Top Left
glEnd(); // Done Drawing The Quad
}
|
|
|
|
|
Again
we enable blending and select our texture for scene 1. We map this texture
on top of it's mask. Notice we roll this texture as well, otherwise the
mask and final image wouldn't line up. |
|
|
|
|
glBlendFunc(GL_ONE, GL_ONE); // Copy Image 1 Color To The Screen
glBindTexture(GL_TEXTURE_2D, texture[2]); // Select The First Image Texture
glBegin(GL_QUADS); // Start Drawing A Textured Quad
glTexCoord2f(roll+0.0f, 0.0f); glVertex3f(-1.1f, -1.1f, 0.0f); // Bottom Left
glTexCoord2f(roll+4.0f, 0.0f); glVertex3f( 1.1f, -1.1f, 0.0f); // Bottom Right
glTexCoord2f(roll+4.0f, 4.0f); glVertex3f( 1.1f, 1.1f, 0.0f); // Top Right
glTexCoord2f(roll+0.0f, 4.0f); glVertex3f(-1.1f, 1.1f, 0.0f); // Top Left
glEnd(); // Done Drawing The Quad
}
|
|
|
|
|
Next
we enable depth testing, and disable blending. This prevents strange things
from happening in the rest of our program :) |
|
|
|
|
glEnable(GL_DEPTH_TEST); // Enable Depth Testing
glDisable(GL_BLEND); // Disable Blending
|
|
|
|
|
Finally
all we have left to do is increase the value of roll. If roll
is greater than 1.0 we subtract 1.0. This prevents the value of roll
from getting to high. |
|
|
|
|
roll+=0.002f; // Increase Our Texture Roll Variable
if (roll>1.0f) // Is Roll Greater Than One
{
roll-=1.0f; // Subtract 1 From Roll
}
return TRUE; // Everything Went OK
}
|
|
|
|
|
The
KillGLWindow(), CreateGLWindow() and WndProc() code hasn't changed so we'll
skip over it.
The first thing you will
notice different in the WinMain() code is the Window title. It's now titled
"NeHe's Masking Tutorial". Change it to whatever you want :) |
|
|
|
|
int WINAPI WinMain( HINSTANCE hInstance, // Instance
HINSTANCE hPrevInstance, // Previous Instance
LPSTR lpCmdLine, // Command Line Parameters
int nCmdShow) // Window Show State
{
MSG msg; // Windows Message Structure
BOOL done=FALSE; // Bool Variable To Exit Loop
// Ask The User Which Screen Mode They Prefer
if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
{
fullscreen=FALSE; // Windowed Mode
}
// Create Our OpenGL Window
if (!CreateGLWindow("NeHe's Masking Tutorial",640,480,16,fullscreen))
{
return 0; // Quit If Window Was Not Created
}
while(!done) // Loop That Runs While done=FALSE
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) // Is There A Message Waiting?
{
if (msg.message==WM_QUIT) // Have We Received A Quit Message?
{
done=TRUE; // If So done=TRUE
}
else // If Not, Deal With Window Messages
{
TranslateMessage(&msg); // Translate The Message
DispatchMessage(&msg); // Dispatch The Message
}
}
else // If There Are No Messages
{
// Draw The Scene. Watch For ESC Key And Quit Messages From DrawGLScene()
if ((active && !DrawGLScene()) || keys[VK_ESCAPE]) // Active? Was There A Quit Received?
{
done=TRUE; // ESC or DrawGLScene Signalled A Quit
}
else // Not Time To Quit, Update Screen
{
SwapBuffers(hDC); // Swap Buffers (Double Buffering)
|
|
|
|
|
Now
for our simple key handling code. We check to see if the spacebar is being
pressed. If it is, we set the sp variable to TRUE. If sp
is TRUE, the code below will not run a second time until the spacebar has
been released. This keeps our program from flipping back and forth from
scene to scene very rapidly. After we set sp to TRUE, we toggle
the scene. If it was TRUE, it becomes FALSE, if it was FALSE it becomes
TRUE. In our drawing code above, if
scene is FALSE the first scene
is drawn. If scene is TRUE the second scene is drawn. |
|
|
|
|
if (keys[' '] && !sp) // Is Space Being Pressed?
{
sp=TRUE; // Tell Program Spacebar Is Being Held
scene=!scene; // Toggle From One Scene To The Other
}
|
|
|
|
|
The
code below checks to see if we have released the spacebar (if NOT ' ').
If the spacebar has been released, we set sp to FALSE letting our
program know that the spacebar is NOT being held down. By setting sp
to FALSE the code above will check to see if the spacebar has been pressed
again, and if so the cycle will start over. |
|
|
|
|
if (!keys[' ']) // Has Spacebar Been Released?
{
sp=FALSE; // Tell Program Spacebar Has Been Released
}
|
|
|
|
|
The
next section of code checks to see if the 'M' key is being pressed. If
it is being pressed, we set mp to TRUE, telling our program not
to check again until the key is released, and we toggle masking
from TRUE to FALSE or FALSE to TRUE. If masking is TRUE, the drawing
code will turn on masking. If it is FALSE masking will be off. If masking
is off, the object will be blended to the screen using the old fashioned
blending we've been using up until now. |
|
|
|
|
if (keys['M'] && !mp) // Is M Being Pressed?
{
mp=TRUE; // Tell Program M Is Being Held
masking=!masking; // Toggle Masking Mode OFF/ON
}
|
|
|
|
|
The
last bit of code checks to see if we've stopped pressing 'M'. If we have,
mp becomes FALSE letting the program know that we are no longer
holding the 'M' key down. Once the 'M' key has been released, we are able
to press it once again to toggle masking on or off. |
|
|
|
|
if (!keys['M']) // Has M Been Released?
{
mp=FALSE; // Tell Program That M Has Been Released
}
|
|
|
|
|
Like
all the previous tutorials, make sure the title at the top of the window
is correct. |
|
|
|
|
if (keys[VK_F1]) // Is F1 Being Pressed?
{
keys[VK_F1]=FALSE; // If So Make Key FALSE
KillGLWindow(); // Kill Our Current Window
fullscreen=!fullscreen; // Toggle Fullscreen / Windowed Mode
// Recreate Our OpenGL Window
if (!CreateGLWindow("NeHe's Masking Tutorial",640,480,16,fullscreen))
{
return 0; // Quit If Window Was Not Created
}
}
}
}
}
// Shutdown
KillGLWindow(); // Kill The Window
return (msg.wParam); // Exit The Program
}
|
|
|
|
|
Creating
a mask isn't to hard. A little time consuming. The best way to make a mask
if you already have your image made is to load your image into an art program
or a handy program like infranview, and reduce it to a gray scale image.
After you've done that, turn the contrast way up so that gray pixels become
black. You can also try turning down the brightness, etc. It's important
that the white is bright white, and the black is pure black. If you have
any gray pixels in your mask, that section of the image will appear transparent.
The most reliable way to make sure your mask is a perfect copy of your
image is to trace over the image with black. It's also very important that
your image has a BLACK background and the mask has a WHITE background!
If you create a mask and notice a square shape around your texture, either
your white isn't bright enough (255 or FFFFFF) or your black isn't true
black (0 or 000000). Below you can see an example of a mask and the image
that goes over top of the mask. the image can be any color you want as
long as the background is black. The mask must have a white background
and a black copy of your image.
This is the mask ->
This is the image ->
Eric
Desrosiers pointed out that you can also check
the value of each pixel in your bitmap while you load it. If you want the
pixel transparent you can give it an alpha value of 0. For all the other
colors you can give them an alpha value of 255. This method will also work
but requires some extra coding. The current tutorial is simple and requires
very little extra code. I'm not blind to other techniques, but when
I write a tutorial I try to make the code easy to understand and easy to
use. I just wanted to point out that there are always other ways to get
the job done. Thanks for the feedback Eric.
In this tutorial I have
shown you a simple, but effective way to draw sections of a texture to
the screen without using the alpha channel. Normal blending usually looks
bad (textures are either transparent or they're not), and texturing with
an alpha channel requires that your images support the alpha channel. Bitmaps
are convenient to work with, but they do not support the alpha channel
this program shows us how to get around the limitations of bitmap images,
while demonstrating a cool way to create overlay type effects.
Thanks
to Rob Santa
for the idea and for example code. I had never heard of this little trick
until he pointed it out. He wanted me to point out that although this trick
does work, it takes two passes, which causes a performance hit. He recommends
that you use textures that support the alpha channel for complex scenes.
I hope you enjoyed this
tutorial. If you had any problems understanding it, or you've found a mistake
in the tutorial please let me know. I want to make the best tutorials available.
Your feedback is important!
Jeff
Molofee (NeHe)
* DOWNLOAD Visual
C++ Code For This Lesson.
* DOWNLOAD Visual
C++ / OpenIL Code For This Lesson. ( Conversion by Denton
Woods )
* DOWNLOAD Visual
Basic Code For This Lesson. ( Conversion by Edo
)
* DOWNLOAD Cygwin
(FREE Language) Code For This Lesson.
( Conversion by Stephan Ferraro
)
* DOWNLOAD Irix
/ GLUT Code For This Lesson. ( Conversion by Rob
Fletcher )
* DOWNLOAD Delphi
Code For This Lesson. ( Conversion by Marc
Aarts )
* DOWNLOAD Mac
OS Code For This Lesson. ( Conversion by Anthony
Parker )
* DOWNLOAD MingW32
& Allegro Code For This Lesson. ( Conversion by Peter
Puck )
* DOWNLOAD Borland
C++ Builder 4.0 Code For This Lesson. ( Conversion by Patrick
Salmons )
* DOWNLOAD Linux
Code For This Lesson. ( Conversion by Daniel
Davis ) |
|
|
|
|
|
Back
To NeHe Productions!
|
|
|
|
|