📄 main.cpp
字号:
#define WIN32_LEAN_AND_MEAN // trim the excess fat from Windows
/*******************************************************************
* Program: Chapter 8 Texture Example 2: The Waving Flag Example
* OpenGL Game Programming
* Author: Kevin Hawkins
* Description: Displays a "waving" American flag. The flag waves
* based on the sin() function.
********************************************************************/
////// Defines
#define BITMAP_ID 0x4D42 // the universal bitmap ID
////// Includes
#include <windows.h> // standard Windows app include
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gl/gl.h> // standard OpenGL include
#include <gl/glu.h> // OpenGL utilties
////// Global Variables
HDC g_HDC; // global device context
bool fullScreen = false; // true = fullscreen; false = windowed
bool keyPressed[256]; // holds true for keys that are pressed
////// Texture Information
BITMAPINFOHEADER bitmapInfoHeader; // bitmap info header
unsigned char* bitmapData; // the texture data
unsigned int texture; // the texture object
////// Flag Data
float flagPoints[36][20][3]; // flag is 36x20 (in points)
float wrapValue; // used to wrap point data
// InitializeFlag()
// desc: initializes the waving texture mapped flag's data by calculating
// a sin wave across the flag.
void InitializeFlag()
{
int xIdx; // counter index for x-plane
int yIdx; // counter index for y-plane
// loop through all of the flag points and calculate the sin wave
// for the z-coordinate. x- and y- coordinates equal to counter indices
for (xIdx = 0; xIdx < 36; xIdx++)
{
for (yIdx = 0; yIdx < 20; yIdx++)
{
flagPoints[xIdx][yIdx][0] = (float)xIdx;
flagPoints[xIdx][yIdx][1] = (float)yIdx;
flagPoints[xIdx][yIdx][2] = float(sin((((float)xIdx*20.0f)/360.0f)*3.14159f*2.0f));
}
}
}
// DrawFlag()
// desc: draws the waving texture mapped flag
void DrawFlag()
{
int xIdx; // counter index for x-direction
int yIdx; // counter index for y-direction
float texLeft; // left texture coordinate for quads
float texBottom; // bottom texture coordinate for quads
float texTop; // top texture coordinate for quads
float texRight; // right texture coordinate for quads
glPushMatrix();
glBindTexture(GL_TEXTURE_2D, texture); // bind our texture
glBegin(GL_QUADS); // draw flag using quads
// loop through the flag's points, minus the last 2 in each direction
// since we only use them to draw the last GL_QUAD in each direction
for (xIdx = 0; xIdx < 36; xIdx++) // x-direction
{
for (yIdx = 0; yIdx < 18; yIdx++) // y-direction
{
// calculate texture coordinates for current quad
texLeft = float(xIdx) / 35.0f; // left texture coordinate
texBottom = float(yIdx) / 18.0f; // bottom texture coordinate
texRight = float(xIdx+1) / 35.0f; // right texture coordinate
texTop = float(yIdx+1) / 18.0f; // top texture coordinate
// bottom left
glTexCoord2f( texLeft, texBottom);
glVertex3f( flagPoints[xIdx][yIdx][0], flagPoints[xIdx][yIdx][1], flagPoints[xIdx][yIdx][2] );
// bottom right
glTexCoord2f( texRight, texBottom );
glVertex3f( flagPoints[xIdx+1][yIdx][0], flagPoints[xIdx+1][yIdx][1], flagPoints[xIdx+1][yIdx][2] );
// top right
glTexCoord2f( texRight, texTop );
glVertex3f( flagPoints[xIdx+1][yIdx+1][0], flagPoints[xIdx+1][yIdx+1][1], flagPoints[xIdx+1][yIdx+1][2] );
// top left
glTexCoord2f( texLeft, texTop );
glVertex3f( flagPoints[xIdx][yIdx+1][0], flagPoints[xIdx][yIdx+1][1], flagPoints[xIdx][yIdx+1][2] );
}
}
glEnd();
/*
Now we do the flag movement:
We go to each point in the flag by row and move the z-coordinate
of each point one point to the right to simulate the movement of a
a wave.
*/
for( yIdx = 0; yIdx < 19; yIdx++ ) // loop for y-plane
{
// store the furthest right point's z-coordinate value for this row
wrapValue = flagPoints[35][yIdx][2];
for( xIdx = 35; xIdx >= 0; xIdx--) // loop for x-plane
{
// current point z-coordinate is set to the previous point's z-coordinate
flagPoints[xIdx][yIdx][2] = flagPoints[xIdx-1][yIdx][2];
}
// set the furthest left point's z-coordinate to the store'd wrapValue
flagPoints[0][yIdx][2] = wrapValue;
}
glPopMatrix();
}
// LoadBitmapFile
// desc: Returns a pointer to the bitmap image of the bitmap specified
// by filename. Also returns the bitmap header information.
// No support for 8-bit bitmaps.
unsigned char *LoadBitmapFile(char *filename, BITMAPINFOHEADER *bitmapInfoHeader)
{
FILE *filePtr; // the file pointer
BITMAPFILEHEADER bitmapFileHeader; // bitmap file header
unsigned char *bitmapImage; // bitmap image data
int imageIdx = 0; // image index counter
unsigned char tempRGB; // swap variable
// open filename in "read binary" mode
filePtr = fopen(filename, "rb");
if (filePtr == NULL)
return NULL;
// read the bitmap file header
fread(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);
// verify that this is a bitmap by checking for the universal bitmap id
if (bitmapFileHeader.bfType != BITMAP_ID)
{
fclose(filePtr);
return NULL;
}
// read the bitmap information header
fread(bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);
// move file pointer to beginning of bitmap data
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
// allocate enough memory for the bitmap image data
bitmapImage = (unsigned char*)malloc(bitmapInfoHeader->biSizeImage);
// verify memory allocation
if (!bitmapImage)
{
free(bitmapImage);
fclose(filePtr);
return NULL;
}
// read in the bitmap image data
fread(bitmapImage, 1, bitmapInfoHeader->biSizeImage, filePtr);
// make sure bitmap image data was read
if (bitmapImage == NULL)
{
fclose(filePtr);
return NULL;
}
// swap the R and B values to get RGB since the bitmap color format is in BGR
for (imageIdx = 0; imageIdx < bitmapInfoHeader->biSizeImage; imageIdx+=3)
{
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
bitmapImage[imageIdx + 2] = tempRGB;
}
// close the file and return the bitmap image data
fclose(filePtr);
return bitmapImage;
}
// Initialize
// desc: initializes OpenGL
void Initialize()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // clear to black
glShadeModel(GL_SMOOTH); // use smooth shading
glEnable(GL_DEPTH_TEST); // hidden surface removal
glEnable(GL_CULL_FACE); // do not calculate inside of poly's
glFrontFace(GL_CCW); // counter clock-wise polygons are out
glEnable(GL_TEXTURE_2D); // enable 2D texturing
// load our bitmap file
bitmapData = LoadBitmapFile("usflag.bmp", &bitmapInfoHeader);
glGenTextures(1, &texture); // generate texture object
glBindTexture(GL_TEXTURE_2D, texture); // enable our texture object
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// generate the texture image
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, bitmapInfoHeader.biWidth,
bitmapInfoHeader.biHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, bitmapData);
InitializeFlag();
}
// Render
// desc: handles drawing of scene
void Render()
{
// clear screen and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(-15.0f, -10.0f, -50.0f); // perform transformations
DrawFlag(); // draw flag
glFlush();
SwapBuffers(g_HDC); // bring backbuffer to foreground
}
// function to set the pixel format for the device context
void SetupPixelFormat(HDC hDC)
{
int nPixelFormat; // our pixel format index
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // size of structure
1, // default version
PFD_DRAW_TO_WINDOW | // window drawing support
PFD_SUPPORT_OPENGL | // OpenGL support
PFD_DOUBLEBUFFER, // double buffering support
PFD_TYPE_RGBA, // RGBA color mode
32, // 32 bit color mode
0, 0, 0, 0, 0, 0, // ignore color bits, non-palettized mode
0, // no alpha buffer
0, // ignore shift bit
0, // no accumulation buffer
0, 0, 0, 0, // ignore accumulation bits
16, // 16 bit z-buffer size
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main drawing plane
0, // reserved
0, 0, 0 }; // layer masks ignored
nPixelFormat = ChoosePixelFormat(hDC, &pfd); // choose best matching pixel format
SetPixelFormat(hDC, nPixelFormat, &pfd); // set pixel format to device context
}
// the Windows Procedure event handler
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HGLRC hRC; // rendering context
static HDC hDC; // device context
int width, height; // window width and height
switch(message)
{
case WM_CREATE: // window is being created
hDC = GetDC(hwnd); // get current window's device context
g_HDC = hDC;
SetupPixelFormat(hDC); // call our pixel format setup function
// create rendering context and make it current
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
return 0;
break;
case WM_CLOSE: // windows is closing
// deselect rendering context and delete it
wglMakeCurrent(hDC, NULL);
wglDeleteContext(hRC);
// send WM_QUIT to message queue
PostQuitMessage(0);
return 0;
break;
case WM_SIZE:
height = HIWORD(lParam); // retrieve width and height
width = LOWORD(lParam);
if (height==0) // don't want a divide by zero
{
height=1;
}
glViewport(0, 0, width, height); // reset the viewport to new dimensions
glMatrixMode(GL_PROJECTION); // set projection matrix current matrix
glLoadIdentity(); // reset projection matrix
// calculate aspect ratio of window
gluPerspective(54.0f,(GLfloat)width/(GLfloat)height,1.0f,1000.0f);
glMatrixMode(GL_MODELVIEW); // set modelview matrix
glLoadIdentity(); // reset modelview matrix
return 0;
break;
case WM_KEYDOWN: // is a key pressed?
keyPressed[wParam] = true;
return 0;
break;
case WM_KEYUP:
keyPressed[wParam] = false;
return 0;
break;
default:
break;
}
return (DefWindowProc(hwnd, message, wParam, lParam));
}
// the main windows entry point
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEX windowClass; // window class
HWND hwnd; // window handle
MSG msg; // message
bool done; // flag saying when our app is complete
DWORD dwExStyle; // Window Extended Style
DWORD dwStyle; // Window Style
RECT windowRect;
// temp var's
int width = 800;
int height = 600;
int bits = 32;
//fullScreen = TRUE;
windowRect.left=(long)0; // Set Left Value To 0
windowRect.right=(long)width; // Set Right Value To Requested Width
windowRect.top=(long)0; // Set Top Value To 0
windowRect.bottom=(long)height; // Set Bottom Value To Requested Height
// fill out the window class structure
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WndProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); // default icon
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); // default arrow
windowClass.hbrBackground = NULL; // don't need background
windowClass.lpszMenuName = NULL; // no menu
windowClass.lpszClassName = "MyClass";
windowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO); // windows logo small icon
// register the windows class
if (!RegisterClassEx(&windowClass))
return 0;
if (fullScreen) // fullscreen?
{
DEVMODE dmScreenSettings; // device mode
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = width; // screen width
dmScreenSettings.dmPelsHeight = height; // screen height
dmScreenSettings.dmBitsPerPel = bits; // bits per pixel
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
//
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
// setting display mode failed, switch to windowed
MessageBox(NULL, "Display mode failed", NULL, MB_OK);
fullScreen=FALSE;
}
}
if (fullScreen) // Are We Still In Fullscreen Mode?
{
dwExStyle=WS_EX_APPWINDOW; // Window Extended Style
dwStyle=WS_POPUP; // Windows Style
ShowCursor(FALSE); // Hide Mouse Pointer
}
else
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style
dwStyle=WS_OVERLAPPEDWINDOW; // Windows Style
}
AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size
// class registered, so now create our window
hwnd = CreateWindowEx(NULL, // extended style
"MyClass", // class name
"Texture Example 2: The Waving Flag Example", // app name
dwStyle | WS_CLIPCHILDREN |
WS_CLIPSIBLINGS,
0, 0, // x,y coordinate
windowRect.right - windowRect.left,
windowRect.bottom - windowRect.top, // width, height
NULL, // handle to parent
NULL, // handle to menu
hInstance, // application instance
NULL); // no extra params
// check if window creation failed (hwnd would equal NULL)
if (!hwnd)
return 0;
ShowWindow(hwnd, SW_SHOW); // display the window
UpdateWindow(hwnd); // update the window
done = false; // intialize the loop condition variable
Initialize(); // initialize OpenGL
// main message loop
while (!done)
{
PeekMessage(&msg, hwnd, NULL, NULL, PM_REMOVE);
if (msg.message == WM_QUIT) // do we receive a WM_QUIT message?
{
done = true; // if so, time to quit the application
}
else
{
if (keyPressed[VK_ESCAPE])
done = true;
else
{
Render();
TranslateMessage(&msg); // translate and dispatch to event queue
DispatchMessage(&msg);
}
}
}
free(bitmapData);
if (fullScreen)
{
ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop
ShowCursor(TRUE); // Show Mouse Pointer
}
return msg.wParam;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -