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