samplers.c revision 32001f49
1/** 2 * Exercise all available GLSL texture samplers. 3 * 4 * Copyright (C) 2009 VMware, Inc. 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 * We generate a fragment shader which uses the maximum number of supported 26 * texture samplers. 27 * For each sampler we create a separate texture. Each texture has a 28 * single strip of color at a different intensity. The fragment shader 29 * samples all the textures at the same coordinate and sums the values. 30 * The result should be a quad with rows of colors of increasing intensity 31 * from bottom to top. 32 * 33 * Brian Paul 34 * 1 Jan 2009 35 */ 36 37#include <assert.h> 38#include <math.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42#include <GL/glew.h> 43#include "glut_wrap.h" 44#include "shaderutil.h" 45 46 47#define MAX_SAMPLERS 128 48 49 50static const char *Demo = "samplers"; 51 52static GLuint Program; 53static GLint NumSamplers; 54static GLuint Textures[MAX_SAMPLERS]; 55static GLfloat Xrot = 0.0, Yrot = .0, Zrot = 0.0; 56static GLfloat EyeDist = 10; 57static GLboolean Anim = GL_FALSE; 58 59 60static void 61DrawPolygon(GLfloat size) 62{ 63 glPushMatrix(); 64 glNormal3f(0, 0, 1); 65 glBegin(GL_POLYGON); 66 67 glMultiTexCoord2f(GL_TEXTURE0, 0, 0); 68 glVertex2f(-size, -size); 69 70 glMultiTexCoord2f(GL_TEXTURE0, 1, 0); 71 glVertex2f( size, -size); 72 73 glMultiTexCoord2f(GL_TEXTURE0, 1, 1); 74 glVertex2f( size, size); 75 76 glMultiTexCoord2f(GL_TEXTURE0, 0, 1); 77 glVertex2f(-size, size); 78 79 glEnd(); 80 glPopMatrix(); 81} 82 83 84static void 85draw(void) 86{ 87 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 88 89 glPushMatrix(); 90 glTranslatef(0.0, 0.0, -EyeDist); 91 glRotatef(Zrot, 0, 0, 1); 92 glRotatef(Yrot, 0, 1, 0); 93 glRotatef(Xrot, 1, 0, 0); 94 95 DrawPolygon(3.0); 96 97 glPopMatrix(); 98 99 glutSwapBuffers(); 100} 101 102 103static void 104idle(void) 105{ 106 GLfloat t = 0.05 * glutGet(GLUT_ELAPSED_TIME); 107 Yrot = t; 108 glutPostRedisplay(); 109} 110 111 112static void 113key(unsigned char k, int x, int y) 114{ 115 (void) x; 116 (void) y; 117 switch (k) { 118 case ' ': 119 case 'a': 120 Anim = !Anim; 121 if (Anim) 122 glutIdleFunc(idle); 123 else 124 glutIdleFunc(NULL); 125 break; 126 case 'z': 127 EyeDist -= 0.5; 128 if (EyeDist < 3.0) 129 EyeDist = 3.0; 130 break; 131 case 'Z': 132 EyeDist += 0.5; 133 if (EyeDist > 90.0) 134 EyeDist = 90; 135 break; 136 case 27: 137 exit(0); 138 } 139 glutPostRedisplay(); 140} 141 142 143static void 144specialkey(int key, int x, int y) 145{ 146 GLfloat step = 2.0; 147 (void) x; 148 (void) y; 149 switch (key) { 150 case GLUT_KEY_UP: 151 Xrot += step; 152 break; 153 case GLUT_KEY_DOWN: 154 Xrot -= step; 155 break; 156 case GLUT_KEY_LEFT: 157 Yrot -= step; 158 break; 159 case GLUT_KEY_RIGHT: 160 Yrot += step; 161 break; 162 } 163 glutPostRedisplay(); 164} 165 166 167/* new window size or exposure */ 168static void 169Reshape(int width, int height) 170{ 171 GLfloat ar = (float) width / (float) height; 172 glViewport(0, 0, (GLint)width, (GLint)height); 173 glMatrixMode(GL_PROJECTION); 174 glLoadIdentity(); 175 glFrustum(-2.0*ar, 2.0*ar, -2.0, 2.0, 4.0, 100.0); 176 glMatrixMode(GL_MODELVIEW); 177 glLoadIdentity(); 178} 179 180 181static void 182InitTextures(void) 183{ 184 const GLint size = MAX_SAMPLERS; 185 GLubyte *texImage; 186 GLenum filter = GL_NEAREST; 187 GLint stripeSize; 188 GLint s; 189 190 texImage = (GLubyte *) malloc(size * size * 4); 191 192 glGenTextures(NumSamplers, Textures); 193 194 /* size of texels stripe */ 195 stripeSize = size / NumSamplers; 196 197 /* create a texture for each sampler */ 198 for (s = 0; s < NumSamplers; s++) { 199 GLint x, y, ypos; 200 GLubyte intensity = 31 + s * (256-32) / (NumSamplers - 1); 201 202 printf("Texture %d: color = %d, %d, %d\n", s, 203 (int) intensity, 0, (int) intensity ); 204 205 /* initialize the texture to black */ 206 memset(texImage, 0, size * size * 4); 207 208 /* set a stripe of texels to the intensity value */ 209 ypos = s * stripeSize; 210 for (y = 0; y < stripeSize; y++) { 211 for (x = 0; x < size; x++) { 212 GLint k = 4 * ((ypos + y) * size + x); 213 if (x < size / 2) { 214 texImage[k + 0] = intensity; 215 texImage[k + 1] = intensity; 216 texImage[k + 2] = 0; 217 texImage[k + 3] = 255; 218 } 219 else { 220 texImage[k + 0] = 255 - intensity; 221 texImage[k + 1] = 0; 222 texImage[k + 2] = 0; 223 texImage[k + 3] = 255; 224 } 225 } 226 } 227 228 glActiveTexture(GL_TEXTURE0 + s); 229 glBindTexture(GL_TEXTURE_2D, Textures[s]); 230 gluBuild2DMipmaps(GL_TEXTURE_2D, 4, size, size, 231 GL_RGBA, GL_UNSIGNED_BYTE, texImage); 232 233 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 234 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 235 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); 236 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); 237 } 238 239 free(texImage); 240} 241 242 243/** 244 * Generate a fragment shader that uses the given number of samplers. 245 */ 246static char * 247GenFragmentShader(GLint numSamplers) 248{ 249 const int maxLen = 10 * 1000; 250 char *prog = (char *) malloc(maxLen); 251 char *p = prog; 252 int s; 253 254 p += sprintf(p, "// Generated fragment shader:\n"); 255#ifndef SAMPLERS_ARRAY 256 for (s = 0; s < numSamplers; s++) { 257 p += sprintf(p, "uniform sampler2D tex%d;\n", s); 258 } 259#else 260 p += sprintf(p, "uniform sampler2D tex[%d];\n", numSamplers); 261#endif 262 p += sprintf(p, "void main()\n"); 263 p += sprintf(p, "{\n"); 264 p += sprintf(p, " vec4 color = vec4(0.0);\n"); 265 for (s = 0; s < numSamplers; s++) { 266#ifndef SAMPLERS_ARRAY 267 p += sprintf(p, " color += texture2D(tex%d, gl_TexCoord[0].xy);\n", s); 268#else 269 p += sprintf(p, " color += texture2D(tex[%d], gl_TexCoord[0].xy);\n", s); 270#endif 271 } 272 p += sprintf(p, " gl_FragColor = color;\n"); 273 p += sprintf(p, "}\n"); 274 275 assert(p - prog < maxLen); 276 return prog; 277} 278 279 280/** Create & bind shader program */ 281static GLuint 282CreateAProgram(void) 283{ 284 GLuint fragShader, vertShader, program; 285 const char *vertShaderText = 286 "void main() \n" 287 "{ \n" 288 " gl_TexCoord[0] = gl_MultiTexCoord0; \n" 289 " gl_Position = ftransform(); \n" 290 "} \n"; 291 char *fragShaderText = GenFragmentShader(NumSamplers); 292 293 printf("%s", fragShaderText); 294 295 vertShader = CompileShaderText(GL_VERTEX_SHADER, vertShaderText); 296 fragShader = CompileShaderText(GL_FRAGMENT_SHADER, fragShaderText); 297 assert(vertShader); 298 program = LinkShaders(vertShader, fragShader); 299 300 glUseProgram(program); 301 302 free(fragShaderText); 303 304 return program; 305} 306 307 308static void 309InitProgram(void) 310{ 311 GLint s; 312 313 Program = CreateAProgram(); 314 315 /* init sampler uniforms */ 316 for (s = 0; s < NumSamplers; s++) { 317 char uname[10]; 318 GLint loc; 319 320#ifndef SAMPLERS_ARRAY 321 sprintf(uname, "tex%d", s); 322#else 323 sprintf(uname, "tex[%d]", s); 324#endif 325 loc = glGetUniformLocation(Program, uname); 326 assert(loc >= 0); 327 328 glUniform1i(loc, s); 329 } 330} 331 332 333static void 334InitGL(void) 335{ 336 if (!ShadersSupported()) { 337 printf("GLSL not supported!\n"); 338 exit(1); 339 } 340 341 printf("GL_RENDERER = %s\n", (const char *) glGetString(GL_RENDERER)); 342 343 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &NumSamplers); 344 if (NumSamplers > MAX_SAMPLERS) 345 NumSamplers = MAX_SAMPLERS; 346 printf("Testing %d samplers\n", NumSamplers); 347 348 InitTextures(); 349 InitProgram(); 350 351 glClearColor(.6, .6, .9, 0); 352 glColor3f(1.0, 1.0, 1.0); 353 354 printf("Each color corresponds to a separate sampler/texture.\n"); 355} 356 357 358int 359main(int argc, char *argv[]) 360{ 361 glutInit(&argc, argv); 362 glutInitWindowSize(500, 400); 363 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 364 glutCreateWindow(Demo); 365 glewInit(); 366 glutReshapeFunc(Reshape); 367 glutKeyboardFunc(key); 368 glutSpecialFunc(specialkey); 369 glutDisplayFunc(draw); 370 if (Anim) 371 glutIdleFunc(idle); 372 InitGL(); 373 glutMainLoop(); 374 return 0; 375} 376