1/** 2 * Test multi-texturing with GL shading language. 3 * 4 * Copyright (C) 2008 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 = "multitex"; 37 38static const char *VertFile = "multitex.vert"; 39static const char *FragFile = "multitex.frag"; 40 41static const char *TexFiles[2] = 42 { 43 DEMOS_DATA_DIR "tile.rgb", 44 DEMOS_DATA_DIR "tree2.rgba" 45 }; 46 47 48static GLuint Program; 49 50static GLfloat Xrot = 0.0, Yrot = .0, Zrot = 0.0; 51static GLfloat EyeDist = 10; 52static GLboolean Anim = GL_TRUE; 53static GLboolean UseArrays = GL_TRUE; 54static GLboolean UseVBO = GL_TRUE; 55static GLuint VBO = 0; 56 57static GLint VertCoord_attr = -1, TexCoord0_attr = -1, TexCoord1_attr = -1; 58 59 60/* value[0] = tex unit */ 61static struct uniform_info Uniforms[] = { 62 { "tex1", 1, GL_SAMPLER_2D, { 0, 0, 0, 0 }, -1 }, 63 { "tex2", 1, GL_SAMPLER_2D, { 1, 0, 0, 0 }, -1 }, 64 END_OF_UNIFORMS 65}; 66 67 68static const GLfloat Tex0Coords[4][2] = { 69 { 0.0, 0.0 }, { 2.0, 0.0 }, { 2.0, 2.0 }, { 0.0, 2.0 } 70}; 71 72static const GLfloat Tex1Coords[4][2] = { 73 { 0.0, 0.0 }, { 1.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 1.0 } 74}; 75 76static const GLfloat VertCoords[4][2] = { 77 { -3.0, -3.0 }, { 3.0, -3.0 }, { 3.0, 3.0 }, { -3.0, 3.0 } 78}; 79 80 81 82static void 83SetupVertexBuffer(void) 84{ 85 glGenBuffersARB(1, &VBO); 86 glBindBufferARB(GL_ARRAY_BUFFER_ARB, VBO); 87 88 glBufferDataARB(GL_ARRAY_BUFFER_ARB, 89 sizeof(VertCoords) + 90 sizeof(Tex0Coords) + 91 sizeof(Tex1Coords), 92 NULL, 93 GL_STATIC_DRAW_ARB); 94 95 /* non-interleaved vertex arrays */ 96 97 glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 98 0, /* offset */ 99 sizeof(VertCoords), /* size */ 100 VertCoords); /* data */ 101 102 glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 103 sizeof(VertCoords), /* offset */ 104 sizeof(Tex0Coords), /* size */ 105 Tex0Coords); /* data */ 106 107 glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 108 sizeof(VertCoords) + 109 sizeof(Tex0Coords), /* offset */ 110 sizeof(Tex1Coords), /* size */ 111 Tex1Coords); /* data */ 112 113 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); 114} 115 116 117static void 118DrawPolygonArray(void) 119{ 120 void *vertPtr, *tex0Ptr, *tex1Ptr; 121 122 if (UseVBO) { 123 glBindBufferARB(GL_ARRAY_BUFFER_ARB, VBO); 124 vertPtr = (void *) 0; 125 tex0Ptr = (void *) sizeof(VertCoords); 126 tex1Ptr = (void *) (sizeof(VertCoords) + sizeof(Tex0Coords)); 127 } 128 else { 129 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); 130 vertPtr = VertCoords; 131 tex0Ptr = Tex0Coords; 132 tex1Ptr = Tex1Coords; 133 } 134 135 if (VertCoord_attr >= 0) { 136 glVertexAttribPointer(VertCoord_attr, 2, GL_FLOAT, GL_FALSE, 137 0, vertPtr); 138 glEnableVertexAttribArray(VertCoord_attr); 139 } 140 else { 141 glVertexPointer(2, GL_FLOAT, 0, vertPtr); 142 glEnableClientState(GL_VERTEX_ARRAY); 143 } 144 145 glVertexAttribPointer(TexCoord0_attr, 2, GL_FLOAT, GL_FALSE, 146 0, tex0Ptr); 147 glEnableVertexAttribArray(TexCoord0_attr); 148 149 glVertexAttribPointer(TexCoord1_attr, 2, GL_FLOAT, GL_FALSE, 150 0, tex1Ptr); 151 glEnableVertexAttribArray(TexCoord1_attr); 152 153 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 154 155 glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); 156} 157 158 159static void 160DrawPolygonVert(void) 161{ 162 GLuint i; 163 164 glBegin(GL_TRIANGLE_FAN); 165 166 for (i = 0; i < 4; i++) { 167 glVertexAttrib2fv(TexCoord0_attr, Tex0Coords[i]); 168 glVertexAttrib2fv(TexCoord1_attr, Tex1Coords[i]); 169 170 if (VertCoord_attr >= 0) 171 glVertexAttrib2fv(VertCoord_attr, VertCoords[i]); 172 else 173 glVertex2fv(VertCoords[i]); 174 } 175 176 glEnd(); 177} 178 179 180static void 181draw(void) 182{ 183 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 184 185 glPushMatrix(); /* modelview matrix */ 186 glTranslatef(0.0, 0.0, -EyeDist); 187 glRotatef(Zrot, 0, 0, 1); 188 glRotatef(Yrot, 0, 1, 0); 189 glRotatef(Xrot, 1, 0, 0); 190 191 if (UseArrays) 192 DrawPolygonArray(); 193 else 194 DrawPolygonVert(); 195 196 glPopMatrix(); 197 198 glutSwapBuffers(); 199} 200 201 202static void 203idle(void) 204{ 205 GLfloat t = 0.05 * glutGet(GLUT_ELAPSED_TIME); 206 Yrot = t; 207 glutPostRedisplay(); 208} 209 210 211static void 212key(unsigned char k, int x, int y) 213{ 214 (void) x; 215 (void) y; 216 switch (k) { 217 case 'a': 218 UseArrays = !UseArrays; 219 printf("Arrays: %d\n", UseArrays); 220 break; 221 case 'v': 222 UseVBO = !UseVBO; 223 printf("Use VBO: %d\n", UseVBO); 224 break; 225 case ' ': 226 Anim = !Anim; 227 if (Anim) 228 glutIdleFunc(idle); 229 else 230 glutIdleFunc(NULL); 231 break; 232 case 'z': 233 EyeDist -= 0.5; 234 if (EyeDist < 3.0) 235 EyeDist = 3.0; 236 break; 237 case 'Z': 238 EyeDist += 0.5; 239 if (EyeDist > 90.0) 240 EyeDist = 90; 241 break; 242 case 27: 243 exit(0); 244 } 245 glutPostRedisplay(); 246} 247 248 249static void 250specialkey(int key, int x, int y) 251{ 252 GLfloat step = 2.0; 253 (void) x; 254 (void) y; 255 switch (key) { 256 case GLUT_KEY_UP: 257 Xrot += step; 258 break; 259 case GLUT_KEY_DOWN: 260 Xrot -= step; 261 break; 262 case GLUT_KEY_LEFT: 263 Yrot -= step; 264 break; 265 case GLUT_KEY_RIGHT: 266 Yrot += step; 267 break; 268 } 269 glutPostRedisplay(); 270} 271 272 273/* new window size or exposure */ 274static void 275Reshape(int width, int height) 276{ 277 GLfloat ar = (float) width / (float) height; 278 glViewport(0, 0, (GLint)width, (GLint)height); 279 glMatrixMode(GL_PROJECTION); 280 glLoadIdentity(); 281 glFrustum(-2.0*ar, 2.0*ar, -2.0, 2.0, 4.0, 100.0); 282 glMatrixMode(GL_MODELVIEW); 283 glLoadIdentity(); 284} 285 286 287static void 288InitTextures(void) 289{ 290 GLenum filter = GL_LINEAR; 291 int i; 292 293 for (i = 0; i < 2; i++) { 294 GLint imgWidth, imgHeight; 295 GLenum imgFormat; 296 GLubyte *image = NULL; 297 298 image = LoadRGBImage(TexFiles[i], &imgWidth, &imgHeight, &imgFormat); 299 if (!image) { 300 printf("Couldn't read %s\n", TexFiles[i]); 301 exit(0); 302 } 303 304 glActiveTexture(GL_TEXTURE0 + i); 305 glBindTexture(GL_TEXTURE_2D, 42 + i); 306 gluBuild2DMipmaps(GL_TEXTURE_2D, 4, imgWidth, imgHeight, 307 imgFormat, GL_UNSIGNED_BYTE, image); 308 free(image); 309 310 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 311 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 312 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); 313 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); 314 } 315} 316 317 318static GLuint 319CreateAProgram(const char *vertProgFile, const char *fragProgFile, 320 struct uniform_info *uniforms) 321{ 322 GLuint fragShader, vertShader, program; 323 324 vertShader = CompileShaderFile(GL_VERTEX_SHADER, vertProgFile); 325 fragShader = CompileShaderFile(GL_FRAGMENT_SHADER, fragProgFile); 326 assert(vertShader); 327 program = LinkShaders(vertShader, fragShader); 328 329 glUseProgram(program); 330 331 assert(ValidateShaderProgram(program)); 332 333 VertCoord_attr = glGetAttribLocation(program, "VertCoord"); 334 if (VertCoord_attr > 0) { 335 /* We want the VertCoord attrib to have position zero so that 336 * the call to glVertexAttrib(0, xyz) triggers vertex processing. 337 * Otherwise, if TexCoord0 or TexCoord1 gets position 0 we'd have 338 * to set that attribute last (which is a PITA to manage). 339 */ 340 glBindAttribLocation(program, 0, "VertCoord"); 341 /* re-link */ 342 glLinkProgram(program); 343 /* VertCoord_attr should be zero now */ 344 VertCoord_attr = glGetAttribLocation(program, "VertCoord"); 345 assert(VertCoord_attr == 0); 346 } 347 348 TexCoord0_attr = glGetAttribLocation(program, "TexCoord0"); 349 TexCoord1_attr = glGetAttribLocation(program, "TexCoord1"); 350 351 printf("TexCoord0_attr = %d\n", TexCoord0_attr); 352 printf("TexCoord1_attr = %d\n", TexCoord1_attr); 353 printf("VertCoord_attr = %d\n", VertCoord_attr); 354 355 SetUniformValues(program, uniforms); 356 PrintUniforms(Uniforms); 357 358 return program; 359} 360 361 362static void 363InitPrograms(void) 364{ 365 Program = CreateAProgram(VertFile, FragFile, Uniforms); 366} 367 368 369static void 370InitGL(void) 371{ 372 if (!ShadersSupported()) 373 exit(1); 374 375 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER)); 376 printf("Usage:\n"); 377 printf(" a - toggle arrays vs. immediate mode rendering\n"); 378 printf(" v - toggle VBO usage for array rendering\n"); 379 printf(" z/Z - change viewing distance\n"); 380 printf(" SPACE - toggle animation\n"); 381 printf(" Esc - exit\n"); 382 383 InitTextures(); 384 InitPrograms(); 385 386 SetupVertexBuffer(); 387 388 glEnable(GL_DEPTH_TEST); 389 390 glClearColor(.6, .6, .9, 0); 391 glColor3f(1.0, 1.0, 1.0); 392} 393 394 395int 396main(int argc, char *argv[]) 397{ 398 glutInit(&argc, argv); 399 glutInitWindowSize(500, 400); 400 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 401 glutCreateWindow(Demo); 402 glewInit(); 403 glutReshapeFunc(Reshape); 404 glutKeyboardFunc(key); 405 glutSpecialFunc(specialkey); 406 glutDisplayFunc(draw); 407 if (Anim) 408 glutIdleFunc(idle); 409 InitGL(); 410 glutMainLoop(); 411 return 0; 412} 413