added stb, more binaryout changes"
[henge/apc.git] / stb / tests / caveview / stb_glprog.h
1 // stb_glprog v0.02 public domain functions to reduce GLSL boilerplate
2 // http://nothings.org/stb/stb_glprog.h especially with GL1 + ARB extensions
3 //
4 // Following defines *before* including have following effects:
5 //
6 // STB_GLPROG_IMPLEMENTATION
7 // creates the implementation
8 //
9 // STB_GLPROG_STATIC
10 // forces the implementation to be static (private to file that creates it)
11 //
12 // STB_GLPROG_ARB
13 // uses ARB extension names for GLSL functions and enumerants instead of core names
14 //
15 // STB_GLPROG_ARB_DEFINE_EXTENSIONS
16 // instantiates function pointers needed, static to implementing file
17 // to avoid collisions (but will collide if implementing file also
18 // defines any; best to isolate this to its own file in this case).
19 // This will try to automatically #include glext.h, but if it's not
20 // in the default include directories you'll need to include it
21 // yourself and define the next macro.
22 //
23 // STB_GLPROG_SUPPRESS_GLEXT_INCLUDE
24 // disables the automatic #include of glext.h which is normally
25 // forced by STB_GLPROG_ARB_DEFINE_EXTENSIONS
26 //
27 // So, e.g., sample usage on an old Windows compiler:
28 //
29 // #define STB_GLPROG_IMPLEMENTATION
30 // #define STB_GLPROG_ARB_DEFINE_EXTENSIONS
31 // #include <windows.h>
32 // #include "gl/gl.h"
33 // #include "stb_glprog.h"
34 //
35 // Note though that the header-file version of this (when you don't define
36 // STB_GLPROG_IMPLEMENTATION) still uses GLint and such, so you basically
37 // can only include it in places where you're already including GL, especially
38 // on Windows where including "gl.h" requires (some of) "windows.h".
39 //
40 // See following comment blocks for function documentation.
41 //
42 // Version history:
43 // 2013-12-08 v0.02 slightly simplified API and reduced GL resource usage (@rygorous)
44 // 2013-12-08 v0.01 initial release
45
46
47 // header file section starts here
48 #if !defined(INCLUDE_STB_GLPROG_H)
49 #define INCLUDE_STB_GLPROG_H
50
51 #ifndef STB_GLPROG_STATIC
52 #ifdef __cplusplus
53 extern "C" {
54 #endif
55
56 //////////////////////////////////////////////////////////////////////////////
57
58 ///////////// SHADER CREATION
59
60
61 /// EASY API
62
63 extern GLuint stbgl_create_program(char const **vertex_source, char const **frag_source, char const **binds, char *error, int error_buflen);
64 // This function returns a compiled program or 0 if there's an error.
65 // To free the created program, call stbgl_delete_program.
66 //
67 // stbgl_create_program(
68 // char **vertex_source, // NULL or one or more strings with the vertex shader source, with a final NULL
69 // char **frag_source, // NULL or one or more strings with the fragment shader source, with a final NULL
70 // char **binds, // NULL or zero or more strings with attribute bind names, with a final NULL
71 // char *error, // output location where compile error message is placed
72 // int error_buflen) // length of error output buffer
73 //
74 // Returns a GLuint with the GL program object handle.
75 //
76 // If an individual bind string is "", no name is bound to that slot (this
77 // allows you to create binds that aren't continuous integers starting at 0).
78 //
79 // If the vertex shader is NULL, then fixed-function vertex pipeline
80 // is used, if that's legal in your version of GL.
81 //
82 // If the fragment shader is NULL, then fixed-function fragment pipeline
83 // is used, if that's legal in your version of GL.
84
85 extern void stgbl_delete_program(GLuint program);
86 // deletes a program created by stbgl_create_program or stbgl_link_program
87
88
89 /// FLEXIBLE API
90
91 extern GLuint stbgl_compile_shader(GLenum type, char const **sources, int num_sources, char *error, int error_buflen);
92 // compiles a shader. returns the shader on success or 0 on failure.
93 //
94 // type either: GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
95 // or GL_VERTEX_SHADER_ARB or GL_FRAGMENT_SHADER_ARB
96 // or STBGL_VERTEX_SHADER or STBGL_FRAGMENT_SHADER
97 // sources array of strings containing the shader source
98 // num_sources number of string in sources, or -1 meaning sources is NULL-terminated
99 // error string to output compiler error to
100 // error_buflen length of error buffer in chars
101
102 extern GLuint stbgl_link_program(GLuint vertex_shader, GLuint fragment_shader, char const **binds, int num_binds, char *error, int error_buflen);
103 // links a shader. returns the linked program on success or 0 on failure.
104 //
105 // vertex_shader a compiled vertex shader from stbgl_compile_shader, or 0 for fixed-function (if legal)
106 // fragment_shader a compiled fragment shader from stbgl_compile_shader, or 0 for fixed-function (if legal)
107 //
108
109 extern void stbgl_delete_shader(GLuint shader);
110 // deletes a shader created by stbgl_compile_shader
111
112
113 ///////////// RENDERING WITH SHADERS
114
115 extern GLint stbgl_find_uniform(GLuint prog, char *uniform);
116
117 extern void stbgl_find_uniforms(GLuint prog, GLint *locations, char const **uniforms, int num_uniforms);
118 // Given the locations array that is num_uniforms long, fills out
119 // the locations of each of those uniforms for the specified program.
120 // If num_uniforms is -1, then uniforms[] must be NULL-terminated
121
122 // the following functions just wrap the difference in naming between GL2+ and ARB,
123 // so you don't need them unless you're using both ARB and GL2+ in the same codebase,
124 // or you're relying on this lib to provide the extensions
125 extern void stbglUseProgram(GLuint program);
126 extern void stbglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer);
127 extern void stbglEnableVertexAttribArray(GLuint index);
128 extern void stbglDisableVertexAttribArray(GLuint index);
129 extern void stbglUniform1fv(GLint loc, GLsizei count, const GLfloat *v);
130 extern void stbglUniform2fv(GLint loc, GLsizei count, const GLfloat *v);
131 extern void stbglUniform3fv(GLint loc, GLsizei count, const GLfloat *v);
132 extern void stbglUniform4fv(GLint loc, GLsizei count, const GLfloat *v);
133 extern void stbglUniform1iv(GLint loc, GLsizei count, const GLint *v);
134 extern void stbglUniform2iv(GLint loc, GLsizei count, const GLint *v);
135 extern void stbglUniform3iv(GLint loc, GLsizei count, const GLint *v);
136 extern void stbglUniform4iv(GLint loc, GLsizei count, const GLint *v);
137 extern void stbglUniform1f(GLint loc, float v0);
138 extern void stbglUniform2f(GLint loc, float v0, float v1);
139 extern void stbglUniform3f(GLint loc, float v0, float v1, float v2);
140 extern void stbglUniform4f(GLint loc, float v0, float v1, float v2, float v3);
141 extern void stbglUniform1i(GLint loc, GLint v0);
142 extern void stbglUniform2i(GLint loc, GLint v0, GLint v1);
143 extern void stbglUniform3i(GLint loc, GLint v0, GLint v1, GLint v2);
144 extern void stbglUniform4i(GLint loc, GLint v0, GLint v1, GLint v2, GLint v3);
145
146
147 ////////////// END OF FUNCTIONS
148
149 //////////////////////////////////////////////////////////////////////////////
150
151 #ifdef __cplusplus
152 }
153 #endif
154 #endif // STB_GLPROG_STATIC
155
156 #ifdef STB_GLPROG_ARB
157 #define STBGL_VERTEX_SHADER GL_VERTEX_SHADER_ARB
158 #define STBGL_FRAGMENT_SHADER GL_FRAGMENT_SHADER_ARB
159 #else
160 #define STBGL_VERTEX_SHADER GL_VERTEX_SHADER
161 #define STBGL_FRAGMENT_SHADER GL_FRAGMENT_SHADER
162 #endif
163
164 #endif // INCLUDE_STB_GLPROG_H
165
166
167 ///////// header file section ends here
168
169
170 #ifdef STB_GLPROG_IMPLEMENTATION
171 #include <string.h> // strncpy
172
173 #ifdef STB_GLPROG_STATIC
174 #define STB_GLPROG_DECLARE static
175 #else
176 #define STB_GLPROG_DECLARE extern
177 #endif
178
179 // check if user wants this file to define the GL extensions itself
180 #ifdef STB_GLPROG_ARB_DEFINE_EXTENSIONS
181 #define STB_GLPROG_ARB // make sure later code uses the extensions
182
183 #ifndef STB_GLPROG_SUPPRESS_GLEXT_INCLUDE
184 #include "glext.h"
185 #endif
186
187 #define STB_GLPROG_EXTENSIONS \
188 STB_GLPROG_FUNC(ATTACHOBJECT , AttachObject ) \
189 STB_GLPROG_FUNC(BINDATTRIBLOCATION , BindAttribLocation ) \
190 STB_GLPROG_FUNC(COMPILESHADER , CompileShader ) \
191 STB_GLPROG_FUNC(CREATEPROGRAMOBJECT , CreateProgramObject ) \
192 STB_GLPROG_FUNC(CREATESHADEROBJECT , CreateShaderObject ) \
193 STB_GLPROG_FUNC(DELETEOBJECT , DeleteObject ) \
194 STB_GLPROG_FUNC(DETACHOBJECT , DetachObject ) \
195 STB_GLPROG_FUNC(DISABLEVERTEXATTRIBARRAY, DisableVertexAttribArray) \
196 STB_GLPROG_FUNC(ENABLEVERTEXATTRIBARRAY, EnableVertexAttribArray ) \
197 STB_GLPROG_FUNC(GETATTACHEDOBJECTS , GetAttachedObjects ) \
198 STB_GLPROG_FUNC(GETOBJECTPARAMETERIV, GetObjectParameteriv) \
199 STB_GLPROG_FUNC(GETINFOLOG , GetInfoLog ) \
200 STB_GLPROG_FUNC(GETUNIFORMLOCATION , GetUniformLocation ) \
201 STB_GLPROG_FUNC(LINKPROGRAM , LinkProgram ) \
202 STB_GLPROG_FUNC(SHADERSOURCE , ShaderSource ) \
203 STB_GLPROG_FUNC(UNIFORM1F , Uniform1f ) \
204 STB_GLPROG_FUNC(UNIFORM2F , Uniform2f ) \
205 STB_GLPROG_FUNC(UNIFORM3F , Uniform3f ) \
206 STB_GLPROG_FUNC(UNIFORM4F , Uniform4f ) \
207 STB_GLPROG_FUNC(UNIFORM1I , Uniform1i ) \
208 STB_GLPROG_FUNC(UNIFORM2I , Uniform2i ) \
209 STB_GLPROG_FUNC(UNIFORM3I , Uniform3i ) \
210 STB_GLPROG_FUNC(UNIFORM4I , Uniform4i ) \
211 STB_GLPROG_FUNC(UNIFORM1FV , Uniform1fv ) \
212 STB_GLPROG_FUNC(UNIFORM2FV , Uniform2fv ) \
213 STB_GLPROG_FUNC(UNIFORM3FV , Uniform3fv ) \
214 STB_GLPROG_FUNC(UNIFORM4FV , Uniform4fv ) \
215 STB_GLPROG_FUNC(UNIFORM1IV , Uniform1iv ) \
216 STB_GLPROG_FUNC(UNIFORM2IV , Uniform2iv ) \
217 STB_GLPROG_FUNC(UNIFORM3IV , Uniform3iv ) \
218 STB_GLPROG_FUNC(UNIFORM4IV , Uniform4iv ) \
219 STB_GLPROG_FUNC(USEPROGRAMOBJECT , UseProgramObject ) \
220 STB_GLPROG_FUNC(VERTEXATTRIBPOINTER , VertexAttribPointer )
221
222 // define the static function pointers
223
224 #define STB_GLPROG_FUNC(x,y) static PFNGL##x##ARBPROC gl##y##ARB;
225 STB_GLPROG_EXTENSIONS
226 #undef STB_GLPROG_FUNC
227
228 // define the GetProcAddress
229
230 #ifdef _WIN32
231 #ifndef WINGDIAPI
232 #ifndef STB__HAS_WGLPROC
233 typedef int (__stdcall *stbgl__voidfunc)(void);
234 static __declspec(dllimport) stbgl__voidfunc wglGetProcAddress(char *);
235 #endif
236 #endif
237 #define STBGL__GET_FUNC(x) wglGetProcAddress(x)
238 #else
239 #error "need to define how this platform gets extensions"
240 #endif
241
242 // create a function that fills out the function pointers
243
244 static void stb_glprog_init(void)
245 {
246 static int initialized = 0; // not thread safe!
247 if (initialized) return;
248 #define STB_GLPROG_FUNC(x,y) gl##y##ARB = (PFNGL##x##ARBPROC) STBGL__GET_FUNC("gl" #y "ARB");
249 STB_GLPROG_EXTENSIONS
250 #undef STB_GLPROG_FUNC
251 }
252 #undef STB_GLPROG_EXTENSIONS
253
254 #else
255 static void stb_glprog_init(void)
256 {
257 }
258 #endif
259
260
261 // define generic names for many of the gl functions or extensions for later use;
262 // note that in some cases there are two functions in core and one function in ARB
263 #ifdef STB_GLPROG_ARB
264 #define stbglCreateShader glCreateShaderObjectARB
265 #define stbglDeleteShader glDeleteObjectARB
266 #define stbglAttachShader glAttachObjectARB
267 #define stbglDetachShader glDetachObjectARB
268 #define stbglShaderSource glShaderSourceARB
269 #define stbglCompileShader glCompileShaderARB
270 #define stbglGetShaderStatus(a,b) glGetObjectParameterivARB(a, GL_OBJECT_COMPILE_STATUS_ARB, b)
271 #define stbglGetShaderInfoLog glGetInfoLogARB
272 #define stbglCreateProgram glCreateProgramObjectARB
273 #define stbglDeleteProgram glDeleteObjectARB
274 #define stbglLinkProgram glLinkProgramARB
275 #define stbglGetProgramStatus(a,b) glGetObjectParameterivARB(a, GL_OBJECT_LINK_STATUS_ARB, b)
276 #define stbglGetProgramInfoLog glGetInfoLogARB
277 #define stbglGetAttachedShaders glGetAttachedObjectsARB
278 #define stbglBindAttribLocation glBindAttribLocationARB
279 #define stbglGetUniformLocation glGetUniformLocationARB
280 #define stbgl_UseProgram glUseProgramObjectARB
281 #else
282 #define stbglCreateShader glCreateShader
283 #define stbglDeleteShader glDeleteShader
284 #define stbglAttachShader glAttachShader
285 #define stbglDetachShader glDetachShader
286 #define stbglShaderSource glShaderSource
287 #define stbglCompileShader glCompileShader
288 #define stbglGetShaderStatus(a,b) glGetShaderiv(a, GL_COMPILE_STATUS, b)
289 #define stbglGetShaderInfoLog glGetShaderInfoLog
290 #define stbglCreateProgram glCreateProgram
291 #define stbglDeleteProgram glDeleteProgram
292 #define stbglLinkProgram glLinkProgram
293 #define stbglGetProgramStatus(a,b) glGetProgramiv(a, GL_LINK_STATUS, b)
294 #define stbglGetProgramInfoLog glGetProgramInfoLog
295 #define stbglGetAttachedShaders glGetAttachedShaders
296 #define stbglBindAttribLocation glBindAttribLocation
297 #define stbglGetUniformLocation glGetUniformLocation
298 #define stbgl_UseProgram glUseProgram
299 #endif
300
301
302 // perform a safe strcat of 3 strings, given that we can't rely on portable snprintf
303 // if you need to break on error, this is the best place to place a breakpoint
304 static void stb_glprog_error(char *error, int error_buflen, char *str1, char *str2, char *str3)
305 {
306 int n = strlen(str1);
307 strncpy(error, str1, error_buflen);
308 if (n < error_buflen && str2) {
309 strncpy(error+n, str2, error_buflen - n);
310 n += strlen(str2);
311 if (n < error_buflen && str3) {
312 strncpy(error+n, str3, error_buflen - n);
313 }
314 }
315 error[error_buflen-1] = 0;
316 }
317
318 STB_GLPROG_DECLARE GLuint stbgl_compile_shader(GLenum type, char const **sources, int num_sources, char *error, int error_buflen)
319 {
320 char *typename = (type == STBGL_VERTEX_SHADER ? "vertex" : "fragment");
321 int len;
322 GLint result;
323 GLuint shader;
324
325 // initialize the extensions if we haven't already
326 stb_glprog_init();
327
328 // allocate
329
330 shader = stbglCreateShader(type);
331 if (!shader) {
332 stb_glprog_error(error, error_buflen, "Couldn't allocate shader object in stbgl_compile_shader for ", typename, NULL);
333 return 0;
334 }
335
336 // compile
337
338 // if num_sources is negative, assume source is NULL-terminated and count the non-NULL ones
339 if (num_sources < 0)
340 for (num_sources = 0; sources[num_sources] != NULL; ++num_sources)
341 ;
342 stbglShaderSource(shader, num_sources, sources, NULL);
343 stbglCompileShader(shader);
344 stbglGetShaderStatus(shader, &result);
345 if (result)
346 return shader;
347
348 // errors
349
350 stb_glprog_error(error, error_buflen, "Compile error for ", typename, " shader: ");
351 len = strlen(error);
352 if (len < error_buflen)
353 stbglGetShaderInfoLog(shader, error_buflen-len, NULL, error+len);
354
355 stbglDeleteShader(shader);
356 return 0;
357 }
358
359 STB_GLPROG_DECLARE GLuint stbgl_link_program(GLuint vertex_shader, GLuint fragment_shader, char const **binds, int num_binds, char *error, int error_buflen)
360 {
361 int len;
362 GLint result;
363
364 // allocate
365
366 GLuint prog = stbglCreateProgram();
367 if (!prog) {
368 stb_glprog_error(error, error_buflen, "Couldn't allocate program object in stbgl_link_program", NULL, NULL);
369 return 0;
370 }
371
372 // attach
373
374 if (vertex_shader)
375 stbglAttachShader(prog, vertex_shader);
376 if (fragment_shader)
377 stbglAttachShader(prog, fragment_shader);
378
379 // attribute binds
380
381 if (binds) {
382 int i;
383 // if num_binds is negative, then it is NULL terminated
384 if (num_binds < 0)
385 for (num_binds=0; binds[num_binds]; ++num_binds)
386 ;
387 for (i=0; i < num_binds; ++i)
388 if (binds[i] && binds[i][0]) // empty binds can be NULL or ""
389 stbglBindAttribLocation(prog, i, binds[i]);
390 }
391
392 // link
393
394 stbglLinkProgram(prog);
395
396 // detach
397
398 if (vertex_shader)
399 stbglDetachShader(prog, vertex_shader);
400 if (fragment_shader)
401 stbglDetachShader(prog, fragment_shader);
402
403 // errors
404
405 stbglGetProgramStatus(prog, &result);
406 if (result)
407 return prog;
408
409 stb_glprog_error(error, error_buflen, "Link error: ", NULL, NULL);
410 len = strlen(error);
411 if (len < error_buflen)
412 stbglGetProgramInfoLog(prog, error_buflen-len, NULL, error+len);
413
414 stbglDeleteProgram(prog);
415 return 0;
416 }
417
418 STB_GLPROG_DECLARE GLuint stbgl_create_program(char const **vertex_source, char const **frag_source, char const **binds, char *error, int error_buflen)
419 {
420 GLuint vertex, fragment, prog=0;
421 vertex = stbgl_compile_shader(STBGL_VERTEX_SHADER, vertex_source, -1, error, error_buflen);
422 if (vertex) {
423 fragment = stbgl_compile_shader(STBGL_FRAGMENT_SHADER, frag_source, -1, error, error_buflen);
424 if (fragment)
425 prog = stbgl_link_program(vertex, fragment, binds, -1, error, error_buflen);
426 if (fragment)
427 stbglDeleteShader(fragment);
428 stbglDeleteShader(vertex);
429 }
430 return prog;
431 }
432
433 STB_GLPROG_DECLARE void stbgl_delete_shader(GLuint shader)
434 {
435 stbglDeleteShader(shader);
436 }
437
438 STB_GLPROG_DECLARE void stgbl_delete_program(GLuint program)
439 {
440 stbglDeleteProgram(program);
441 }
442
443 GLint stbgl_find_uniform(GLuint prog, char *uniform)
444 {
445 return stbglGetUniformLocation(prog, uniform);
446 }
447
448 STB_GLPROG_DECLARE void stbgl_find_uniforms(GLuint prog, GLint *locations, char const **uniforms, int num_uniforms)
449 {
450 int i;
451 if (num_uniforms < 0)
452 num_uniforms = 999999;
453 for (i=0; i < num_uniforms && uniforms[i]; ++i)
454 locations[i] = stbglGetUniformLocation(prog, uniforms[i]);
455 }
456
457 STB_GLPROG_DECLARE void stbglUseProgram(GLuint program)
458 {
459 stbgl_UseProgram(program);
460 }
461
462 #ifdef STB_GLPROG_ARB
463 #define STBGL_ARBIFY(name) name##ARB
464 #else
465 #define STBGL_ARBIFY(name) name
466 #endif
467
468 STB_GLPROG_DECLARE void stbglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer)
469 {
470 STBGL_ARBIFY(glVertexAttribPointer)(index, size, type, normalized, stride, pointer);
471 }
472
473 STB_GLPROG_DECLARE void stbglEnableVertexAttribArray (GLuint index) { STBGL_ARBIFY(glEnableVertexAttribArray )(index); }
474 STB_GLPROG_DECLARE void stbglDisableVertexAttribArray(GLuint index) { STBGL_ARBIFY(glDisableVertexAttribArray)(index); }
475
476 STB_GLPROG_DECLARE void stbglUniform1fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform1fv)(loc,count,v); }
477 STB_GLPROG_DECLARE void stbglUniform2fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform2fv)(loc,count,v); }
478 STB_GLPROG_DECLARE void stbglUniform3fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform3fv)(loc,count,v); }
479 STB_GLPROG_DECLARE void stbglUniform4fv(GLint loc, GLsizei count, const GLfloat *v) { STBGL_ARBIFY(glUniform4fv)(loc,count,v); }
480
481 STB_GLPROG_DECLARE void stbglUniform1iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform1iv)(loc,count,v); }
482 STB_GLPROG_DECLARE void stbglUniform2iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform2iv)(loc,count,v); }
483 STB_GLPROG_DECLARE void stbglUniform3iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform3iv)(loc,count,v); }
484 STB_GLPROG_DECLARE void stbglUniform4iv(GLint loc, GLsizei count, const GLint *v) { STBGL_ARBIFY(glUniform4iv)(loc,count,v); }
485
486 STB_GLPROG_DECLARE void stbglUniform1f(GLint loc, float v0)
487 { STBGL_ARBIFY(glUniform1f)(loc,v0); }
488 STB_GLPROG_DECLARE void stbglUniform2f(GLint loc, float v0, float v1)
489 { STBGL_ARBIFY(glUniform2f)(loc,v0,v1); }
490 STB_GLPROG_DECLARE void stbglUniform3f(GLint loc, float v0, float v1, float v2)
491 { STBGL_ARBIFY(glUniform3f)(loc,v0,v1,v2); }
492 STB_GLPROG_DECLARE void stbglUniform4f(GLint loc, float v0, float v1, float v2, float v3)
493 { STBGL_ARBIFY(glUniform4f)(loc,v0,v1,v2,v3); }
494
495 STB_GLPROG_DECLARE void stbglUniform1i(GLint loc, GLint v0)
496 { STBGL_ARBIFY(glUniform1i)(loc,v0); }
497 STB_GLPROG_DECLARE void stbglUniform2i(GLint loc, GLint v0, GLint v1)
498 { STBGL_ARBIFY(glUniform2i)(loc,v0,v1); }
499 STB_GLPROG_DECLARE void stbglUniform3i(GLint loc, GLint v0, GLint v1, GLint v2)
500 { STBGL_ARBIFY(glUniform3i)(loc,v0,v1,v2); }
501 STB_GLPROG_DECLARE void stbglUniform4i(GLint loc, GLint v0, GLint v1, GLint v2, GLint v3)
502 { STBGL_ARBIFY(glUniform4i)(loc,v0,v1,v2,v3); }
503
504 #endif