"Fossies" - the Fresh Open Source Software Archive

Member "SDL2-2.0.22/test/testshader.c" (9 Apr 2022, 16719 Bytes) of package /linux/misc/SDL2-2.0.22.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "testshader.c": 2.0.20_vs_2.0.22.

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