1 /*
2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
3 *
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on the
6 * source.
7 *
8 */
9
10
11 #include "globalincs/pstypes.h"
12 #include "globalincs/def_files.h"
13
14 #include "graphics/2d.h"
15 #include "lighting/lighting.h"
16 #include "graphics/grinternal.h"
17 #include "graphics/gropengl.h"
18 #include "graphics/gropenglextension.h"
19 #include "graphics/gropengltexture.h"
20 #include "graphics/gropengllight.h"
21 #include "graphics/gropengltnl.h"
22 #include "graphics/gropengldraw.h"
23 #include "graphics/gropenglshader.h"
24 #include "graphics/gropenglpostprocessing.h"
25 #include "graphics/gropenglstate.h"
26
27 #include "math/vecmat.h"
28 #include "render/3d.h"
29 #include "cmdline/cmdline.h"
30 #include "mod_table/mod_table.h"
31
32
33 SCP_vector<opengl_shader_t> GL_shader;
34
35 static char *GLshader_info_log = NULL;
36 static const int GLshader_info_log_size = 8192;
37 GLuint Framebuffer_fallback_texture_id = 0;
38
39 static int Effect_num = 0;
40 static float Anim_timer = 0.0f;
41
42
43 /**
44 * Static lookup reference for main shader uniforms
45 * When adding a new SDR_ flag, list all associated uniforms and attributes here
46 */
47 static opengl_shader_uniform_reference_t GL_Uniform_Reference_Main[] = {
48 { SDR_FLAG_LIGHT, 1, {"n_lights"}, 0, { NULL }, "Lighting" },
49 { SDR_FLAG_FOG, 0, { NULL }, 0, { NULL }, "Fog Effect" },
50 { SDR_FLAG_DIFFUSE_MAP, 5, {"sBasemap", "desaturate", "desaturate_r", "desaturate_g", "desaturate_b"}, 0, { NULL }, "Diffuse Mapping"},
51 { SDR_FLAG_GLOW_MAP, 1, {"sGlowmap"}, 0, { NULL }, "Glow Mapping" },
52 { SDR_FLAG_SPEC_MAP, 1, {"sSpecmap"}, 0, { NULL }, "Specular Mapping" },
53 { SDR_FLAG_NORMAL_MAP, 1, {"sNormalmap"}, 0, { NULL }, "Normal Mapping" },
54 { SDR_FLAG_HEIGHT_MAP, 1, {"sHeightmap"}, 0, { NULL }, "Parallax Mapping" },
55 { SDR_FLAG_ENV_MAP, 3, {"sEnvmap", "alpha_spec", "envMatrix"}, 0, { NULL }, "Environment Mapping" },
56 { SDR_FLAG_ANIMATED, 5, {"sFramebuffer", "effect_num", "anim_timer", "vpwidth", "vpheight"}, 0, { NULL }, "Animated Effects" },
57 { SDR_FLAG_MISC_MAP, 1, {"sMiscmap"}, 0, { NULL }, "Utility mapping" },
58 { SDR_FLAG_TEAMCOLOR, 2, {"stripe_color", "base_color"}, 0, { NULL }, "Team Colors" },
59 { SDR_FLAG_THRUSTER, 1, {"thruster_scale"}, 0, { NULL }, "Thruster scaling" }
60 };
61
62 static const int Main_shader_flag_references = sizeof(GL_Uniform_Reference_Main) / sizeof(opengl_shader_uniform_reference_t);
63
64 /**
65 * Static lookup referene for particle shader uniforms
66 */
67 static opengl_shader_uniform_reference_t GL_Uniform_Reference_Particle[] = {
68 { (SDR_FLAG_SOFT_QUAD | SDR_FLAG_DISTORTION), 6, {"baseMap", "window_width", "window_height", "distMap", "frameBuffer", "use_offset"}, 1, { "offset_in" }, "Distorted Particles" },
69 { (SDR_FLAG_SOFT_QUAD), 6, {"baseMap", "depthMap", "window_width", "window_height", "nearZ", "farZ"}, 1, { "radius_in" }, "Depth-blended Particles" }
70 };
71
72 static const int Particle_shader_flag_references = sizeof(GL_Uniform_Reference_Particle) / sizeof(opengl_shader_uniform_reference_t);
73
74 opengl_shader_t *Current_shader = NULL;
75
76
77 void opengl_shader_check_info_log(GLhandleARB shader_object);
78
79 /**
80 * Set the currently active shader
81 * @param shader_obj Pointer to an opengl_shader_t object. This function calls glUseProgramARB with parameter 0 if shader_obj is NULL or if function is called without parameters, causing OpenGL to revert to fixed-function processing
82 */
opengl_shader_set_current(opengl_shader_t * shader_obj)83 void opengl_shader_set_current(opengl_shader_t *shader_obj)
84 {
85 if (shader_obj != NULL) {
86 if(!Current_shader || (Current_shader->program_id != shader_obj->program_id)) {
87 Current_shader = shader_obj;
88 vglUseProgramObjectARB(Current_shader->program_id);
89
90 #ifndef NDEBUG
91 if ( opengl_check_for_errors("shader_set_current()") ) {
92 vglValidateProgramARB(Current_shader->program_id);
93
94 GLint obj_status = 0;
95 vglGetObjectParameterivARB(Current_shader->program_id, GL_OBJECT_VALIDATE_STATUS_ARB, &obj_status);
96
97 if ( !obj_status ) {
98 opengl_shader_check_info_log(Current_shader->program_id);
99
100 mprintf(("VALIDATE INFO-LOG:\n"));
101
102 if (strlen(GLshader_info_log) > 5) {
103 mprintf(("%s\n", GLshader_info_log));
104 } else {
105 mprintf(("<EMPTY>\n"));
106 }
107 }
108 }
109 #endif
110 }
111 } else {
112 Current_shader = NULL;
113 vglUseProgramObjectARB(0);
114 }
115 }
116
117 /**
118 * Given a set of flags, determine whether a shader with these flags exists within the GL_shader vector. If no shader with the requested flags exists, attempt to compile one.
119 *
120 * @param flags Integer variable, holding a combination of SDR_* flags
121 * @return Index into GL_shader, referencing a valid shader, or -1 if shader compilation failed
122 */
gr_opengl_maybe_create_shader(int flags)123 int gr_opengl_maybe_create_shader(int flags)
124 {
125 if (Use_GLSL < 2)
126 return -1;
127
128 size_t idx;
129 size_t max = GL_shader.size();
130
131 for (idx = 0; idx < max; idx++) {
132 if (GL_shader[idx].flags == flags) {
133 return idx;
134 }
135 }
136
137 // If we are here, it means we need to compile a new shader
138 opengl_compile_main_shader(flags);
139 if (GL_shader.back().flags == flags)
140 return (int)GL_shader.size() - 1;
141
142 // If even that has failed, bail
143 return -1;
144 }
145
146 /**
147 * Go through GL_shader and call glDeleteObject() for all created shaders, then clear GL_shader
148 */
opengl_shader_shutdown()149 void opengl_shader_shutdown()
150 {
151 size_t i;
152
153 if ( !Use_GLSL ) {
154 return;
155 }
156
157 for (i = 0; i < GL_shader.size(); i++) {
158 if (GL_shader[i].program_id) {
159 vglDeleteObjectARB(GL_shader[i].program_id);
160 GL_shader[i].program_id = 0;
161 }
162
163 GL_shader[i].uniforms.clear();
164 }
165
166 GL_shader.clear();
167
168 if (GLshader_info_log != NULL) {
169 vm_free(GLshader_info_log);
170 GLshader_info_log = NULL;
171 }
172 }
173
174 /**
175 * Load a shader file from disc or from the builtin defaults in def_files.cpp if none can be found.
176 * This function will also create a list of preprocessor defines for the GLSL compiler based on the shader flags
177 * and the supported GLSL version as reported by the GPU driver.
178 *
179 * @param filename C-string holding the filename (with extension) of the shader file
180 * @param flags integer variable holding a combination of SDR_* flags
181 * @return C-string holding the complete shader source code
182 */
opengl_load_shader(char * filename,int flags)183 static char *opengl_load_shader(char *filename, int flags)
184 {
185 SCP_string sflags;
186
187 if (Use_GLSL >= 4) {
188 sflags += "#define SHADER_MODEL 4\n";
189 } else if (Use_GLSL == 3) {
190 sflags += "#define SHADER_MODEL 3\n";
191 } else {
192 sflags += "#define SHADER_MODEL 2\n";
193 }
194
195 if (flags & SDR_FLAG_DIFFUSE_MAP) {
196 sflags += "#define FLAG_DIFFUSE_MAP\n";
197 }
198
199 if (flags & SDR_FLAG_ENV_MAP) {
200 sflags += "#define FLAG_ENV_MAP\n";
201 }
202
203 if (flags & SDR_FLAG_FOG) {
204 sflags += "#define FLAG_FOG\n";
205 }
206
207 if (flags & SDR_FLAG_GLOW_MAP) {
208 sflags += "#define FLAG_GLOW_MAP\n";
209 }
210
211 if (flags & SDR_FLAG_HEIGHT_MAP) {
212 sflags += "#define FLAG_HEIGHT_MAP\n";
213 }
214
215 if (flags & SDR_FLAG_LIGHT) {
216 sflags += "#define FLAG_LIGHT\n";
217 }
218
219 if (flags & SDR_FLAG_NORMAL_MAP) {
220 sflags += "#define FLAG_NORMAL_MAP\n";
221 }
222
223 if (flags & SDR_FLAG_SPEC_MAP) {
224 sflags += "#define FLAG_SPEC_MAP\n";
225 }
226
227 if (flags & SDR_FLAG_ANIMATED) {
228 sflags += "#define FLAG_ANIMATED\n";
229 }
230
231 if (flags & SDR_FLAG_DISTORTION) {
232 sflags += "#define FLAG_DISTORTION\n";
233 }
234
235 if (flags & SDR_FLAG_MISC_MAP) {
236 sflags += "#define FLAG_MISC_MAP\n";
237 }
238
239 if (flags & SDR_FLAG_TEAMCOLOR) {
240 sflags += "#define FLAG_TEAMCOLOR\n";
241 }
242
243 if (flags & SDR_FLAG_THRUSTER) {
244 sflags += "#define FLAG_THRUSTER\n";
245 }
246
247 const char *shader_flags = sflags.c_str();
248 int flags_len = strlen(shader_flags);
249
250 if (Enable_external_shaders) {
251 CFILE *cf_shader = cfopen(filename, "rt", CFILE_NORMAL, CF_TYPE_EFFECTS);
252
253 if (cf_shader != NULL) {
254 int len = cfilelength(cf_shader);
255 char *shader = (char*) vm_malloc(len + flags_len + 1);
256
257 strcpy(shader, shader_flags);
258 memset(shader + flags_len, 0, len + 1);
259 cfread(shader + flags_len, len + 1, 1, cf_shader);
260 cfclose(cf_shader);
261
262 return shader;
263 }
264 }
265
266 //If we're still here, proceed with internals
267 mprintf((" Loading built-in default shader for: %s\n", filename));
268 char* def_shader = defaults_get_file(filename);
269 size_t len = strlen(def_shader);
270 char *shader = (char*) vm_malloc(len + flags_len + 1);
271
272 strcpy(shader, shader_flags);
273 strcat(shader, def_shader);
274
275 return shader;
276 }
277
278 /**
279 * Compiles a new shader, and creates an opengl_shader_t that will be put into the GL_shader vector
280 * if compilation is successful.
281 * This function is used for main (i.e. model rendering) and particle shaders, post processing shaders use their own infrastructure
282 *
283 * @param flags Combination of SDR_* flags
284 */
opengl_compile_main_shader(int flags)285 void opengl_compile_main_shader(int flags) {
286 char *vert = NULL, *frag = NULL;
287
288 mprintf(("Compiling new shader:\n"));
289
290 bool in_error = false;
291 opengl_shader_t new_shader;
292
293 // choose appropriate files
294 char vert_name[NAME_LENGTH];
295 char frag_name[NAME_LENGTH];
296
297 if (flags & SDR_FLAG_SOFT_QUAD) {
298 strcpy_s( vert_name, "soft-v.sdr");
299 strcpy_s( frag_name, "soft-f.sdr");
300 } else {
301 strcpy_s( vert_name, "main-v.sdr");
302 strcpy_s( frag_name, "main-f.sdr");
303 }
304
305 // read vertex shader
306 if ( (vert = opengl_load_shader(vert_name, flags)) == NULL ) {
307 in_error = true;
308 goto Done;
309 }
310
311 // read fragment shader
312 if ( (frag = opengl_load_shader(frag_name, flags)) == NULL ) {
313 in_error = true;
314 goto Done;
315 }
316
317 Verify( vert != NULL );
318 Verify( frag != NULL );
319
320 new_shader.program_id = opengl_shader_create(vert, frag);
321
322 if ( !new_shader.program_id ) {
323 in_error = true;
324 goto Done;
325 }
326
327 new_shader.flags = flags;
328
329 opengl_shader_set_current( &new_shader );
330
331 mprintf(("Shader features:\n"));
332
333 //Init all the uniforms
334 if (new_shader.flags & SDR_FLAG_SOFT_QUAD) {
335 for (int j = 0; j < Particle_shader_flag_references; j++) {
336 if (new_shader.flags == GL_Uniform_Reference_Particle[j].flag) {
337 int k;
338
339 // Equality check needed because the combination of SDR_FLAG_SOFT_QUAD and SDR_FLAG_DISTORTION define something very different
340 // than just SDR_FLAG_SOFT_QUAD alone
341 for (k = 0; k < GL_Uniform_Reference_Particle[j].num_uniforms; k++) {
342 opengl_shader_init_uniform( GL_Uniform_Reference_Particle[j].uniforms[k] );
343 }
344
345 for (k = 0; k < GL_Uniform_Reference_Particle[j].num_attributes; k++) {
346 opengl_shader_init_attribute( GL_Uniform_Reference_Particle[j].attributes[k] );
347 }
348
349 mprintf((" %s\n", GL_Uniform_Reference_Particle[j].name));
350 }
351 }
352 } else {
353 for (int j = 0; j < Main_shader_flag_references; j++) {
354 if (new_shader.flags & GL_Uniform_Reference_Main[j].flag) {
355 if (GL_Uniform_Reference_Main[j].num_uniforms > 0) {
356 for (int k = 0; k < GL_Uniform_Reference_Main[j].num_uniforms; k++) {
357 opengl_shader_init_uniform( GL_Uniform_Reference_Main[j].uniforms[k] );
358 }
359 }
360
361 if (GL_Uniform_Reference_Main[j].num_attributes > 0) {
362 for (int k = 0; k < GL_Uniform_Reference_Main[j].num_attributes; k++) {
363 opengl_shader_init_attribute( GL_Uniform_Reference_Main[j].attributes[k] );
364 }
365 }
366
367 mprintf((" %s\n", GL_Uniform_Reference_Main[j].name));
368 }
369 }
370 }
371
372 opengl_shader_set_current();
373
374 // add it to our list of embedded shaders
375 GL_shader.push_back( new_shader );
376
377 Done:
378 if (vert != NULL) {
379 vm_free(vert);
380 vert = NULL;
381 }
382
383 if (frag != NULL) {
384 vm_free(frag);
385 frag = NULL;
386 }
387
388 if (in_error) {
389 // shut off relevant usage things ...
390 bool dealt_with = false;
391
392 if (flags & SDR_FLAG_HEIGHT_MAP) {
393 mprintf((" Shader in_error! Disabling height maps!\n"));
394 Cmdline_height = 0;
395 dealt_with = true;
396 }
397
398 if (flags & SDR_FLAG_NORMAL_MAP) {
399 mprintf((" Shader in_error! Disabling normal maps and height maps!\n"));
400 Cmdline_height = 0;
401 Cmdline_normal = 0;
402 dealt_with = true;
403 }
404
405 if (!dealt_with) {
406 if (flags == 0) {
407 mprintf((" Shader in_error! Disabling GLSL!\n"));
408
409 Use_GLSL = 0;
410 Cmdline_height = 0;
411 Cmdline_normal = 0;
412
413 GL_shader.clear();
414 } else {
415 // We died on a lighting shader, probably due to instruction count.
416 // Drop down to a special var that will use fixed-function rendering
417 // but still allow for post-processing to work
418 mprintf((" Shader in_error! Disabling GLSL model rendering!\n"));
419 Use_GLSL = 1;
420 Cmdline_height = 0;
421 Cmdline_normal = 0;
422 }
423 }
424 }
425 }
426
427 /**
428 * Initializes the shader system. Creates a 1x1 texture that can be used as a fallback texture when framebuffer support is missing.
429 * Also compiles the shaders used for particle rendering.
430 */
opengl_shader_init()431 void opengl_shader_init()
432 {
433 if ( !Use_GLSL ) {
434 return;
435 }
436
437 glGenTextures(1,&Framebuffer_fallback_texture_id);
438 GL_state.Texture.SetActiveUnit(0);
439 GL_state.Texture.SetTarget(GL_TEXTURE_2D);
440 GL_state.Texture.Enable(Framebuffer_fallback_texture_id);
441
442 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
443 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
444 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
445 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
446 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
447 GLuint pixels[4] = {0,0,0,0};
448 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &pixels);
449
450 if (Cmdline_no_glsl_model_rendering) {
451 Use_GLSL = 1;
452 }
453
454 GL_shader.clear();
455
456 // Reserve 32 shader slots. This should cover most use cases in real life.
457 GL_shader.reserve(32);
458
459 // Compile the particle shaders, since these are most definitely going to be used
460 opengl_compile_main_shader(SDR_FLAG_SOFT_QUAD);
461 opengl_compile_main_shader(SDR_FLAG_SOFT_QUAD | SDR_FLAG_DISTORTION);
462
463 mprintf(("\n"));
464 }
465
466 /**
467 * Retrieve the compilation log for a given shader object, and store it in the GLshader_info_log global variable
468 *
469 * @param shader_object OpenGL handle of a shader object
470 */
opengl_shader_check_info_log(GLhandleARB shader_object)471 void opengl_shader_check_info_log(GLhandleARB shader_object)
472 {
473 if (GLshader_info_log == NULL) {
474 GLshader_info_log = (char *) vm_malloc(GLshader_info_log_size);
475 }
476
477 memset(GLshader_info_log, 0, GLshader_info_log_size);
478
479 vglGetInfoLogARB(shader_object, GLshader_info_log_size-1, 0, GLshader_info_log);
480 }
481
482 /**
483 * Pass a GLSL shader source to OpenGL and compile it into a usable shader object.
484 * Prints compilation errors (if any) to the log.
485 * Note that this will only compile shaders into objects, linking them into executables happens later
486 *
487 * @param shader_source GLSL sourcecode for the shader
488 * @param shader_type OpenGL ID for the type of shader being used, like GL_FRAGMENT_SHADER_ARB, GL_VERTEX_SHADER_ARB
489 * @return OpenGL handle for the compiled shader object
490 */
opengl_shader_compile_object(const GLcharARB * shader_source,GLenum shader_type)491 GLhandleARB opengl_shader_compile_object(const GLcharARB *shader_source, GLenum shader_type)
492 {
493 GLhandleARB shader_object = 0;
494 GLint status = 0;
495
496 shader_object = vglCreateShaderObjectARB(shader_type);
497
498 vglShaderSourceARB(shader_object, 1, &shader_source, NULL);
499 vglCompileShaderARB(shader_object);
500
501 // check if the compile was successful
502 vglGetObjectParameterivARB(shader_object, GL_OBJECT_COMPILE_STATUS_ARB, &status);
503
504 opengl_shader_check_info_log(shader_object);
505
506 // we failed, bail out now...
507 if (status == 0) {
508 // basic error check
509 mprintf(("%s shader failed to compile:\n%s\n", (shader_type == GL_VERTEX_SHADER_ARB) ? "Vertex" : "Fragment", GLshader_info_log));
510
511 // this really shouldn't exist, but just in case
512 if (shader_object) {
513 vglDeleteObjectARB(shader_object);
514 }
515
516 return 0;
517 }
518
519 // we succeeded, maybe output warnings too
520 if (strlen(GLshader_info_log) > 5) {
521 nprintf(("SHADER-DEBUG", "%s shader compiled with warnings:\n%s\n", (shader_type == GL_VERTEX_SHADER_ARB) ? "Vertex" : "Fragment", GLshader_info_log));
522 }
523
524 return shader_object;
525 }
526
527 /**
528 * Link a vertex shader object and a fragment shader object into a usable shader executable.
529 * Prints linker errors (if any) to the log.
530 *
531 * @param vertex_object Compiled vertex shader object
532 * @param fragment_object Compiled fragment shader object
533 * @return Shader executable
534 */
opengl_shader_link_object(GLhandleARB vertex_object,GLhandleARB fragment_object)535 GLhandleARB opengl_shader_link_object(GLhandleARB vertex_object, GLhandleARB fragment_object)
536 {
537 GLhandleARB shader_object = 0;
538 GLint status = 0;
539
540 shader_object = vglCreateProgramObjectARB();
541
542 if (vertex_object) {
543 vglAttachObjectARB(shader_object, vertex_object);
544 }
545
546 if (fragment_object) {
547 vglAttachObjectARB(shader_object, fragment_object);
548 }
549
550 vglLinkProgramARB(shader_object);
551
552 // check if the link was successful
553 vglGetObjectParameterivARB(shader_object, GL_OBJECT_LINK_STATUS_ARB, &status);
554
555 opengl_shader_check_info_log(shader_object);
556
557 // we failed, bail out now...
558 if (status == 0) {
559 mprintf(("Shader failed to link:\n%s\n", GLshader_info_log));
560
561 if (shader_object) {
562 vglDeleteObjectARB(shader_object);
563 }
564
565 return 0;
566 }
567
568 // we succeeded, maybe output warnings too
569 if (strlen(GLshader_info_log) > 5) {
570 nprintf(("SHADER-DEBUG", "Shader linked with warnings:\n%s\n", GLshader_info_log));
571 }
572
573 return shader_object;
574 }
575
576 /**
577 * Creates an executable shader.
578 *
579 * @param vs Vertex shader source code
580 * @param fs Fragment shader source code
581 * @return Internal ID of the compiled and linked shader as generated by OpenGL
582 */
opengl_shader_create(const char * vs,const char * fs)583 GLhandleARB opengl_shader_create(const char *vs, const char *fs)
584 {
585 GLhandleARB vs_o = 0;
586 GLhandleARB fs_o = 0;
587 GLhandleARB program = 0;
588
589 if (vs) {
590 vs_o = opengl_shader_compile_object( (const GLcharARB*)vs, GL_VERTEX_SHADER_ARB );
591
592 if ( !vs_o ) {
593 mprintf(("ERROR! Unable to create vertex shader!\n"));
594 goto Done;
595 }
596 }
597
598 if (fs) {
599 fs_o = opengl_shader_compile_object( (const GLcharARB*)fs, GL_FRAGMENT_SHADER_ARB );
600
601 if ( !fs_o ) {
602 mprintf(("ERROR! Unable to create fragment shader!\n"));
603 goto Done;
604 }
605 }
606
607 program = opengl_shader_link_object(vs_o, fs_o);
608
609 if ( !program ) {
610 mprintf(("ERROR! Unable to create shader program!\n"));
611 }
612
613 Done:
614 if (vs_o) {
615 vglDeleteObjectARB(vs_o);
616 }
617
618 if (fs_o) {
619 vglDeleteObjectARB(fs_o);
620 }
621
622 return program;
623 }
624
625 /**
626 * Initialize a shader attribute. Requires that the Current_shader global variable is valid.
627 *
628 * @param attribute_text Name of the attribute to be initialized
629 */
opengl_shader_init_attribute(const char * attribute_text)630 void opengl_shader_init_attribute(const char *attribute_text)
631 {
632 opengl_shader_uniform_t new_attribute;
633
634 if ( ( Current_shader == NULL ) || ( attribute_text == NULL ) ) {
635 Int3();
636 return;
637 }
638
639 new_attribute.text_id = attribute_text;
640 new_attribute.location = vglGetAttribLocationARB(Current_shader->program_id, attribute_text);
641
642 if ( new_attribute.location < 0 ) {
643 nprintf(("SHADER-DEBUG", "WARNING: Unable to get shader attribute location for \"%s\"!\n", attribute_text));
644 return;
645 }
646
647 Current_shader->attributes.push_back( new_attribute );
648 }
649
650 /**
651 * Get the internal OpenGL location for a given attribute. Requires that the Current_shader global variable is valid
652 *
653 * @param attribute_text Name of the attribute
654 * @return Internal OpenGL location for the attribute
655 */
opengl_shader_get_attribute(const char * attribute_text)656 GLint opengl_shader_get_attribute(const char *attribute_text)
657 {
658 if ( (Current_shader == NULL) || (attribute_text == NULL) ) {
659 Int3();
660 return -1;
661 }
662
663 SCP_vector<opengl_shader_uniform_t>::iterator attribute;
664
665 for (attribute = Current_shader->attributes.begin(); attribute != Current_shader->attributes.end(); ++attribute) {
666 if ( !attribute->text_id.compare(attribute_text) ) {
667 return attribute->location;
668 }
669 }
670
671 return -1;
672 }
673
674 /**
675 * Initialize a shader uniform. Requires that the Current_shader global variable is valid.
676 *
677 * @param uniform_text Name of the uniform to be initialized
678 */
opengl_shader_init_uniform(const char * uniform_text)679 void opengl_shader_init_uniform(const char *uniform_text)
680 {
681 opengl_shader_uniform_t new_uniform;
682
683 if ( (Current_shader == NULL) || (uniform_text == NULL) ) {
684 Int3();
685 return;
686 }
687
688 new_uniform.text_id = uniform_text;
689 new_uniform.location = vglGetUniformLocationARB(Current_shader->program_id, uniform_text);
690
691 if (new_uniform.location < 0) {
692 nprintf(("SHADER-DEBUG", "WARNING: Unable to get shader uniform location for \"%s\"!\n", uniform_text));
693 return;
694 }
695
696 Current_shader->uniforms.push_back( new_uniform );
697 }
698
699 /**
700 * Get the internal OpenGL location for a given uniform. Requires that the Current_shader global variable is valid
701 *
702 * @param uniform_text Name of the uniform
703 * @return Internal OpenGL location for the uniform
704 */
opengl_shader_get_uniform(const char * uniform_text)705 GLint opengl_shader_get_uniform(const char *uniform_text)
706 {
707 if ( (Current_shader == NULL) || (uniform_text == NULL) ) {
708 Int3();
709 return -1;
710 }
711
712 SCP_vector<opengl_shader_uniform_t>::iterator uniform;
713 SCP_vector<opengl_shader_uniform_t>::iterator uniforms_end = Current_shader->uniforms.end();
714
715 for (uniform = Current_shader->uniforms.begin(); uniform != uniforms_end; ++uniform) {
716 if ( !uniform->text_id.compare(uniform_text) ) {
717 return uniform->location;
718 }
719 }
720
721 return -1;
722 }
723
724 /**
725 * Sets the currently active animated effect.
726 *
727 * @param effect Effect ID, needs to be implemented and checked for in the shader
728 */
opengl_shader_set_animated_effect(int effect)729 void opengl_shader_set_animated_effect(int effect)
730 {
731 Assert(effect > -1);
732 Effect_num = effect;
733 }
734
735 /**
736 * Returns the currently active animated effect ID.
737 *
738 * @return Currently active effect ID
739 */
opengl_shader_get_animated_effect()740 int opengl_shader_get_animated_effect()
741 {
742 return Effect_num;
743 }
744
745 /**
746 * Set the timer for animated effects.
747 *
748 * @param timer Timer value to be passed to the shader
749 */
opengl_shader_set_animated_timer(float timer)750 void opengl_shader_set_animated_timer(float timer)
751 {
752 Anim_timer = timer;
753 }
754
755 /**
756 * Get the timer for animated effects.
757 */
opengl_shader_get_animated_timer()758 float opengl_shader_get_animated_timer()
759 {
760 return Anim_timer;
761 }
762