1/** 2 * Test texturing with GL shading language. 3 * 4 * Copyright (C) 2007 Brian Paul All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 20 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24 25 26#include <assert.h> 27#include <math.h> 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31#include <GL/glew.h> 32#include "glut_wrap.h" 33#include "readtex.h" 34#include "shaderutil.h" 35 36static const char *Demo = "texdemo1"; 37 38static const char *ReflectVertFile = "reflect.vert"; 39static const char *CubeFragFile = "cubemap.frag"; 40 41static const char *SimpleVertFile = "simple.vert"; 42static const char *SimpleTexFragFile = "shadowtex.frag"; 43 44static const char *GroundImage = DEMOS_DATA_DIR "tile.rgb"; 45 46static GLuint Program1, Program2; 47 48static GLfloat TexXrot = 0, TexYrot = 0; 49static GLfloat Xrot = 20.0, Yrot = 20.0, Zrot = 0.0; 50static GLfloat EyeDist = 10; 51static GLboolean Anim = GL_TRUE; 52static int win = 0; 53 54 55static struct uniform_info ReflectUniforms[] = { 56 { "cubeTex", 1, GL_SAMPLER_CUBE, { 0, 0, 0, 0 }, -1 }, 57 { "lightPos", 1, GL_FLOAT_VEC3, { 10, 10, 20, 0 }, -1 }, 58 END_OF_UNIFORMS 59}; 60 61static struct uniform_info SimpleUniforms[] = { 62 { "tex2d", 1, GL_SAMPLER_2D, { 1, 0, 0, 0 }, -1 }, 63 { "lightPos", 1, GL_FLOAT_VEC3, { 10, 10, 20, 0 }, -1 }, 64 END_OF_UNIFORMS 65}; 66 67 68static void 69DrawGround(GLfloat size) 70{ 71 glPushMatrix(); 72 glRotatef(90, 1, 0, 0); 73 glNormal3f(0, 0, 1); 74 glBegin(GL_POLYGON); 75 glTexCoord2f(-2, -2); glVertex2f(-size, -size); 76 glTexCoord2f( 2, -2); glVertex2f( size, -size); 77 glTexCoord2f( 2, 2); glVertex2f( size, size); 78 glTexCoord2f(-2, 2); glVertex2f(-size, size); 79 glEnd(); 80 glPopMatrix(); 81} 82 83 84static void 85draw(void) 86{ 87 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 88 89 glEnable(GL_TEXTURE_2D); 90 91 glPushMatrix(); /* modelview matrix */ 92 glTranslatef(0.0, 0.0, -EyeDist); 93 glRotatef(Xrot, 1, 0, 0); 94 glRotatef(Yrot, 0, 1, 0); 95 glRotatef(Zrot, 0, 0, 1); 96 97 /* sphere w/ reflection map */ 98 glPushMatrix(); 99 glTranslatef(0, 1, 0); 100 glUseProgram(Program1); 101 102 /* setup texture matrix */ 103 glActiveTexture(GL_TEXTURE0); 104 glMatrixMode(GL_TEXTURE); 105 glLoadIdentity(); 106 glRotatef(-TexYrot, 0, 1, 0); 107 glRotatef(-TexXrot, 1, 0, 0); 108 109 glEnable(GL_TEXTURE_GEN_S); 110 glEnable(GL_TEXTURE_GEN_T); 111 glEnable(GL_TEXTURE_GEN_R); 112 glutSolidSphere(2.0, 20, 20); 113 114 glLoadIdentity(); /* texture matrix */ 115 glMatrixMode(GL_MODELVIEW); 116 glPopMatrix(); 117 118 /* ground */ 119 glUseProgram(Program2); 120 glTranslatef(0, -1.0, 0); 121 DrawGround(5); 122 123 glPopMatrix(); 124 125 glutSwapBuffers(); 126} 127 128 129static void 130idle(void) 131{ 132 GLfloat t = 0.05 * glutGet(GLUT_ELAPSED_TIME); 133 TexYrot = t; 134 glutPostRedisplay(); 135} 136 137 138static void 139key(unsigned char k, int x, int y) 140{ 141 (void) x; 142 (void) y; 143 switch (k) { 144 case ' ': 145 case 'a': 146 Anim = !Anim; 147 if (Anim) 148 glutIdleFunc(idle); 149 else 150 glutIdleFunc(NULL); 151 break; 152 case 'z': 153 EyeDist -= 0.5; 154 if (EyeDist < 6.0) 155 EyeDist = 6.0; 156 break; 157 case 'Z': 158 EyeDist += 0.5; 159 if (EyeDist > 90.0) 160 EyeDist = 90; 161 break; 162 case 27: 163 glutDestroyWindow(win); 164 exit(0); 165 } 166 glutPostRedisplay(); 167} 168 169 170static void 171specialkey(int key, int x, int y) 172{ 173 GLfloat step = 2.0; 174 (void) x; 175 (void) y; 176 switch (key) { 177 case GLUT_KEY_UP: 178 Xrot += step; 179 break; 180 case GLUT_KEY_DOWN: 181 Xrot -= step; 182 break; 183 case GLUT_KEY_LEFT: 184 Yrot -= step; 185 break; 186 case GLUT_KEY_RIGHT: 187 Yrot += step; 188 break; 189 } 190 glutPostRedisplay(); 191} 192 193 194/* new window size or exposure */ 195static void 196Reshape(int width, int height) 197{ 198 GLfloat ar = (float) width / (float) height; 199 glViewport(0, 0, (GLint)width, (GLint)height); 200 glMatrixMode(GL_PROJECTION); 201 glLoadIdentity(); 202 glFrustum(-2.0*ar, 2.0*ar, -2.0, 2.0, 4.0, 100.0); 203 glMatrixMode(GL_MODELVIEW); 204 glLoadIdentity(); 205} 206 207 208static void 209InitCheckers(void) 210{ 211#define CUBE_TEX_SIZE 64 212 GLubyte image[CUBE_TEX_SIZE][CUBE_TEX_SIZE][3]; 213 static const GLubyte colors[6][3] = { 214 { 255, 0, 0 }, /* face 0 - red */ 215 { 0, 255, 255 }, /* face 1 - cyan */ 216 { 0, 255, 0 }, /* face 2 - green */ 217 { 255, 0, 255 }, /* face 3 - purple */ 218 { 0, 0, 255 }, /* face 4 - blue */ 219 { 255, 255, 0 } /* face 5 - yellow */ 220 }; 221 static const GLenum targets[6] = { 222 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 223 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, 224 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, 225 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, 226 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, 227 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 228 }; 229 230 GLint i, j, f; 231 232 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 233 234 /* make colored checkerboard cube faces */ 235 for (f = 0; f < 6; f++) { 236 for (i = 0; i < CUBE_TEX_SIZE; i++) { 237 for (j = 0; j < CUBE_TEX_SIZE; j++) { 238 if ((i/4 + j/4) & 1) { 239 image[i][j][0] = colors[f][0]; 240 image[i][j][1] = colors[f][1]; 241 image[i][j][2] = colors[f][2]; 242 } 243 else { 244 image[i][j][0] = 255; 245 image[i][j][1] = 255; 246 image[i][j][2] = 255; 247 } 248 } 249 } 250 251 glTexImage2D(targets[f], 0, GL_RGB, CUBE_TEX_SIZE, CUBE_TEX_SIZE, 0, 252 GL_RGB, GL_UNSIGNED_BYTE, image); 253 } 254} 255 256 257static void 258LoadFace(GLenum target, const char *filename, 259 GLboolean flipTB, GLboolean flipLR) 260{ 261 GLint w, h; 262 GLenum format; 263 GLubyte *img = LoadRGBImage(filename, &w, &h, &format); 264 if (!img) { 265 printf("Error: couldn't load texture image %s\n", filename); 266 exit(1); 267 } 268 assert(format == GL_RGB); 269 270 /* <sigh> the way the texture cube mapping works, we have to flip 271 * images to make things look right. 272 */ 273 if (flipTB) { 274 const int stride = 3 * w; 275 GLubyte temp[3*1024]; 276 int i; 277 for (i = 0; i < h / 2; i++) { 278 memcpy(temp, img + i * stride, stride); 279 memcpy(img + i * stride, img + (h - i - 1) * stride, stride); 280 memcpy(img + (h - i - 1) * stride, temp, stride); 281 } 282 } 283 if (flipLR) { 284 const int stride = 3 * w; 285 GLubyte temp[3]; 286 GLubyte *row; 287 int i, j; 288 for (i = 0; i < h; i++) { 289 row = img + i * stride; 290 for (j = 0; j < w / 2; j++) { 291 int k = w - j - 1; 292 temp[0] = row[j*3+0]; 293 temp[1] = row[j*3+1]; 294 temp[2] = row[j*3+2]; 295 row[j*3+0] = row[k*3+0]; 296 row[j*3+1] = row[k*3+1]; 297 row[j*3+2] = row[k*3+2]; 298 row[k*3+0] = temp[0]; 299 row[k*3+1] = temp[1]; 300 row[k*3+2] = temp[2]; 301 } 302 } 303 } 304 305 gluBuild2DMipmaps(target, GL_RGB, w, h, format, GL_UNSIGNED_BYTE, img); 306 free(img); 307} 308 309 310static void 311LoadEnvmaps(void) 312{ 313 LoadFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, "right.rgb", GL_TRUE, GL_FALSE); 314 LoadFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, "left.rgb", GL_TRUE, GL_FALSE); 315 LoadFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, "top.rgb", GL_FALSE, GL_TRUE); 316 LoadFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, "bottom.rgb", GL_FALSE, GL_TRUE); 317 LoadFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, "front.rgb", GL_TRUE, GL_FALSE); 318 LoadFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, "back.rgb", GL_TRUE, GL_FALSE); 319} 320 321 322static void 323InitTextures(GLboolean useImageFiles) 324{ 325 GLenum filter; 326 327 /* 328 * Env map 329 */ 330 glActiveTexture(GL_TEXTURE0); 331 glBindTexture(GL_TEXTURE_CUBE_MAP, 1); 332 if (useImageFiles) { 333 LoadEnvmaps(); 334 filter = GL_LINEAR; 335 } 336 else { 337 InitCheckers(); 338 filter = GL_NEAREST; 339 } 340 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, filter); 341 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, filter); 342 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 343 glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 344 345 /* 346 * Ground texture 347 */ 348 { 349 GLint imgWidth, imgHeight; 350 GLenum imgFormat; 351 GLubyte *image = NULL; 352 353 image = LoadRGBImage(GroundImage, &imgWidth, &imgHeight, &imgFormat); 354 if (!image) { 355 printf("Couldn't read %s\n", GroundImage); 356 exit(0); 357 } 358 359 glActiveTexture(GL_TEXTURE1); 360 glBindTexture(GL_TEXTURE_2D, 2); 361 gluBuild2DMipmaps(GL_TEXTURE_2D, 3, imgWidth, imgHeight, 362 imgFormat, GL_UNSIGNED_BYTE, image); 363 free(image); 364 365 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 367 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 368 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 369 } 370} 371 372 373static GLuint 374CreateAProgram(const char *vertProgFile, const char *fragProgFile, 375 struct uniform_info *uniforms) 376{ 377 GLuint fragShader, vertShader, program; 378 379 vertShader = CompileShaderFile(GL_VERTEX_SHADER, vertProgFile); 380 fragShader = CompileShaderFile(GL_FRAGMENT_SHADER, fragProgFile); 381 program = LinkShaders(vertShader, fragShader); 382 383 glUseProgram(program); 384 385 SetUniformValues(program, uniforms); 386 PrintUniforms(uniforms); 387 388 return program; 389} 390 391 392static void 393InitPrograms(void) 394{ 395 Program1 = CreateAProgram(ReflectVertFile, CubeFragFile, ReflectUniforms); 396 Program2 = CreateAProgram(SimpleVertFile, SimpleTexFragFile, SimpleUniforms); 397} 398 399 400static void 401Init(GLboolean useImageFiles) 402{ 403 if (!ShadersSupported()) { 404 exit(1); 405 } 406 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER)); 407 408 InitTextures(useImageFiles); 409 InitPrograms(); 410 411 glEnable(GL_DEPTH_TEST); 412 413 glClearColor(.6, .6, .9, 0); 414 glColor3f(1.0, 1.0, 1.0); 415} 416 417 418int 419main(int argc, char *argv[]) 420{ 421 glutInit(&argc, argv); 422 glutInitWindowSize(500, 400); 423 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 424 win = glutCreateWindow(Demo); 425 glewInit(); 426 glutReshapeFunc(Reshape); 427 glutKeyboardFunc(key); 428 glutSpecialFunc(specialkey); 429 glutDisplayFunc(draw); 430 if (Anim) 431 glutIdleFunc(idle); 432 if (argc > 1 && strcmp(argv[1] , "-i") == 0) 433 Init(1); 434 else 435 Init(0); 436 glutMainLoop(); 437 return 0; 438} 439