outdated: 22.Bump-Mapping, Multi-Texturing & Extensions

这几天杂事太多,没及时更新,抱歉。

  • 如何控制图形加速器实现多重纹理?
  • 如何实现凹凸纹理贴图?
  • 如何在混合色彩渲染的场景上实现标志浮动?
  • 如何多重渲染?
  • 如何高效地矩阵转换?

本章主要说的是多重纹理,即凹凸纹理。

isInString()函数在特定的字符串中搜寻特定的字符串,更高效的算法可以用KMP算法。

initMultitexture()函数中使用了strdup()函数,为了复制字符串(调用了malloc),vs2015中替换为_strdup()函数,其参数为glGetString()函数,返回一个描述当前OpenGL连接的字符串,参数(符号常量)含义见超链接。glGetIntegerv()函数提取第一个参数输入到第二个变量参数中。wglGetProcAddress()函数访问一个不在标准OpenGL库中的扩展函数。如果该扩展函数存在当前的执行中,那么返回一个用来访问该函数的函数指针。否则,返回NULL.

LoadGLTextures()函数中,使用了一些新的函数。其中就有设置像素传输模式的函数glPixelTransferf()。在贴图纹理Base.bmp和Bmup.bmp之间设置了像素的传输模式,使亮度是之前的50%。

glPixelTransferf(GL_RED_SCALE, 0.5f);             // Scale RGB by 50%
glPixelTransferf(GL_GREEN_SCALE, 0.5f);
glPixelTransferf(GL_BLUE_SCALE, 0.5f);

重要的是两个部分贴图之间Image的data值,

for (int i = 0; i < 3 * Image->sizeX * Image->sizeY; ++i) {
    Image->data[i] = 255 - Image->data[i];
}

接着,Image的data值为255减去灰白贴图的数值。使之与Base融合。

doMesh2TexelUnits()函数中,glTexEnvf()函数设置映射纹理的方式。glMultiTexCoord2fARB()函数设置当前多重纹理的坐标值。glActiveTextureARB()函数选择活动纹理单元。

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

   1 /*****************************************************************************************************************************************/
   2 /*****************************************************************************************************************************************/
   3 #include <windows.h>
   4 #include <stdarg.h>
   5 #include <stdio.h>
   6 #include <math.h>
   7 #include <string.h>
   8 #include <gl/glew.h>
   9 #include <gl/glut.h>
  10 #include <GL/GLUAX.H>
  11 #include <GL/glext.h>
  12 #pragma comment(lib, "legacy_stdio_definitions.lib")
  13 
  14 /*
  15 *  Every OpenGL program is linked to a Rendering Context.
  16 *  A Rendering Context is what links OpenGL calls to the Device Context.
  17 *  In order for your program to draw to a Window you need to create a Device Context.
  18 *  The DC connects the Window to the GDI (Graphics Device Interface).
  19 */
  20 
  21 HGLRC     hRC = NULL;         // Permanent rendering context
  22 HDC       hDC = NULL;         // Private GDI device context
  23 HWND      hWnd = NULL;        // Holds our window handle
  24 HINSTANCE hInstance;          // Holds the instance of the application
  25 
  26 /*
  27 *  It's important to make this global so that each procedure knows if
  28 *  the program is running in fullscreen mode or not.
  29 */
  30 
  31 bool keys[256];         // Array used for the keyboard routine
  32 bool active = TRUE;     // Window active flag set to TRUE by default
  33 bool fullscreen = TRUE; // Fullscreen flag set to fullscreen mode by default
  34 
  35 //The GLfloat MAX_EMBOSS specifies the "strength" of the Bump Mapping-Effect
  36 // but reduce visual quality to the same extent by leaving so-called "artefacts" at the edges of the surfaces.
  37 #define MAX_EMBOSS (GLfloat)0.01f      // Maximum emboss-translate. Increase to get higher immersion
  38 #define __ARB_ENABLE true               // Used to disable ARB extensions entirely
  39 // #define EXT_INFO                    // Uncomment to see your extensions at start_up?
  40 #define MAX_EXTENSION_SPACE 10240      // Character for extension-strings
  41 #define MAX_EXTENSION_LENGTH 256       // Maxiunm character in one extension-string
  42 bool multitextureSupported = false;    // Flag indicating whether multitexture is supported
  43 bool useMultitexture = true;           // Use it if it is supported
  44 GLint maxTexelUnits = 1;                // Number of texel-pipelines.
  45 
  46 // GDI-context handles
  47 PFNGLMULTITEXCOORD1FARBPROC glMultiTexCoord1fARB = NULL;
  48 PFNGLMULTITEXCOORD2FARBPROC    glMultiTexCoord2fARB = NULL;
  49 PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3fARB = NULL;
  50 PFNGLMULTITEXCOORD4FARBPROC    glMultiTexCoord4fARB = NULL;
  51 PFNGLACTIVETEXTUREARBPROC   glActiveTextureARB = NULL;
  52 PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = NULL;
  53 
  54 bool emboss = false;
  55 bool bumps = true;
  56 
  57 GLfloat xrot;
  58 GLfloat yrot;
  59 GLfloat xspeed;
  60 GLfloat yspeed;
  61 GLfloat z = -5.0f;
  62 
  63 GLuint filter = 1;                                    // Which filter to use
  64 GLuint texture[3];
  65 GLuint bump[3];                                       // Bumpmappings
  66 GLuint invbump[3];                                    // Inverted bumpmaps
  67 GLuint glLogo;                                        // Handle for Opengl-Logo
  68 GLuint multiLogo;                                     // Handle for multitexture-enabled-logo
  69 GLfloat LightAmbient[] = { 0.2f, 0.2f, 0.2f };
  70 GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f };
  71 GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f };
  72 GLfloat Gray[] = { 0.5f, 0.5f, 0.5f, 1.0f };
  73 
  74 // Data contains the faces of the cube in format 2xTexCoord, 3xVertex.
  75 // Note That the tesselation of the cube is only absolute minimum.
  76 GLfloat data[] = {
  77     // Front face
  78     0.0f, 0.0f,     -1.0f, -1.0f, +1.0f,
  79     1.0f, 0.0f,     +1.0f, -1.0f, +1.0f,
  80     1.0f, 1.0f,     +1.0f, +1.0f, +1.0f,
  81     0.0f, 1.0f,     -1.0f, +1.0f, +1.0f,
  82     // Back face
  83     1.0f, 0.0f,     -1.0f, -1.0f, -1.0f,
  84     1.0f, 1.0f,     -1.0f, +1.0f, -1.0f,
  85     0.0f, 1.0f,     +1.0f, +1.0f, -1.0f,
  86     0.0f, 0.0f,     +1.0f, -1.0f, -1.0f,
  87     // Top Face
  88     0.0f, 1.0f,     -1.0f, +1.0f, -1.0f,
  89     0.0f, 0.0f,     -1.0f, +1.0f, +1.0f,
  90     1.0f, 0.0f,     +1.0f, +1.0f, +1.0f,
  91     1.0f, 1.0f,     +1.0f, +1.0f, -1.0f,
  92     // Bottom Face
  93     1.0f, 1.0f,     -1.0f, -1.0f, -1.0f,
  94     0.0f, 1.0f,     +1.0f, -1.0f, -1.0f,
  95     0.0f, 0.0f,     +1.0f, -1.0f, +1.0f,
  96     1.0f, 0.0f,     -1.0f, -1.0f, +1.0f,
  97     // Right Face
  98     1.0f, 0.0f,     +1.0f, -1.0f, -1.0f,
  99     1.0f, 1.0f,     +1.0f, +1.0f, -1.0f,
 100     0.0f, 1.0f,     +1.0f, +1.0f, +1.0f,
 101     0.0f, 0.0f,     +1.0f, -1.0f, +1.0f,
 102     // Left Face
 103     0.0f, 0.0f,     -1.0f, -1.0f, -1.0f,
 104     1.0f, 0.0f,     -1.0f, -1.0f, +1.0f,
 105     1.0f, 1.0f,     -1.0f, +1.0f, +1.0f,
 106     0.0f, 1.0f,     -1.0f, +1.0f, -1.0f
 107 };
 108 
 109 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration for WndProc
 110 
 111 bool isInString(char* string, const char* search)     // String search
 112 {
 113     int pos = 0;
 114     int maxpos = strlen(search) - 1;
 115     int len = strlen(string);
 116     char* other;
 117     for (int i = 0; i < len; ++i) {
 118         if ((i == 0) || ((i > 1) && string[i - 1] == '\n')) {    // New extension begins here
 119             other = &string[i];
 120             pos = 0;                                   // Begin new search
 121             while (string[i] != '\n') {                // Search whole extension-string
 122                 if (string[i] == search[pos]) pos++;   // Next position
 123                 if ((pos > maxpos) && string[i + 1] == '\n')
 124                     return true;
 125                 i++;
 126             }
 127         }
 128     }
 129     return false;
 130 }
 131 
 132 bool initMultitexture(void)
 133 {
 134     char* extensions;
 135     extensions = _strdup((char*)glGetString(GL_EXTENSIONS));    // Fetch extension string
 136     int len = strlen(extensions);
 137     for (int i = 0; i < len; ++i) {
 138         if (extensions[i] == ' ') {
 139             extensions[i] = '\n';
 140         }
 141     }
 142 #ifdef EXT_INFO
 143             MessageBox(hWnd, extensions, "supported GL extensions", MB_OK | MB_ICONINFORMATION);
 144 #endif
 145     if (isInString(extensions, "GL_ARB_multitexture") &&     // Is multitexturing suported
 146         __ARB_ENABLE &&                                       // Override flag
 147         isInString(extensions, "GL_EXT_texture_env_combine"))// Texture-environment-combining supported
 148     {
 149         glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTexelUnits);
 150         glMultiTexCoord1fARB = (PFNGLMULTITEXCOORD1FARBPROC)wglGetProcAddress("glMultiTexCoord1fARB");
 151         glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)wglGetProcAddress("glMultiTexCoord2fARB");
 152         glMultiTexCoord3fARB = (PFNGLMULTITEXCOORD3FARBPROC)wglGetProcAddress("glMultiTexCoord3fARB");
 153         glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC)wglGetProcAddress("glMultiTexCoord4fARB");
 154         glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
 155         glClientActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)
 156             wglGetProcAddress("glClientActiveTextureARB");
 157 #ifdef EXT_INFO
 158         MessageBox(hWnd, "The GL_ARB_multitexture extension will be used.", "feature supported!",
 159             MB_OK | MB_ICONINFORMATION);
 160 #endif
 161         return true;
 162     }
 163     useMultitexture = false;
 164     return false;
 165 }
 166 
 167 void initLights(void)
 168 {
 169     glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
 170     glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
 171     glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
 172     glEnable(GL_LIGHT1);
 173 }
 174 
 175 int LoadGLTextures(void)
 176 {
 177     bool status = true;
 178     AUX_RGBImageRec* Image = NULL;                  // Create storage space for the texture
 179     char* alpha = NULL;
 180 
 181     // Load the title-bitmap for base-texture
 182     if (Image = auxDIBImageLoad("Data/Base.bmp")) {
 183         glGenTextures(3, texture);
 184 
 185         // Create nearest filtered texture
 186         glBindTexture(GL_TEXTURE_2D, texture[0]);
 187         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 188         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 189         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, Image->sizeX, Image->sizeY, 0, GL_RGB, 
 190             GL_UNSIGNED_BYTE, Image->data);
 191         // Create linear filtered texture
 192         glBindTexture(GL_TEXTURE_2D, texture[1]);
 193         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 194         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 195         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, Image->sizeX, Image->sizeY, 0, GL_RGB, 
 196             GL_UNSIGNED_BYTE, Image->data);
 197         // Create mipmapped texture
 198         glBindTexture(GL_TEXTURE_2D, texture[2]);
 199         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 200         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
 201         gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, Image->sizeX, Image->sizeY, GL_RGB, 
 202             GL_UNSIGNED_BYTE, Image->data);
 203     }
 204     else {
 205         status = false;
 206     }
 207 
 208     if (Image) {
 209         if (Image->data) {
 210             delete Image->data;
 211         }
 212         delete Image;
 213         Image = NULL;
 214     }
 215 
 216     // Load the bumpmaps
 217     if (Image = auxDIBImageLoad("Data/Bump.bmp")) {
 218         glPixelTransferf(GL_RED_SCALE, 0.5f);             // Scale RGB by 50%
 219         glPixelTransferf(GL_GREEN_SCALE, 0.5f);
 220         glPixelTransferf(GL_BLUE_SCALE, 0.5f);
 221         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
 222         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
 223         glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, Gray);
 224         glGenTextures(3, bump);
 225 
 226         // Create nearest filtered texture
 227         glBindTexture(GL_TEXTURE_2D, bump[0]);
 228         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 229         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 230         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, Image->sizeX, Image->sizeY, 0, GL_RGB,
 231             GL_UNSIGNED_BYTE, Image->data);
 232         // Create linear filtered texture
 233         glBindTexture(GL_TEXTURE_2D, bump[1]);
 234         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 235         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 236         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, Image->sizeX, Image->sizeY, 0, GL_RGB,
 237             GL_UNSIGNED_BYTE, Image->data);
 238         // Create mipmapped texture
 239         glBindTexture(GL_TEXTURE_2D, bump[2]);
 240         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 241         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
 242         gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, Image->sizeX, Image->sizeY, GL_RGB,
 243             GL_UNSIGNED_BYTE, Image->data);
 244 
 245         for (int i = 0; i < 3 * Image->sizeX * Image->sizeY; ++i) {
 246             Image->data[i] = 255 - Image->data[i];
 247         }
 248         glGenTextures(3, invbump);
 249         // Create nearest filtered texture
 250         glBindTexture(GL_TEXTURE_2D, invbump[0]);
 251         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 252         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 253         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, Image->sizeX, Image->sizeY, 0, GL_RGB,
 254             GL_UNSIGNED_BYTE, Image->data);
 255         // Create linear filtered texture
 256         glBindTexture(GL_TEXTURE_2D, invbump[1]);
 257         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 258         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 259         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, Image->sizeX, Image->sizeY, 0, GL_RGB,
 260             GL_UNSIGNED_BYTE, Image->data);
 261         // Create mipmapped texture
 262         glBindTexture(GL_TEXTURE_2D, invbump[2]);
 263         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 264         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
 265         gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB8, Image->sizeX, Image->sizeY, GL_RGB,
 266             GL_UNSIGNED_BYTE, Image->data);
 267 
 268         glPixelTransferf(GL_RED_SCALE, 1.0f);                // Scale RGB back to 100% again        
 269         glPixelTransferf(GL_GREEN_SCALE, 1.0f);
 270         glPixelTransferf(GL_BLUE_SCALE, 1.0f);
 271     }
 272     else {
 273         status = false;
 274     }
 275     if (Image) {
 276         if (Image->data) {
 277             delete Image->data;
 278         }
 279         delete Image;
 280         Image = NULL;
 281     }
 282 
 283     if (Image = auxDIBImageLoad("Data/OpenGL_ALPHA.bmp")) {
 284         alpha = new char[4 * Image->sizeX * Image->sizeY];
 285         // Create memory for RGBAB8-Texture
 286         for (int a = 0; a < Image->sizeX * Image->sizeY; ++a) {
 287             alpha[4 * a + 3] = Image->data[a * 3];               // Pick only red value as alpha
 288         }
 289         if (!(Image = auxDIBImageLoad("Data/OpenGL.bmp"))) {
 290             status = false;
 291         }
 292         for (int a = 0; a < Image->sizeX * Image->sizeY; ++a) {
 293             alpha[4 * a] = Image->data[a * 3];                   // R
 294             alpha[4 * a + 1] = Image->data[a * 3 + 1];           // G
 295             alpha[4 * a + 2] = Image->data[a * 3 + 2];           // B
 296         }
 297         glGenTextures(1, &glLogo);
 298         // RGBA8-Texture
 299         glBindTexture(GL_TEXTURE_2D, glLogo);
 300         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 301         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 302         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Image->sizeX, Image->sizeY, 0, GL_RGBA,
 303             GL_UNSIGNED_BYTE, alpha);
 304         delete alpha;
 305     }
 306     else {
 307         status = false;
 308     }
 309     if (Image) {
 310         if (Image->data)
 311             delete Image->data;
 312         delete Image;
 313         Image = NULL;
 314     }
 315 
 316     if (Image = auxDIBImageLoad("Data/multi_on_alpha.bmp")) {
 317         // Create memory for RGBAB8-Texture
 318         alpha = new char[4 * Image->sizeX *Image->sizeY];
 319         for (int a = 0; a < Image->sizeX * Image->sizeY; ++a) {
 320             alpha[4 * a + 3] = Image->data[a * 3];               // Pick only red value as alpha
 321         }
 322         if (!(Image = auxDIBImageLoad("Data/multi_on.bmp"))) {
 323             status = false;
 324         }
 325         for (int a = 0; a < Image->sizeX * Image->sizeY; ++a) {
 326             alpha[4 * a] = Image->data[a * 3];                   // R
 327             alpha[4 * a + 1] = Image->data[a * 3 + 1];           // G
 328             alpha[4 * a + 2] = Image->data[a * 3 + 2];           // B
 329         }
 330         glGenTextures(1, &multiLogo);
 331 
 332         // RGBA8-Texture
 333         glBindTexture(GL_TEXTURE_2D, multiLogo);
 334         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 335         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 336         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Image->sizeX, Image->sizeY, 0, GL_RGBA,
 337             GL_UNSIGNED_BYTE, alpha);
 338         delete alpha;
 339     }
 340     else {
 341         status = false;
 342     }
 343     if (Image) {
 344         if (Image->data)
 345             delete Image->data;
 346         delete Image;
 347         Image = NULL;
 348     }
 349     return status;
 350 }
 351 
 352 void doCube(void)
 353 {
 354     int i;
 355     glBegin(GL_QUADS);
 356         // Front face
 357         glNormal3f(0.0f, 0.0f, 1.0f);
 358         for (i = 0; i < 4; ++i) {
 359             glTexCoord2f(data[5 * i], data[5 * i + 1]);
 360             glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 361         }
 362         // Back face
 363         glNormal3f(0.0f, 0.0f, -1.0f);
 364         for (i = 4; i < 8; ++i) {
 365             glTexCoord2f(data[5 * i], data[5 * i + 1]);
 366             glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 367         }
 368         // Top face
 369         glNormal3f(0.0f, 1.0f, 0.0f);
 370         for (i = 8; i < 12; ++i) {
 371             glTexCoord2f(data[5 * i], data[5 * i + 1]);
 372             glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 373         }
 374         // Bottom face
 375         glNormal3f(0.0f,-1.0f, 0.0f);
 376         for (i = 12; i < 16; ++i) {
 377             glTexCoord2f(data[5 * i], data[5 * i + 1]);
 378             glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 379         }
 380         // Right face
 381         glNormal3f(1.0f, 0.0f, 0.0f);
 382         for (i = 16; i < 20; ++i) {
 383             glTexCoord2f(data[5 * i], data[5 * i + 1]);
 384             glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 385         }
 386         // Left face
 387         glNormal3f(-1.0f, 0.0f, 0.0f);
 388         for (i = 20; i < 24; ++i) {
 389             glTexCoord2f(data[5 * i], data[5 * i + 1]);
 390             glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 391         }
 392     glEnd();
 393 }
 394 
 395 GLvoid ReSizeGLScene(GLsizei width, GLsizei height)   // Resize and initialize the GL window
 396 {
 397     if (height == 0) {                                // Prevent a divide by zero by
 398         height = 1;                                   // Making height equal one
 399     }
 400     
 401     glViewport(0, 0, width, height);                  // Reset the current viewport
 402 
 403     /*
 404      *  The following lines set the screen up for a perspective view. 
 405      *  Meaning things in the distance get smaller. This creates a realistic looking scene. 
 406      *  The perspective is calculated with a 45 degree viewing angle based on 
 407      *  the windows width and height. The 0.1f, 100.0f is the starting point and 
 408      *  ending point for how deep we can draw into the screen.
 409      *
 410      *  The projection matrix is responsible for adding perspective to our scene.
 411      *  glLoadIdentity() restores the selected matrix to it's original state.
 412      *  The modelview matrix is where our object information is stored.
 413      *   Lastly we reset the modelview matrix.
 414      */
 415 
 416     glMatrixMode(GL_PROJECTION);                      // Select the projection matrix
 417     glLoadIdentity();                                 // Reset the projection matrix
 418     
 419                                                       // Calculate the aspect ratio of the window
 420     gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
 421 //    glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);  // Create orhto 640X480 view (0, 0, at the top)
 422 
 423     glMatrixMode(GL_MODELVIEW);                       // Seclet the modelview matrix
 424     glLoadIdentity();                                 // Reset the modelview matrix
 425 }
 426 
 427 int InitGL(GLvoid)                                    // All setup for OpenGL goes here
 428 {
 429     /*
 430      *  Smooth shading blends colors nicely across a polygon, and smoothes out lighting.
 431      */
 432     multitextureSupported = initMultitexture();
 433     if (!LoadGLTextures()) {
 434         return FALSE;
 435     }
 436 
 437     glEnable(GL_TEXTURE_2D);
 438     glShadeModel(GL_SMOOTH);                          // Enables smooth shading
 439     glClearColor(0.0f, 0.0f, 0.0f, 0.5f);             // Black background
 440 
 441     glClearDepth(1.0f);                               // Depth buffer setup
 442 
 443     glClearDepth(1.0f);
 444     glEnable(GL_DEPTH_TEST);
 445     glDepthFunc(GL_LEQUAL);                           // Type of depth testing
 446     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);           // Set line antialiasing
 447 
 448     initLights();                                      // Initialize OpenGL light
 449     return TRUE;
 450 }
 451 // Calculates V = VM, M    is 4X4 in column-major, V is 4dim. Row (i.e. "Transposed")
 452 void VMatMult(GLfloat* M, GLfloat* V)
 453 {
 454     GLfloat res[3];
 455     res[0] = M[0] * V[0] + M[1] * V[1] + M[2] * V[2] + M[3] * V[3];
 456     res[1] = M[4] * V[0] + M[5] * V[1] + M[6] * V[2] + M[7] * V[3];
 457     res[2] = M[8] * V[0] + M[9] * V[1] + M[10] * V[2] + M[11] * V[3];
 458     V[0] = res[0];
 459     V[1] = res[1];
 460     V[2] = res[2];
 461     V[3] = M[15];                                      // Homogenous coordinate
 462 }
 463 // Sets up the texture-offsets
 464 // n: Normal on surface. Must be of length 1
 465 // c: Current vertex on surface
 466 // l: Lightposition
 467 // s: Direction of s-texture-coordinate in object space (Must be normalized)
 468 // t: Direction of t-texture-coordinate in object space (Must be normalized)
 469 void SetUpBumps(GLfloat* n, GLfloat* c, GLfloat* l, GLfloat* s, GLfloat* t) 
 470 {
 471     GLfloat v[3];                                        // Vector form current position to light
 472     GLfloat lenQ;                                        // Used to normalize
 473     // Calculate v from current vertex c to lightposition and normalized v
 474     v[0] = l[0] - c[0];
 475     v[1] = l[1] - c[1];
 476     v[2] = l[2] - c[2];
 477     lenQ = (GLfloat)sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
 478     v[0] /= lenQ;
 479     v[1] /= lenQ;
 480     v[2] /= lenQ;
 481     // Project v such that we get two values along each texture-coordinate axis
 482     c[0] = (s[0] * v[0] + s[1] * v[1] + s[2] * v[2]) * MAX_EMBOSS;
 483     c[1] = (t[0] * v[0] + t[1] * v[1] + t[2] * v[2]) * MAX_EMBOSS;
 484 }
 485 
 486 void doLogo(void)
 487 {
 488     // Must call this list. Billboards the two logos.
 489     glDepthFunc(GL_ALWAYS);
 490     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 491     glEnable(GL_BLEND);
 492     glDisable(GL_LIGHTING);
 493     glLoadIdentity();
 494     glBindTexture(GL_TEXTURE_2D, glLogo);
 495     glBegin(GL_QUADS);
 496         glTexCoord2f(0.0f, 0.0f); glVertex3f(0.23f, -0.4f, -1.0f);
 497         glTexCoord2f(1.0f, 0.0f); glVertex3f(0.53f, -0.4f, -1.0f);
 498         glTexCoord2f(1.0f, 1.0f); glVertex3f(0.53f, -0.25f, -1.0f);
 499         glTexCoord2f(0.0f, 1.0f); glVertex3f(0.23f, -0.25f, -1.0f);
 500     glEnd();
 501     if (useMultitexture) {
 502         glBindTexture(GL_TEXTURE_2D, multiLogo);
 503         glBegin(GL_QUADS);
 504             glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.53f, -0.25f, -1.0f);
 505             glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.33f, -0.25f, -1.0f);
 506             glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.33f, -0.15f, -1.0f);
 507             glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.53f, -0.15f, -1.0f);
 508         glEnd();
 509     }
 510     glDepthFunc(GL_LEQUAL);
 511 }
 512 
 513 bool doMesh1TexelUnits(void)
 514 {
 515     GLfloat c[4] = { 0.0f, 0.0f, 0.0f, 1.0f };           // Holds current vertex
 516     GLfloat n[4] = { 0.0f, 0.0f, 0.0f, 1.0f };           // Normalized normal of current surface
 517     GLfloat s[4] = { 0.0f, 0.0f, 0.0f, 1.0f };           // s-Texture coordinate direction
 518     GLfloat t[4] = { 0.0f, 0.0f, 0.0f, 1.0f };           // t-Texture coordinate direction
 519     GLfloat l[4];                 // Holds our lightposition to be transformed into object space
 520     GLfloat Minv[16];             // Holds the inverted modeview matrix to do so
 521     int i;
 522 
 523     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 524     // Build inverse modeview matrix first. This substitutes one push/pop with one glLoadIdentity()
 525     // Simply build it by doing all transformation negated and in reverse order
 526     glLoadIdentity();
 527     glRotatef(-yrot, 0.0f, 1.0f, 0.0f);
 528     glRotatef(-xrot, 1.0f, 0.0f, 0.0f);
 529     glTranslatef(0.0f, 0.0f, -z);
 530     glGetFloatv(GL_MODELVIEW_MATRIX, Minv);
 531     glLoadIdentity();
 532     glTranslatef(0.0f, 0.0f, z);
 533     glRotatef(xrot, 1.0f, 0.0f, 0.0f);
 534     glRotatef(yrot, 0.0f, 1.0f, 0.0f);
 535 
 536     // Transform the lightposition into object coordinate
 537     l[0] = LightPosition[0];
 538     l[1] = LightPosition[1];
 539     l[2] = LightPosition[2];
 540     l[3] = 1.0f;
 541     VMatMult(Minv, l);
 542     // First pass. This will render a cube only consisting out of bump map.
 543     glBindTexture(GL_TEXTURE_2D, bump[filter]);
 544     glDisable(GL_BLEND);
 545     glDisable(GL_LIGHTING);
 546     doCube();
 547     // Second pass. This will render a cube with the correct emboss bump mapping, but without colors.
 548     glBindTexture(GL_TEXTURE_2D, invbump[filter]);
 549     glBlendFunc(GL_ONE, GL_ONE);
 550     glDepthFunc(GL_LEQUAL);
 551     glEnable(GL_BLEND);
 552 
 553     glBegin(GL_QUADS);
 554     // Front face
 555     n[0] = 0.0f; n[1] = 0.0f; n[2] = 1.0f;
 556     s[0] = 1.0f; s[1] = 0.0f; s[2] = 0.0f;
 557     t[0] = 0.0f; t[1] = 1.0f; t[3] = 0.0f;
 558     for (i = 0; i < 4; ++i) {
 559         c[0] = data[5 * i + 2];
 560         c[1] = data[5 * i + 3];
 561         c[2] = data[5 * i + 4];
 562         SetUpBumps(n, c, l, s, t);
 563         glTexCoord2f(data[5 * i] + c[0], data[5 * i + 1] + c[1]);
 564         glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 565     }
 566     // back face
 567     n[0] = 0.0f; n[1] = 0.0f; n[2] = -1.0f;
 568     s[0] = -1.0f; s[1] = 0.0f; s[2] = 0.0f;
 569     t[0] = 0.0f; t[1] = 1.0f; t[2] = 0.0f;
 570     for (i = 4; i<8; i++) {
 571         c[0] = data[5 * i + 2];
 572         c[1] = data[5 * i + 3];
 573         c[2] = data[5 * i + 4];
 574         SetUpBumps(n, c, l, s, t);
 575         glTexCoord2f(data[5 * i] + c[0], data[5 * i + 1] + c[1]);
 576         glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 577     }
 578     // Top face
 579     n[0] = 0.0f; n[1] = 1.0f; n[2] = 0.0f;
 580     s[0] = 1.0f; s[1] = 0.0f; s[2] = 0.0f;
 581     t[0] = 0.0f; t[1] = 0.0f; t[2] = -1.0f;
 582     for (i = 8; i<12; i++) {
 583         c[0] = data[5 * i + 2];
 584         c[1] = data[5 * i + 3];
 585         c[2] = data[5 * i + 4];
 586         SetUpBumps(n, c, l, s, t);
 587         glTexCoord2f(data[5 * i] + c[0], data[5 * i + 1] + c[1]);
 588         glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 589     }
 590     // Bottom face
 591     n[0] = 0.0f; n[1] = -1.0f; n[2] = 0.0f;
 592     s[0] = -1.0f; s[1] = 0.0f; s[2] = 0.0f;
 593     t[0] = 0.0f; t[1] = 0.0f; t[2] = -1.0f;
 594     for (i = 12; i<16; i++) {
 595         c[0] = data[5 * i + 2];
 596         c[1] = data[5 * i + 3];
 597         c[2] = data[5 * i + 4];
 598         SetUpBumps(n, c, l, s, t);
 599         glTexCoord2f(data[5 * i] + c[0], data[5 * i + 1] + c[1]);
 600         glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 601     }
 602     // Right face
 603     n[0] = 1.0f; n[1] = 0.0f; n[2] = 0.0f;
 604     s[0] = 0.0f; s[1] = 0.0f; s[2] = -1.0f;
 605     t[0] = 0.0f; t[1] = 1.0f; t[2] = 0.0f;
 606     for (i = 16; i<20; i++) {
 607         c[0] = data[5 * i + 2];
 608         c[1] = data[5 * i + 3];
 609         c[2] = data[5 * i + 4];
 610         SetUpBumps(n, c, l, s, t);
 611         glTexCoord2f(data[5 * i] + c[0], data[5 * i + 1] + c[1]);
 612         glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 613     }
 614     // Left face
 615     n[0] = -1.0f; n[1] = 0.0f; n[2] = 0.0f;
 616     s[0] = 0.0f; s[1] = 0.0f; s[2] = 1.0f;
 617     t[0] = 0.0f; t[1] = 1.0f; t[2] = 0.0f;
 618     for (i = 20; i<24; i++) {
 619         c[0] = data[5 * i + 2];
 620         c[1] = data[5 * i + 3];
 621         c[2] = data[5 * i + 4];
 622         SetUpBumps(n, c, l, s, t);
 623         glTexCoord2f(data[5 * i] + c[0], data[5 * i + 1] + c[1]);
 624         glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 625     }
 626     glEnd();
 627     // Third pass. This will finish cube-rendering, complete with lighting.
 628     if (!emboss) {
 629         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 630         glBindTexture(GL_TEXTURE_2D, texture[filter]);
 631         glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
 632         glEnable(GL_LIGHTING);
 633         doCube();
 634     }
 635     // Last pass
 636     xrot += xspeed;
 637     yrot += yspeed;
 638     if (xrot > 360.0f) xrot -= 360.0f;
 639     if (xrot < 0.0f) xrot += 360.0f;
 640     if (yrot > 360.0f) xrot -= 360.0f;
 641     if (yrot < 0.0f) xrot += 360.0f;
 642 
 643     doLogo();
 644     return true;
 645 }
 646 
 647 bool doMesh2TexelUnits(void)
 648 {
 649     GLfloat c[4] = { 0.0f, 0.0f, 0.0f, 1.0f };           // Holds current vertex
 650     GLfloat n[4] = { 0.0f, 0.0f, 0.0f, 1.0f };           // Normalized normal of current surface
 651     GLfloat s[4] = { 0.0f, 0.0f, 0.0f, 1.0f };           // s-Texture coordinate direction
 652     GLfloat t[4] = { 0.0f, 0.0f, 0.0f, 1.0f };           // t-Texture coordinate direction
 653     GLfloat l[4];                 // Holds our lightposition to be transformed into object space
 654     GLfloat Minv[16];             // Holds the inverted modeview matrix to do so
 655     int i;
 656 
 657     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 658     // Build inverse modeview matrix first. This substitutes one push/pop with one
 659     // Simply build it by doing all transformation negated and in reverse order
 660     glLoadIdentity();
 661     glRotatef(-yrot, 0.0f, 1.0f, 0.0f);
 662     glRotatef(-xrot, 1.0f, 0.0f, 0.0f);
 663     glTranslatef(0.0f, 0.0f, -z);
 664     glGetFloatv(GL_MODELVIEW_MATRIX, Minv);
 665     glLoadIdentity();
 666     glTranslatef(0.0f, 0.0f, z);
 667     glRotatef(xrot, 1.0f, 0.0f, 0.0f);
 668     glRotatef(yrot, 0.0f, 1.0f, 0.0f);
 669 
 670     // Transform the lightposition into object coordinate
 671     l[0] = LightPosition[0];
 672     l[1] = LightPosition[1];
 673     l[2] = LightPosition[2];
 674     l[3] = 1.0f;
 675     VMatMult(Minv, l);
 676     // First pass. This will render a cube consisting out of the grey-scale erode map.
 677     // Texture-units #0
 678     glActiveTextureARB(GL_TEXTURE0_ARB);
 679     glEnable(GL_TEXTURE_2D);
 680     glBindTexture(GL_TEXTURE_2D, bump[filter]);
 681     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
 682     glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);
 683 
 684     // Texture-units #1
 685     glActiveTextureARB(GL_TEXTURE1_ARB);
 686     glEnable(GL_TEXTURE_2D);
 687     glBindTexture(GL_TEXTURE_2D, invbump[filter]);
 688     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
 689     glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
 690 
 691     //General switches
 692     glDisable(GL_BLEND);
 693     glDisable(GL_LIGHTING);
 694 
 695     glBegin(GL_QUADS);
 696     // Front face
 697     n[0] = 0.0f;
 698     n[1] = 0.0f;
 699     n[2] = 1.0f;
 700     s[0] = 1.0f;
 701     s[1] = 0.0f;
 702     s[2] = 0.0f;
 703     t[0] = 0.0f;
 704     t[1] = 1.0f;
 705     t[2] = 0.0f;
 706     for (i = 0; i < 4; i++) {
 707         c[0] = data[5 * i + 2];
 708         c[1] = data[5 * i + 3];
 709         c[2] = data[5 * i + 4];
 710         SetUpBumps(n, c, l, s, t);
 711         glMultiTexCoord2fARB(GL_TEXTURE0_ARB, data[5 * i], data[5 * i + 1]);
 712         glMultiTexCoord2fARB(GL_TEXTURE1_ARB, data[5 * i] + c[0], data[5 * i + 1] + c[1]);
 713         glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 714     }
 715     // Back face
 716     n[0] = 0.0f;
 717     n[1] = 0.0f;
 718     n[2] = -1.0f;
 719     s[0] = -1.0f;
 720     s[1] = 0.0f;
 721     s[2] = 0.0f;
 722     t[0] = 0.0f;
 723     t[1] = 1.0f;
 724     t[2] = 0.0f;
 725     for (i = 4; i<8; i++) {
 726         c[0] = data[5 * i + 2];
 727         c[1] = data[5 * i + 3];
 728         c[2] = data[5 * i + 4];
 729         SetUpBumps(n, c, l, s, t);
 730         glMultiTexCoord2fARB(GL_TEXTURE0_ARB, data[5 * i], data[5 * i + 1]);
 731         glMultiTexCoord2fARB(GL_TEXTURE1_ARB, data[5 * i] + c[0], data[5 * i + 1] + c[1]);
 732         glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 733     }
 734     // Top face
 735     n[0] = 0.0f;
 736     n[1] = 1.0f;
 737     n[2] = 0.0f;
 738     s[0] = 1.0f;
 739     s[1] = 0.0f;
 740     s[2] = 0.0f;
 741     t[0] = 0.0f;
 742     t[1] = 0.0f;
 743     t[2] = -1.0f;
 744     for (i = 8; i<12; i++) {
 745         c[0] = data[5 * i + 2];
 746         c[1] = data[5 * i + 3];
 747         c[2] = data[5 * i + 4];
 748         SetUpBumps(n, c, l, s, t);
 749         glMultiTexCoord2fARB(GL_TEXTURE0_ARB, data[5 * i], data[5 * i + 1]);
 750         glMultiTexCoord2fARB(GL_TEXTURE1_ARB, data[5 * i] + c[0], data[5 * i + 1] + c[1]);
 751         glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 752     }
 753     // Bottom face
 754     n[0] = 0.0f;
 755     n[1] = -1.0f;
 756     n[2] = 0.0f;
 757     s[0] = -1.0f;
 758     s[1] = 0.0f;
 759     s[2] = 0.0f;
 760     t[0] = 0.0f;
 761     t[1] = 0.0f;
 762     t[2] = -1.0f;
 763     for (i = 12; i<16; i++) {
 764         c[0] = data[5 * i + 2];
 765         c[1] = data[5 * i + 3];
 766         c[2] = data[5 * i + 4];
 767         SetUpBumps(n, c, l, s, t);
 768         glMultiTexCoord2fARB(GL_TEXTURE0_ARB, data[5 * i], data[5 * i + 1]);
 769         glMultiTexCoord2fARB(GL_TEXTURE1_ARB, data[5 * i] + c[0], data[5 * i + 1] + c[1]);
 770         glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 771     }
 772     // Right face
 773     n[0] = 1.0f;
 774     n[1] = 0.0f;
 775     n[2] = 0.0f;
 776     s[0] = 0.0f;
 777     s[1] = 0.0f;
 778     s[2] = -1.0f;
 779     t[0] = 0.0f;
 780     t[1] = 1.0f;
 781     t[2] = 0.0f;
 782     for (i = 16; i<20; i++) {
 783         c[0] = data[5 * i + 2];
 784         c[1] = data[5 * i + 3];
 785         c[2] = data[5 * i + 4];
 786         SetUpBumps(n, c, l, s, t);
 787         glMultiTexCoord2fARB(GL_TEXTURE0_ARB, data[5 * i], data[5 * i + 1]);
 788         glMultiTexCoord2fARB(GL_TEXTURE1_ARB, data[5 * i] + c[0], data[5 * i + 1] + c[1]);
 789         glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 790     }
 791     // Left face
 792     n[0] = -1.0f;
 793     n[1] = 0.0f;
 794     n[2] = 0.0f;
 795     s[0] = 0.0f;
 796     s[1] = 0.0f;
 797     s[2] = 1.0f;
 798     t[0] = 0.0f;
 799     t[1] = 1.0f;
 800     t[2] = 0.0f;
 801     for (i = 20; i<24; i++) {
 802         c[0] = data[5 * i + 2];
 803         c[1] = data[5 * i + 3];
 804         c[2] = data[5 * i + 4];
 805         SetUpBumps(n, c, l, s, t);
 806         glMultiTexCoord2fARB(GL_TEXTURE0_ARB, data[5 * i], data[5 * i + 1]);
 807         glMultiTexCoord2fARB(GL_TEXTURE1_ARB, data[5 * i] + c[0], data[5 * i + 1] + c[1]);
 808         glVertex3f(data[5 * i + 2], data[5 * i + 3], data[5 * i + 4]);
 809     }
 810     glEnd();
 811 
 812     // Second pass. This will render our complete bump-mapped cube.
 813     glActiveTextureARB(GL_TEXTURE1_ARB);
 814     glDisable(GL_TEXTURE_2D);
 815     glActiveTextureARB(GL_TEXTURE0_ARB);
 816     if (!emboss) {
 817         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 818         glBindTexture(GL_TEXTURE_2D, texture[filter]);
 819         glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
 820         glEnable(GL_BLEND);
 821         glEnable(GL_LIGHTING);
 822         doCube();
 823     }
 824 
 825     // Last pass.
 826     xrot += xspeed;
 827     yrot += yspeed;
 828     if (xrot>360.0f) xrot -= 360.0f;
 829     if (xrot<0.0f) xrot += 360.0f;
 830     if (yrot>360.0f) yrot -= 360.0f;
 831     if (yrot<0.0f) yrot += 360.0f;
 832 
 833     doLogo();
 834     return true;
 835 }
 836 
 837 bool doMeshNoBumps(void) {
 838     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);         // Clear The Screen And The Depth Buffer
 839     glLoadIdentity();                           // Reset The View
 840     glTranslatef(0.0f, 0.0f, z);
 841 
 842     glRotatef(xrot, 1.0f, 0.0f, 0.0f);
 843     glRotatef(yrot, 0.0f, 1.0f, 0.0f);
 844 
 845     if (useMultitexture) {
 846         glActiveTextureARB(GL_TEXTURE1_ARB);
 847         glDisable(GL_TEXTURE_2D);
 848         glActiveTextureARB(GL_TEXTURE0_ARB);
 849     }
 850 
 851     glDisable(GL_BLEND);
 852     glBindTexture(GL_TEXTURE_2D, texture[filter]);
 853     glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
 854     glEnable(GL_LIGHTING);
 855     doCube();
 856 
 857     xrot += xspeed;
 858     yrot += yspeed;
 859     if (xrot>360.0f) xrot -= 360.0f;
 860     if (xrot<0.0f) xrot += 360.0f;
 861     if (yrot>360.0f) yrot -= 360.0f;
 862     if (yrot<0.0f) yrot += 360.0f;
 863 
 864     doLogo();
 865     return true;
 866 }
 867 
 868 /*
 869  *  For now all we will do is clear the screen to the color we previously decided on,
 870  *  clear the depth buffer and reset the scene. We wont draw anything yet.
 871  */
 872 int DrawGLScene(GLvoid)                                  // Here's where we do all the drawing
 873 {
 874     if (bumps) {
 875         if (useMultitexture && maxTexelUnits > 1)
 876             return  doMesh2TexelUnits();
 877         else return doMesh1TexelUnits();
 878     }
 879     else return doMeshNoBumps();
 880 }
 881 /*****************************************************************************************************************************************/
 882 /*****************************************************************************************************************************************/
 883 /*
 884  *  The job of KillGLWindow() is to release the Rendering Context, 
 885  *  the Device Context and finally the Window Handle. 
 886  */
 887 
 888 GLvoid KillGLWindow(GLvoid)                              // Properly kill the window
 889 {
 890     if (fullscreen) {                                    // Are we in fullscreen mode
 891         
 892         /*
 893          *  We use ChangeDisplaySettings(NULL,0) to return us to our original desktop.
 894          *  After we've switched back to the desktop we make the cursor visible again.
 895          */
 896 
 897         ChangeDisplaySettings(NULL, 0);                  // if so switch back to the desktop
 898         ShowCursor(TRUE);                                // Show mouse pointer
 899     }
 900 
 901     if (hRC) {                                           // Do we have a rendering context
 902         if (!wglMakeCurrent(NULL, NULL)) {                // Are we able to release the DC and RC contexts
 903             MessageBox(NULL, "Release of DC and RC failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 904         }
 905 
 906         if (!wglDeleteContext(hRC)) {                     // Are we able to delete the RC
 907             MessageBox(NULL, "Release rendering context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 908             hRC = NULL;                                  // Set RC to NULL
 909         }
 910 
 911         if (hDC && !ReleaseDC(hWnd, hDC)) {              // Are we able to release the DC
 912             MessageBox(NULL, "Release device context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 913             hDC = NULL;                                  // Set DC to NULL
 914         }
 915         if (hWnd && !DestroyWindow(hWnd)) {              // Are we able to destroy the window
 916             MessageBox(NULL, "Could not release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 917             hWnd = NULL;                                 // Set hWnd to NULL
 918         }
 919 
 920         if (!UnregisterClass("OpenGL", hInstance)) {     // Are we able to unregister class
 921             MessageBox(NULL, "Could not register class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
 922             hInstance = NULL;                            // Set hInstance to NULL
 923         }
 924     }
 925 }
 926 
 927 /*
 928  * The next section of code creates our OpenGL Window.
 929  */
 930 
 931 BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
 932 {
 933     /*
 934      * Find  a pixel format that matches the one we want
 935      */
 936     GLuint PixelFormat;                                  // Holds the result after serching for a match
 937     
 938     /*
 939      * Before you create a window, you MUST register a Class for the window
 940      */
 941     WNDCLASS wc;                                         // Windows class structure
 942 
 943     /*
 944      *  dwExStyle and dwStyle will store the Extended and normal Window Style Information.
 945     */
 946     DWORD dwExStyle;                                     // Window extend style
 947     DWORD dwStyle;                                       // Window style
 948 
 949     RECT WindowRect;                                     // Grabs rectangle upper left/lower right values
 950     WindowRect.left = (long)0;                           // Set left value to 0
 951     WindowRect.right = (long)width;                      // Set right value to requested width
 952     WindowRect.top = (long)0;                            // Set top value to 0
 953     WindowRect.bottom = (long)height;                    // Set bottom value to requested height
 954 
 955     fullscreen = fullscreenflag;                         // Set the global fullscreen flag
 956 
 957     /*
 958      *  The style CS_HREDRAW and CS_VREDRAW force the Window to redraw whenever it is resized. 
 959      *  CS_OWNDC creates a private DC for the Window. Meaning the DC is not shared across applications. 
 960      *  WndProc is the procedure that watches for messages in our program. 
 961      *  No extra Window data is used so we zero the two fields. Then we set the instance. 
 962      *  Next we set hIcon to NULL meaning we don't want an ICON in the Window, 
 963      *  and for a mouse pointer we use the standard arrow. The background color doesn't matter 
 964      *  (we set that in GL). We don't want a menu in this Window so we set it to NULL, 
 965      *  and the class name can be any name you want. I'll use "OpenGL" for simplicity.
 966      */
 967     hInstance = GetModuleHandle(NULL);                   // Grab an instance for our window
 968     wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;       // Redraw on move, and own DC for window
 969     wc.lpfnWndProc = (WNDPROC)WndProc;                   // WndProc handles message
 970     wc.cbClsExtra = 0;                                   // No extra window date
 971     wc.cbWndExtra = 0;                                   // No extra window date
 972     wc.hInstance = hInstance;                            // set the instance
 973     wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);              // Load the default icon
 974     wc.hCursor = LoadCursor(NULL, IDC_ARROW);            // Load the arrow pointer
 975     wc.hbrBackground = NULL;                             // No background requried for GL
 976     wc.lpszMenuName = NULL;                              // We don't want a menu
 977     wc.lpszClassName = "OpenGL";                         // set the class name
 978 
 979     if (!RegisterClass(&wc)) {                           // Attempt to register the window class
 980         MessageBox(NULL, "Failed to register the window class.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
 981         return FALSE;                                    // Exit and return false
 982     }
 983 
 984     if (fullscreen) {                                    // attempt fullsreen model
 985         
 986         /*
 987         T*  here are a few very important things you should keep in mind when switching to full screen mode.
 988          *  Make sure the width and height that you use in fullscreen mode is the same as 
 989          *  the width and height you plan to use for your window, and most importantly,
 990          *  set fullscreen mode BEFORE you create your window.
 991          */
 992         DEVMODE dmScreenSettings;                        // Device mode
 993         memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // Make sure memory's cleared
 994         dmScreenSettings.dmSize = sizeof(dmScreenSettings);     // Size of devmode structure
 995         dmScreenSettings.dmPelsWidth = width;            // Select window width
 996         dmScreenSettings.dmPelsHeight = height;          // Select window height
 997         dmScreenSettings.dmBitsPerPel = bits;            // Select bits per pixel
 998         dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
 999         
1000         /*
1001          *  In the line below ChangeDisplaySettings tries to switch to a mode that matches 
1002          *  what we stored in dmScreenSettings. I use the parameter CDS_FULLSCREEN when switching modes, 
1003          *  because it's supposed to remove the start bar at the bottom of the screen, 
1004          *  plus it doesn't move or resize the windows on your desktop when you switch to 
1005          *  fullscreen mode and back.
1006          */
1007         //Try to set selected mode and get results. Note: CDS_FULLSCREEN gets rid of start bar
1008         if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
1009             //If the mode fails, offer two options. Quit or run in a window
1010             if (MessageBox(NULL, "The requested fullscreen mode is not supported by\n your video card. Use"
1011                 "windowed mode instead?", "GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
1012             {
1013                 fullscreen = FALSE;                       // Select windowed mode (fullscreen=FLASE)
1014             }
1015             else {
1016                 // Pop up a message box letting user know the programe is closing.
1017                 MessageBox(NULL, "Program will now close.", "ERROR", MB_OK | MB_ICONSTOP);
1018                 return FALSE;                             // Exit and return FALSE
1019             }
1020         }
1021     }
1022 
1023     if (fullscreen) {                                     // Are we still in fullscreen mode
1024         
1025         /*
1026          *  If we are still in fullscreen mode we'll set the extended style to WS_EX_APPWINDOW, 
1027          *  which force a top level window down to the taskbar once our window is visible. 
1028          *  For the window style we'll create a WS_POPUP window. 
1029          *  This type of window has no border around it, making it perfect for fullscreen mode.
1030 
1031          *  Finally, we disable the mouse pointer. If your program is not interactive, 
1032          *  it's usually nice to disable the mouse pointer when in fullscreen mode. It's up to you though.
1033          */
1034         dwExStyle = WS_EX_APPWINDOW;                      // Window extended style
1035         dwStyle = WS_POPUP;                               // Window style
1036         ShowCursor(FALSE);                                // Hide mosue pointer 
1037     }
1038     else {
1039 
1040         /*
1041          *  If we're using a window instead of fullscreen mode, 
1042          *  we'll add WS_EX_WINDOWEDGE to the extended style. This gives the window a more 3D look. 
1043          *  For style we'll use WS_OVERLAPPEDWINDOW instead of WS_POPUP. 
1044          *  WS_OVERLAPPEDWINDOW creates a window with a title bar, sizing border, 
1045          *  window menu, and minimize / maximize buttons.
1046          */
1047         dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;   // Window extended style
1048         dwStyle = WS_OVERLAPPEDWINDOW;                    // Window style
1049     }
1050 
1051     /*
1052      *  By using the AdjustWindowRectEx command none of our OpenGL scene will be covered up by the borders, 
1053      *  instead, the window will be made larger to account for the pixels needed to draw the window border. 
1054      *  In fullscreen mode, this command has no effect.
1055      */
1056     AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);  // Adjust window to true resqusted
1057     
1058     /*
1059      *  WS_CLIPSIBLINGS and WS_CLIPCHILDREN are both REQUIRED for OpenGL to work properly. 
1060      *  These styles prevent other windows from drawing over or into our OpenGL Window.
1061      */
1062     if (!(hWnd = CreateWindowEx(dwExStyle,                // Extended style for the window
1063         "OpenGL",                                         // Class name
1064         title,                                            // Window title
1065         WS_CLIPSIBLINGS |                                 // Requried window style
1066         WS_CLIPCHILDREN |                                 // Requried window style
1067         dwStyle,                                          // Select window style
1068         0, 0,                                             // Window position
1069         WindowRect.right - WindowRect.left,               // Calculate adjusted window width
1070         WindowRect.bottom - WindowRect.top,               // Calculate adjusted window height
1071         NULL,                                             // No parent window
1072         NULL,                                             // No menu
1073         hInstance,                                        // Instance
1074         NULL)))                                           // Don't pass anything to WM_CREATE
1075     {
1076         KillGLWindow();                                   //Reset the display
1077         MessageBox(NULL, "Window creation error.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1078         return FALSE;                                     // Retrurn FALSE;
1079     }
1080 
1081     /*
1082      *  aside from the stencil buffer and the (slow) accumulation buffer
1083      */
1084     static PIXELFORMATDESCRIPTOR pfd =                    // pfd tells windows how we want things to be 
1085     {
1086         sizeof(PIXELFORMATDESCRIPTOR),                    // Size of this pixel format descriptor
1087         1,                                                // Version number
1088         PFD_DRAW_TO_WINDOW |                              // Format must support window
1089         PFD_SUPPORT_OPENGL |                              // Format must support OpenGL
1090         PFD_DOUBLEBUFFER,                                 // Must support double buffer
1091         PFD_TYPE_RGBA,                                    // Request an RGBA format
1092         bits,                                             // Select our color depth
1093         0, 0, 0, 0, 0, 0,                                 // Color bits ignored
1094         0,                                                // No alpha buffer
1095         0,                                                // shift bit ignored
1096         0,                                                // No accumulation buffer
1097         0, 0, 0, 0,                                       // Accumulation bits ignored
1098         16,                                               // 16Bits Z_Buffer (depth buffer)
1099         0,                                                // No stencil buffer
1100         0,                                                // No auxiliary buffer
1101         PFD_MAIN_PLANE,                                   // Main drawing layer
1102         0,                                                // Reserved
1103         0, 0, 0                                           // Layer makes ignored
1104     };
1105 
1106     if (!(hDC = GetDC(hWnd))) {                           // Did we get a device context
1107         KillGLWindow();                                   // Reset the display
1108         MessageBox(NULL, "Can't create a GL device context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1109         return FALSE;                                     // Return FALSE
1110     }
1111 
1112     if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) {  // Did window find a matching pixel format
1113         KillGLWindow();                                   // Reset the display
1114         MessageBox(NULL, "Can't find a suitable pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1115         return FALSE;                                     // Return FALSE;
1116     }
1117 
1118     if (!SetPixelFormat(hDC, PixelFormat, &pfd)) {        // Are we able to set the pixel format
1119         KillGLWindow();                                   // Reset the display
1120         MessageBox(NULL, "Can't set the pixelformat.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1121         return FALSE;                                     // Return FALSE;
1122     }
1123 
1124     if (!(hRC = wglCreateContext(hDC))) {                 // Are we able to rendering context
1125         KillGLWindow();                                   // Reset the display
1126         MessageBox(NULL, "Can't create a GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1127         return FALSE;                                     // Return FASLE;
1128     }
1129 
1130     if (!wglMakeCurrent(hDC, hRC)) {                      // Try to activate the rendering context
1131         KillGLWindow();                                   // Reset the display
1132         MessageBox(NULL, "Can't activate the GL rendering context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1133         return FALSE;                                     // Return FALSE    
1134     }
1135 
1136     /*
1137      *  ReSizeGLScene passing the screen width and height to set up our perspective OpenGL screen.
1138      */
1139     ShowWindow(hWnd, SW_SHOW);                            // Show the window
1140     SetForegroundWindow(hWnd);                            // slightly higher priority
1141     SetFocus(hWnd);                                       // Sets keyboard focus to the window
1142     ReSizeGLScene(width, height);                         // Set up our perspective GL screen
1143 
1144 /*
1145  *  we can set up lighting, textures, and anything else that needs to be setup in InitGL().
1146  */
1147     if (!InitGL()) {                                      // Initialize our newly created GL window
1148         KillGLWindow();                                   // Reset the display
1149         MessageBox(NULL, "Initialize Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
1150         return FALSE;                                     // Return FALSE
1151     }
1152     return TRUE;
1153 }
1154 
1155 LRESULT CALLBACK WndProc(HWND hWnd,                       // Handle for this window
1156     UINT uMsg,                                            // Message for this window
1157     WPARAM wParam,                                        // Additional message information
1158     LPARAM lParam)                                        // Additional message information
1159 {
1160     switch (uMsg) {                                       // Check for window message
1161     case WM_ACTIVATE: {                               // Check minimization state
1162         if (!HIWORD(wParam)) {
1163             active = TRUE;                            // Program is active
1164         }
1165         else {
1166             active = FALSE;                           // Program is no longer active
1167         }
1168         return 0;                                     // Return to the message loop
1169     }
1170     case WM_SYSCOMMAND: {                             // Intercept system commands
1171         switch (wParam) {                             // Check system calls
1172         case SC_SCREENSAVE:                       // Screensaver trying to start
1173         case SC_MONITORPOWER:                     // Monitor trying to enter powersave
1174             return 0;                                 // Prevent form happening
1175         }
1176         break;                                        // Exit
1177     }
1178     case WM_CLOSE: {                                  // Did we receive a close message
1179         PostQuitMessage(0);                           // Send a quit message
1180         return 0;
1181     }
1182     case WM_KEYDOWN: {                                // Is a key being held down
1183         keys[wParam] = TRUE;                          // if so, mark it as TRUE
1184         return 0;                                     // Jump back
1185     }
1186     case WM_KEYUP: {                                  // Has a key been released
1187         keys[wParam] = FALSE;                         // if so, mark it as FALSE
1188         return 0;                                     // Jump back
1189     }
1190     case WM_SIZE: {                                   // Resize the OpenGL window
1191         ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));   // LoWord = width HiWord = height
1192         return 0;                                     // Jump back
1193     }
1194     }
1195     return DefWindowProc(hWnd, uMsg, wParam, lParam);     // Pass all unhandled message to DefWindwProc
1196 }
1197 
1198 int WINAPI WinMain(HINSTANCE hInstance,                   // Instance
1199     HINSTANCE hPrevInstance,                              // Previous instance
1200     LPSTR lpCmdLine,                                      // Command line parameters
1201     int nCmdShow)                                         // Window show state
1202 {
1203     MSG msg;                                              // Window message structure
1204     BOOL done = FALSE;                                    // Bool variable to exit loop
1205                                                           // Ask the user which screen mode they prefer
1206     if (MessageBox(NULL, "Would you like to run in fullscreen mode?",
1207         "Start fullscreen?", MB_YESNO | MB_ICONQUESTION) == IDNO)
1208     {
1209         fullscreen = FALSE;                               // Window mode
1210     }
1211     // Create our OpenGL window
1212     if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) {  // (Modified)
1213         return 0;                                         // Quit if window was not create
1214     }
1215 /*****************************************************************************************************************************************/
1216 /*****************************************************************************************************************************************/
1217 
1218     while (!done) {                                       // Loop that runs until donw = TRUE
1219         if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {   // Is there a message wating
1220             if (msg.message == WM_QUIT) {                 // Havw we received a quit message
1221                 done = TRUE;                              // if so done  = TRUE
1222             }
1223             else {                                        // If not, deal with window message
1224                 TranslateMessage(&msg);                   // Translate message
1225                 DispatchMessage(&msg);                    // Dispatch message
1226             }
1227         }
1228         else {
1229             // Draw the scene. Watch for ESC key and quit message from DrawGLScene()
1230             if (active) {                                 // Program active
1231                 if (keys[VK_ESCAPE]) {                    // Was ESC pressed
1232                     done = TRUE;                          // ESC signalled a quit
1233                 }
1234                 else {                                    // Not time to quit, update screen
1235                     DrawGLScene();                        // Draw scene
1236                     SwapBuffers(hDC);                     // Swap buffers (double buffering)
1237                 }
1238             }
1239             if (keys['E'])
1240             {
1241                 keys['E'] = false;
1242                 emboss = !emboss;
1243             }
1244 
1245             if (keys['M'])
1246             {
1247                 keys['M'] = false;
1248                 useMultitexture = ((!useMultitexture) && multitextureSupported);
1249             }
1250 
1251             if (keys['B'])
1252             {
1253                 keys['B'] = false;
1254                 bumps = !bumps;
1255             }
1256 
1257             if (keys['F'])
1258             {
1259                 keys['F'] = false;
1260                 filter++;
1261                 filter %= 3;
1262             }
1263 
1264             if (keys[VK_PRIOR])
1265             {
1266                 z -= 0.02f;
1267             }
1268 
1269             if (keys[VK_NEXT])
1270             {
1271                 z += 0.02f;
1272             }
1273 
1274             if (keys[VK_UP])
1275             {
1276                 xspeed -= 0.0001f;
1277             }
1278 
1279             if (keys[VK_DOWN])
1280             {
1281                 xspeed += 0.0001f;
1282             }
1283 
1284             if (keys[VK_RIGHT])
1285             {
1286                 yspeed += 0.0001f;
1287             }
1288 
1289             if (keys[VK_LEFT])
1290             {
1291                 yspeed -= 0.0001f;
1292             }
1293             /*
1294             *  It allows us to press the F1 key to switch from fullscreen mode to
1295             *  windowed mode or windowed mode to fullscreen mode.
1296             */
1297             if (keys[VK_F1]) {                            // Is F1 being pressed
1298                 keys[VK_F1] = FALSE;                      // If so make key FASLE
1299                 KillGLWindow();                           // Kill our current window
1300                 fullscreen = !fullscreen;                 // Toggle fullscreen / window mode
1301                 //Recreate our OpenGL window(modified)
1302                 if (!CreateGLWindow("3D Shapes", 640, 480, 16, fullscreen)) {
1303                     return 0;                             // Quit if window was not create
1304                 }
1305             }
1306         }
1307     }
1308     // Shutdown
1309     KillGLWindow();                                       // Kill the window
1310     return (msg.wParam);                                  // Exit the program
1311 }
1312 /*****************************************************************************************************************************************/
1313 /*****************************************************************************************************************************************/

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

posted @ 2016-07-28 16:51  clairvoyant  阅读(475)  评论(0编辑  收藏  举报