Home | History | Annotate | Line # | Download | only in glsl
      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 
     50 static const char *Demo = "samplers";
     51 
     52 static GLuint Program;
     53 static GLint NumSamplers;
     54 static GLuint Textures[MAX_SAMPLERS];
     55 static GLfloat Xrot = 0.0, Yrot = .0, Zrot = 0.0;
     56 static GLfloat EyeDist = 10;
     57 static GLboolean Anim = GL_FALSE;
     58 
     59 
     60 static void
     61 DrawPolygon(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 
     84 static void
     85 draw(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 
    103 static void
    104 idle(void)
    105 {
    106    GLfloat t = 0.05 * glutGet(GLUT_ELAPSED_TIME);
    107    Yrot = t;
    108    glutPostRedisplay();
    109 }
    110 
    111 
    112 static void
    113 key(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 
    143 static void
    144 specialkey(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 */
    168 static void
    169 Reshape(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 
    181 static void
    182 InitTextures(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  */
    246 static char *
    247 GenFragmentShader(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 */
    281 static GLuint
    282 CreateAProgram(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 
    308 static void
    309 InitProgram(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 
    333 static void
    334 InitGL(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 
    358 int
    359 main(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