test/testshader.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 25 Apr 2013 00:26:17 -0700
changeset 7110 2a98852fd58d
parent 6256 1d905b13b102
child 7191 75360622e65f
permissions -rw-r--r--
Fixed bug 1582 - Allow disabling SDL_VIDEO_DRIVER_WINDOWS

Marcus von Appen

Trying to build SDL 2.x (HG) on Win32 platforms with either VS.NET or MinGW requires one to have the video subsystem and SDL_VIDEO_DRIVER_WINDOWS flag enabled due to the helper window creation routines.

The attached patch changes the helper window creation behaviour, so that one can build SDL2 without the video subsystem or Windows video drivers on Win32 platforms.
     1 /*
     2   Copyright (C) 1997-2011 Sam Lantinga <slouken@libsdl.org>
     3 
     4   This software is provided 'as-is', without any express or implied
     5   warranty.  In no event will the authors be held liable for any damages
     6   arising from the use of this software.
     7 
     8   Permission is granted to anyone to use this software for any purpose,
     9   including commercial applications, and to alter it and redistribute it
    10   freely.
    11 */
    12 /* This is a simple example of using GLSL shaders with SDL */
    13 
    14 #if 1 /* FIXME: Rework this using the 2.0 API */
    15 #include <stdio.h>
    16 
    17 int main(int argc, char *argv[])
    18 {
    19     printf("FIXME\n");
    20     return 0;
    21 }
    22 #else
    23 #include "SDL.h"
    24 
    25 #ifdef HAVE_OPENGL
    26 
    27 #include "SDL_opengl.h"
    28 
    29 
    30 static SDL_bool shaders_supported;
    31 static int      current_shader = 0;
    32 
    33 enum {
    34     SHADER_COLOR,
    35     SHADER_TEXTURE,
    36     SHADER_TEXCOORDS,
    37     NUM_SHADERS
    38 };
    39 
    40 typedef struct {
    41     GLhandleARB program;
    42     GLhandleARB vert_shader;
    43     GLhandleARB frag_shader;
    44     const char *vert_source;
    45     const char *frag_source;
    46 } ShaderData;
    47 
    48 static ShaderData shaders[NUM_SHADERS] = {
    49 
    50     /* SHADER_COLOR */
    51     { 0, 0, 0,
    52         /* vertex shader */
    53 "varying vec4 v_color;\n"
    54 "\n"
    55 "void main()\n"
    56 "{\n"
    57 "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
    58 "    v_color = gl_Color;\n"
    59 "}",
    60         /* fragment shader */
    61 "varying vec4 v_color;\n"
    62 "\n"
    63 "void main()\n"
    64 "{\n"
    65 "    gl_FragColor = v_color;\n"
    66 "}"
    67     },
    68 
    69     /* SHADER_TEXTURE */
    70     { 0, 0, 0,
    71         /* vertex shader */
    72 "varying vec4 v_color;\n"
    73 "varying vec2 v_texCoord;\n"
    74 "\n"
    75 "void main()\n"
    76 "{\n"
    77 "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
    78 "    v_color = gl_Color;\n"
    79 "    v_texCoord = vec2(gl_MultiTexCoord0);\n"
    80 "}",
    81         /* fragment shader */
    82 "varying vec4 v_color;\n"
    83 "varying vec2 v_texCoord;\n"
    84 "uniform sampler2D tex0;\n"
    85 "\n"
    86 "void main()\n"
    87 "{\n"
    88 "    gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n"
    89 "}"
    90     },
    91 
    92     /* SHADER_TEXCOORDS */
    93     { 0, 0, 0,
    94         /* vertex shader */
    95 "varying vec2 v_texCoord;\n"
    96 "\n"
    97 "void main()\n"
    98 "{\n"
    99 "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
   100 "    v_texCoord = vec2(gl_MultiTexCoord0);\n"
   101 "}",
   102         /* fragment shader */
   103 "varying vec2 v_texCoord;\n"
   104 "\n"
   105 "void main()\n"
   106 "{\n"
   107 "    vec4 color;\n"
   108 "    vec2 delta;\n"
   109 "    float dist;\n"
   110 "\n"
   111 "    delta = vec2(0.5, 0.5) - v_texCoord;\n"
   112 "    dist = dot(delta, delta);\n"
   113 "\n"
   114 "    color.r = v_texCoord.x;\n"
   115 "    color.g = v_texCoord.x * v_texCoord.y;\n"
   116 "    color.b = v_texCoord.y;\n"
   117 "    color.a = 1.0 - (dist * 4.0);\n"
   118 "    gl_FragColor = color;\n"
   119 "}"
   120     },
   121 };
   122     
   123 static PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
   124 static PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
   125 static PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
   126 static PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
   127 static PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
   128 static PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
   129 static PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
   130 static PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;
   131 static PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
   132 static PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
   133 static PFNGLUNIFORM1IARBPROC glUniform1iARB;
   134 static PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
   135 
   136 static SDL_bool CompileShader(GLhandleARB shader, const char *source)
   137 {
   138     GLint status;
   139 
   140     glShaderSourceARB(shader, 1, &source, NULL);
   141     glCompileShaderARB(shader);
   142     glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
   143     if (status == 0) {
   144         GLint length;
   145         char *info;
   146 
   147         glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
   148         info = SDL_stack_alloc(char, length+1);
   149         glGetInfoLogARB(shader, length, NULL, info);
   150         fprintf(stderr, "Failed to compile shader:\n%s\n%s", source, info);
   151         SDL_stack_free(info);
   152 
   153         return SDL_FALSE;
   154     } else {
   155         return SDL_TRUE;
   156     }
   157 }
   158 
   159 static SDL_bool CompileShaderProgram(ShaderData *data)
   160 {
   161     const int num_tmus_bound = 4;
   162     int i;
   163     GLint location;
   164 
   165     glGetError();
   166 
   167     /* Create one program object to rule them all */
   168     data->program = glCreateProgramObjectARB();
   169 
   170     /* Create the vertex shader */
   171     data->vert_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
   172     if (!CompileShader(data->vert_shader, data->vert_source)) {
   173         return SDL_FALSE;
   174     }
   175 
   176     /* Create the fragment shader */
   177     data->frag_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
   178     if (!CompileShader(data->frag_shader, data->frag_source)) {
   179         return SDL_FALSE;
   180     }
   181 
   182     /* ... and in the darkness bind them */
   183     glAttachObjectARB(data->program, data->vert_shader);
   184     glAttachObjectARB(data->program, data->frag_shader);
   185     glLinkProgramARB(data->program);
   186 
   187     /* Set up some uniform variables */
   188     glUseProgramObjectARB(data->program);
   189     for (i = 0; i < num_tmus_bound; ++i) {
   190         char tex_name[5];
   191         SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i);
   192         location = glGetUniformLocationARB(data->program, tex_name);
   193         if (location >= 0) {
   194             glUniform1iARB(location, i);
   195         }
   196     }
   197     glUseProgramObjectARB(0);
   198  
   199     return (glGetError() == GL_NO_ERROR);
   200 }
   201 
   202 static void DestroyShaderProgram(ShaderData *data)
   203 {
   204     if (shaders_supported) {
   205         glDeleteObjectARB(data->vert_shader);
   206         glDeleteObjectARB(data->frag_shader);
   207         glDeleteObjectARB(data->program);
   208     }
   209 }
   210 
   211 static SDL_bool InitShaders()
   212 {
   213     int i;
   214 
   215     /* Check for shader support */
   216     shaders_supported = SDL_FALSE;
   217     if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") &&
   218         SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") &&
   219         SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") &&
   220         SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) {
   221         glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");
   222         glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");
   223         glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");
   224         glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");
   225         glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");
   226         glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");
   227         glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");
   228         glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");
   229         glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");
   230         glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");
   231         glUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");
   232         glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB");
   233         if (glAttachObjectARB &&
   234             glCompileShaderARB &&
   235             glCreateProgramObjectARB &&
   236             glCreateShaderObjectARB &&
   237             glDeleteObjectARB &&
   238             glGetInfoLogARB &&
   239             glGetObjectParameterivARB &&
   240             glGetUniformLocationARB &&
   241             glLinkProgramARB &&
   242             glShaderSourceARB &&
   243             glUniform1iARB &&
   244             glUseProgramObjectARB) {
   245             shaders_supported = SDL_TRUE;
   246         }
   247     }
   248 
   249     if (!shaders_supported) {
   250         return SDL_FALSE;
   251     }
   252 
   253     /* Compile all the shaders */
   254     for (i = 0; i < NUM_SHADERS; ++i) {
   255         if (!CompileShaderProgram(&shaders[i])) {
   256             fprintf(stderr, "Unable to compile shader!\n");
   257             return SDL_FALSE;
   258         }
   259     }
   260 
   261     /* We're done! */
   262     return SDL_TRUE;
   263 }
   264 
   265 static void QuitShaders()
   266 {
   267     int i;
   268 
   269     for (i = 0; i < NUM_SHADERS; ++i) {
   270         DestroyShaderProgram(&shaders[i]);
   271     }
   272 }
   273 
   274 /* Quick utility function for texture creation */
   275 static int
   276 power_of_two(int input)
   277 {
   278     int value = 1;
   279 
   280     while (value < input) {
   281         value <<= 1;
   282     }
   283     return value;
   284 }
   285 
   286 GLuint
   287 SDL_GL_LoadTexture(SDL_Surface * surface, GLfloat * texcoord)
   288 {
   289     GLuint texture;
   290     int w, h;
   291     SDL_Surface *image;
   292     SDL_Rect area;
   293     Uint32 saved_flags;
   294     Uint8 saved_alpha;
   295 
   296     /* Use the surface width and height expanded to powers of 2 */
   297     w = power_of_two(surface->w);
   298     h = power_of_two(surface->h);
   299     texcoord[0] = 0.0f;         /* Min X */
   300     texcoord[1] = 0.0f;         /* Min Y */
   301     texcoord[2] = (GLfloat) surface->w / w;     /* Max X */
   302     texcoord[3] = (GLfloat) surface->h / h;     /* Max Y */
   303 
   304     image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
   305 #if SDL_BYTEORDER == SDL_LIL_ENDIAN     /* OpenGL RGBA masks */
   306                                  0x000000FF,
   307                                  0x0000FF00, 0x00FF0000, 0xFF000000
   308 #else
   309                                  0xFF000000,
   310                                  0x00FF0000, 0x0000FF00, 0x000000FF
   311 #endif
   312         );
   313     if (image == NULL) {
   314         return 0;
   315     }
   316 
   317     /* Save the alpha blending attributes */
   318     saved_flags = surface->flags & (SDL_SRCALPHA | SDL_RLEACCELOK);
   319     SDL_GetSurfaceAlphaMod(surface, &saved_alpha);
   320     if ((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
   321         SDL_SetAlpha(surface, 0, 0);
   322     }
   323 
   324     /* Copy the surface into the GL texture image */
   325     area.x = 0;
   326     area.y = 0;
   327     area.w = surface->w;
   328     area.h = surface->h;
   329     SDL_BlitSurface(surface, &area, image, &area);
   330 
   331     /* Restore the alpha blending attributes */
   332     if ((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
   333         SDL_SetAlpha(surface, saved_flags, saved_alpha);
   334     }
   335 
   336     /* Create an OpenGL texture for the image */
   337     glGenTextures(1, &texture);
   338     glBindTexture(GL_TEXTURE_2D, texture);
   339     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   340     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   341     glTexImage2D(GL_TEXTURE_2D,
   342                  0,
   343                  GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
   344     SDL_FreeSurface(image);     /* No longer needed */
   345 
   346     return texture;
   347 }
   348 
   349 /* A general OpenGL initialization function.    Sets all of the initial parameters. */
   350 void InitGL(int Width, int Height)                    // We call this right after our OpenGL window is created.
   351 {
   352     GLdouble aspect;
   353 
   354     glViewport(0, 0, Width, Height);
   355     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);        // This Will Clear The Background Color To Black
   356     glClearDepth(1.0);                // Enables Clearing Of The Depth Buffer
   357     glDepthFunc(GL_LESS);                // The Type Of Depth Test To Do
   358     glEnable(GL_DEPTH_TEST);            // Enables Depth Testing
   359     glShadeModel(GL_SMOOTH);            // Enables Smooth Color Shading
   360 
   361     glMatrixMode(GL_PROJECTION);
   362     glLoadIdentity();                // Reset The Projection Matrix
   363 
   364     aspect = (GLdouble)Width / Height;
   365     glOrtho(-3.0, 3.0, -3.0 / aspect, 3.0 / aspect, 0.0, 1.0);
   366 
   367     glMatrixMode(GL_MODELVIEW);
   368 }
   369 
   370 /* The main drawing function. */
   371 void DrawGLScene(GLuint texture, GLfloat * texcoord)
   372 {
   373     /* Texture coordinate lookup, to make it simple */
   374     enum {
   375         MINX,
   376         MINY,
   377         MAXX,
   378         MAXY
   379     };
   380 
   381     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);        // Clear The Screen And The Depth Buffer
   382     glLoadIdentity();                // Reset The View
   383 
   384     glTranslatef(-1.5f,0.0f,0.0f);        // Move Left 1.5 Units
   385     
   386     // draw a triangle (in smooth coloring mode)
   387     glBegin(GL_POLYGON);                // start drawing a polygon
   388     glColor3f(1.0f,0.0f,0.0f);            // Set The Color To Red
   389     glVertex3f( 0.0f, 1.0f, 0.0f);        // Top
   390     glColor3f(0.0f,1.0f,0.0f);            // Set The Color To Green
   391     glVertex3f( 1.0f,-1.0f, 0.0f);        // Bottom Right
   392     glColor3f(0.0f,0.0f,1.0f);            // Set The Color To Blue
   393     glVertex3f(-1.0f,-1.0f, 0.0f);        // Bottom Left    
   394     glEnd();                    // we're done with the polygon (smooth color interpolation)    
   395 
   396     glTranslatef(3.0f,0.0f,0.0f);         // Move Right 3 Units
   397 
   398     // Enable blending
   399     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
   400     glEnable(GL_BLEND);
   401     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   402 
   403     // draw a textured square (quadrilateral)
   404     glEnable(GL_TEXTURE_2D);
   405     glBindTexture(GL_TEXTURE_2D, texture);
   406     glColor3f(1.0f,1.0f,1.0f);
   407     if (shaders_supported) {
   408         glUseProgramObjectARB(shaders[current_shader].program);
   409     }
   410 
   411     glBegin(GL_QUADS);                // start drawing a polygon (4 sided)
   412     glTexCoord2f(texcoord[MINX], texcoord[MINY]);
   413     glVertex3f(-1.0f, 1.0f, 0.0f);        // Top Left
   414     glTexCoord2f(texcoord[MAXX], texcoord[MINY]);
   415     glVertex3f( 1.0f, 1.0f, 0.0f);        // Top Right
   416     glTexCoord2f(texcoord[MAXX], texcoord[MAXY]);
   417     glVertex3f( 1.0f,-1.0f, 0.0f);        // Bottom Right
   418     glTexCoord2f(texcoord[MINX], texcoord[MAXY]);
   419     glVertex3f(-1.0f,-1.0f, 0.0f);        // Bottom Left    
   420     glEnd();                    // done with the polygon
   421 
   422     if (shaders_supported) {
   423         glUseProgramObjectARB(0);
   424     }
   425     glDisable(GL_TEXTURE_2D);
   426 
   427     // swap buffers to display, since we're double buffered.
   428     SDL_GL_SwapBuffers();
   429 }
   430 
   431 int main(int argc, char **argv) 
   432 {    
   433     int done;
   434     SDL_Surface *surface;
   435     GLuint texture;
   436     GLfloat texcoords[4];
   437 
   438     /* Initialize SDL for video output */
   439     if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
   440         fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
   441         exit(1);
   442     }
   443 
   444     /* Create a 640x480 OpenGL screen */
   445     if ( SDL_SetVideoMode(640, 480, 0, SDL_OPENGL) == NULL ) {
   446         fprintf(stderr, "Unable to create OpenGL screen: %s\n", SDL_GetError());
   447         SDL_Quit();
   448         exit(2);
   449     }
   450 
   451     /* Set the title bar in environments that support it */
   452     SDL_WM_SetCaption("Shader Demo", NULL);
   453 
   454     surface = SDL_LoadBMP("icon.bmp");
   455     if ( ! surface ) {
   456         fprintf(stderr, "Unable to load icon.bmp: %s\n", SDL_GetError());
   457         SDL_Quit();
   458         exit(3);
   459     }
   460     texture = SDL_GL_LoadTexture(surface, texcoords);
   461     SDL_FreeSurface(surface);
   462 
   463     /* Loop, drawing and checking events */
   464     InitGL(640, 480);
   465     if (InitShaders()) {
   466         printf("Shaders supported, press SPACE to cycle them.\n");
   467     } else {
   468         printf("Shaders not supported!\n");
   469     }
   470     done = 0;
   471     while ( ! done ) {
   472         DrawGLScene(texture, texcoords);
   473 
   474         /* This could go in a separate function */
   475         { SDL_Event event;
   476             while ( SDL_PollEvent(&event) ) {
   477                 if ( event.type == SDL_QUIT ) {
   478                     done = 1;
   479                 }
   480                 if ( event.type == SDL_KEYDOWN ) {
   481                     if ( event.key.keysym.sym == SDLK_SPACE ) {
   482                         current_shader = (current_shader + 1) % NUM_SHADERS;
   483                     }
   484                     if ( event.key.keysym.sym == SDLK_ESCAPE ) {
   485                         done = 1;
   486                     }
   487                 }
   488             }
   489         }
   490     }
   491     QuitShaders();
   492     SDL_Quit();
   493     return 1;
   494 }
   495 
   496 #else /* HAVE_OPENGL */
   497 
   498 int
   499 main(int argc, char *argv[])
   500 {
   501     printf("No OpenGL support on this system\n");
   502     return 1;
   503 }
   504 
   505 #endif /* HAVE_OPENGL */
   506 #endif
   507 
   508 /* vi: set ts=4 sw=4 expandtab: */