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 #include "graphics/opengl/gropenglshader.h"
11
12 #include "ShaderProgram.h"
13
14 #include "cfile/cfile.h"
15 #include "cmdline/cmdline.h"
16 #include "def_files/def_files.h"
17 #include "graphics/2d.h"
18 #include "graphics/grinternal.h"
19 #include "graphics/matrix.h"
20 #include "graphics/opengl/gropengldraw.h"
21 #include "graphics/opengl/gropenglpostprocessing.h"
22 #include "graphics/opengl/gropenglstate.h"
23 #include "graphics/opengl/gropengltexture.h"
24 #include "graphics/opengl/gropengltnl.h"
25 #include "graphics/util/uniform_structs.h"
26 #include "lighting/lighting.h"
27 #include "math/vecmat.h"
28 #include "mod_table/mod_table.h"
29 #include "render/3d.h"
30
31 #include <jansson.h>
32 #include <md5.h>
33
34 SCP_vector<opengl_shader_t> GL_shader;
35
36 typedef std::pair<int, uint32_t> shader_descriptor_t;
37
38 struct key_hasher
39 {
operator ()key_hasher40 size_t operator()(const shader_descriptor_t &obj) const
41 {
42 return obj.first ^ obj.second;
43 }
44 };
45
46 SCP_unordered_map<shader_descriptor_t, size_t, key_hasher> GL_shader_map;
47
48 GLuint Framebuffer_fallback_texture_id = 0;
49
50 SCP_vector<opengl_vert_attrib> GL_vertex_attrib_info =
51 {
52 { opengl_vert_attrib::POSITION, "vertPosition", {{{ 0.0f, 0.0f, 0.0f, 1.0f }}} },
53 { opengl_vert_attrib::COLOR, "vertColor", {{{ 1.0f, 1.0f, 1.0f, 1.0f }}} },
54 { opengl_vert_attrib::TEXCOORD, "vertTexCoord", {{{ 1.0f, 1.0f, 1.0f, 1.0f }}} },
55 { opengl_vert_attrib::NORMAL, "vertNormal", {{{ 0.0f, 0.0f, 1.0f, 0.0f }}} },
56 { opengl_vert_attrib::TANGENT, "vertTangent", {{{ 1.0f, 0.0f, 0.0f, 0.0f }}} },
57 { opengl_vert_attrib::MODEL_ID, "vertModelID", {{{ 0.0f, 0.0f, 0.0f, 0.0f }}} },
58 { opengl_vert_attrib::RADIUS, "vertRadius", {{{ 1.0f, 0.0f, 0.0f, 0.0f }}} },
59 { opengl_vert_attrib::UVEC, "vertUvec", {{{ 0.0f, 1.0f, 0.0f, 0.0f }}} },
60 { opengl_vert_attrib::WORLD_MATRIX, "vertWorldMatrix", {{{ 1.0f, 0.0f, 0.0f, 0.0f }}} },
61 };
62
63 struct opengl_uniform_block_binding {
64 uniform_block_type block_type;
65 const char* name;
66 };
67
68 opengl_uniform_block_binding GL_uniform_blocks[] = {
69 {uniform_block_type::Lights, "lightData"},
70 {uniform_block_type::ModelData, "modelData"},
71 {uniform_block_type::NanoVGData, "NanoVGUniformData"},
72 {uniform_block_type::DecalInfo, "decalInfoData"},
73 {uniform_block_type::DecalGlobals, "decalGlobalData"},
74 {uniform_block_type::DeferredGlobals, "globalDeferredData"},
75 {uniform_block_type::Matrices, "matrixData"},
76 {uniform_block_type::GenericData, "genericData"},
77 };
78
79 /**
80 * Static lookup reference for shader uniforms
81 * When adding a new shader, list all associated uniforms and attributes here
82 */
83 // clang-format off
84 static opengl_shader_type_t GL_shader_types[] = {
85 { SDR_TYPE_MODEL, "main-v.sdr", "main-f.sdr", "main-g.sdr",
86 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::NORMAL, opengl_vert_attrib::TANGENT, opengl_vert_attrib::MODEL_ID }, "Model Rendering", false },
87
88 { SDR_TYPE_EFFECT_PARTICLE, "effect-v.sdr", "effect-f.sdr", "effect-g.sdr",
89 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::RADIUS, opengl_vert_attrib::COLOR }, "Particle Effects", false },
90
91 { SDR_TYPE_EFFECT_DISTORTION, "effect-distort-v.sdr", "effect-distort-f.sdr", 0,
92 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::RADIUS, opengl_vert_attrib::COLOR }, "Distortion Effects", false },
93
94 { SDR_TYPE_POST_PROCESS_MAIN, "post-v.sdr", "post-f.sdr", 0,
95 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Post Processing", false },
96
97 { SDR_TYPE_POST_PROCESS_BLUR, "post-v.sdr", "blur-f.sdr", 0,
98 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Gaussian Blur", false },
99
100 { SDR_TYPE_POST_PROCESS_BLOOM_COMP, "post-v.sdr", "bloom-comp-f.sdr", 0,
101 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Bloom Compositing", false },
102
103 { SDR_TYPE_POST_PROCESS_BRIGHTPASS, "post-v.sdr", "brightpass-f.sdr", 0,
104 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Bloom Brightpass", false },
105
106 { SDR_TYPE_POST_PROCESS_FXAA, "fxaa-v.sdr", "fxaa-f.sdr", 0,
107 { opengl_vert_attrib::POSITION }, "FXAA", false },
108
109 { SDR_TYPE_POST_PROCESS_FXAA_PREPASS, "post-v.sdr", "fxaapre-f.sdr", 0,
110 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "FXAA Prepass", false },
111
112 { SDR_TYPE_POST_PROCESS_LIGHTSHAFTS, "post-v.sdr", "ls-f.sdr", 0,
113 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Lightshafts", false },
114
115 { SDR_TYPE_POST_PROCESS_TONEMAPPING, "post-v.sdr", "tonemapping-f.sdr", 0,
116 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Tonemapping", false },
117
118 { SDR_TYPE_DEFERRED_LIGHTING, "deferred-v.sdr", "deferred-f.sdr", 0,
119 { opengl_vert_attrib::POSITION }, "Deferred Lighting", false },
120
121 { SDR_TYPE_DEFERRED_CLEAR, "deferred-clear-v.sdr", "deferred-clear-f.sdr", 0,
122 { opengl_vert_attrib::POSITION }, "Clear Deferred Lighting Buffer", false },
123
124 { SDR_TYPE_VIDEO_PROCESS, "video-v.sdr", "video-f.sdr", 0,
125 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Video Playback", false },
126
127 { SDR_TYPE_PASSTHROUGH_RENDER, "passthrough-v.sdr", "passthrough-f.sdr", 0,
128 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::COLOR }, "Passthrough", false },
129
130 { SDR_TYPE_SHIELD_DECAL, "shield-impact-v.sdr", "shield-impact-f.sdr", 0,
131 { opengl_vert_attrib::POSITION, opengl_vert_attrib::NORMAL }, "Shield Decals", false },
132
133 { SDR_TYPE_BATCHED_BITMAP, "batched-v.sdr", "batched-f.sdr", nullptr,
134 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::COLOR }, "Batched bitmaps", false },
135
136 { SDR_TYPE_DEFAULT_MATERIAL, "default-material.vert.spv.glsl", "default-material.frag.spv.glsl", nullptr,
137 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD, opengl_vert_attrib::COLOR }, "Default material", true },
138
139 { SDR_TYPE_NANOVG, "nanovg-v.sdr", "nanovg-f.sdr", nullptr,
140 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "NanoVG shader", false },
141
142 { SDR_TYPE_DECAL, "decal-v.sdr", "decal-f.sdr", nullptr,
143 { opengl_vert_attrib::POSITION, opengl_vert_attrib::WORLD_MATRIX }, "Decal rendering", false },
144
145 { SDR_TYPE_SCENE_FOG, "post-v.sdr", "fog-f.sdr", nullptr,
146 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "Scene fogging", false },
147
148 { SDR_TYPE_ROCKET_UI, "rocketui-v.sdr", "rocketui-f.sdr", nullptr,
149 { opengl_vert_attrib::POSITION, opengl_vert_attrib::COLOR, opengl_vert_attrib::TEXCOORD }, "libRocket UI", false },
150
151 { SDR_TYPE_POST_PROCESS_SMAA_EDGE, "smaa-edge-v.sdr", "smaa-edge-f.sdr", nullptr,
152 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "SMAA Edge detection", false },
153
154 { SDR_TYPE_POST_PROCESS_SMAA_BLENDING_WEIGHT, "smaa-blend-v.sdr", "smaa-blend-f.sdr", nullptr,
155 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "SMAA Blending weight calculation", false },
156
157 { SDR_TYPE_POST_PROCESS_SMAA_NEIGHBORHOOD_BLENDING, "smaa-neighbour-v.sdr", "smaa-neighbour-f.sdr", nullptr,
158 { opengl_vert_attrib::POSITION, opengl_vert_attrib::TEXCOORD }, "SMAA Neighborhood Blending", false },
159 };
160 // clang-format on
161
162 /**
163 * Static lookup reference for shader variant uniforms
164 * When adding a new shader variant for a shader, list all associated uniforms and attributes here
165 */
166 static opengl_shader_variant_t GL_shader_variants[] = {
167 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_LIGHT, "FLAG_LIGHT", {}, "Lighting"},
168
169 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_FOG, "FLAG_FOG", {}, "Fog Effect"},
170
171 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_DIFFUSE_MAP, "FLAG_DIFFUSE_MAP", {}, "Diffuse Mapping"},
172
173 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_GLOW_MAP, "FLAG_GLOW_MAP", {}, "Glow Mapping"},
174
175 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_SPEC_MAP, "FLAG_SPEC_MAP", {}, "Specular Mapping"},
176
177 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_NORMAL_MAP, "FLAG_NORMAL_MAP", {}, "Normal Mapping"},
178
179 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_HEIGHT_MAP, "FLAG_HEIGHT_MAP", {}, "Parallax Mapping"},
180
181 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_ENV_MAP, "FLAG_ENV_MAP", {}, "Environment Mapping"},
182
183 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_ANIMATED, "FLAG_ANIMATED", {}, "Animated Effects"},
184
185 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_MISC_MAP, "FLAG_MISC_MAP", {}, "Utility mapping"},
186
187 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_TEAMCOLOR, "FLAG_TEAMCOLOR", {}, "Team Colors"},
188
189 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_DEFERRED, "FLAG_DEFERRED", {}, "Deferred lighting"},
190
191 {SDR_TYPE_MODEL, true, SDR_FLAG_MODEL_SHADOW_MAP, "FLAG_SHADOW_MAP", {}, "Shadow Mapping"},
192
193 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_SHADOWS, "FLAG_SHADOWS", {}, "Shadows"},
194
195 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_THRUSTER, "FLAG_THRUSTER", {}, "Thruster scaling"},
196
197 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_TRANSFORM, "FLAG_TRANSFORM", {}, "Submodel Transforms"},
198
199 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_CLIP, "FLAG_CLIP", {}, "Clip Plane"},
200
201 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_HDR, "FLAG_HDR", {}, "High Dynamic Range"},
202
203 { SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_AMBIENT_MAP, "FLAG_AMBIENT_MAP",
204 { }, "Ambient Occlusion Map"},
205
206 {SDR_TYPE_MODEL, false, SDR_FLAG_MODEL_NORMAL_ALPHA, "FLAG_NORMAL_ALPHA", {}, "Normal Alpha"},
207
208 {SDR_TYPE_MODEL, true, SDR_FLAG_MODEL_THICK_OUTLINES, "FLAG_THICK_OUTLINE", {}, "Thick outlines"},
209
210 {SDR_TYPE_EFFECT_PARTICLE,
211 true,
212 SDR_FLAG_PARTICLE_POINT_GEN,
213 "FLAG_EFFECT_GEOMETRY",
214 {opengl_vert_attrib::UVEC},
215 "Geometry shader point-based particles"},
216
217 {SDR_TYPE_POST_PROCESS_BLUR, false, SDR_FLAG_BLUR_HORIZONTAL, "PASS_0", {}, "Horizontal blur pass"},
218
219 {SDR_TYPE_POST_PROCESS_BLUR, false, SDR_FLAG_BLUR_VERTICAL, "PASS_1", {}, "Vertical blur pass"},
220
221 {SDR_TYPE_NANOVG, false, SDR_FLAG_NANOVG_EDGE_AA, "EDGE_AA", {}, "NanoVG edge anti-alias"},
222
223 {SDR_TYPE_DECAL, false, SDR_FLAG_DECAL_USE_NORMAL_MAP, "USE_NORMAL_MAP", {}, "Decal use scene normal map"},
224 };
225
226 static const int GL_num_shader_variants = sizeof(GL_shader_variants) / sizeof(opengl_shader_variant_t);
227
228 opengl_shader_t *Current_shader = NULL;
229
opengl_shader_t()230 opengl_shader_t::opengl_shader_t() : shader(SDR_TYPE_NONE), flags(0), flags2(0)
231 {
232 }
opengl_shader_t(opengl_shader_t && other)233 opengl_shader_t::opengl_shader_t(opengl_shader_t&& other) noexcept {
234 *this = std::move(other);
235 }
236 // NOLINTNEXTLINE(misc-unconventional-assign-operator)
operator =(opengl_shader_t && other)237 opengl_shader_t& opengl_shader_t::operator=(opengl_shader_t&& other) noexcept {
238 // VS2013 doesn't support implicit move constructors so we need to explicitly declare it
239 shader = other.shader;
240 flags = other.flags;
241 flags2 = other.flags2;
242
243 program = std::move(other.program);
244
245 return *this;
246 }
247
248 /**
249 * Set the currently active shader
250 * @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
251 */
opengl_shader_set_current(opengl_shader_t * shader_obj)252 void opengl_shader_set_current(opengl_shader_t *shader_obj)
253 {
254 if (Current_shader != shader_obj) {
255 GR_DEBUG_SCOPE("Set shader");
256
257 GL_state.Array.ResetVertexAttribs();
258
259 if(shader_obj) {
260 shader_obj->program->use();
261 } else {
262 GL_state.UseProgram(0);
263 }
264
265 Current_shader = shader_obj;
266 }
267 }
268
opengl_shader_set_current(int handle)269 void opengl_shader_set_current(int handle)
270 {
271 Assert(handle >= 0);
272 Assert(handle < (int)GL_shader.size());
273
274 opengl_shader_set_current(&GL_shader[handle]);
275 }
276
opengl_get_shader_idx(shader_type shader_t,unsigned int flags)277 size_t opengl_get_shader_idx(shader_type shader_t, unsigned int flags)
278 {
279 auto found = GL_shader_map.find(shader_descriptor_t(shader_t, flags));
280 if (found != GL_shader_map.end()) {
281 return found->second;
282 }
283 return GL_shader.size();
284 }
285
286 /**
287 * 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.
288 *
289 * @param shader_t shader_type variable, a reference to the shader program needed
290 * @param flags Integer variable, holding a combination of SDR_* flags
291 * @return Index into GL_shader, referencing a valid shader, or -1 if shader compilation failed
292 */
gr_opengl_maybe_create_shader(shader_type shader_t,unsigned int flags)293 int gr_opengl_maybe_create_shader(shader_type shader_t, unsigned int flags)
294 {
295 size_t idx = opengl_get_shader_idx(shader_t, flags);
296
297 if (idx < GL_shader.size())
298 return (int)idx;
299
300 // If we are here, it means we need to compile a new shader
301 return opengl_compile_shader(shader_t, flags);
302 }
303
opengl_delete_shader(int sdr_handle)304 void opengl_delete_shader(int sdr_handle)
305 {
306 Assert(sdr_handle >= 0);
307 Assert(sdr_handle < (int)GL_shader.size());
308 opengl_shader_t &victim = GL_shader[sdr_handle];
309 GL_shader_map.erase(shader_descriptor_t(victim.shader, victim.flags));
310
311 GL_shader[sdr_handle].program.reset();
312
313 GL_shader[sdr_handle].flags = 0;
314 GL_shader[sdr_handle].flags2 = 0;
315 GL_shader[sdr_handle].shader = NUM_SHADER_TYPES;
316 }
317
318 /**
319 * Go through GL_shader and call glDeleteObject() for all created shaders, then clear GL_shader
320 */
opengl_shader_shutdown()321 void opengl_shader_shutdown()
322 {
323 GL_shader.clear();
324 GL_shader_map.clear();
325 }
326
opengl_shader_get_header(shader_type type_id,int flags,bool has_geo_shader)327 static SCP_string opengl_shader_get_header(shader_type type_id, int flags, bool has_geo_shader) {
328 SCP_stringstream sflags;
329
330 sflags << "#version " << GLSL_version << " core\n";
331
332 if (Detail.lighting < 3) {
333 sflags << "#define FLAG_LIGHT_MODEL_BLINN_PHONG\n";
334 }
335
336 if (has_geo_shader) {
337 // If there is a geometry shader then we define a special preprocessor symbol to make writing shaders easier
338 sflags << "#define HAS_GEOMETRY_SHADER\n";
339 }
340
341 if (type_id == SDR_TYPE_POST_PROCESS_MAIN || type_id == SDR_TYPE_POST_PROCESS_LIGHTSHAFTS ||
342 type_id == SDR_TYPE_POST_PROCESS_FXAA || type_id == SDR_TYPE_POST_PROCESS_SMAA_EDGE ||
343 type_id == SDR_TYPE_POST_PROCESS_SMAA_BLENDING_WEIGHT ||
344 type_id == SDR_TYPE_POST_PROCESS_SMAA_NEIGHBORHOOD_BLENDING) {
345 // ignore looking for variants. main post process, lightshafts, and FXAA shaders need special headers to be hacked in
346 opengl_post_shader_header(sflags, type_id, flags);
347 } else {
348 for (int i = 0; i < GL_num_shader_variants; ++i) {
349 opengl_shader_variant_t &variant = GL_shader_variants[i];
350
351 if (type_id == variant.type_id && flags & variant.flag) {
352 sflags << "#define " << variant.flag_text << "\n";
353 }
354 }
355 }
356
357 return sflags.str();
358 }
359
360 /**
361 * Load a shader file from disc or from the builtin defaults in def_files.cpp if none can be found.
362 * This function will also create a list of preprocessor defines for the GLSL compiler based on the shader flags
363 * and the supported GLSL version as reported by the GPU driver.
364 *
365 * @param shader shader_type enum defined with which shader we're loading
366 * @param filename C-string holding the filename (with extension) of the shader file
367 * @param flags integer variable holding a combination of SDR_* flags
368 * @return C-string holding the complete shader source code
369 */
opengl_load_shader(const char * filename)370 static SCP_string opengl_load_shader(const char* filename) {
371 SCP_string content;
372 if (Enable_external_shaders) {
373 CFILE* cf_shader = cfopen(filename, "rt", CFILE_NORMAL, CF_TYPE_EFFECTS);
374
375 if (cf_shader != NULL) {
376 int len = cfilelength(cf_shader);
377 content.resize(len);
378
379 cfread(&content[0], len + 1, 1, cf_shader);
380 cfclose(cf_shader);
381
382 return content;
383 }
384 }
385
386 //If we're still here, proceed with internals
387 mprintf((" Loading built-in default shader for: %s\n", filename));
388 auto def_shader = defaults_get_file(filename);
389 content.assign(reinterpret_cast<const char*>(def_shader.data), def_shader.size);
390
391 return content;
392 }
393
handle_includes_impl(SCP_vector<SCP_string> & include_stack,SCP_stringstream & output,int & include_counter,const SCP_string & filename,const SCP_string & original)394 static void handle_includes_impl(SCP_vector<SCP_string>& include_stack,
395 SCP_stringstream& output,
396 int& include_counter,
397 const SCP_string& filename,
398 const SCP_string& original) {
399 include_stack.emplace_back(filename);
400 auto current_source_number = include_counter + 1;
401
402 const char* INCLUDE_STRING = "#include";
403 SCP_stringstream input(original);
404
405 int line_num = 1;
406 for (SCP_string line; std::getline(input, line);) {
407 auto include_start = line.find(INCLUDE_STRING);
408 if (include_start != SCP_string::npos) {
409 auto first_quote = line.find('"', include_start + strlen(INCLUDE_STRING));
410 auto second_quote = line.find('"', first_quote + 1);
411
412 if (first_quote == SCP_string::npos || second_quote == SCP_string::npos) {
413 Error(LOCATION,
414 "Shader %s:%d: Malformed include line. Could not find both quote charaters.",
415 filename.c_str(),
416 line_num);
417 }
418
419 auto file_name = line.substr(first_quote + 1, second_quote - first_quote - 1);
420 auto existing_name = std::find_if(include_stack.begin(), include_stack.end(), [&file_name](const SCP_string& str) {
421 return str == file_name;
422 });
423 if (existing_name != include_stack.end()) {
424 SCP_stringstream stack_string;
425 for (auto& name : include_stack) {
426 stack_string << "\t" << name << "\n";
427 }
428
429 Error(LOCATION,
430 "Shader %s:%d: Detected cyclic include! Previous includes (top level file first):\n%s",
431 filename.c_str(),
432 line_num,
433 stack_string.str().c_str());
434 }
435
436 ++include_counter;
437 // The second parameter defines which source string we are currently working with. We keep track of how many
438 // excludes have been in the file so far to specify this
439 output << "#line 1 " << include_counter + 1 << "\n";
440
441 handle_includes_impl(include_stack,
442 output,
443 include_counter,
444 file_name,
445 opengl_load_shader(file_name.c_str()));
446
447 // We are done with the include file so now we can return to the original file
448 output << "#line " << line_num + 1 << " " << current_source_number << "\n";
449 } else {
450 output << line << "\n";
451 }
452
453 ++line_num;
454 }
455
456 include_stack.pop_back();
457 }
458
handle_includes(const char * filename,const SCP_string & original)459 static SCP_string handle_includes(const char* filename, const SCP_string& original) {
460 SCP_stringstream output;
461 SCP_vector<SCP_string> include_stack;
462 auto include_counter = 0;
463
464 handle_includes_impl(include_stack, output, include_counter, filename, original);
465
466 return output.str();
467 }
468
469 static SCP_vector<SCP_string>
opengl_get_shader_content(shader_type type_id,const char * filename,int flags,bool has_geo_shader,bool spirv_shader)470 opengl_get_shader_content(shader_type type_id, const char* filename, int flags, bool has_geo_shader, bool spirv_shader)
471 {
472 SCP_vector<SCP_string> parts;
473 if (spirv_shader) {
474 // No need to add a header here or handle includes since the original compiler did that
475 parts.push_back(opengl_load_shader(filename));
476 } else {
477 parts.push_back(opengl_shader_get_header(type_id, flags, has_geo_shader));
478
479 parts.push_back(handle_includes(filename, opengl_load_shader(filename)));
480 }
481
482 return parts;
483 }
484
add_shader_parts(MD5 & md5,const SCP_vector<SCP_string> & parts)485 static void add_shader_parts(MD5& md5, const SCP_vector<SCP_string>& parts) {
486 for (auto& part : parts) {
487 md5.update(part.c_str(), (MD5::size_type) part.size());
488 }
489 }
490
get_shader_hash(const SCP_vector<SCP_string> & vert,const SCP_vector<SCP_string> & geom_content,const SCP_vector<SCP_string> & frag)491 static SCP_string get_shader_hash(const SCP_vector<SCP_string>& vert,
492 const SCP_vector<SCP_string>& geom_content,
493 const SCP_vector<SCP_string>& frag) {
494 MD5 md5;
495 add_shader_parts(md5, vert);
496 add_shader_parts(md5, geom_content);
497 add_shader_parts(md5, frag);
498
499 // Add the attribute locations so that changes get detected
500 for (uint32_t i = 0; i < (uint32_t)GL_vertex_attrib_info.size(); ++i) {
501 md5.update(GL_vertex_attrib_info[i].name.c_str(), (MD5::size_type) GL_vertex_attrib_info[i].name.size());
502 md5.update(reinterpret_cast<const char*>(&i), sizeof(i));
503 }
504
505 md5.update(GL_implementation_id.data(),
506 (MD5::size_type)GL_implementation_id.size() * sizeof(SCP_string::value_type));
507
508 md5.finalize();
509
510 return md5.hexdigest();
511 }
512
do_shader_caching()513 static bool do_shader_caching() {
514 if (!GLAD_GL_ARB_get_program_binary) {
515 // Not supported until OpenGL 4.1
516 return false;
517 }
518 if (Cmdline_noshadercache) {
519 // Shader cache is disabled
520 return false;
521 }
522 return true;
523 }
524
load_cached_shader_binary(opengl::ShaderProgram * program,const SCP_string & hash)525 static bool load_cached_shader_binary(opengl::ShaderProgram* program, const SCP_string& hash) {
526 if (!do_shader_caching()) {
527 return false;
528 }
529
530 auto base_filename = SCP_string("ogl_shader-") + hash;
531
532 auto metadata = base_filename + ".json";
533 auto binary = base_filename + ".bin";
534
535 auto metadata_fp = cfopen(metadata.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE, false,
536 CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
537 if (!metadata_fp) {
538 nprintf(("ShaderCache", "Metadata file does not exist.\n"));
539 return false;
540 }
541
542 auto size = cfilelength(metadata_fp);
543 SCP_string metadata_content;
544 metadata_content.resize((size_t) size);
545 cfread(&metadata_content[0], 1, size, metadata_fp);
546
547 cfclose(metadata_fp);
548
549 auto metadata_root = json_loads(metadata_content.c_str(), 0, nullptr);
550 if (!metadata_root) {
551 mprintf(("Loading of cache metadata failed! Falling back to GLSL shader...\n"));
552 return false;
553 }
554
555 json_int_t format;
556 if (json_unpack(metadata_root, "{sI}", "format", &format) != 0) {
557 mprintf(("Failed to unpack values from metadata JSON! Falling back to GLSL shader...\n"));
558 return false;
559 }
560 auto binary_format = (GLenum) format;
561 json_decref(metadata_root);
562
563 bool supported = false;
564 for (auto supported_fmt : GL_binary_formats) {
565 if ((GLenum)supported_fmt == binary_format) {
566 supported = true;
567 break;
568 }
569 }
570
571 if (!supported) {
572 // This can happen in case an implementation stops supporting a particular binary format
573 nprintf(("ShaderCache", "Unsupported binary format %d encountered in shader cache.\n", binary_format));
574 return false;
575 }
576
577 auto binary_fp = cfopen(binary.c_str(), "rb", CFILE_NORMAL, CF_TYPE_CACHE, false,
578 CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
579 if (!binary_fp) {
580 nprintf(("ShaderCache", "Binary file does not exist.\n"));
581 return false;
582 }
583
584 GR_DEBUG_SCOPE("Loading cached shader");
585
586 SCP_vector<uint8_t> buffer;
587 int length = cfilelength(binary_fp);
588 buffer.resize((size_t) length);
589 cfread(&buffer[0], 1, length, binary_fp);
590
591 cfclose(binary_fp);
592
593 // Load the data!
594 glProgramBinary(program->getShaderHandle(), binary_format, buffer.data(), (GLsizei) buffer.size());
595
596 // Check the status...
597 GLint status;
598 glGetProgramiv(program->getShaderHandle(), GL_LINK_STATUS, &status);
599
600 return status == GL_TRUE;
601 }
json_write_callback(const char * buffer,size_t size,void * data)602 static int json_write_callback(const char *buffer, size_t size, void *data) {
603 CFILE* cfp = (CFILE*)data;
604
605 if ((size_t)cfwrite(buffer, 1, (int)size, cfp) != size) {
606 return -1; // Error
607 } else {
608 return 0; // Success
609 }
610 }
611
cache_program_binary(GLuint program,const SCP_string & hash)612 static void cache_program_binary(GLuint program, const SCP_string& hash) {
613 if (!do_shader_caching()) {
614 return;
615 }
616
617 GR_DEBUG_SCOPE("Saving shader binary");
618
619 GLint size;
620 glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &size);
621
622 if (size <= 0) {
623 // No binary available (I'm looking at you Mesa...)
624 return;
625 }
626
627 SCP_vector<uint8_t> binary;
628 binary.resize((size_t) size);
629 GLenum binary_fmt;
630 GLsizei length;
631 glGetProgramBinary(program, (GLsizei) binary.size(), &length, &binary_fmt, binary.data());
632 if (length == 0) {
633 return;
634 }
635
636 auto base_filename = SCP_string("ogl_shader-") + hash;
637
638 auto metadata_name = base_filename + ".json";
639 auto binary_name = base_filename + ".bin";
640
641 auto metadata_fp = cfopen(metadata_name.c_str(), "wb", CFILE_NORMAL, CF_TYPE_CACHE, false,
642 CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
643 if (!metadata_fp) {
644 mprintf(("Could not open shader cache metadata file!\n"));
645 return;
646 }
647
648 auto metadata = json_pack("{sI}", "format", (json_int_t)binary_fmt);
649 if (json_dump_callback(metadata, json_write_callback, metadata_fp, 0) != 0) {
650 mprintf(("Failed to write shader cache metadata file!\n"));
651 cfclose(metadata_fp);
652 return;
653 }
654 cfclose(metadata_fp);
655 json_decref(metadata);
656
657 auto binary_fp = cfopen(binary_name.c_str(), "wb", CFILE_NORMAL, CF_TYPE_CACHE, false,
658 CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
659 if (!binary_fp) {
660 mprintf(("Could not open shader cache binary file!\n"));
661 return;
662 }
663 cfwrite(binary.data(), 1, (int) binary.size(), binary_fp);
664 cfclose(binary_fp);
665 }
666
opengl_set_default_uniforms(const opengl_shader_t & sdr)667 static void opengl_set_default_uniforms(const opengl_shader_t& sdr) {
668 switch (sdr.shader) {
669 case SDR_TYPE_DEFERRED_LIGHTING:
670 Current_shader->program->Uniforms.setTextureUniform("ColorBuffer", 0);
671 Current_shader->program->Uniforms.setTextureUniform("NormalBuffer", 1);
672 Current_shader->program->Uniforms.setTextureUniform("PositionBuffer", 2);
673 Current_shader->program->Uniforms.setTextureUniform("SpecBuffer", 3);
674 Current_shader->program->Uniforms.setTextureUniform("shadow_map", 4);
675 break;
676
677 case SDR_TYPE_PASSTHROUGH_RENDER:
678 Current_shader->program->Uniforms.setTextureUniform("baseMap", 0);
679 Current_shader->program->Uniforms.setTextureUniform("clipEnabled", 0);
680 break;
681
682 default:
683 // No default values for this shader type.
684 break;
685 }
686 }
687
opengl_compile_shader_actual(shader_type sdr,const uint & flags,opengl_shader_t & new_shader)688 void opengl_compile_shader_actual(shader_type sdr, const uint &flags, opengl_shader_t &new_shader)
689 {
690 opengl_shader_type_t *sdr_info = &GL_shader_types[sdr];
691
692 Assert(sdr_info->type_id == sdr);
693 mprintf(("Compiling new shader:\n"));
694 mprintf((" %s\n", sdr_info->description));
695
696 // figure out if the variant requested needs a geometry shader
697 bool use_geo_sdr = false;
698
699 // do we even have a geometry shader?
700 if (sdr_info->geo != NULL) {
701 for (int i = 0; i < GL_num_shader_variants; ++i) {
702 opengl_shader_variant_t *variant = &GL_shader_variants[i];
703
704 if (variant->type_id == sdr && flags & variant->flag && variant->use_geometry_sdr) {
705 use_geo_sdr = true;
706 break;
707 }
708 }
709 }
710
711 auto vert_content =
712 opengl_get_shader_content(sdr_info->type_id, sdr_info->vert, flags, use_geo_sdr, sdr_info->spirv_shader);
713 auto frag_content =
714 opengl_get_shader_content(sdr_info->type_id, sdr_info->frag, flags, use_geo_sdr, sdr_info->spirv_shader);
715 SCP_vector<SCP_string> geom_content;
716
717 if (use_geo_sdr) {
718 // read geometry shader
719 geom_content =
720 opengl_get_shader_content(sdr_info->type_id, sdr_info->geo, flags, use_geo_sdr, sdr_info->spirv_shader);
721 }
722
723 auto shader_hash = get_shader_hash(vert_content, geom_content, frag_content);
724 std::unique_ptr<opengl::ShaderProgram> program(new opengl::ShaderProgram(sdr_info->description));
725
726 if (!load_cached_shader_binary(program.get(), shader_hash)) {
727 GR_DEBUG_SCOPE("Compiling shader code");
728 try {
729 program->addShaderCode(opengl::STAGE_VERTEX, sdr_info->vert, vert_content);
730 program->addShaderCode(opengl::STAGE_FRAGMENT, sdr_info->frag, frag_content);
731 if (use_geo_sdr) {
732 program->addShaderCode(opengl::STAGE_GEOMETRY, sdr_info->geo, geom_content);
733 }
734
735 for (size_t i = 0; i < GL_vertex_attrib_info.size(); ++i) {
736 // Check that the enum values match the position in the vector to make accessing that information more efficient
737 Assertion(GL_vertex_attrib_info[i].attribute_id == (int)i, "Mistmatch between enum values and attribute vector detected!");
738
739 // assign vert attribute binding locations before we link the shader
740 glBindAttribLocation(program->getShaderHandle(), (GLint)i, GL_vertex_attrib_info[i].name.c_str());
741 }
742
743 // bind fragment data locations before we link the shader
744 glBindFragDataLocation(program->getShaderHandle(), 0, "fragOut0");
745 glBindFragDataLocation(program->getShaderHandle(), 1, "fragOut1");
746 glBindFragDataLocation(program->getShaderHandle(), 2, "fragOut2");
747 glBindFragDataLocation(program->getShaderHandle(), 3, "fragOut3");
748 glBindFragDataLocation(program->getShaderHandle(), 4, "fragOut4");
749
750 if (do_shader_caching()) {
751 // Enable shader caching
752 glProgramParameteri(program->getShaderHandle(), GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
753 }
754
755 program->linkProgram();
756 }
757 catch (const std::exception&) {
758 // Since all shaders are required a compilation failure is a fatal error
759 Error(LOCATION, "A shader failed to compile! Check the debug log for more information.");
760 }
761
762 cache_program_binary(program->getShaderHandle(), shader_hash);
763 }
764
765 new_shader.shader = sdr_info->type_id;
766 new_shader.flags = flags;
767 new_shader.program = std::move(program);
768
769 opengl_shader_set_current(&new_shader);
770
771 // initialize the attributes
772 for (auto& attr : sdr_info->attributes) {
773 new_shader.program->initAttribute(GL_vertex_attrib_info[attr].name, GL_vertex_attrib_info[attr].attribute_id, GL_vertex_attrib_info[attr].default_value);
774 }
775
776 for (auto& uniform_block : GL_uniform_blocks) {
777 auto blockIndex = glGetUniformBlockIndex(new_shader.program->getShaderHandle(), uniform_block.name);
778
779 if (blockIndex != GL_INVALID_INDEX) {
780 glUniformBlockBinding(new_shader.program->getShaderHandle(), blockIndex, static_cast<GLuint>(uniform_block.block_type));
781 }
782 }
783
784 mprintf(("Shader Variant Features:\n"));
785
786 // initialize all uniforms and attributes that are specific to this variant
787 for (int i = 0; i < GL_num_shader_variants; ++i) {
788 opengl_shader_variant_t &variant = GL_shader_variants[i];
789
790 if (sdr_info->type_id == variant.type_id && variant.flag & flags) {
791 for (auto& attr : variant.attributes) {
792 auto& attr_info = GL_vertex_attrib_info[attr];
793 new_shader.program->initAttribute(attr_info.name, attr_info.attribute_id, attr_info.default_value);
794 }
795
796 mprintf((" %s\n", variant.description));
797 }
798 }
799
800 opengl_set_default_uniforms(new_shader);
801 }
802
803 /**
804 * Compiles a new shader, and creates an opengl_shader_t that will be put into the GL_shader vector
805 * if compilation is successful.
806 *
807 * @param sdr Identifier defined with the program we wish to compile
808 * @param flags Combination of SDR_* flags
809 * @param replacement_idx The index of the shader this replaces. If -1, the newly compiled shader will be appended to the GL_shader vector
810 * or inserted at the first available empty slot
811 */
opengl_compile_shader(shader_type sdr,uint flags)812 int opengl_compile_shader(shader_type sdr, uint flags)
813 {
814 GR_DEBUG_SCOPE("Creating new shader");
815
816 int sdr_index = -1;
817 int empty_idx;
818 opengl_shader_t new_shader;
819
820 Assert(sdr < NUM_SHADER_TYPES);
821
822 opengl_compile_shader_actual(sdr, flags, new_shader);
823
824 opengl_shader_set_current();
825
826 // add it to our list of embedded shaders
827 // see if we have empty shader slots
828 empty_idx = -1;
829 for (int i = 0; i < (int)GL_shader.size(); ++i) {
830 if (GL_shader[i].shader == NUM_SHADER_TYPES) {
831 empty_idx = i;
832 break;
833 }
834 }
835
836 int new_shader_shader = new_shader.shader;
837 uint32_t new_shader_flags = new_shader.flags;
838 // then insert it at an empty slot or at the end
839 if ( empty_idx >= 0 ) {
840 GL_shader[empty_idx] = std::move(new_shader);
841 sdr_index = empty_idx;
842 } else {
843 sdr_index = (int)GL_shader.size();
844 GL_shader.push_back(std::move(new_shader));
845 }
846 GL_shader_map[shader_descriptor_t(new_shader_shader, new_shader_flags)] = sdr_index;
847 return sdr_index;
848 }
849
gr_opengl_recompile_all_shaders(const std::function<void (size_t,size_t)> & progress_callback)850 void gr_opengl_recompile_all_shaders(const std::function<void(size_t, size_t)>& progress_callback)
851 {
852 for (auto sdr = GL_shader.begin(); sdr != GL_shader.end(); ++sdr)
853 {
854 if (progress_callback)
855 progress_callback(std::distance(GL_shader.begin(), sdr), GL_shader.size());
856 sdr->program.reset();
857 opengl_compile_shader_actual(sdr->shader, sdr->flags, *sdr);
858 }
859 }
860
opengl_purge_shader_cache_type(const char * ext)861 static void opengl_purge_shader_cache_type(const char* ext) {
862
863 SCP_string filter("*.");
864 filter += ext;
865
866 // Previously the cache files were stored in the mod directory. Since we have a better system now, those files
867 // should be cleaned out. This is only needed if we have a mod directory since otherwise we would delete the actual
868 // cache files
869 if (Cmdline_mod != nullptr && strlen(Cmdline_mod) > 0) {
870 SCP_vector<SCP_string> cache_files;
871 cf_get_file_list(cache_files, CF_TYPE_CACHE, filter.c_str(), CF_SORT_NONE, nullptr,
872 CF_LOCATION_TYPE_PRIMARY_MOD | CF_LOCATION_TYPE_SECONDARY_MODS);
873
874 for (auto& file : cache_files) {
875 cf_delete((file + "." + ext).c_str(), CF_TYPE_CACHE,
876 CF_LOCATION_TYPE_PRIMARY_MOD | CF_LOCATION_TYPE_SECONDARY_MODS);
877 }
878 }
879
880 SCP_vector<SCP_string> cache_files;
881 SCP_vector<file_list_info> file_info;
882 cf_get_file_list(cache_files, CF_TYPE_CACHE, filter.c_str(), CF_SORT_NONE, &file_info,
883 CF_LOCATION_ROOT_USER | CF_LOCATION_ROOT_GAME | CF_LOCATION_TYPE_ROOT);
884
885 Assertion(cache_files.size() == file_info.size(),
886 "cf_get_file_list returned different sizes for file names and file informations!");
887
888 const auto TIMEOUT = 2.0 * 30.0 * 24.0 * 60.0 * 60.0; // purge timeout in seconds which is ~2 months
889 const SCP_string PREFIX = "ogl_shader-";
890
891 auto now = std::time(nullptr);
892 for (size_t i = 0; i < cache_files.size(); ++i) {
893 auto& name = cache_files[i];
894 auto write_time = file_info[i].write_time;
895
896 if (name.compare(0, PREFIX.size(), PREFIX) != 0) {
897 // Not an OpenGL cache file
898 continue;
899 }
900
901 auto diff = std::difftime(now, write_time);
902
903 if (diff > TIMEOUT) {
904 auto full_name = name + "." + ext;
905
906 cf_delete(full_name.c_str(), CF_TYPE_CACHE);
907 }
908 }
909 }
910
opengl_purge_old_shader_cache()911 static void opengl_purge_old_shader_cache()
912 {
913 opengl_purge_shader_cache_type("json");
914 opengl_purge_shader_cache_type("bin");
915 }
916
917 /**
918 * Initializes the shader system. Creates a 1x1 texture that can be used as a fallback texture when framebuffer support is missing.
919 * Also compiles the shaders used for particle rendering.
920 */
opengl_shader_init()921 void opengl_shader_init()
922 {
923 glGenTextures(1,&Framebuffer_fallback_texture_id);
924 GL_state.Texture.SetActiveUnit(0);
925 GL_state.Texture.SetTarget(GL_TEXTURE_2D);
926 GL_state.Texture.Enable(Framebuffer_fallback_texture_id);
927
928 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
929 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
930 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
931 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
932 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
933 GLuint pixels[4] = {0,0,0,0};
934 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &pixels);
935
936 GL_shader.clear();
937 GL_shader_map.clear();
938
939 // Reserve 32 shader slots. This should cover most use cases in real life.
940 GL_shader.reserve(32);
941
942 opengl_purge_old_shader_cache();
943
944 // compile effect shaders
945 gr_opengl_maybe_create_shader(SDR_TYPE_EFFECT_PARTICLE, 0);
946 gr_opengl_maybe_create_shader(SDR_TYPE_EFFECT_PARTICLE, SDR_FLAG_PARTICLE_POINT_GEN);
947 gr_opengl_maybe_create_shader(SDR_TYPE_EFFECT_DISTORTION, 0);
948
949 gr_opengl_maybe_create_shader(SDR_TYPE_SHIELD_DECAL, 0);
950
951 // compile deferred lighting shaders
952 gr_opengl_maybe_create_shader(SDR_TYPE_DEFERRED_LIGHTING, 0);
953 gr_opengl_maybe_create_shader(SDR_TYPE_DEFERRED_CLEAR, 0);
954
955 // compile passthrough shader
956 mprintf(("Compiling passthrough shader...\n"));
957 gr_opengl_maybe_create_shader(SDR_TYPE_PASSTHROUGH_RENDER, 0);
958
959 mprintf(("\n"));
960 }
961
962 /**
963 * Get the internal OpenGL location for a given attribute. Requires that the Current_shader global variable is valid
964 *
965 * @param attribute_text Name of the attribute
966 * @return Internal OpenGL location for the attribute
967 */
opengl_shader_get_attribute(opengl_vert_attrib::attrib_id attribute)968 GLint opengl_shader_get_attribute(opengl_vert_attrib::attrib_id attribute)
969 {
970 Assertion(Current_shader != nullptr, "Current shader may not be null!");
971
972 return Current_shader->program->getAttributeLocation(attribute);
973 }
974
opengl_shader_set_passthrough(bool textured,bool hdr)975 void opengl_shader_set_passthrough(bool textured, bool hdr)
976 {
977 opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_PASSTHROUGH_RENDER, 0));
978
979 gr_matrix_set_uniforms();
980
981 opengl_set_generic_uniform_data<graphics::generic_data::passthrough_data>(
982 [=](graphics::generic_data::passthrough_data* data) {
983 data->noTexturing = textured ? 0 : 1;
984 data->srgb = hdr ? 1 : 0;
985 });
986 }
987
opengl_shader_set_default_material(bool textured,bool alpha,vec4 * clr,float color_scale,uint32_t array_index,const material::clip_plane & clip_plane)988 void opengl_shader_set_default_material(bool textured, bool alpha, vec4* clr, float color_scale, uint32_t array_index,
989 const material::clip_plane& clip_plane)
990 {
991 Current_shader->program->Uniforms.setTextureUniform("baseMap", 0);
992
993 opengl_set_generic_uniform_data<genericData_default_material_vert>(
994 [=](genericData_default_material_vert* data) {
995 if (textured) {
996 data->noTexturing = 0;
997 data->baseMapIndex = array_index;
998 } else {
999 data->noTexturing = 1;
1000 // array_index is probably not valid here
1001 data->baseMapIndex = 0;
1002 }
1003
1004 if (alpha) {
1005 data->alphaTexture = 1;
1006 } else {
1007 data->alphaTexture = 0;
1008 }
1009
1010 if (High_dynamic_range) {
1011 data->srgb = 1;
1012 data->intensity = color_scale;
1013 } else {
1014 data->srgb = 0;
1015 data->intensity = 1.0f;
1016 }
1017
1018 data->alphaThreshold = GL_alpha_threshold;
1019
1020 if (clr != nullptr) {
1021 data->color = *clr;
1022 } else {
1023 data->color.xyzw.x = 1.0f;
1024 data->color.xyzw.y = 1.0f;
1025 data->color.xyzw.z = 1.0f;
1026 data->color.xyzw.w = 1.0f;
1027 }
1028
1029 if (clip_plane.enabled) {
1030 data->clipEnabled = 1;
1031
1032 vec4 clip_equation;
1033 clip_equation.xyzw.x = clip_plane.normal.xyz.x;
1034 clip_equation.xyzw.y = clip_plane.normal.xyz.y;
1035 clip_equation.xyzw.z = clip_plane.normal.xyz.z;
1036 clip_equation.xyzw.w = -vm_vec_dot(&clip_plane.normal, &clip_plane.position);
1037
1038 data->clipEquation = clip_equation;
1039 data->modelMatrix = gr_model_matrix_stack.get_transform();
1040 } else {
1041 data->clipEnabled = 0;
1042 }
1043 });
1044
1045 gr_matrix_set_uniforms();
1046 }
1047