outdated: 10.Loading And Moving Through A 3D World

这一节主要说的是camera的移动以及视角的旋转问题。

我在原本代码的基础上做了添加和修改,将移动方向的改为WSAD,并将视角旋转的向上向下向左向右改为UPDOWNLEFTRIGHT。最后还添加了下蹲为Ctrl键跳跃SPACE键(空格),其实就是CS里的几个虚拟键的实现。

想想如果把世界坐标的数据存在于程序中是非常繁琐的,所以给出了读取世界数据信息的格式:

X1 Y1 Z1 U1 V1
X2 Y2 Z2 U2 V2
X3 Y3 Z3 U3 V3

...

NUMPOLLIES 36

// Floor 1
-3.0  0.0 -3.0 0.0 6.0
-3.0  0.0  3.0 0.0 0.0
 3.0  0.0  3.0 6.0 0.0

-3.0  0.0 -3.0 0.0 6.0
 3.0  0.0 -3.0 6.0 6.0
 3.0  0.0  3.0 6.0 0.0

// Ceiling 1
-3.0  1.0 -3.0 0.0 6.0
-3.0  1.0  3.0 0.0 0.0
 3.0  1.0  3.0 6.0 0.0
-3.0  1.0 -3.0 0.0 6.0
 3.0  1.0 -3.0 6.0 6.0
 3.0  1.0  3.0 6.0 0.0

// A1

-2.0  1.0  -2.0 0.0 1.0
-2.0  0.0  -2.0 0.0 0.0
-0.5  0.0  -2.0 1.5 0.0
-2.0  1.0  -2.0 0.0 1.0
-0.5  1.0  -2.0 1.5 1.0
-0.5  0.0  -2.0 1.5 0.0

// A2

 2.0  1.0  -2.0 2.0 1.0
 2.0  0.0  -2.0 2.0 0.0
 0.5  0.0  -2.0 0.5 0.0
 2.0  1.0  -2.0 2.0 1.0
 0.5  1.0  -2.0 0.5 1.0
 0.5  0.0  -2.0 0.5 0.0

// B1

-2.0  1.0  2.0 2.0  1.0
-2.0  0.0   2.0 2.0 0.0
-0.5  0.0   2.0 0.5 0.0
-2.0  1.0  2.0 2.0  1.0
-0.5  1.0  2.0 0.5  1.0
-0.5  0.0   2.0 0.5 0.0

// B2

 2.0  1.0  2.0 2.0  1.0
 2.0  0.0   2.0 2.0 0.0
 0.5  0.0   2.0 0.5 0.0
 2.0  1.0  2.0 2.0  1.0
 0.5  1.0  2.0 0.5  1.0
 0.5  0.0   2.0 0.5 0.0

// C1

-2.0  1.0  -2.0 0.0  1.0
-2.0  0.0   -2.0 0.0 0.0
-2.0  0.0   -0.5 1.5 0.0
-2.0  1.0  -2.0 0.0  1.0
-2.0  1.0  -0.5 1.5  1.0
-2.0  0.0   -0.5 1.5 0.0

// C2

-2.0  1.0   2.0 2.0 1.0
-2.0  0.0   2.0 2.0 0.0
-2.0  0.0   0.5 0.5 0.0
-2.0  1.0  2.0 2.0 1.0
-2.0  1.0  0.5 0.5 1.0
-2.0  0.0   0.5 0.5 0.0

// D1

2.0  1.0  -2.0 0.0 1.0
2.0  0.0   -2.0 0.0 0.0
2.0  0.0   -0.5 1.5 0.0
2.0  1.0  -2.0 0.0 1.0
2.0  1.0  -0.5 1.5 1.0
2.0  0.0   -0.5 1.5 0.0

// D2

2.0  1.0  2.0 2.0 1.0
2.0  0.0   2.0 2.0 0.0
2.0  0.0   0.5 0.5 0.0
2.0  1.0  2.0 2.0 1.0
2.0  1.0  0.5 0.5 1.0
2.0  0.0   0.5 0.5 0.0

// Upper hallway - L
-0.5  1.0  -3.0 0.0 1.0
-0.5  0.0   -3.0 0.0 0.0
-0.5  0.0   -2.0 1.0 0.0
-0.5  1.0  -3.0 0.0 1.0
-0.5  1.0  -2.0 1.0 1.0
-0.5  0.0   -2.0 1.0 0.0

// Upper hallway - R
0.5  1.0  -3.0 0.0 1.0
0.5  0.0   -3.0 0.0 0.0
0.5  0.0   -2.0 1.0 0.0
0.5  1.0  -3.0 0.0 1.0
0.5  1.0  -2.0 1.0 1.0
0.5  0.0   -2.0 1.0 0.0

// Lower hallway - L
-0.5  1.0  3.0 0.0 1.0
-0.5  0.0   3.0 0.0 0.0
-0.5  0.0   2.0 1.0 0.0
-0.5  1.0  3.0 0.0 1.0
-0.5  1.0  2.0 1.0 1.0
-0.5  0.0   2.0 1.0 0.0

// Lower hallway - R
0.5  1.0  3.0 0.0 1.0
0.5  0.0   3.0 0.0 0.0
0.5  0.0   2.0 1.0 0.0
0.5  1.0  3.0 0.0 1.0
0.5  1.0  2.0 1.0 1.0
0.5  0.0   2.0 1.0 0.0


// Left hallway - Lw

-3.0  1.0  0.5 1.0 1.0
-3.0  0.0   0.5 1.0 0.0
-2.0  0.0   0.5 0.0 0.0
-3.0  1.0  0.5 1.0 1.0
-2.0  1.0  0.5 0.0 1.0
-2.0  0.0   0.5 0.0 0.0

// Left hallway - Hi

-3.0  1.0  -0.5 1.0 1.0
-3.0  0.0   -0.5 1.0 0.0
-2.0  0.0   -0.5 0.0 0.0
-3.0  1.0  -0.5 1.0 1.0
-2.0  1.0  -0.5 0.0 1.0
-2.0  0.0   -0.5 0.0 0.0

// Right hallway - Lw

3.0  1.0  0.5 1.0 1.0
3.0  0.0   0.5 1.0 0.0
2.0  0.0   0.5 0.0 0.0
3.0  1.0  0.5 1.0 1.0
2.0  1.0  0.5 0.0 1.0
2.0  0.0   0.5 0.0 0.0

// Right hallway - Hi

3.0  1.0  -0.5 1.0 1.0
3.0  0.0   -0.5 1.0 0.0
2.0  0.0   -0.5 0.0 0.0
3.0  1.0  -0.5 1.0 1.0
2.0  1.0 -0.5 0.0 1.0
2.0  0.0   -0.5 0.0 0.0
世界坐标数据文件

对于camera的移动以及视角的旋转,我们并不是直接实现camera的移动以及视角的旋转,而是

  • 以与镜头平移方向相反的方向来平移世界,进而让人产生镜头移动的错觉。
  • 围绕原点,以镜头相反的方向旋转世界,进而让人产生镜头旋转的错觉。

实现起来还算简单。

下蹲:

跳跃:

正常:

 

代码如下,同样修改部分位于双行星号内。

  1 #include <windows.h>
  2 #include <stdio.h>
  3 #include <math.h>
  4 #include <gl/glew.h>
  5 #include <gl/glut.h>
  6 #include <GL/GLUAX.H>
  7 #pragma comment(lib, "legacy_stdio_definitions.lib")
  8 /*
  9  *  Every OpenGL program is linked to a Rendering Context.
 10  *  A Rendering Context is what links OpenGL calls to the Device Context.
 11  *  In order for your program to draw to a Window you need to create a Device Context.
 12  *  The DC connects the Window to the GDI (Graphics Device Interface).
 13  */
 14 
 15 HGLRC     hRC = NULL;         // Permanent rendering context
 16 HDC       hDC = NULL;         // Private GDI device context
 17 HWND      hWnd = NULL;        // Holds our window handle
 18 HINSTANCE hInstance;          // Holds the instance of the application
 19 
 20 /*
 21  *  It's important to make this global so that each procedure knows if 
 22  *  the program is running in fullscreen mode or not.
 23  */
 24 
 25 bool keys[256];         // Array used for the keyboard routine
 26 bool active = TRUE;     // Window active flag set to TRUE by default
 27 bool fullscreen = TRUE; // Fullscreen flag set to fullscreen mode by default
 28 
 29 BOOL light;             // Lighting ON/OFF
 30 BOOL blend;             // Blend ON/OFF
 31 BOOL twinkle;           // Twinkling stars
 32 BOOL tp;                // T pressed
 33 BOOL lp;                // L pressed
 34 BOOL fp;                // F pressed
 35 BOOL bp;                // B pressed
 36 
 37 GLfloat LightAmbient[] = {0.5f, 0.5f, 0.5f, 1.0f};    // Ambient light values
 38 
 39 GLfloat LightDiffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};    // Diffuse light values
 40 
 41 GLfloat LightPosition[] = {0.0f, 0.0f, 2.0f, 1.0f};   // Light position
 42 /******************************************************************************************************************************************/
 43 /******************************************************************************************************************************************/
 44 GLuint filter;
 45 GLuint texture[3];
 46 // Piover180 is simply a conversion factor for converting between degrees and radians
 47 const float piover180 = 0.0174532925f;
 48 float heading;
 49 float xpos;
 50 float zpos;
 51 float ytemp1;
 52 float ytemp2;
 53 
 54 GLfloat yrot;
 55 GLfloat walkbias = 0.0f;
 56 GLfloat walkbiasangle = 0.0f;
 57 GLfloat lookupdown = 0.0f;
 58 GLfloat z = 0.0f;
 59 
 60 typedef struct tagVERTEX VERTEX;
 61 struct tagVERTEX {
 62     float x, y, z;                                    // 3D Coordinates
 63     float u, v;                                       // Texture Coordinates
 64 };
 65 
 66 typedef struct tagTRIANGLE TRIANGLE;
 67 struct tagTRIANGLE {
 68     VERTEX vertex[3];                                 // Array Of Three Vertices
 69 };
 70 
 71 typedef struct tagSECTOR SECTOR;
 72 struct tagSECTOR {                                    // Build Our Sector Structure
 73     int numtriangles;                                 // Number Of Triangles In Sector
 74     TRIANGLE* triangle;                               // Pointer To Array Of Triangles
 75 };
 76 
 77 SECTOR sector1;
 78 
 79 /*
 80  *  CreateGLWindow() has a reference to WndProc() but WndProc() comes after CreateGLWindow().
 81  */
 82 
 83 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration for WndProc
 84 
 85 /*
 86  *  The job of the next section of code is to resize the OpenGL scene 
 87  *  whenever the window (assuming you are using a Window rather than fullscreen mode) has been resized.
 88  */
 89 void readstr(FILE* f, char* string)
 90 {
 91     do {
 92         fgets(string, 255, f);
 93     } while ((string[0] == '/') || (string[0] == '\n'));
 94     return ;
 95 }
 96 
 97 void SetupWorld()
 98 {
 99     float x, y, z, u, v;
100     int numtriangles;
101     FILE* filein;
102     char oneline[255];
103     filein = fopen("World.txt", "rt");
104 
105     readstr(filein, oneline);
106     sscanf(oneline, "NUMPOLLIES %d\n", &numtriangles);
107 
108     sector1.triangle = new TRIANGLE[numtriangles];
109     sector1.numtriangles = numtriangles;
110 
111     for (int triloop = 0; triloop < numtriangles; ++triloop) {
112         for (int vertloop = 0; vertloop < 3; ++vertloop) {
113             readstr(filein, oneline);
114             sscanf(oneline, "%f %f %f %f %f", &x, &y, &z, &u, &v);
115             sector1.triangle[triloop].vertex[vertloop].x = x;
116             sector1.triangle[triloop].vertex[vertloop].y = y;
117             sector1.triangle[triloop].vertex[vertloop].z = z;
118             sector1.triangle[triloop].vertex[vertloop].u = u;
119             sector1.triangle[triloop].vertex[vertloop].v = v;
120         }
121     }
122     fclose(filein);
123     return ;
124 }
125  /******************************************************************************************************************************************/
126  /******************************************************************************************************************************************/
127 AUX_RGBImageRec* LoadBMP(char* Filename)              // Loads a bitmap image
128 {
129     FILE* File = NULL;                                // File handle
130 
131     if (!Filename) {                                  // Make sure a filename was given
132         return NULL;                                  // If not return NULL
133     }
134 
135     File = fopen(Filename, "r");                      // Check to see of the file exists
136     if (File) {
137         fclose(File);
138         return auxDIBImageLoad(Filename);             // Load the bitmap and return a pointer
139     }
140 
141     return NULL;
142 }
143 
144 int LoadGLTextures()                                  // Load bitmap and convert to texture
145 {
146     int Status = FALSE;                               // Status indicator
147 
148     AUX_RGBImageRec* TextureImage[1];                 // Create    storage space for the texture
149 
150     memset(TextureImage, 0, sizeof(void*)*1);         // Set the pointer to NULL
151 
152     // Load the bitmap, check for error, if bitmap's not found quit
153     if (TextureImage[0] = LoadBMP("1.bmp")) {
154         Status = TRUE;
155 
156         glGenTextures(1, &texture[0]);                // Create the texture
157 /******************************************************************************************************************************************/
158 /******************************************************************************************************************************************/
159         glBindTexture(GL_TEXTURE_2D, texture[0]);
160         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Linear filtering
161         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Linear filtering
162         glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB,
163             GL_UNSIGNED_BYTE, TextureImage[0]->data);
164         
165         glBindTexture(GL_TEXTURE_2D, texture[1]);
166         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Linear filtering
167         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear filtering
168         glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB,
169             GL_UNSIGNED_BYTE, TextureImage[0]->data);
170 
171         glBindTexture(GL_TEXTURE_2D, texture[2]);
172         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
173         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
174         gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, GL_RGB,
175             GL_UNSIGNED_BYTE, TextureImage[0]->data);
176     }
177 /******************************************************************************************************************************************/
178 /******************************************************************************************************************************************/
179     if (TextureImage[0]) {
180         if (TextureImage[0]->data) {
181             free(TextureImage[0]->data);
182         }
183         free(TextureImage[0]);
184     }
185     return Status;
186 }
187 
188 
189 GLvoid ReSizeGLScene(GLsizei width, GLsizei height)   // Resize and initialize the GL window
190 {
191     if (height == 0) {                                // Prevent a divide by zero by
192         height = 1;                                   // Making height equal one
193     }
194     
195     glViewport(0, 0, width, height);                  // Reset the current viewport
196 
197     /*
198      *  The following lines set the screen up for a perspective view. 
199      *  Meaning things in the distance get smaller. This creates a realistic looking scene. 
200      *  The perspective is calculated with a 45 degree viewing angle based on 
201      *  the windows width and height. The 0.1f, 100.0f is the starting point and 
202      *  ending point for how deep we can draw into the screen.
203      *
204      *  The projection matrix is responsible for adding perspective to our scene.
205      *  glLoadIdentity() restores the selected matrix to it's original state.
206      *  The modelview matrix is where our object information is stored.
207      *   Lastly we reset the modelview matrix.
208      */
209 
210     glMatrixMode(GL_PROJECTION);                      // Select the projection matrix
211     glLoadIdentity();                                 // Reset the projection matrix
212     
213                                                       // Calculate the aspect ratio of the window
214     gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
215 
216     glMatrixMode(GL_MODELVIEW);                       // Seclet the modelview matrix
217     glLoadIdentity();                                 // Reset the modelview matrix
218 }
219 
220 int InitGL(GLvoid)                                    // All setup for OpenGL goes here
221 {
222     if (!LoadGLTextures()) {                          // Jump to texture loading routine
223         return FALSE;                                 // If texture didn't load return false
224     }
225     glEnable(GL_TEXTURE_2D);                          // Enable texture mapping
226     /*
227      *  Smooth shading blends colors nicely across a polygon, and smoothes out lighting.
228      */
229 
230 /******************************************************************************************************************************************/
231 /******************************************************************************************************************************************/
232     glBlendFunc(GL_SRC_ALPHA, GL_ONE);
233     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);             // Black background
234 
235     /*
236      *  Think of the depth buffer as layers into the screen. 
237      *  The depth buffer keeps track of how deep objects are into the screen.
238      */
239 
240     glClearDepth(1.0f);                               // Depth buffer setup
241     /*
242      *  Next we tell OpenGL we want the best perspective correction to be done. 
243      *  This causes a very tiny performance hit, but makes the perspective view look a bit better.
244      */
245     glDepthFunc(GL_LESS);
246     glEnable(GL_DEPTH_TEST);
247     glShadeModel(GL_SMOOTH);                          // Enables smooth shading
248     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);   // Really nice perspective calculations
249 
250     SetupWorld();
251     return TRUE;
252 }
253 
254 /*
255  *  For now all we will do is clear the screen to the color we previously decided on, 
256  *  clear the depth buffer and reset the scene. We wont draw anything yet.
257  */
258 int DrawGLScene(GLvoid)                                  // Here's where we do all the drawing
259 {
260     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // Clear the screen and the depth buffer
261     glLoadIdentity();
262 
263     GLfloat x_m, y_m, z_m, u_m, v_m;
264     GLfloat xtrans = -xpos;
265     GLfloat ztrans = -zpos;
266     GLfloat ytrans = -walkbias - 0.25f - ytemp1 - ytemp2;   // Used for bouncing motion up and down
267     GLfloat sceneroty = 360.0f - yrot;                   // 360 degree angle for player direction
268     
269     int numtriangles;
270 
271     glRotatef(lookupdown, 1.0f, 0.0f, 0.0f);
272     glRotatef(sceneroty, 0.0f, 1.0f, 0.0f);
273     
274     glTranslatef(xtrans, ytrans-0.2, ztrans);
275     glBindTexture(GL_TEXTURE_2D, texture[filter]);
276 
277     numtriangles = sector1.numtriangles;
278 
279     for (int loop_m = 0; loop_m < numtriangles; ++loop_m) {
280         glBegin(GL_TRIANGLES);
281             glNormal3f(0.0f, 0.0f, 1.0f);
282             x_m = sector1.triangle[loop_m].vertex[0].x;
283             y_m = sector1.triangle[loop_m].vertex[0].y;
284             z_m = sector1.triangle[loop_m].vertex[0].z;
285             u_m = sector1.triangle[loop_m].vertex[0].u;
286             v_m = sector1.triangle[loop_m].vertex[0].v;
287             glTexCoord2f(u_m, v_m); glVertex3f(x_m, y_m, z_m);
288 
289             x_m = sector1.triangle[loop_m].vertex[1].x;
290             y_m = sector1.triangle[loop_m].vertex[1].y;
291             z_m = sector1.triangle[loop_m].vertex[1].z;
292             u_m = sector1.triangle[loop_m].vertex[1].u;
293             v_m = sector1.triangle[loop_m].vertex[1].v;
294             glTexCoord2f(u_m, v_m); glVertex3f(x_m, y_m, z_m);
295 
296             x_m = sector1.triangle[loop_m].vertex[2].x;
297             y_m = sector1.triangle[loop_m].vertex[2].y;
298             z_m = sector1.triangle[loop_m].vertex[2].z;
299             u_m = sector1.triangle[loop_m].vertex[2].u;
300             v_m = sector1.triangle[loop_m].vertex[2].v;
301             glTexCoord2f(u_m, v_m); glVertex3f(x_m, y_m, z_m);
302         glEnd();
303     }
304     return TRUE;                                         // everthing went OK
305 }
306 /******************************************************************************************************************************************/
307 /******************************************************************************************************************************************/
308 /*
309  *  The job of KillGLWindow() is to release the Rendering Context, 
310  *  the Device Context and finally the Window Handle. 
311  */
312 
313 GLvoid KillGLWindow(GLvoid)                              // Properly kill the window
314 {
315     if (fullscreen) {                                    // Are we in fullscreen mode
316         
317         /*
318          *  We use ChangeDisplaySettings(NULL,0) to return us to our original desktop.
319          *  After we've switched back to the desktop we make the cursor visible again.
320          */
321 
322         ChangeDisplaySettings(NULL, 0);                  // if so switch back to the desktop
323         ShowCursor(TRUE);                                // Show mouse pointer
324     }
325 
326     if (hRC) {                                           // Do we have a rendering context
327         if (!wglMakeCurrent(NULL, NULL)) {                // Are we able to release the DC and RC contexts
328             MessageBox(NULL, "Release of DC and RC failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
329         }
330 
331         if (!wglDeleteContext(hRC)) {                     // Are we able to delete the RC
332             MessageBox(NULL, "Release rendering context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
333             hRC = NULL;                                  // Set RC to NULL
334         }
335 
336         if (hDC && !ReleaseDC(hWnd, hDC)) {              // Are we able to release the DC
337             MessageBox(NULL, "Release device context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
338             hDC = NULL;                                  // Set DC to NULL
339         }
340         if (hWnd && !DestroyWindow(hWnd)) {              // Are we able to destroy the window
341             MessageBox(NULL, "Could not release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
342             hWnd = NULL;                                 // Set hWnd to NULL
343         }
344 
345         if (!UnregisterClass("OpenGL", hInstance)) {     // Are we able to unregister class
346             MessageBox(NULL, "Could not register class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
347             hInstance = NULL;                            // Set hInstance to NULL
348         }
349     }
350 }
351 
352 /*
353  * The next section of code creates our OpenGL Window.
354  */
355 
356 BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
357 {
358     /*
359      * Find  a pixel format that matches the one we want
360      */
361     GLuint PixelFormat;                                  // Holds the result after serching for a match
362     
363     /*
364      * Before you create a window, you MUST register a Class for the window
365      */
366     WNDCLASS wc;                                         // Windows class structure
367 
368     /*
369      *  dwExStyle and dwStyle will store the Extended and normal Window Style Information.
370     */
371     DWORD dwExStyle;                                     // Window extend style
372     DWORD dwStyle;                                       // Window style
373 
374     RECT WindowRect;                                     // Grabs rectangle upper left/lower right values
375     WindowRect.left = (long)0;                           // Set left value to 0
376     WindowRect.right = (long)width;                      // Set right value to requested width
377     WindowRect.top = (long)0;                            // Set top value to 0
378     WindowRect.bottom = (long)height;                    // Set bottom value to requested height
379 
380     fullscreen = fullscreenflag;                         // Set the global fullscreen flag
381 
382     /*
383      *  The style CS_HREDRAW and CS_VREDRAW force the Window to redraw whenever it is resized. 
384      *  CS_OWNDC creates a private DC for the Window. Meaning the DC is not shared across applications. 
385      *  WndProc is the procedure that watches for messages in our program. 
386      *  No extra Window data is used so we zero the two fields. Then we set the instance. 
387      *  Next we set hIcon to NULL meaning we don't want an ICON in the Window, 
388      *  and for a mouse pointer we use the standard arrow. The background color doesn't matter 
389      *  (we set that in GL). We don't want a menu in this Window so we set it to NULL, 
390      *  and the class name can be any name you want. I'll use "OpenGL" for simplicity.
391      */
392     hInstance = GetModuleHandle(NULL);                   // Grab an instance for our window
393     wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;       // Redraw on move, and own DC for window
394     wc.lpfnWndProc = (WNDPROC)WndProc;                   // WndProc handles message
395     wc.cbClsExtra = 0;                                   // No extra window date
396     wc.cbWndExtra = 0;                                   // No extra window date
397     wc.hInstance = hInstance;                            // set the instance
398     wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);              // Load the default icon
399     wc.hCursor = LoadCursor(NULL, IDC_ARROW);            // Load the arrow pointer
400     wc.hbrBackground = NULL;                             // No background requried for GL
401     wc.lpszMenuName = NULL;                              // We don't want a menu
402     wc.lpszClassName = "OpenGL";                         // set the class name
403 
404     if (!RegisterClass(&wc)) {                           // Attempt to register the window class
405         MessageBox(NULL, "Failed to register the window class.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
406         return FALSE;                                    // Exit and return false
407     }
408 
409     if (fullscreen) {                                    // attempt fullsreen model
410         
411         /*
412         T*  here are a few very important things you should keep in mind when switching to full screen mode.
413          *  Make sure the width and height that you use in fullscreen mode is the same as 
414          *  the width and height you plan to use for your window, and most importantly,
415          *  set fullscreen mode BEFORE you create your window.
416          */
417         DEVMODE dmScreenSettings;                        // Device mode
418         memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // Make sure memory's cleared
419         dmScreenSettings.dmSize = sizeof(dmScreenSettings);     // Size of devmode structure
420         dmScreenSettings.dmPelsWidth = width;            // Select window width
421         dmScreenSettings.dmPelsHeight = height;          // Select window height
422         dmScreenSettings.dmBitsPerPel = bits;            // Select bits per pixel
423         dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
424         
425         /*
426          *  In the line below ChangeDisplaySettings tries to switch to a mode that matches 
427          *  what we stored in dmScreenSettings. I use the parameter CDS_FULLSCREEN when switching modes, 
428          *  because it's supposed to remove the start bar at the bottom of the screen, 
429          *  plus it doesn't move or resize the windows on your desktop when you switch to 
430          *  fullscreen mode and back.
431          */
432         //Try to set selected mode and get results. Note: CDS_FULLSCREEN gets rid of start bar
433         if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
434             //If the mode fails, offer two options. Quit or run in a window
435             if (MessageBox(NULL, "The requested fullscreen mode is not supported by\n your video card. Use"
436                 "windowed mode instead?", "GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
437             {
438                 fullscreen = FALSE;                       // Select windowed mode (fullscreen=FLASE)
439             }
440             else {
441                 // Pop up a message box letting user know the programe is closing.
442                 MessageBox(NULL, "Program will now close.", "ERROR", MB_OK | MB_ICONSTOP);
443                 return FALSE;                             // Exit and return FALSE
444             }
445         }
446     }
447 
448     if (fullscreen) {                                     // Are we still in fullscreen mode
449         
450         /*
451          *  If we are still in fullscreen mode we'll set the extended style to WS_EX_APPWINDOW, 
452          *  which force a top level window down to the taskbar once our window is visible. 
453          *  For the window style we'll create a WS_POPUP window. 
454          *  This type of window has no border around it, making it perfect for fullscreen mode.
455 
456          *  Finally, we disable the mouse pointer. If your program is not interactive, 
457          *  it's usually nice to disable the mouse pointer when in fullscreen mode. It's up to you though.
458          */
459         dwExStyle = WS_EX_APPWINDOW;                      // Window extended style
460         dwStyle = WS_POPUP;                               // Window style
461         ShowCursor(FALSE);                                // Hide mosue pointer 
462     }
463     else {
464 
465         /*
466          *  If we're using a window instead of fullscreen mode, 
467          *  we'll add WS_EX_WINDOWEDGE to the extended style. This gives the window a more 3D look. 
468          *  For style we'll use WS_OVERLAPPEDWINDOW instead of WS_POPUP. 
469          *  WS_OVERLAPPEDWINDOW creates a window with a title bar, sizing border, 
470          *  window menu, and minimize / maximize buttons.
471          */
472         dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;   // Window extended style
473         dwStyle = WS_OVERLAPPEDWINDOW;                    // Window style
474     }
475 
476     /*
477      *  By using the AdjustWindowRectEx command none of our OpenGL scene will be covered up by the borders, 
478      *  instead, the window will be made larger to account for the pixels needed to draw the window border. 
479      *  In fullscreen mode, this command has no effect.
480      */
481     AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);  // Adjust window to true resqusted
482     
483     /*
484      *  WS_CLIPSIBLINGS and WS_CLIPCHILDREN are both REQUIRED for OpenGL to work properly. 
485      *  These styles prevent other windows from drawing over or into our OpenGL Window.
486      */
487     if (!(hWnd = CreateWindowEx(dwExStyle,                // Extended style for the window
488         "OpenGL",                                         // Class name
489         title,                                            // Window title
490         WS_CLIPSIBLINGS |                                 // Requried window style
491         WS_CLIPCHILDREN |                                 // Requried window style
492         dwStyle,                                          // Select window style
493         0, 0,                                             // Window position
494         WindowRect.right - WindowRect.left,               // Calculate adjusted window width
495         WindowRect.bottom - WindowRect.top,               // Calculate adjusted window height
496         NULL,                                             // No parent window
497         NULL,                                             // No menu
498         hInstance,                                        // Instance
499         NULL)))                                           // Don't pass anything to WM_CREATE
500     {
501         KillGLWindow();                                   //Reset the display
502         MessageBox(NULL, "Window creation error.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
503         return FALSE;                                     // Retrurn FALSE;
504     }
505 
506     /*
507      *  aside from the stencil buffer and the (slow) accumulation buffer
508      */
509     static PIXELFORMATDESCRIPTOR pfd =                    // pfd tells windows how we want things to be 
510     {
511         sizeof(PIXELFORMATDESCRIPTOR),                    // Size of this pixel format descriptor
512         1,                                                // Version number
513         PFD_DRAW_TO_WINDOW |                              // Format must support window
514         PFD_SUPPORT_OPENGL |                              // Format must support OpenGL
515         PFD_DOUBLEBUFFER,                                 // Must support double buffer
516         PFD_TYPE_RGBA,                                    // Request an RGBA format
517         bits,                                             // Select our color depth
518         0, 0, 0, 0, 0, 0,                                 // Color bits ignored
519         0,                                                // No alpha buffer
520         0,                                                // shift bit ignored
521         0,                                                // No accumulation buffer
522         0, 0, 0, 0,                                       // Accumulation bits ignored
523         16,                                               // 16Bits Z_Buffer (depth buffer)
524         0,                                                // No stencil buffer
525         0,                                                // No auxiliary buffer
526         PFD_MAIN_PLANE,                                   // Main drawing layer
527         0,                                                // Reserved
528         0, 0, 0                                           // Layer makes ignored
529     };
530 
531     if (!(hDC = GetDC(hWnd))) {                           // Did we get a device context
532         KillGLWindow();                                   // Reset the display
533         MessageBox(NULL, "Can't create a GL device context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
534         return FALSE;                                     // Return FALSE
535     }
536 
537     if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) {  // Did window find a matching pixel format
538         KillGLWindow();                                   // Reset the display
539         MessageBox(NULL, "Can't find a suitable pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
540         return FALSE;                                     // Return FALSE;
541     }
542 
543     if (!SetPixelFormat(hDC, PixelFormat, &pfd)) {        // Are we able to set the pixel format
544         KillGLWindow();                                   // Reset the display
545         MessageBox(NULL, "Can't set the pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
546         return FALSE;                                     // Return FALSE;
547     }
548 
549     if (!(hRC = wglCreateContext(hDC))) {                 // Are we able to rendering context
550         KillGLWindow();                                   // Reset the display
551         MessageBox(NULL, "Can't create a GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
552         return FALSE;                                     // Return FASLE;
553     }
554 
555     if (!wglMakeCurrent(hDC, hRC)) {                      // Try to activate the rendering context
556         KillGLWindow();                                   // Reset the display
557         MessageBox(NULL, "Can't activate the GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
558         return FALSE;                                     // Return FALSE    
559     }
560 
561     /*
562      *  ReSizeGLScene passing the screen width and height to set up our perspective OpenGL screen.
563      */
564     ShowWindow(hWnd, SW_SHOW);                            // Show the window
565     SetForegroundWindow(hWnd);                            // slightly higher priority
566     SetFocus(hWnd);                                       // Sets keyboard focus to the window
567     ReSizeGLScene(width, height);                         // Set up our perspective GL screen
568 
569 /*
570  *  we can set up lighting, textures, and anything else that needs to be setup in InitGL().
571  */
572 if (!InitGL()) {                                      // Initialize our newly created GL window
573     KillGLWindow();                                   // Reset the display
574     MessageBox(NULL, "Initialize Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
575     return FALSE;                                     // Return FALSE
576 }
577 return TRUE;
578 }
579 
580 LRESULT CALLBACK WndProc(HWND hWnd,                       // Handle for this window
581     UINT uMsg,                                            // Message for this window
582     WPARAM wParam,                                        // Additional message information
583     LPARAM lParam)                                        // Additional message information
584 {
585     switch (uMsg) {                                       // Check for window message
586     case WM_ACTIVATE: {                               // Check minimization state
587         if (!HIWORD(wParam)) {
588             active = TRUE;                            // Program is active
589         }
590         else {
591             active = FALSE;                           // Program is no longer active
592         }
593         return 0;                                     // Return to the message loop
594     }
595     case WM_SYSCOMMAND: {                             // Intercept system commands
596         switch (wParam) {                             // Check system calls
597         case SC_SCREENSAVE:                       // Screensaver trying to start
598         case SC_MONITORPOWER:                     // Monitor trying to enter powersave
599             return 0;                                 // Prevent form happening
600         }
601         break;                                        // Exit
602     }
603     case WM_CLOSE: {                                  // Did we receive a close message
604         PostQuitMessage(0);                           // Send a quit message
605         return 0;
606     }
607     case WM_KEYDOWN: {                                // Is a key being held down
608         keys[wParam] = TRUE;                          // if so, mark it as TRUE
609         return 0;                                     // Jump back
610     }
611     case WM_KEYUP: {                                  // Has a key been released
612         keys[wParam] = FALSE;                         // if so, mark it as FALSE
613         return 0;                                     // Jump back
614     }
615     case WM_SIZE: {                                   // Resize the OpenGL window
616         ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));   // LoWord = width HiWord = height
617         return 0;                                     // Jump back
618     }
619     }
620     return DefWindowProc(hWnd, uMsg, wParam, lParam);     // Pass all unhandled message to DefWindwProc
621 }
622 
623 int WINAPI WinMain(HINSTANCE hInstance,                   // Instance
624     HINSTANCE hPrevInstance,                              // Previous instance
625     LPSTR lpCmdLine,                                      // Command line parameters
626     int nCmdShow)                                         // Window show state
627 {
628     MSG msg;                                              // Window message structure
629     BOOL done = FALSE;                                    // Bool variable to exit loop
630                                                           // Ask the user which screen mode they prefer
631     if (MessageBox(NULL, "Would you like to run in fullscreen mode?",
632         "Start fullscreen?", MB_YESNO | MB_ICONQUESTION) == IDNO)
633     {
634         fullscreen = FALSE;                               // Window mode
635     }
636     // Create our OpenGL window
637     if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) {  // (Modified)
638         return 0;                                         // Quit if window was not create
639     }
640 
641     while (!done) {                                       // Loop that runs until donw = TRUE
642         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {   // Is there a message wating
643             if (msg.message == WM_QUIT) {                 // Havw we received a quit message
644                 done = TRUE;                              // if so done  = TRUE
645             }
646             else {                                        // If not, deal with window message
647                 TranslateMessage(&msg);                   // Translate message
648                 DispatchMessage(&msg);                    // Dispatch message
649             }
650         }
651         else {
652             // Draw the scene. Watch for ESC key and quit message from DrawGLScene()
653             if (active) {                                 // Program active
654                 if (keys[VK_ESCAPE]) {                    // Was ESC pressed
655                     done = TRUE;                          // ESC signalled a quit
656                 }
657                 else {                                    // Not time to quit, update screen
658                     DrawGLScene();                        // Draw scene
659                     SwapBuffers(hDC);                     // Swap buffers (double buffering)
660                 }
661             }
662 
663             /*
664              *  It allows us to press the F1 key to switch from fullscreen mode to
665              *  windowed mode or windowed mode to fullscreen mode.
666              */
667 
668             if (keys['L'] && !lp) {                       // L key being pressed not held
669                 lp = TRUE;                                // lp become TRUE
670                 light = !light;                           // Toggle light TRUE/FALSE
671 
672                 if (!light) {
673                     glDisable(GL_LIGHTING);               // Disable light
674                 }
675                 else {
676                     glEnable(GL_LIGHTING);                // Enable light
677                 }
678             }
679             if (!keys['L']) {
680                 lp = FALSE;
681             }
682 
683             if (keys['F'] && !fp) {
684                 fp = TRUE;
685                 filter += 1;
686                 if (filter > 2) {
687                     filter = 0;
688                 }
689             }
690             if (!keys['F']) {
691                 fp = FALSE;
692             }
693 /******************************************************************************************************************************************/
694 /******************************************************************************************************************************************/
695             if (keys['W']) {                      //VK_PRIOR
696                 xpos -= (float)sin(heading*piover180) * 0.0005f;
697                 zpos -= (float)cos(heading*piover180) * 0.0005f;
698                 if (walkbiasangle >= 359.0f) {
699                     walkbiasangle = 0.0f;
700                 }
701                 else {
702                     walkbiasangle += 0.02f;
703                 }
704                 walkbias = (float)sin(walkbiasangle*piover180) / 20.0f;
705             }
706             if (keys['S']) {                           // VK_NEXT
707                 xpos += (float)sin(heading*piover180) * 0.0005f;
708                 zpos += (float)cos(heading*piover180) * 0.0005f;
709                 if (walkbiasangle <= 1.0f) {
710                     walkbiasangle = 359.0f;
711                 }
712                 else {
713                     walkbiasangle -= 0.02f;
714                 }
715                 walkbias = (float)sin(walkbiasangle*piover180) / 20.0f;
716             }
717             
718             if (keys['A']) {
719                 zpos += (float)sin(heading * piover180) * 0.0005f;
720                 xpos -= (float)cos(heading * piover180) * 0.0005f;
721                 if (walkbiasangle >= 359.0f) {
722                     walkbiasangle = 0.0f;
723                 }
724                 else {
725                     walkbiasangle += 0.02f;
726                 }
727                 walkbias = (float)sin(walkbiasangle*piover180) / 20.0f;
728             }
729             if (keys['D']) {
730                 zpos -= (float)sin(heading * piover180) * 0.0005f;
731                 xpos += (float)cos(heading * piover180) * 0.0005f;
732                 if (walkbiasangle <= 1.0f) {
733                     walkbiasangle = 359.0f;
734                 }
735                 else {
736                     walkbiasangle -= 0.02f;
737                 }
738                 walkbias = (float)sin(walkbiasangle*piover180) / 20.0f;
739             }
740 
741             if (keys[VK_SPACE]) {
742                 if (ytemp2 < 0.3)
743                     ytemp2 += 0.0008;
744             }
745             else {
746                 if (ytemp2 >= 0.08)
747                 ytemp2 -= 0.0008;
748             }
749 
750             if (keys[VK_CONTROL]) {
751                 if (ytemp1 > -0.3)
752                     ytemp1 -= 0.0008;
753             }
754             else {
755                 if (ytemp1 <= 0.01)
756                     ytemp1 += 0.0008;
757             }
758 
759             if (keys['T'] && !tp) {
760                 tp = TRUE;
761                 twinkle = !twinkle;
762             }
763             if (!keys['T']) {
764                 tp = FALSE;
765             }
766             if (keys[VK_UP]) {
767                 z -= 0.05f;
768                 lookupdown -= 0.05f;
769             }
770             if (keys[VK_DOWN]) {
771                 z += 0.05f;
772                 lookupdown += 0.05f;
773             }
774 
775             if (keys[VK_RIGHT]) {
776                 heading -= 0.05f;
777                 yrot = heading;
778             }
779 
780             if (keys[VK_LEFT]) {
781                 heading += 0.05f;
782                 yrot = heading;
783             }
784 
785 /******************************************************************************************************************************************/
786 /******************************************************************************************************************************************/
787             if (keys['B'] && !bp) {
788                 bp = TRUE;
789                 blend = !blend;
790                 if (blend) {
791                     glEnable(GL_BLEND);
792                     glDisable(GL_DEPTH_TEST);
793                 }
794                 else {
795                     glDisable(GL_BLEND);
796                     glEnable(GL_DEPTH_TEST);
797                 }
798             }
799             if (keys['B']) {
800                 bp = FALSE;
801             }
802             if (keys[VK_F1]) {                            // Is F1 being pressed
803                 keys[VK_F1] = FALSE;                      // If so make key FASLE
804                 KillGLWindow();                           // Kill our current window
805                 fullscreen = !fullscreen;                 // Toggle fullscreen / window mode
806                 //Recreate our OpenGL window(modified)
807                 if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) {
808                     return 0;                             // Quit if window was not create
809                 }
810             }
811         }
812     }
813     // Shutdown
814     KillGLWindow();                                       // Kill the window
815     return (msg.wParam);                                  // Exit the program
816 }

Thanks for Nehe's tutorials, this is his home.

 

posted @ 2016-07-07 13:11  clairvoyant  阅读(127)  评论(0编辑  收藏  举报