diff options
author | 2016-02-27 16:28:05 +0100 | |
---|---|---|
committer | 2016-02-27 16:53:49 +0100 | |
commit | cf6dc7d370407914020f3e623719f09c8668c692 (patch) | |
tree | 46b3416d091b4c09b50fba7ffcbd310aed032cc8 /3rdparty/SDL2/test/testshader.c | |
parent | 64135e73f973d9b95beb0c60b65feb34fbfec64a (diff) |
Placed SDL2 source since we need it on some platforms (nw)
Diffstat (limited to '3rdparty/SDL2/test/testshader.c')
-rw-r--r-- | 3rdparty/SDL2/test/testshader.c | 500 |
1 files changed, 500 insertions, 0 deletions
diff --git a/3rdparty/SDL2/test/testshader.c b/3rdparty/SDL2/test/testshader.c new file mode 100644 index 00000000000..fc6da29875b --- /dev/null +++ b/3rdparty/SDL2/test/testshader.c @@ -0,0 +1,500 @@ +/* + Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org> + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely. +*/ +/* This is a simple example of using GLSL shaders with SDL */ + +#include "SDL.h" + +#ifdef HAVE_OPENGL + +#include "SDL_opengl.h" + + +static SDL_bool shaders_supported; +static int current_shader = 0; + +enum { + SHADER_COLOR, + SHADER_TEXTURE, + SHADER_TEXCOORDS, + NUM_SHADERS +}; + +typedef struct { + GLhandleARB program; + GLhandleARB vert_shader; + GLhandleARB frag_shader; + const char *vert_source; + const char *frag_source; +} ShaderData; + +static ShaderData shaders[NUM_SHADERS] = { + + /* SHADER_COLOR */ + { 0, 0, 0, + /* vertex shader */ +"varying vec4 v_color;\n" +"\n" +"void main()\n" +"{\n" +" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" +" v_color = gl_Color;\n" +"}", + /* fragment shader */ +"varying vec4 v_color;\n" +"\n" +"void main()\n" +"{\n" +" gl_FragColor = v_color;\n" +"}" + }, + + /* SHADER_TEXTURE */ + { 0, 0, 0, + /* vertex shader */ +"varying vec4 v_color;\n" +"varying vec2 v_texCoord;\n" +"\n" +"void main()\n" +"{\n" +" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" +" v_color = gl_Color;\n" +" v_texCoord = vec2(gl_MultiTexCoord0);\n" +"}", + /* fragment shader */ +"varying vec4 v_color;\n" +"varying vec2 v_texCoord;\n" +"uniform sampler2D tex0;\n" +"\n" +"void main()\n" +"{\n" +" gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n" +"}" + }, + + /* SHADER_TEXCOORDS */ + { 0, 0, 0, + /* vertex shader */ +"varying vec2 v_texCoord;\n" +"\n" +"void main()\n" +"{\n" +" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n" +" v_texCoord = vec2(gl_MultiTexCoord0);\n" +"}", + /* fragment shader */ +"varying vec2 v_texCoord;\n" +"\n" +"void main()\n" +"{\n" +" vec4 color;\n" +" vec2 delta;\n" +" float dist;\n" +"\n" +" delta = vec2(0.5, 0.5) - v_texCoord;\n" +" dist = dot(delta, delta);\n" +"\n" +" color.r = v_texCoord.x;\n" +" color.g = v_texCoord.x * v_texCoord.y;\n" +" color.b = v_texCoord.y;\n" +" color.a = 1.0 - (dist * 4.0);\n" +" gl_FragColor = color;\n" +"}" + }, +}; + +static PFNGLATTACHOBJECTARBPROC glAttachObjectARB; +static PFNGLCOMPILESHADERARBPROC glCompileShaderARB; +static PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB; +static PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB; +static PFNGLDELETEOBJECTARBPROC glDeleteObjectARB; +static PFNGLGETINFOLOGARBPROC glGetInfoLogARB; +static PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; +static PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB; +static PFNGLLINKPROGRAMARBPROC glLinkProgramARB; +static PFNGLSHADERSOURCEARBPROC glShaderSourceARB; +static PFNGLUNIFORM1IARBPROC glUniform1iARB; +static PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB; + +static SDL_bool CompileShader(GLhandleARB shader, const char *source) +{ + GLint status; + + glShaderSourceARB(shader, 1, &source, NULL); + glCompileShaderARB(shader); + glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status); + if (status == 0) { + GLint length; + char *info; + + glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); + info = SDL_stack_alloc(char, length+1); + glGetInfoLogARB(shader, length, NULL, info); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to compile shader:\n%s\n%s", source, info); + SDL_stack_free(info); + + return SDL_FALSE; + } else { + return SDL_TRUE; + } +} + +static SDL_bool CompileShaderProgram(ShaderData *data) +{ + const int num_tmus_bound = 4; + int i; + GLint location; + + glGetError(); + + /* Create one program object to rule them all */ + data->program = glCreateProgramObjectARB(); + + /* Create the vertex shader */ + data->vert_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); + if (!CompileShader(data->vert_shader, data->vert_source)) { + return SDL_FALSE; + } + + /* Create the fragment shader */ + data->frag_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); + if (!CompileShader(data->frag_shader, data->frag_source)) { + return SDL_FALSE; + } + + /* ... and in the darkness bind them */ + glAttachObjectARB(data->program, data->vert_shader); + glAttachObjectARB(data->program, data->frag_shader); + glLinkProgramARB(data->program); + + /* Set up some uniform variables */ + glUseProgramObjectARB(data->program); + for (i = 0; i < num_tmus_bound; ++i) { + char tex_name[5]; + SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i); + location = glGetUniformLocationARB(data->program, tex_name); + if (location >= 0) { + glUniform1iARB(location, i); + } + } + glUseProgramObjectARB(0); + + return (glGetError() == GL_NO_ERROR) ? SDL_TRUE : SDL_FALSE; +} + +static void DestroyShaderProgram(ShaderData *data) +{ + if (shaders_supported) { + glDeleteObjectARB(data->vert_shader); + glDeleteObjectARB(data->frag_shader); + glDeleteObjectARB(data->program); + } +} + +static SDL_bool InitShaders() +{ + int i; + + /* Check for shader support */ + shaders_supported = SDL_FALSE; + if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") && + SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") && + SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") && + SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) { + glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB"); + glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB"); + glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB"); + glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB"); + glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB"); + glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB"); + glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB"); + glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB"); + glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB"); + glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB"); + glUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB"); + glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB"); + if (glAttachObjectARB && + glCompileShaderARB && + glCreateProgramObjectARB && + glCreateShaderObjectARB && + glDeleteObjectARB && + glGetInfoLogARB && + glGetObjectParameterivARB && + glGetUniformLocationARB && + glLinkProgramARB && + glShaderSourceARB && + glUniform1iARB && + glUseProgramObjectARB) { + shaders_supported = SDL_TRUE; + } + } + + if (!shaders_supported) { + return SDL_FALSE; + } + + /* Compile all the shaders */ + for (i = 0; i < NUM_SHADERS; ++i) { + if (!CompileShaderProgram(&shaders[i])) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to compile shader!\n"); + return SDL_FALSE; + } + } + + /* We're done! */ + return SDL_TRUE; +} + +static void QuitShaders() +{ + int i; + + for (i = 0; i < NUM_SHADERS; ++i) { + DestroyShaderProgram(&shaders[i]); + } +} + +/* Quick utility function for texture creation */ +static int +power_of_two(int input) +{ + int value = 1; + + while (value < input) { + value <<= 1; + } + return value; +} + +GLuint +SDL_GL_LoadTexture(SDL_Surface * surface, GLfloat * texcoord) +{ + GLuint texture; + int w, h; + SDL_Surface *image; + SDL_Rect area; + SDL_BlendMode saved_mode; + + /* Use the surface width and height expanded to powers of 2 */ + w = power_of_two(surface->w); + h = power_of_two(surface->h); + texcoord[0] = 0.0f; /* Min X */ + texcoord[1] = 0.0f; /* Min Y */ + texcoord[2] = (GLfloat) surface->w / w; /* Max X */ + texcoord[3] = (GLfloat) surface->h / h; /* Max Y */ + + image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, +#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */ + 0x000000FF, + 0x0000FF00, 0x00FF0000, 0xFF000000 +#else + 0xFF000000, + 0x00FF0000, 0x0000FF00, 0x000000FF +#endif + ); + if (image == NULL) { + return 0; + } + + /* Save the alpha blending attributes */ + SDL_GetSurfaceBlendMode(surface, &saved_mode); + SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE); + + /* Copy the surface into the GL texture image */ + area.x = 0; + area.y = 0; + area.w = surface->w; + area.h = surface->h; + SDL_BlitSurface(surface, &area, image, &area); + + /* Restore the alpha blending attributes */ + SDL_SetSurfaceBlendMode(surface, saved_mode); + + /* Create an OpenGL texture for the image */ + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); + SDL_FreeSurface(image); /* No longer needed */ + + return texture; +} + +/* A general OpenGL initialization function. Sets all of the initial parameters. */ +void InitGL(int Width, int Height) /* We call this right after our OpenGL window is created. */ +{ + GLdouble aspect; + + glViewport(0, 0, Width, Height); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); /* This Will Clear The Background Color To Black */ + glClearDepth(1.0); /* Enables Clearing Of The Depth Buffer */ + glDepthFunc(GL_LESS); /* The Type Of Depth Test To Do */ + glEnable(GL_DEPTH_TEST); /* Enables Depth Testing */ + glShadeModel(GL_SMOOTH); /* Enables Smooth Color Shading */ + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); /* Reset The Projection Matrix */ + + aspect = (GLdouble)Width / Height; + glOrtho(-3.0, 3.0, -3.0 / aspect, 3.0 / aspect, 0.0, 1.0); + + glMatrixMode(GL_MODELVIEW); +} + +/* The main drawing function. */ +void DrawGLScene(SDL_Window *window, GLuint texture, GLfloat * texcoord) +{ + /* Texture coordinate lookup, to make it simple */ + enum { + MINX, + MINY, + MAXX, + MAXY + }; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* Clear The Screen And The Depth Buffer */ + glLoadIdentity(); /* Reset The View */ + + glTranslatef(-1.5f,0.0f,0.0f); /* Move Left 1.5 Units */ + + /* draw a triangle (in smooth coloring mode) */ + glBegin(GL_POLYGON); /* start drawing a polygon */ + glColor3f(1.0f,0.0f,0.0f); /* Set The Color To Red */ + glVertex3f( 0.0f, 1.0f, 0.0f); /* Top */ + glColor3f(0.0f,1.0f,0.0f); /* Set The Color To Green */ + glVertex3f( 1.0f,-1.0f, 0.0f); /* Bottom Right */ + glColor3f(0.0f,0.0f,1.0f); /* Set The Color To Blue */ + glVertex3f(-1.0f,-1.0f, 0.0f); /* Bottom Left */ + glEnd(); /* we're done with the polygon (smooth color interpolation) */ + + glTranslatef(3.0f,0.0f,0.0f); /* Move Right 3 Units */ + + /* Enable blending */ + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + /* draw a textured square (quadrilateral) */ + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texture); + glColor3f(1.0f,1.0f,1.0f); + if (shaders_supported) { + glUseProgramObjectARB(shaders[current_shader].program); + } + + glBegin(GL_QUADS); /* start drawing a polygon (4 sided) */ + glTexCoord2f(texcoord[MINX], texcoord[MINY]); + glVertex3f(-1.0f, 1.0f, 0.0f); /* Top Left */ + glTexCoord2f(texcoord[MAXX], texcoord[MINY]); + glVertex3f( 1.0f, 1.0f, 0.0f); /* Top Right */ + glTexCoord2f(texcoord[MAXX], texcoord[MAXY]); + glVertex3f( 1.0f,-1.0f, 0.0f); /* Bottom Right */ + glTexCoord2f(texcoord[MINX], texcoord[MAXY]); + glVertex3f(-1.0f,-1.0f, 0.0f); /* Bottom Left */ + glEnd(); /* done with the polygon */ + + if (shaders_supported) { + glUseProgramObjectARB(0); + } + glDisable(GL_TEXTURE_2D); + + /* swap buffers to display, since we're double buffered. */ + SDL_GL_SwapWindow(window); +} + +int main(int argc, char **argv) +{ + int done; + SDL_Window *window; + SDL_Surface *surface; + GLuint texture; + GLfloat texcoords[4]; + + /* Enable standard application logging */ + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + + /* Initialize SDL for video output */ + if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + + /* Create a 640x480 OpenGL screen */ + window = SDL_CreateWindow( "Shader Demo", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_OPENGL ); + if ( !window ) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create OpenGL window: %s\n", SDL_GetError()); + SDL_Quit(); + exit(2); + } + + if ( !SDL_GL_CreateContext(window)) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create OpenGL context: %s\n", SDL_GetError()); + SDL_Quit(); + exit(2); + } + + surface = SDL_LoadBMP("icon.bmp"); + if ( ! surface ) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to load icon.bmp: %s\n", SDL_GetError()); + SDL_Quit(); + exit(3); + } + texture = SDL_GL_LoadTexture(surface, texcoords); + SDL_FreeSurface(surface); + + /* Loop, drawing and checking events */ + InitGL(640, 480); + if (InitShaders()) { + SDL_Log("Shaders supported, press SPACE to cycle them.\n"); + } else { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Shaders not supported!\n"); + } + done = 0; + while ( ! done ) { + DrawGLScene(window, texture, texcoords); + + /* This could go in a separate function */ + { SDL_Event event; + while ( SDL_PollEvent(&event) ) { + if ( event.type == SDL_QUIT ) { + done = 1; + } + if ( event.type == SDL_KEYDOWN ) { + if ( event.key.keysym.sym == SDLK_SPACE ) { + current_shader = (current_shader + 1) % NUM_SHADERS; + } + if ( event.key.keysym.sym == SDLK_ESCAPE ) { + done = 1; + } + } + } + } + } + QuitShaders(); + SDL_Quit(); + return 1; +} + +#else /* HAVE_OPENGL */ + +int +main(int argc, char *argv[]) +{ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No OpenGL support on this system\n"); + return 1; +} + +#endif /* HAVE_OPENGL */ + +/* vi: set ts=4 sw=4 expandtab: */ |