"Fossies" - the Fresh Open Source Software Archive

Member "SDL2-2.28.5/test/testshader.c" (2 Nov 2023, 16939 Bytes) of package /linux/misc/SDL2-2.28.5.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 last Fossies "Diffs" side-by-side code changes report for "testshader.c": 2.26.5_vs_2.27.1.

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