📄 lesson21.cpp
字号:
/*
* This Code Was Created By Jeff Molofee 2000
* If You've Found This Code Useful, Please Let Me Know.
* Visit My Site At nehe.gamedev.net
*/
#include <windows.h> // Header File For Windows
#include <stdio.h> // Header File For Standard Input / Output
#include <stdarg.h> // Header File For Variable Argument Routines
#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
bool keys[256]; // Array Used For The Keyboard Routine
bool vline[11][10]; // Keeps Track Of Verticle Lines
bool hline[10][11]; // Keeps Track Of Horizontal Lines
bool ap; // 'A' Key Pressed?
bool filled; // Done Filling In The Grid?
bool gameover; // Is The Game Over?
bool anti=TRUE; // Antialiasing?
bool active=TRUE; // Window Active Flag Set To TRUE By Default
bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default
int loop1; // Generic Loop1
int loop2; // Generic Loop2
int delay; // Enemy Delay
int adjust=3; // Speed Adjustment For Really Slow Video Cards
int lives=5; // Player Lives
int level=1; // Internal Game Level
int level2=level; // Displayed Game Level
int stage=1; // Game Stage
struct object // Create A Structure For Our Player
{
int fx, fy; // Fine Movement Position
int x, y; // Current Player Position
float spin; // Spin Direction
};
struct object player; // Player Information
struct object enemy[9]; // Enemy Information
struct object hourglass; // Hourglass Information
struct // Create A Structure For The Timer Information
{
__int64 frequency; // Timer Frequency
float resolution; // Timer Resolution
unsigned long mm_timer_start; // Multimedia Timer Start Value
unsigned long mm_timer_elapsed; // Multimedia Timer Elapsed Time
bool performance_timer; // Using The Performance Timer?
__int64 performance_timer_start; // Performance Timer Start Value
__int64 performance_timer_elapsed; // Performance Timer Elapsed Time
} timer; // Structure Is Named timer
int steps[6]={ 1, 2, 4, 5, 10, 20 }; // Stepping Values For Slow Video Adjustment
GLuint texture[2]; // Font Texture Storage Space
GLuint base; // Base Display List For The Font
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc
void TimerInit(void) // Initialize Our Timer (Get It Ready)
{
memset(&timer, 0, sizeof(timer)); // Clear Our Timer Structure
// Check To See If A Performance Counter Is Available
// If One Is Available The Timer Frequency Will Be Updated
if (!QueryPerformanceFrequency((LARGE_INTEGER *) &timer.frequency))
{
// No Performace Counter Available
timer.performance_timer = FALSE; // Set Performance Timer To FALSE
timer.mm_timer_start = timeGetTime(); // Use timeGetTime() To Get Current Time
timer.resolution = 1.0f/1000.0f; // Set Our Timer Resolution To .001f
timer.frequency = 1000; // Set Our Timer Frequency To 1000
timer.mm_timer_elapsed = timer.mm_timer_start; // Set The Elapsed Time To The Current Time
}
else
{
// Performance Counter Is Available, Use It Instead Of The Multimedia Timer
// Get The Current Time And Store It In performance_timer_start
QueryPerformanceCounter((LARGE_INTEGER *) &timer.performance_timer_start);
timer.performance_timer = TRUE; // Set Performance Timer To TRUE
// Calculate The Timer Resolution Using The Timer Frequency
timer.resolution = (float) (((double)1.0f)/((double)timer.frequency));
// Set The Elapsed Time To The Current Time
timer.performance_timer_elapsed = timer.performance_timer_start;
}
}
float TimerGetTime() // Get Time In Milliseconds
{
__int64 time; // time Will Hold A 64 Bit Integer
if (timer.performance_timer) // Are We Using The Performance Timer?
{
QueryPerformanceCounter((LARGE_INTEGER *) &time); // Grab The Current Performance Time
// Return The Current Time Minus The Start Time Multiplied By The Resolution And 1000 (To Get MS)
return ( (float) ( time - timer.performance_timer_start) * timer.resolution)*1000.0f;
}
else
{
// Return The Current Time Minus The Start Time Multiplied By The Resolution And 1000 (To Get MS)
return( (float) ( timeGetTime() - timer.mm_timer_start) * timer.resolution)*1000.0f;
}
}
void ResetObjects(void) // Reset Player And Enemies
{
player.x=0; // Reset Player X Position To Far Left Of The Screen
player.y=0; // Reset Player Y Position To The Top Of The Screen
player.fx=0; // Set Fine X Position To Match
player.fy=0; // Set Fine Y Position To Match
for (loop1=0; loop1<(stage*level); loop1++) // Loop Through All The Enemies
{
enemy[loop1].x=5+rand()%6; // Select A Random X Position
enemy[loop1].y=rand()%11; // Select A Random Y Position
enemy[loop1].fx=enemy[loop1].x*60; // Set Fine X To Match
enemy[loop1].fy=enemy[loop1].y*40; // Set Fine Y To Match
}
}
AUX_RGBImageRec *LoadBMP(char *Filename) // Loads The Bitmap Images
{
FILE *File=NULL; // File Handle
if (!Filename) // Make Sure A Filename Was Given
{
return NULL; // If Not Return NULL
}
File=fopen(Filename,"r"); // Check To See If The File Exists
if (File) // Does The File Exist?
{
fclose(File); // Close The Handle
return auxDIBImageLoad(Filename); // Load The Bitmap And Return A Pointer
}
return NULL; // If Load Failed Return NULL
}
int LoadGLTextures() // Load Bitmaps And Convert To Textures
{
int Status=FALSE; // Status Indicator
AUX_RGBImageRec *TextureImage[2]; // Create Storage Space For The Textures
memset(TextureImage,0,sizeof(void *)*2); // Set The Pointer To NULL
if ((TextureImage[0]=LoadBMP("Data/Font.bmp")) && // Load The Font
(TextureImage[1]=LoadBMP("Data/Image.bmp"))) // Load Background Image
{
Status=TRUE; // Set The Status To TRUE
glGenTextures(2, &texture[0]); // Create The Texture
for (loop1=0; loop1<2; loop1++) // Loop Through 2 Textures
{
glBindTexture(GL_TEXTURE_2D, texture[loop1]);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[loop1]->sizeX, TextureImage[loop1]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop1]->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}
for (loop1=0; loop1<2; loop1++) // Loop Through 2 Textures
{
if (TextureImage[loop1]) // If Texture Exists
{
if (TextureImage[loop1]->data) // If Texture Image Exists
{
free(TextureImage[loop1]->data); // Free The Texture Image Memory
}
free(TextureImage[loop1]); // Free The Image Structure
}
}
}
return Status; // Return The Status
}
GLvoid BuildFont(GLvoid) // Build Our Font Display List
{
base=glGenLists(256); // Creating 256 Display Lists
glBindTexture(GL_TEXTURE_2D, texture[0]); // Select Our Font Texture
for (loop1=0; loop1<256; loop1++) // Loop Through All 256 Lists
{
float cx=float(loop1%16)/16.0f; // X Position Of Current Character
float cy=float(loop1/16)/16.0f; // Y Position Of Current Character
glNewList(base+loop1,GL_COMPILE); // Start Building A List
glBegin(GL_QUADS); // Use A Quad For Each Character
glTexCoord2f(cx,1.0f-cy-0.0625f); // Texture Coord (Bottom Left)
glVertex2d(0,16); // Vertex Coord (Bottom Left)
glTexCoord2f(cx+0.0625f,1.0f-cy-0.0625f); // Texture Coord (Bottom Right)
glVertex2i(16,16); // Vertex Coord (Bottom Right)
glTexCoord2f(cx+0.0625f,1.0f-cy); // Texture Coord (Top Right)
glVertex2i(16,0); // Vertex Coord (Top Right)
glTexCoord2f(cx,1.0f-cy); // Texture Coord (Top Left)
glVertex2i(0,0); // Vertex Coord (Top Left)
glEnd(); // Done Building Our Quad (Character)
glTranslated(15,0,0); // Move To The Right Of The Character
glEndList(); // Done Building The Display List
} // Loop Until All 256 Are Built
}
GLvoid KillFont(GLvoid) // Delete The Font From Memory
{
glDeleteLists(base,256); // Delete All 256 Display Lists
}
GLvoid glPrint(GLint x, GLint y, int set, const char *fmt, ...) // Where The Printing Happens
{
char text[256]; // Holds Our String
va_list ap; // Pointer To List Of Arguments
if (fmt == NULL) // If There's No Text
return; // Do Nothing
va_start(ap, fmt); // Parses The String For Variables
vsprintf(text, fmt, ap); // And Converts Symbols To Actual Numbers
va_end(ap); // Results Are Stored In Text
if (set>1) // Did User Choose An Invalid Character Set?
{
set=1; // If So, Select Set 1 (Italic)
}
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glLoadIdentity(); // Reset The Modelview Matrix
glTranslated(x,y,0); // Position The Text (0,0 - Bottom Left)
glListBase(base-32+(128*set)); // Choose The Font Set (0 or 1)
if (set==0) // If Set 0 Is Being Used Enlarge Font
{
glScalef(1.5f,2.0f,1.0f); // Enlarge Font Width And Height
}
glCallLists(strlen(text),GL_UNSIGNED_BYTE, text); // Write The Text To The Screen
glDisable(GL_TEXTURE_2D); // Disable Texture Mapping
}
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize And Initialize The GL Window
{
if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}
glViewport(0,0,width,height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
glOrtho(0.0f,width,height,0.0f,-1.0f,1.0f); // Create Ortho 640x480 View (0,0 At Top Left)
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
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
}
BuildFont(); // Build The Font
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // Set Line Antialiasing
glEnable(GL_BLEND); // Enable Blending
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Type Of Blending To Use
return TRUE; // Initialization Went OK
}
int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glBindTexture(GL_TEXTURE_2D, texture[0]); // Select Our Font Texture
glColor3f(1.0f,0.5f,1.0f); // Set Color To Purple
glPrint(207,24,0,"GRID CRAZY"); // Write GRID CRAZY On The Screen
glColor3f(1.0f,1.0f,0.0f); // Set Color To Yellow
glPrint(20,20,1,"Level:%2i",level2); // Write Actual Level Stats
glPrint(20,40,1,"Stage:%2i",stage); // Write Stage Stats
if (gameover) // Is The Game Over?
{
glColor3ub(rand()%255,rand()%255,rand()%255); // Pick A Random Color
glPrint(472,20,1,"GAME OVER"); // Write GAME OVER To The Screen
glPrint(456,40,1,"PRESS SPACE"); // Write PRESS SPACE To The Screen
}
for (loop1=0; loop1<lives-1; loop1++) // Loop Through Lives Minus Current Life
{
glLoadIdentity(); // Reset The View
glTranslatef(490+(loop1*40.0f),40.0f,0.0f); // Move To The Right Of Our Title Text
glRotatef(-player.spin,0.0f,0.0f,1.0f); // Rotate Counter Clockwise
glColor3f(0.0f,1.0f,0.0f); // Set Player Color To Light Green
glBegin(GL_LINES); // Start Drawing Our Player Using Lines
glVertex2d(-5,-5); // Top Left Of Player
glVertex2d( 5, 5); // Bottom Right Of Player
glVertex2d( 5,-5); // Top Right Of Player
glVertex2d(-5, 5); // Bottom Left Of Player
glEnd(); // Done Drawing The Player
glRotatef(-player.spin*0.5f,0.0f,0.0f,1.0f); // Rotate Counter Clockwise
glColor3f(0.0f,0.75f,0.0f); // Set Player Color To Dark Green
glBegin(GL_LINES); // Start Drawing Our Player Using Lines
glVertex2d(-7, 0); // Left Center Of Player
glVertex2d( 7, 0); // Right Center Of Player
glVertex2d( 0,-7); // Top Center Of Player
glVertex2d( 0, 7); // Bottom Center Of Player
glEnd(); // Done Drawing The Player
}
filled=TRUE; // Set Filled To True Before Testing
glLineWidth(2.0f); // Set Line Width For Cells To 2.0f
glDisable(GL_LINE_SMOOTH); // Disable Antialiasing
glLoadIdentity(); // Reset The Current Modelview Matrix
for (loop1=0; loop1<11; loop1++) // Loop From Left To Right
{
for (loop2=0; loop2<11; loop2++) // Loop From Top To Bottom
{
glColor3f(0.0f,0.5f,1.0f); // Set Line Color To Blue
if (hline[loop1][loop2]) // Has The Horizontal Line Been Traced
{
glColor3f(1.0f,1.0f,1.0f); // If So, Set Line Color To White
}
if (loop1<10) // Dont Draw To Far Right
{
if (!hline[loop1][loop2]) // If A Horizontal Line Isn't Filled
{
filled=FALSE; // filled Becomes False
}
glBegin(GL_LINES); // Start Drawing Horizontal Cell Borders
glVertex2d(20+(loop1*60),70+(loop2*40));// Left Side Of Horizontal Line
glVertex2d(80+(loop1*60),70+(loop2*40));// Right Side Of Horizontal Line
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -