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.