summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/test/testshader.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
committer3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
commit6aaedb813fa11ba0679c3051bc2eb28646b9506c (patch)
tree34acbfc9840e02cb4753e6306ea7ce978bf8b58e /src/contrib/SDL-3.2.20/test/testshader.c
parent8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (diff)
Update to SDL3
Diffstat (limited to 'src/contrib/SDL-3.2.20/test/testshader.c')
-rw-r--r--src/contrib/SDL-3.2.20/test/testshader.c559
1 files changed, 559 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/test/testshader.c b/src/contrib/SDL-3.2.20/test/testshader.c
new file mode 100644
index 0000000..9b13890
--- /dev/null
+++ b/src/contrib/SDL-3.2.20/test/testshader.c
@@ -0,0 +1,559 @@
1/*
2 Copyright (C) 1997-2025 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 <SDL3/SDL.h>
15#include <SDL3/SDL_main.h>
16#include <SDL3/SDL_test.h>
17
18#include "testutils.h"
19
20#include <stdlib.h>
21
22#ifdef HAVE_OPENGL
23
24#include <SDL3/SDL_opengl.h>
25
26static bool shaders_supported;
27static int current_shader = 0;
28
29enum
30{
31 SHADER_COLOR,
32 SHADER_TEXTURE,
33 SHADER_TEXCOORDS,
34 NUM_SHADERS
35};
36
37typedef struct
38{
39 GLhandleARB program;
40 GLhandleARB vert_shader;
41 GLhandleARB frag_shader;
42 const char *vert_source;
43 const char *frag_source;
44} ShaderData;
45
46static ShaderData shaders[NUM_SHADERS] = {
47
48 /* SHADER_COLOR */
49 { 0, 0, 0,
50 /* vertex shader */
51 "varying vec4 v_color;\n"
52 "\n"
53 "void main()\n"
54 "{\n"
55 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
56 " v_color = gl_Color;\n"
57 "}",
58 /* fragment shader */
59 "varying vec4 v_color;\n"
60 "\n"
61 "void main()\n"
62 "{\n"
63 " gl_FragColor = v_color;\n"
64 "}" },
65
66 /* SHADER_TEXTURE */
67 { 0, 0, 0,
68 /* vertex shader */
69 "varying vec4 v_color;\n"
70 "varying vec2 v_texCoord;\n"
71 "\n"
72 "void main()\n"
73 "{\n"
74 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
75 " v_color = gl_Color;\n"
76 " v_texCoord = vec2(gl_MultiTexCoord0);\n"
77 "}",
78 /* fragment shader */
79 "varying vec4 v_color;\n"
80 "varying vec2 v_texCoord;\n"
81 "uniform sampler2D tex0;\n"
82 "\n"
83 "void main()\n"
84 "{\n"
85 " gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n"
86 "}" },
87
88 /* SHADER_TEXCOORDS */
89 { 0, 0, 0,
90 /* vertex shader */
91 "varying vec2 v_texCoord;\n"
92 "\n"
93 "void main()\n"
94 "{\n"
95 " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
96 " v_texCoord = vec2(gl_MultiTexCoord0);\n"
97 "}",
98 /* fragment shader */
99 "varying vec2 v_texCoord;\n"
100 "\n"
101 "void main()\n"
102 "{\n"
103 " vec4 color;\n"
104 " vec2 delta;\n"
105 " float dist;\n"
106 "\n"
107 " delta = vec2(0.5, 0.5) - v_texCoord;\n"
108 " dist = dot(delta, delta);\n"
109 "\n"
110 " color.r = v_texCoord.x;\n"
111 " color.g = v_texCoord.x * v_texCoord.y;\n"
112 " color.b = v_texCoord.y;\n"
113 " color.a = 1.0 - (dist * 4.0);\n"
114 " gl_FragColor = color;\n"
115 "}" },
116};
117
118static PFNGLATTACHOBJECTARBPROC pglAttachObjectARB;
119static PFNGLCOMPILESHADERARBPROC pglCompileShaderARB;
120static PFNGLCREATEPROGRAMOBJECTARBPROC pglCreateProgramObjectARB;
121static PFNGLCREATESHADEROBJECTARBPROC pglCreateShaderObjectARB;
122static PFNGLDELETEOBJECTARBPROC pglDeleteObjectARB;
123static PFNGLGETINFOLOGARBPROC pglGetInfoLogARB;
124static PFNGLGETOBJECTPARAMETERIVARBPROC pglGetObjectParameterivARB;
125static PFNGLGETUNIFORMLOCATIONARBPROC pglGetUniformLocationARB;
126static PFNGLLINKPROGRAMARBPROC pglLinkProgramARB;
127static PFNGLSHADERSOURCEARBPROC pglShaderSourceARB;
128static PFNGLUNIFORM1IARBPROC pglUniform1iARB;
129static PFNGLUSEPROGRAMOBJECTARBPROC pglUseProgramObjectARB;
130
131static bool CompileShader(GLhandleARB shader, const char *source)
132{
133 GLint status = 0;
134
135 pglShaderSourceARB(shader, 1, &source, NULL);
136 pglCompileShaderARB(shader);
137 pglGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
138 if (status == 0) {
139 GLint length = 0;
140 char *info;
141
142 pglGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
143 info = (char *)SDL_malloc((size_t)length + 1);
144 if (!info) {
145 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
146 } else {
147 pglGetInfoLogARB(shader, length, NULL, info);
148 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to compile shader:");
149 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", source);
150 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", info);
151 SDL_free(info);
152 }
153 return false;
154 } else {
155 return true;
156 }
157}
158
159static bool LinkProgram(ShaderData *data)
160{
161 GLint status = 0;
162
163 pglAttachObjectARB(data->program, data->vert_shader);
164 pglAttachObjectARB(data->program, data->frag_shader);
165 pglLinkProgramARB(data->program);
166
167 pglGetObjectParameterivARB(data->program, GL_OBJECT_LINK_STATUS_ARB, &status);
168 if (status == 0) {
169 GLint length = 0;
170 char *info;
171
172 pglGetObjectParameterivARB(data->program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
173 info = (char *)SDL_malloc((size_t)length + 1);
174 if (!info) {
175 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
176 } else {
177 pglGetInfoLogARB(data->program, length, NULL, info);
178 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to link program:");
179 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s", info);
180 SDL_free(info);
181 }
182 return false;
183 } else {
184 return true;
185 }
186}
187
188static bool CompileShaderProgram(ShaderData *data)
189{
190 const int num_tmus_bound = 4;
191 int i;
192 GLint location;
193
194 glGetError();
195
196 /* Create one program object to rule them all */
197 data->program = pglCreateProgramObjectARB();
198
199 /* Create the vertex shader */
200 data->vert_shader = pglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
201 if (!CompileShader(data->vert_shader, data->vert_source)) {
202 return false;
203 }
204
205 /* Create the fragment shader */
206 data->frag_shader = pglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
207 if (!CompileShader(data->frag_shader, data->frag_source)) {
208 return false;
209 }
210
211 /* ... and in the darkness bind them */
212 if (!LinkProgram(data)) {
213 return false;
214 }
215
216 /* Set up some uniform variables */
217 pglUseProgramObjectARB(data->program);
218 for (i = 0; i < num_tmus_bound; ++i) {
219 char tex_name[5];
220 (void)SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i);
221 location = pglGetUniformLocationARB(data->program, tex_name);
222 if (location >= 0) {
223 pglUniform1iARB(location, i);
224 }
225 }
226 pglUseProgramObjectARB(0);
227
228 return (glGetError() == GL_NO_ERROR);
229}
230
231static void DestroyShaderProgram(ShaderData *data)
232{
233 if (shaders_supported) {
234 pglDeleteObjectARB(data->vert_shader);
235 pglDeleteObjectARB(data->frag_shader);
236 pglDeleteObjectARB(data->program);
237 }
238}
239
240static bool InitShaders(void)
241{
242 int i;
243
244 /* Check for shader support */
245 shaders_supported = false;
246 if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") &&
247 SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") &&
248 SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") &&
249 SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) {
250 pglAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)SDL_GL_GetProcAddress("glAttachObjectARB");
251 pglCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)SDL_GL_GetProcAddress("glCompileShaderARB");
252 pglCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glCreateProgramObjectARB");
253 pglCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)SDL_GL_GetProcAddress("glCreateShaderObjectARB");
254 pglDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)SDL_GL_GetProcAddress("glDeleteObjectARB");
255 pglGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)SDL_GL_GetProcAddress("glGetInfoLogARB");
256 pglGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)SDL_GL_GetProcAddress("glGetObjectParameterivARB");
257 pglGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)SDL_GL_GetProcAddress("glGetUniformLocationARB");
258 pglLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)SDL_GL_GetProcAddress("glLinkProgramARB");
259 pglShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)SDL_GL_GetProcAddress("glShaderSourceARB");
260 pglUniform1iARB = (PFNGLUNIFORM1IARBPROC)SDL_GL_GetProcAddress("glUniform1iARB");
261 pglUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glUseProgramObjectARB");
262 if (pglAttachObjectARB &&
263 pglCompileShaderARB &&
264 pglCreateProgramObjectARB &&
265 pglCreateShaderObjectARB &&
266 pglDeleteObjectARB &&
267 pglGetInfoLogARB &&
268 pglGetObjectParameterivARB &&
269 pglGetUniformLocationARB &&
270 pglLinkProgramARB &&
271 pglShaderSourceARB &&
272 pglUniform1iARB &&
273 pglUseProgramObjectARB) {
274 shaders_supported = true;
275 }
276 }
277
278 if (!shaders_supported) {
279 return false;
280 }
281
282 /* Compile all the shaders */
283 for (i = 0; i < NUM_SHADERS; ++i) {
284 if (!CompileShaderProgram(&shaders[i])) {
285 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to compile shader!");
286 return false;
287 }
288 }
289
290 /* We're done! */
291 return true;
292}
293
294static void QuitShaders(void)
295{
296 int i;
297
298 for (i = 0; i < NUM_SHADERS; ++i) {
299 DestroyShaderProgram(&shaders[i]);
300 }
301}
302
303/* Quick utility function for texture creation */
304static int
305power_of_two(int input)
306{
307 int value = 1;
308
309 while (value < input) {
310 value <<= 1;
311 }
312 return value;
313}
314
315static GLuint
316SDL_GL_LoadTexture(SDL_Surface *surface, GLfloat *texcoord)
317{
318 GLuint texture;
319 int w, h;
320 SDL_Surface *image;
321 SDL_Rect area;
322 SDL_BlendMode saved_mode;
323
324 /* Use the surface width and height expanded to powers of 2 */
325 w = power_of_two(surface->w);
326 h = power_of_two(surface->h);
327 texcoord[0] = 0.0f; /* Min X */
328 texcoord[1] = 0.0f; /* Min Y */
329 texcoord[2] = (GLfloat)surface->w / w; /* Max X */
330 texcoord[3] = (GLfloat)surface->h / h; /* Max Y */
331
332 image = SDL_CreateSurface(w, h, SDL_PIXELFORMAT_RGBA32);
333 if (!image) {
334 return 0;
335 }
336
337 /* Save the alpha blending attributes */
338 SDL_GetSurfaceBlendMode(surface, &saved_mode);
339 SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
340
341 /* Copy the surface into the GL texture image */
342 area.x = 0;
343 area.y = 0;
344 area.w = surface->w;
345 area.h = surface->h;
346 SDL_BlitSurface(surface, &area, image, &area);
347
348 /* Restore the alpha blending attributes */
349 SDL_SetSurfaceBlendMode(surface, saved_mode);
350
351 /* Create an OpenGL texture for the image */
352 glGenTextures(1, &texture);
353 glBindTexture(GL_TEXTURE_2D, texture);
354 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
355 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
356 glTexImage2D(GL_TEXTURE_2D,
357 0,
358 GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
359 SDL_DestroySurface(image); /* No longer needed */
360
361 return texture;
362}
363
364/* A general OpenGL initialization function. Sets all of the initial parameters. */
365static void InitGL(int Width, int Height) /* We call this right after our OpenGL window is created. */
366{
367 GLdouble aspect;
368
369 glViewport(0, 0, Width, Height);
370 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); /* This Will Clear The Background Color To Black */
371 glClearDepth(1.0); /* Enables Clearing Of The Depth Buffer */
372 glDepthFunc(GL_LESS); /* The Type Of Depth Test To Do */
373 glEnable(GL_DEPTH_TEST); /* Enables Depth Testing */
374 glShadeModel(GL_SMOOTH); /* Enables Smooth Color Shading */
375
376 glMatrixMode(GL_PROJECTION);
377 glLoadIdentity(); /* Reset The Projection Matrix */
378
379 aspect = (GLdouble)Width / Height;
380 glOrtho(-3.0, 3.0, -3.0 / aspect, 3.0 / aspect, 0.0, 1.0);
381
382 glMatrixMode(GL_MODELVIEW);
383}
384
385/* The main drawing function. */
386static void DrawGLScene(SDL_Window *window, GLuint texture, GLfloat *texcoord)
387{
388 /* Texture coordinate lookup, to make it simple */
389 enum
390 {
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 pglUseProgramObjectARB(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 pglUseProgramObjectARB(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
447int main(int argc, char **argv)
448{
449 int i;
450 int done;
451 SDL_Window *window;
452 char *filename = NULL;
453 SDL_Surface *surface;
454 GLuint texture;
455 GLfloat texcoords[4];
456 SDLTest_CommonState *state;
457
458 /* Initialize test framework */
459 state = SDLTest_CommonCreateState(argv, 0);
460 if (!state) {
461 return 1;
462 }
463
464 /* Parse commandline */
465 for (i = 1; i < argc;) {
466 int consumed;
467
468 consumed = SDLTest_CommonArg(state, i);
469 if (!consumed) {
470 if (!filename) {
471 filename = argv[i];
472 consumed = 1;
473 }
474 }
475 if (consumed <= 0) {
476 static const char *options[] = { "[icon.bmp]", NULL };
477 SDLTest_CommonLogUsage(state, argv[0], options);
478 exit(1);
479 }
480
481 i += consumed;
482 }
483
484 /* Initialize SDL for video output */
485 if (!SDL_Init(SDL_INIT_VIDEO)) {
486 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to initialize SDL: %s", SDL_GetError());
487 exit(1);
488 }
489
490 /* Create a 640x480 OpenGL screen */
491 window = SDL_CreateWindow("Shader Demo", 640, 480, SDL_WINDOW_OPENGL);
492 if (!window) {
493 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create OpenGL window: %s", SDL_GetError());
494 SDL_Quit();
495 exit(2);
496 }
497
498 if (!SDL_GL_CreateContext(window)) {
499 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create OpenGL context: %s", SDL_GetError());
500 SDL_Quit();
501 exit(2);
502 }
503
504 filename = GetResourceFilename(NULL, "icon.bmp");
505 surface = SDL_LoadBMP(filename);
506 SDL_free(filename);
507
508 if (!surface) {
509 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to load icon.bmp: %s", SDL_GetError());
510 SDL_Quit();
511 exit(3);
512 }
513 texture = SDL_GL_LoadTexture(surface, texcoords);
514 SDL_DestroySurface(surface);
515
516 /* Loop, drawing and checking events */
517 InitGL(640, 480);
518 if (InitShaders()) {
519 SDL_Log("Shaders supported, press SPACE to cycle them.");
520 } else {
521 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Shaders not supported!");
522 }
523 done = 0;
524 while (!done) {
525 DrawGLScene(window, texture, texcoords);
526
527 /* This could go in a separate function */
528 {
529 SDL_Event event;
530 while (SDL_PollEvent(&event)) {
531 if (event.type == SDL_EVENT_QUIT) {
532 done = 1;
533 }
534 if (event.type == SDL_EVENT_KEY_DOWN) {
535 if (event.key.key == SDLK_SPACE) {
536 current_shader = (current_shader + 1) % NUM_SHADERS;
537 }
538 if (event.key.key == SDLK_ESCAPE) {
539 done = 1;
540 }
541 }
542 }
543 }
544 }
545 QuitShaders();
546 SDL_Quit();
547 SDLTest_CommonDestroyState(state);
548 return 1;
549}
550
551#else /* HAVE_OPENGL */
552
553int main(int argc, char *argv[])
554{
555 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No OpenGL support on this system");
556 return 1;
557}
558
559#endif /* HAVE_OPENGL */