"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: */