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 #ifdef _WIN32
12 #include <windows.h>
13 #endif
14
15 #include "globalincs/alphacolors.h"
16 #include "globalincs/systemvars.h"
17
18 #include "ShaderProgram.h"
19 #include "gropengldeferred.h"
20 #include "gropengldraw.h"
21 #include "gropenglshader.h"
22 #include "gropenglstate.h"
23 #include "gropengltexture.h"
24 #include "gropengltnl.h"
25
26 #include "cmdline/cmdline.h"
27 #include "def_files/def_files.h"
28 #include "graphics/2d.h"
29 #include "graphics/grinternal.h"
30 #include "graphics/light.h"
31 #include "graphics/material.h"
32 #include "graphics/matrix.h"
33 #include "graphics/shadows.h"
34 #include "graphics/util/uniform_structs.h"
35 #include "lighting/lighting.h"
36 #include "math/vecmat.h"
37 #include "options/Option.h"
38 #include "particle/particle.h"
39 #include "render/3d.h"
40 #include "weapon/trails.h"
41
42 extern int GLOWMAP;
43 extern int SPECMAP;
44 extern int SPECGLOSSMAP;
45 extern int NORMMAP;
46 extern int MISCMAP;
47 extern int HEIGHTMAP;
48 extern int G3_user_clip;
49 extern vec3d G3_user_clip_normal;
50 extern vec3d G3_user_clip_point;
51
52 extern bool Basemap_override;
53 extern bool Envmap_override;
54 extern bool Specmap_override;
55 extern bool Normalmap_override;
56 extern bool Heightmap_override;
57 extern bool Shadow_override;
58
59 size_t GL_vertex_data_in = 0;
60
61 GLint GL_max_elements_vertices = 4096;
62 GLint GL_max_elements_indices = 4096;
63
64 GLuint Shadow_map_texture = 0;
65 GLuint Shadow_map_depth_texture = 0;
66 GLuint shadow_fbo = 0;
67 int Shadow_texture_size = 0;
68
69 gr_buffer_handle Transform_buffer_handle;
70
71 SCP_unordered_map<vertex_layout, GLuint> Stored_vertex_arrays;
72
73 static opengl_vertex_bind GL_array_binding_data[] =
74 {
75 { vertex_format_data::POSITION4, 4, GL_FLOAT, GL_FALSE, opengl_vert_attrib::POSITION },
76 { vertex_format_data::POSITION3, 3, GL_FLOAT, GL_FALSE, opengl_vert_attrib::POSITION },
77 { vertex_format_data::POSITION2, 2, GL_FLOAT, GL_FALSE, opengl_vert_attrib::POSITION },
78 { vertex_format_data::SCREEN_POS, 2, GL_INT, GL_FALSE, opengl_vert_attrib::POSITION },
79 { vertex_format_data::COLOR3, 3, GL_UNSIGNED_BYTE, GL_TRUE,opengl_vert_attrib::COLOR },
80 { vertex_format_data::COLOR4, 4, GL_UNSIGNED_BYTE, GL_TRUE, opengl_vert_attrib::COLOR },
81 { vertex_format_data::COLOR4F, 4, GL_FLOAT, GL_FALSE, opengl_vert_attrib::COLOR },
82 { vertex_format_data::TEX_COORD2, 2, GL_FLOAT, GL_FALSE, opengl_vert_attrib::TEXCOORD },
83 { vertex_format_data::TEX_COORD3, 3, GL_FLOAT, GL_FALSE, opengl_vert_attrib::TEXCOORD },
84 { vertex_format_data::NORMAL, 3, GL_FLOAT, GL_FALSE, opengl_vert_attrib::NORMAL },
85 { vertex_format_data::TANGENT, 4, GL_FLOAT, GL_FALSE, opengl_vert_attrib::TANGENT },
86 { vertex_format_data::MODEL_ID, 1, GL_FLOAT, GL_FALSE, opengl_vert_attrib::MODEL_ID },
87 { vertex_format_data::RADIUS, 1, GL_FLOAT, GL_FALSE, opengl_vert_attrib::RADIUS },
88 { vertex_format_data::UVEC, 3, GL_FLOAT, GL_FALSE, opengl_vert_attrib::UVEC },
89 };
90
91 struct opengl_buffer_object {
92 GLuint buffer_id;
93 GLenum type;
94 GLenum gl_usage;
95 BufferUsageHint usage;
96 size_t size;
97
98 GLuint texture; // for texture buffer objects
99 };
100
101 static SCP_vector<opengl_buffer_object> GL_buffer_objects;
102 static int GL_vertex_buffers_in_use = 0;
103
convertBufferType(BufferType type)104 static GLenum convertBufferType(BufferType type) {
105 switch (type) {
106 case BufferType::Vertex:
107 return GL_ARRAY_BUFFER;
108 case BufferType::Index:
109 return GL_ELEMENT_ARRAY_BUFFER;
110 case BufferType::Uniform:
111 return GL_UNIFORM_BUFFER;
112 default:
113 UNREACHABLE("Unhandled enum value!");
114 return GL_INVALID_ENUM;
115 }
116 }
117
convertUsageHint(BufferUsageHint usage)118 static GLenum convertUsageHint(BufferUsageHint usage) {
119 switch(usage) {
120 case BufferUsageHint::Static:
121 return GL_STATIC_DRAW;
122 case BufferUsageHint::Dynamic:
123 return GL_DYNAMIC_DRAW;
124 case BufferUsageHint::Streaming:
125 return GL_STREAM_DRAW;
126 case BufferUsageHint::PersistentMapping:
127 return GL_NONE; // Dummy value
128 default:
129 UNREACHABLE("Unhandled enum value!");
130 return GL_INVALID_ENUM;
131 }
132 }
133
convertStencilOp(const StencilOperation stencil_op)134 static GLenum convertStencilOp(const StencilOperation stencil_op) {
135 switch (stencil_op) {
136 case StencilOperation::Keep:
137 return GL_KEEP;
138 case StencilOperation::Zero:
139 return GL_ZERO;
140 case StencilOperation::Replace:
141 return GL_REPLACE;
142 case StencilOperation::Increment:
143 return GL_INCR;
144 case StencilOperation::IncrementWrap:
145 return GL_INCR_WRAP;
146 case StencilOperation::Decrement:
147 return GL_DECR;
148 case StencilOperation::DecrementWrap:
149 return GL_DECR_WRAP;
150 case StencilOperation::Invert:
151 return GL_INVERT;
152 default:
153 UNREACHABLE("Unhandled enum value encountered!");
154 return GL_NONE;
155 }
156 }
157
convertComparisionFunction(ComparisionFunction func)158 static GLenum convertComparisionFunction(ComparisionFunction func) {
159 GLenum mode;
160 switch (func) {
161 case ComparisionFunction::Always:
162 mode = GL_ALWAYS;
163 break;
164 case ComparisionFunction::Equal:
165 mode = GL_EQUAL;
166 break;
167 case ComparisionFunction::Greater:
168 mode = GL_GREATER;
169 break;
170 case ComparisionFunction::GreaterOrEqual:
171 mode = GL_GEQUAL;
172 break;
173 case ComparisionFunction::Less:
174 mode = GL_LESS;
175 break;
176 case ComparisionFunction::LessOrEqual:
177 mode = GL_LEQUAL;
178 break;
179 case ComparisionFunction::Never:
180 mode = GL_NEVER;
181 break;
182 case ComparisionFunction::NotEqual:
183 mode = GL_NOTEQUAL;
184 break;
185 default:
186 UNREACHABLE("Unhandled comparision function value!");
187 mode = GL_ALWAYS;
188 break;
189 }
190 return mode;
191 }
192
opengl_create_buffer_object(GLenum type,GLenum gl_usage,BufferUsageHint usage)193 gr_buffer_handle opengl_create_buffer_object(GLenum type, GLenum gl_usage, BufferUsageHint usage)
194 {
195 GR_DEBUG_SCOPE("Create buffer object");
196
197 Assertion(usage != BufferUsageHint::PersistentMapping || GLAD_GL_ARB_buffer_storage != 0,
198 "Persistent mapping is not supported by this OpenGL implementation!");
199
200 opengl_buffer_object buffer_obj;
201
202 buffer_obj.gl_usage = gl_usage;
203 buffer_obj.usage = usage;
204 buffer_obj.type = type;
205 buffer_obj.size = 0;
206
207 glGenBuffers(1, &buffer_obj.buffer_id);
208
209 GL_buffer_objects.push_back(buffer_obj);
210
211 return gr_buffer_handle((int)(GL_buffer_objects.size() - 1));
212 }
213
opengl_bind_buffer_object(gr_buffer_handle handle)214 void opengl_bind_buffer_object(gr_buffer_handle handle)
215 {
216 GR_DEBUG_SCOPE("Bind buffer handle");
217
218 Assert(handle.isValid());
219 Assert((size_t)handle.value() < GL_buffer_objects.size());
220
221 opengl_buffer_object &buffer_obj = GL_buffer_objects[handle.value()];
222
223 switch ( buffer_obj.type ) {
224 case GL_ARRAY_BUFFER:
225 GL_state.Array.BindArrayBuffer(buffer_obj.buffer_id);
226 break;
227 case GL_ELEMENT_ARRAY_BUFFER:
228 GL_state.Array.BindElementBuffer(buffer_obj.buffer_id);
229 break;
230 case GL_TEXTURE_BUFFER:
231 GL_state.Array.BindTextureBuffer(buffer_obj.buffer_id);
232 break;
233 case GL_UNIFORM_BUFFER:
234 GL_state.Array.BindUniformBuffer(buffer_obj.buffer_id);
235 break;
236 default:
237 Int3();
238 return;
239 break;
240 }
241 }
opengl_buffer_get_id(GLenum expected_type,gr_buffer_handle handle)242 GLuint opengl_buffer_get_id(GLenum expected_type, gr_buffer_handle handle)
243 {
244 Assert(handle.isValid());
245 Assert((size_t)handle.value() < GL_buffer_objects.size());
246
247 opengl_buffer_object& buffer_obj = GL_buffer_objects[handle.value()];
248
249 Assertion(expected_type == buffer_obj.type, "Expected buffer type did not match the actual buffer type!");
250
251 return buffer_obj.buffer_id;
252 }
253
gr_opengl_update_buffer_data(gr_buffer_handle handle,size_t size,const void * data)254 void gr_opengl_update_buffer_data(gr_buffer_handle handle, size_t size, const void* data)
255 {
256 // This has to be verified by the caller or else we will run into OPenGL errors
257 Assertion(size > 0, "Buffer updates must include some data!");
258
259 GR_DEBUG_SCOPE("Update buffer data");
260
261 Assert(handle.isValid());
262 Assert((size_t)handle.value() < GL_buffer_objects.size());
263
264 opengl_buffer_object &buffer_obj = GL_buffer_objects[handle.value()];
265
266 opengl_bind_buffer_object(handle);
267
268 if (buffer_obj.usage == BufferUsageHint::PersistentMapping) {
269 Assertion(buffer_obj.size == 0, "Tried to resize a buffer for persistent mapping! This is not allowed.");
270 Assertion(GLAD_GL_ARB_buffer_storage != 0, "Persistent mapping was used when it wasn't supported!");
271 glBufferStorage(buffer_obj.type, size, data, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
272 } else {
273 glBufferData(buffer_obj.type, size, data, buffer_obj.gl_usage);
274 }
275
276 GL_vertex_data_in -= buffer_obj.size;
277 buffer_obj.size = size;
278 GL_vertex_data_in += buffer_obj.size;
279 }
280
gr_opengl_update_buffer_data_offset(gr_buffer_handle handle,size_t offset,size_t size,const void * data)281 void gr_opengl_update_buffer_data_offset(gr_buffer_handle handle, size_t offset, size_t size, const void* data)
282 {
283 GR_DEBUG_SCOPE("Update buffer data with offset");
284
285 Assert(handle.isValid());
286 Assert((size_t)handle.value() < GL_buffer_objects.size());
287
288 opengl_buffer_object &buffer_obj = GL_buffer_objects[handle.value()];
289
290 Assertion(buffer_obj.usage != BufferUsageHint::PersistentMapping,
291 "Persistently mapped buffers may not be updated!");
292
293 opengl_bind_buffer_object(handle);
294
295 glBufferSubData(buffer_obj.type, offset, size, data);
296 }
gr_opengl_map_buffer(gr_buffer_handle handle)297 void* gr_opengl_map_buffer(gr_buffer_handle handle)
298 {
299 GR_DEBUG_SCOPE("Map buffer");
300
301 Assert(handle.isValid());
302 Assert((size_t)handle.value() < GL_buffer_objects.size());
303
304 opengl_buffer_object &buffer_obj = GL_buffer_objects[handle.value()];
305
306 Assertion(buffer_obj.usage == BufferUsageHint::PersistentMapping,
307 "Buffer mapping is only supported for persistently mapped buffers!");
308 Assertion(GLAD_GL_ARB_buffer_storage != 0, "Persistent mapping is not available in this OpenGL context!");
309
310 opengl_bind_buffer_object(handle);
311 return glMapBufferRange(buffer_obj.type, 0, buffer_obj.size,
312 GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT);
313 }
gr_opengl_flush_mapped_buffer(gr_buffer_handle handle,size_t offset,size_t size)314 void gr_opengl_flush_mapped_buffer(gr_buffer_handle handle, size_t offset, size_t size)
315 {
316 GR_DEBUG_SCOPE("Flush mapped buffer");
317
318 Assert(handle.isValid());
319 Assert((size_t)handle.value() < GL_buffer_objects.size());
320
321 opengl_buffer_object &buffer_obj = GL_buffer_objects[handle.value()];
322
323 Assertion(buffer_obj.usage == BufferUsageHint::PersistentMapping,
324 "Buffer mapping is only supported for persistently mapped buffers!");
325 Assertion(GLAD_GL_ARB_buffer_storage != 0, "Persistent mapping is not available in this OpenGL context!");
326
327 opengl_bind_buffer_object(handle);
328 glFlushMappedBufferRange(buffer_obj.type, offset, size);
329 }
330
gr_opengl_delete_buffer(gr_buffer_handle handle)331 void gr_opengl_delete_buffer(gr_buffer_handle handle)
332 {
333 if (GL_buffer_objects.size() == 0) return;
334
335 GR_DEBUG_SCOPE("Deleting buffer");
336
337 Assert(handle.isValid());
338 Assert((size_t)handle.value() < GL_buffer_objects.size());
339
340 opengl_buffer_object &buffer_obj = GL_buffer_objects[handle.value()];
341
342 // de-bind the buffer point so we can clear the recorded state.
343 switch ( buffer_obj.type ) {
344 case GL_ARRAY_BUFFER:
345 GL_state.Array.BindArrayBuffer(0);
346 break;
347 case GL_ELEMENT_ARRAY_BUFFER:
348 GL_state.Array.BindElementBuffer(0);
349 break;
350 case GL_TEXTURE_BUFFER:
351 GL_state.Array.BindTextureBuffer(0);
352 break;
353 case GL_UNIFORM_BUFFER:
354 GL_state.Array.BindUniformBuffer(0);
355 break;
356 default:
357 Int3();
358 return;
359 break;
360 }
361
362 if ( buffer_obj.type == GL_TEXTURE_BUFFER ) {
363 glDeleteTextures(1, &buffer_obj.texture);
364 }
365
366 GL_vertex_data_in -= buffer_obj.size;
367
368 glDeleteBuffers(1, &buffer_obj.buffer_id);
369 }
370
gr_opengl_create_buffer(BufferType type,BufferUsageHint usage)371 gr_buffer_handle gr_opengl_create_buffer(BufferType type, BufferUsageHint usage)
372 {
373 return opengl_create_buffer_object(convertBufferType(type), convertUsageHint(usage), usage);
374 }
375
gr_opengl_bind_uniform_buffer(uniform_block_type bind_point,size_t offset,size_t size,gr_buffer_handle buffer)376 void gr_opengl_bind_uniform_buffer(uniform_block_type bind_point, size_t offset, size_t size, gr_buffer_handle buffer) {
377 GR_DEBUG_SCOPE("Bind uniform buffer range");
378
379 GLuint buffer_handle = 0;
380
381 if (buffer.isValid()) {
382 Assert((size_t)buffer.value() < GL_buffer_objects.size());
383
384 opengl_buffer_object &buffer_obj = GL_buffer_objects[buffer.value()];
385
386 Assertion(buffer_obj.type == GL_UNIFORM_BUFFER, "Only uniform buffers are valid for this function!");
387 buffer_handle = buffer_obj.buffer_id;
388 }
389
390 glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(bind_point), buffer_handle, static_cast<GLintptr>(offset),
391 static_cast<GLsizeiptr>(size));
392 }
393
opengl_create_texture_buffer_object()394 gr_buffer_handle opengl_create_texture_buffer_object()
395 {
396 // create the buffer
397 auto buffer_object_handle =
398 opengl_create_buffer_object(GL_TEXTURE_BUFFER, GL_DYNAMIC_DRAW, BufferUsageHint::Dynamic);
399
400 opengl_check_for_errors();
401
402 opengl_buffer_object& buffer_obj = GL_buffer_objects[buffer_object_handle.value()];
403
404 // create the texture
405 glGenTextures(1, &buffer_obj.texture);
406 glBindTexture(GL_TEXTURE_BUFFER, buffer_obj.texture);
407
408 gr_opengl_update_buffer_data(buffer_object_handle, 100, NULL);
409
410 glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, buffer_obj.buffer_id);
411
412 opengl_check_for_errors();
413
414 return buffer_object_handle;
415 }
416
gr_opengl_update_transform_buffer(void * data,size_t size)417 void gr_opengl_update_transform_buffer(void* data, size_t size)
418 {
419 if (!Transform_buffer_handle.isValid() || size <= 0) {
420 return;
421 }
422
423 gr_opengl_update_buffer_data(Transform_buffer_handle, size, data);
424
425 opengl_buffer_object &buffer_obj = GL_buffer_objects[Transform_buffer_handle.value()];
426
427 // need to rebind the buffer object to the texture buffer after it's been updated.
428 // didn't have to do this on AMD and Nvidia drivers but Intel drivers seem to want it.
429 glBindTexture(GL_TEXTURE_BUFFER, buffer_obj.texture);
430 glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, buffer_obj.buffer_id);
431 }
432
opengl_get_transform_buffer_texture()433 GLuint opengl_get_transform_buffer_texture()
434 {
435 if (!Transform_buffer_handle.isValid()) {
436 return 0;
437 }
438
439 return GL_buffer_objects[Transform_buffer_handle.value()].texture;
440 }
441
opengl_destroy_all_buffers()442 void opengl_destroy_all_buffers()
443 {
444 for ( uint i = 0; i < GL_buffer_objects.size(); i++ ) {
445 gr_opengl_delete_buffer(gr_buffer_handle(i));
446 }
447
448 GL_vertex_buffers_in_use = 0;
449 }
450
opengl_init_shadow_framebuffer(int size,GLenum color_format)451 static bool opengl_init_shadow_framebuffer(int size, GLenum color_format)
452 {
453 mprintf(("Trying to create %dx%d %d-bit shadow framebuffer\n", size, size, color_format == GL_RGBA32F ? 32 : 16));
454
455 glGenFramebuffers(1, &shadow_fbo);
456 GL_state.BindFrameBuffer(shadow_fbo);
457
458 glGenTextures(1, &Shadow_map_depth_texture);
459
460 GL_state.Texture.SetActiveUnit(0);
461 GL_state.Texture.SetTarget(GL_TEXTURE_2D_ARRAY);
462 GL_state.Texture.Enable(Shadow_map_depth_texture);
463
464 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
465 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
466 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
467 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
468 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
469 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32, size, size, 4, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
470
471 glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, Shadow_map_depth_texture, 0);
472
473 glGenTextures(1, &Shadow_map_texture);
474
475 GL_state.Texture.SetActiveUnit(0);
476 GL_state.Texture.SetTarget(GL_TEXTURE_2D_ARRAY);
477 GL_state.Texture.Enable(Shadow_map_texture);
478
479 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
480 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
481 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
482 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
483 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
484 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, color_format, size, size, 4, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
485
486 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, Shadow_map_texture, 0);
487
488 auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
489 GL_state.BindFrameBuffer(0);
490
491 if (status == GL_FRAMEBUFFER_COMPLETE) {
492 // Everything is fine
493 mprintf(("Shadow framebuffer created successfully.\n"));
494 Shadow_texture_size = size;
495 return true;
496 }
497
498 // Clean up resources
499 glDeleteTextures(1, &Shadow_map_texture);
500 glDeleteTextures(1, &Shadow_map_depth_texture);
501 glDeleteFramebuffers(1, &shadow_fbo);
502
503 Shadow_map_texture = 0;
504 Shadow_map_depth_texture = 0;
505 shadow_fbo = 0;
506
507 const char* error;
508 switch (status) {
509 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
510 error = "Incomplete framebuffer attachment";
511 break;
512 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
513 error = "Framebuffer is missing an attachment";
514 break;
515 case GL_FRAMEBUFFER_UNSUPPORTED:
516 error = "Framebuffer configuration is unsupported";
517 break;
518 default:
519 error = "Unknown framebuffer status";
520 break;
521 }
522
523 mprintf(("Failed to create framebuffer: %s\n", error));
524 return false;
525 }
526
opengl_tnl_init()527 void opengl_tnl_init()
528 {
529 Transform_buffer_handle = opengl_create_texture_buffer_object();
530
531 if (Shadow_quality != ShadowQuality::Disabled) {
532 int size;
533 switch (Shadow_quality) {
534 case ShadowQuality::Low:
535 size = 512;
536 break;
537 case ShadowQuality::Medium:
538 size = 1024;
539 break;
540 case ShadowQuality::High:
541 size = 2048;
542 break;
543 case ShadowQuality::Ultra:
544 size = 4096;
545 break;
546 default:
547 size = 256;
548 break;
549 }
550
551 if (!opengl_init_shadow_framebuffer(size, GL_RGBA32F)) {
552 if (!opengl_init_shadow_framebuffer(size, GL_RGBA16F)) {
553 mprintf(("Failed to create either 32 or 16-bit color shadow framebuffer. Disabling shadow support.\n"));
554 Shadow_quality = ShadowQuality::Disabled;
555 }
556 }
557 }
558
559 gr_opengl_deferred_init();
560 }
561
opengl_tnl_shutdown()562 void opengl_tnl_shutdown()
563 {
564 for (auto& vao_entry : Stored_vertex_arrays) {
565 glDeleteVertexArrays(1, &vao_entry.second);
566 }
567 Stored_vertex_arrays.clear();
568
569 gr_opengl_deferred_shutdown();
570
571 if ( Shadow_map_depth_texture ) {
572 glDeleteTextures(1, &Shadow_map_depth_texture);
573 Shadow_map_depth_texture = 0;
574 }
575
576 if ( Shadow_map_texture ) {
577 glDeleteTextures(1, &Shadow_map_texture);
578 Shadow_map_texture = 0;
579 }
580
581 opengl_destroy_all_buffers();
582 }
583
opengl_render_model_program(model_material * material_info,indexed_vertex_source * vert_source,vertex_buffer * bufferp,buffer_data * datap)584 void opengl_render_model_program(model_material* material_info, indexed_vertex_source *vert_source, vertex_buffer* bufferp, buffer_data *datap)
585 {
586 GL_state.Texture.SetShaderMode(GL_TRUE);
587
588 opengl_tnl_set_model_material(material_info);
589
590 auto ibuffer = reinterpret_cast<GLubyte*>(vert_source->Index_offset);
591
592 GLenum element_type = (datap->flags & VB_FLAG_LARGE_INDEX) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
593
594 Assert(vert_source);
595 Assertion(vert_source->Vbuffer_handle.isValid(), "The vertex data must be located in a GPU buffer!");
596 Assertion(vert_source->Ibuffer_handle.isValid(), "The index values must be located in a GPU buffer!");
597
598 // basic setup of all data
599 opengl_bind_vertex_layout(bufferp->layout,
600 opengl_buffer_get_id(GL_ARRAY_BUFFER, vert_source->Vbuffer_handle),
601 opengl_buffer_get_id(GL_ELEMENT_ARRAY_BUFFER, vert_source->Ibuffer_handle));
602
603 // If GL_ARB_gpu_shader5 is supprted then the instancing is handled by the geometry shader
604 if (!GLAD_GL_ARB_gpu_shader5 && Rendering_to_shadow_map) {
605 glDrawElementsInstancedBaseVertex(GL_TRIANGLES,
606 (GLsizei)datap->n_verts,
607 element_type,
608 ibuffer + datap->index_offset,
609 4,
610 (GLint) (vert_source->Base_vertex_offset + bufferp->vertex_num_offset));
611 } else {
612 if (Cmdline_drawelements) {
613 glDrawElementsBaseVertex(GL_TRIANGLES,
614 (GLsizei) datap->n_verts,
615 element_type,
616 ibuffer + datap->index_offset,
617 (GLint) (vert_source->Base_vertex_offset + bufferp->vertex_num_offset));
618 } else {
619 glDrawRangeElementsBaseVertex(GL_TRIANGLES,
620 datap->i_first,
621 datap->i_last,
622 (GLsizei) datap->n_verts,
623 element_type,
624 ibuffer + datap->index_offset,
625 (GLint) (vert_source->Base_vertex_offset + bufferp->vertex_num_offset));
626 }
627 }
628
629
630 GL_state.Texture.SetShaderMode(GL_FALSE);
631 }
632
gr_opengl_render_model(model_material * material_info,indexed_vertex_source * vert_source,vertex_buffer * bufferp,size_t texi)633 void gr_opengl_render_model(model_material* material_info, indexed_vertex_source *vert_source, vertex_buffer* bufferp, size_t texi)
634 {
635 Verify(bufferp != NULL);
636
637 GL_CHECK_FOR_ERRORS("start of render_buffer()");
638
639 buffer_data *datap = &bufferp->tex_buf[texi];
640
641 opengl_render_model_program(material_info, vert_source, bufferp, datap);
642
643 GL_CHECK_FOR_ERRORS("end of render_buffer()");
644 }
645
646 extern GLuint Framebuffer_fallback_texture_id;
647 extern GLuint Scene_depth_texture;
648 extern GLuint Scene_position_texture;
649 extern GLuint Distortion_texture[2];
650 extern int Distortion_switch;
opengl_create_perspective_projection_matrix(matrix4 * out,float left,float right,float bottom,float top,float near_dist,float far_dist)651 void opengl_create_perspective_projection_matrix(matrix4 *out, float left, float right, float bottom, float top, float near_dist, float far_dist)
652 {
653 memset(out, 0, sizeof(matrix4));
654
655 out->a1d[0] = 2.0f * near_dist / (right - left);
656 out->a1d[5] = 2.0f * near_dist / (top - bottom);
657 out->a1d[8] = (right + left) / (right - left);
658 out->a1d[9] = (top + bottom) / (top - bottom);
659 out->a1d[10] = -(far_dist + near_dist) / (far_dist - near_dist);
660 out->a1d[11] = -1.0f;
661 out->a1d[14] = -2.0f * far_dist * near_dist / (far_dist - near_dist);
662 }
663
opengl_create_orthographic_projection_matrix(matrix4 * out,float left,float right,float bottom,float top,float near_dist,float far_dist)664 void opengl_create_orthographic_projection_matrix(matrix4* out, float left, float right, float bottom, float top, float near_dist, float far_dist)
665 {
666 memset(out, 0, sizeof(matrix4));
667
668 out->a1d[0] = 2.0f / (right - left);
669 out->a1d[5] = 2.0f / (top - bottom);
670 out->a1d[10] = -2.0f / (far_dist - near_dist);
671 out->a1d[12] = -(right + left) / (right - left);
672 out->a1d[13] = -(top + bottom) / (top - bottom);
673 out->a1d[14] = -(far_dist + near_dist) / (far_dist - near_dist);
674 out->a1d[15] = 1.0f;
675 }
676
677 extern bool Glowpoint_override;
678 bool Glowpoint_override_save;
679
680 extern bool gr_htl_projection_matrix_set;
681
gr_opengl_shadow_map_start(matrix4 * shadow_view_matrix,const matrix * light_orient,vec3d * eye_pos)682 void gr_opengl_shadow_map_start(matrix4 *shadow_view_matrix, const matrix *light_orient, vec3d* eye_pos)
683 {
684 if (Shadow_quality == ShadowQuality::Disabled)
685 return;
686
687 GL_state.PushFramebufferState();
688 GL_state.BindFrameBuffer(shadow_fbo);
689
690 //glDrawBuffer(GL_COLOR_ATTACHMENT0);
691 GLenum buffers[] = { GL_COLOR_ATTACHMENT0};
692 glDrawBuffers(1, buffers);
693
694 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
695 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
696
697 gr_set_lighting(false,false);
698
699 Rendering_to_shadow_map = true;
700 Glowpoint_override_save = Glowpoint_override;
701 Glowpoint_override = true;
702
703 gr_htl_projection_matrix_set = true;
704
705 gr_set_view_matrix(eye_pos, light_orient);
706
707 *shadow_view_matrix = gr_view_matrix;
708
709 glViewport(0, 0, Shadow_texture_size, Shadow_texture_size);
710 }
711
gr_opengl_shadow_map_end()712 void gr_opengl_shadow_map_end()
713 {
714 if(!Rendering_to_shadow_map)
715 return;
716
717 gr_end_view_matrix();
718 Rendering_to_shadow_map = false;
719
720 gr_zbuffer_set(ZBUFFER_TYPE_FULL);
721 GL_state.PopFramebufferState();
722
723 Glowpoint_override = Glowpoint_override_save;
724 gr_htl_projection_matrix_set = false;
725
726 glViewport(gr_screen.offset_x, (gr_screen.max_h - gr_screen.offset_y - gr_screen.clip_height), gr_screen.clip_width, gr_screen.clip_height);
727 glScissor(gr_screen.offset_x, (gr_screen.max_h - gr_screen.offset_y - gr_screen.clip_height), gr_screen.clip_width, gr_screen.clip_height);
728 }
729
opengl_tnl_set_material(material * material_info,bool set_base_map,bool set_clipping)730 void opengl_tnl_set_material(material* material_info, bool set_base_map, bool set_clipping)
731 {
732 int shader_handle = material_info->get_shader_handle();
733 int base_map = material_info->get_texture_map(TM_BASE_TYPE);
734 vec4 clr = material_info->get_color();
735
736 Assert(shader_handle >= 0);
737
738 opengl_shader_set_current(shader_handle);
739
740 if (material_info->has_buffer_blend_modes()) {
741 Assertion(GLAD_GL_ARB_draw_buffers_blend != 0,
742 "Buffer blend modes are not supported at the moment! Query the capability before using this feature.");
743
744 auto enable_blend = false;
745 for (auto i = 0; i < (int) material::NUM_BUFFER_BLENDS; ++i) {
746 auto mode = material_info->get_blend_mode(i);
747
748 GL_state.SetAlphaBlendModei(i, mode);
749 enable_blend = enable_blend || mode != ALPHA_BLEND_NONE;
750 }
751 GL_state.Blend(enable_blend ? GL_TRUE : GL_FALSE);
752 } else {
753 GL_state.SetAlphaBlendMode(material_info->get_blend_mode());
754 }
755 GL_state.SetZbufferType(material_info->get_depth_mode());
756
757 gr_set_cull(material_info->get_cull_mode() ? 1 : 0);
758
759 gr_zbias(material_info->get_depth_bias());
760
761 gr_set_fill_mode(material_info->get_fill_mode());
762
763 gr_set_texture_addressing(material_info->get_texture_addressing());
764
765 if (set_clipping) {
766 // Only set the clipping state if explicitly requested by the caller to avoid unnecessary state changes
767 auto& clip_params = material_info->get_clip_plane();
768 if (!clip_params.enabled) {
769 GL_state.ClipDistance(0, false);
770 } else {
771 Assertion(Current_shader != nullptr && (Current_shader->shader == SDR_TYPE_MODEL
772 || Current_shader->shader == SDR_TYPE_DEFAULT_MATERIAL),
773 "Clip planes are not supported by this shader!");
774
775 GL_state.ClipDistance(0, true);
776 }
777 }
778
779 GL_state.StencilMask(material_info->get_stencil_mask());
780
781 auto& stencilFunc = material_info->get_stencil_func();
782 GL_state.StencilFunc(convertComparisionFunction(stencilFunc.compare), stencilFunc.ref, stencilFunc.mask);
783
784 auto& frontStencilOp = material_info->get_front_stencil_op();
785 GL_state.StencilOpSeparate(GL_FRONT,
786 convertStencilOp(frontStencilOp.stencilFailOperation),
787 convertStencilOp(frontStencilOp.depthFailOperation),
788 convertStencilOp(frontStencilOp.successOperation));
789 auto& backStencilOp = material_info->get_back_stencil_op();
790 GL_state.StencilOpSeparate(GL_BACK,
791 convertStencilOp(backStencilOp.stencilFailOperation),
792 convertStencilOp(backStencilOp.depthFailOperation),
793 convertStencilOp(backStencilOp.successOperation));
794
795 GL_state.StencilTest(material_info->is_stencil_enabled() ? GL_TRUE : GL_FALSE);
796
797 auto& color_mask = material_info->get_color_mask();
798 GL_state.ColorMask(color_mask.x, color_mask.y, color_mask.z, color_mask.w);
799
800 // This is only needed for the passthrough shader
801 uint32_t array_index = 0;
802 if ( set_base_map && base_map >= 0 ) {
803 float u_scale, v_scale;
804
805 if ( !gr_opengl_tcache_set(base_map, material_info->get_texture_type(), &u_scale, &v_scale, &array_index) ) {
806 mprintf(("WARNING: Error setting bitmap texture (%i)!\n", base_map));
807 }
808 }
809
810 if ( Current_shader->shader == SDR_TYPE_DEFAULT_MATERIAL ) {
811 opengl_shader_set_default_material(base_map >= 0,
812 material_info->get_texture_type() == TCACHE_TYPE_AABITMAP,
813 &clr,
814 material_info->get_color_scale(),
815 array_index,
816 material_info->get_clip_plane());
817 }
818 }
819
opengl_tnl_set_model_material(model_material * material_info)820 void opengl_tnl_set_model_material(model_material *material_info)
821 {
822 float u_scale, v_scale;
823
824 opengl_tnl_set_material(material_info, false, false);
825
826 if ( GL_state.CullFace() ) {
827 GL_state.FrontFaceValue(GL_CW);
828 }
829
830 gr_set_center_alpha(material_info->get_center_alpha());
831
832 Assert( Current_shader->shader == SDR_TYPE_MODEL );
833
834 GL_state.Texture.SetShaderMode(GL_TRUE);
835
836 if (Current_shader->flags & SDR_FLAG_MODEL_CLIP) {
837 GL_state.ClipDistance(0, true);
838 } else {
839 GL_state.ClipDistance(0, false);
840 }
841
842 uint32_t array_index;
843 if ( Current_shader->flags & SDR_FLAG_MODEL_DIFFUSE_MAP ) {
844 Current_shader->program->Uniforms.setTextureUniform("sBasemap", 0);
845
846 gr_opengl_tcache_set(material_info->get_texture_map(TM_BASE_TYPE), TCACHE_TYPE_NORMAL, &u_scale, &v_scale, &array_index, 0);
847 }
848
849 if ( Current_shader->flags & SDR_FLAG_MODEL_GLOW_MAP ) {
850 Current_shader->program->Uniforms.setTextureUniform("sGlowmap", 1);
851
852 gr_opengl_tcache_set(material_info->get_texture_map(TM_GLOW_TYPE), TCACHE_TYPE_NORMAL, &u_scale, &v_scale, &array_index, 1);
853 }
854
855 if ( Current_shader->flags & SDR_FLAG_MODEL_SPEC_MAP ) {
856 Current_shader->program->Uniforms.setTextureUniform("sSpecmap", 2);
857
858 if ( material_info->get_texture_map(TM_SPEC_GLOSS_TYPE) > 0 ) {
859 gr_opengl_tcache_set(material_info->get_texture_map(TM_SPEC_GLOSS_TYPE), TCACHE_TYPE_NORMAL, &u_scale, &v_scale, &array_index, 2);
860 } else {
861 gr_opengl_tcache_set(material_info->get_texture_map(TM_SPECULAR_TYPE), TCACHE_TYPE_NORMAL, &u_scale, &v_scale, &array_index, 2);
862 }
863
864 if ( Current_shader->flags & SDR_FLAG_MODEL_ENV_MAP ) {
865 Current_shader->program->Uniforms.setTextureUniform("sEnvmap", 3);
866
867 gr_opengl_tcache_set(ENVMAP, TCACHE_TYPE_CUBEMAP, &u_scale, &v_scale, &array_index, 3);
868 Assertion(array_index == 0, "Cube map arrays are not supported yet!");
869 }
870 }
871
872 if ( Current_shader->flags & SDR_FLAG_MODEL_NORMAL_MAP ) {
873 Current_shader->program->Uniforms.setTextureUniform("sNormalmap", 4);
874
875 gr_opengl_tcache_set(material_info->get_texture_map(TM_NORMAL_TYPE), TCACHE_TYPE_NORMAL, &u_scale, &v_scale, &array_index, 4);
876 }
877
878 if ( Current_shader->flags & SDR_FLAG_MODEL_HEIGHT_MAP ) {
879 Current_shader->program->Uniforms.setTextureUniform("sHeightmap", 5);
880
881 gr_opengl_tcache_set(material_info->get_texture_map(TM_HEIGHT_TYPE), TCACHE_TYPE_NORMAL, &u_scale, &v_scale, &array_index, 5);
882 }
883
884 if ( Current_shader->flags & SDR_FLAG_MODEL_AMBIENT_MAP ) {
885 Current_shader->program->Uniforms.setTextureUniform("sAmbientmap", 6);
886
887 gr_opengl_tcache_set(material_info->get_texture_map(TM_AMBIENT_TYPE), TCACHE_TYPE_NORMAL, &u_scale, &v_scale, &array_index, 6);
888 }
889
890 if ( Current_shader->flags & SDR_FLAG_MODEL_MISC_MAP ) {
891 Current_shader->program->Uniforms.setTextureUniform("sMiscmap", 7);
892
893 gr_opengl_tcache_set(material_info->get_texture_map(TM_MISC_TYPE), TCACHE_TYPE_NORMAL, &u_scale, &v_scale, &array_index, 7);
894 }
895
896 if ( Current_shader->flags & SDR_FLAG_MODEL_SHADOWS ) {
897 Current_shader->program->Uniforms.setTextureUniform("shadow_map", 8);
898
899 GL_state.Texture.Enable(8, GL_TEXTURE_2D_ARRAY, Shadow_map_texture);
900 }
901
902 if ( Current_shader->flags & SDR_FLAG_MODEL_ANIMATED ) {
903 Current_shader->program->Uniforms.setTextureUniform("sFramebuffer", 9);
904
905 if ( Scene_framebuffer_in_frame ) {
906 GL_state.Texture.Enable(9, GL_TEXTURE_2D, Scene_effect_texture);
907 glDrawBuffer(GL_COLOR_ATTACHMENT0);
908 } else {
909 GL_state.Texture.Enable(9, GL_TEXTURE_2D, Framebuffer_fallback_texture_id);
910 }
911 }
912
913 if ( Current_shader->flags & SDR_FLAG_MODEL_TRANSFORM ) {
914 Current_shader->program->Uniforms.setTextureUniform("transform_tex", 10);
915 GL_state.Texture.Enable(10, GL_TEXTURE_BUFFER, opengl_get_transform_buffer_texture());
916 }
917
918 if ( Deferred_lighting ) {
919 // don't blend if we're drawing to the g-buffers
920 GL_state.SetAlphaBlendMode(ALPHA_BLEND_NONE);
921 }
922 }
923
opengl_tnl_set_material_particle(particle_material * material_info)924 void opengl_tnl_set_material_particle(particle_material * material_info)
925 {
926 opengl_tnl_set_material(material_info, true);
927
928 gr_matrix_set_uniforms();
929
930 opengl_set_generic_uniform_data<graphics::generic_data::effect_data>(
931 [&](graphics::generic_data::effect_data* data) {
932 data->window_width = (float)gr_screen.max_w;
933 data->window_height = (float)gr_screen.max_h;
934 data->nearZ = Min_draw_distance;
935 data->farZ = Max_draw_distance;
936 data->srgb = High_dynamic_range ? 1 : 0;
937 data->blend_alpha = material_info->get_blend_mode() != ALPHA_BLEND_ADDITIVE;
938
939 if (Cmdline_no_deferred_lighting) {
940 data->linear_depth = 0;
941 } else {
942 data->linear_depth = 1;
943 }
944 });
945
946 Current_shader->program->Uniforms.setTextureUniform("baseMap", 0);
947 Current_shader->program->Uniforms.setTextureUniform("depthMap", 1);
948
949 if (!Cmdline_no_deferred_lighting) {
950 Assert(Scene_position_texture != 0);
951
952 GL_state.Texture.Enable(1, GL_TEXTURE_2D, Scene_position_texture);
953 } else {
954 Assert(Scene_depth_texture != 0);
955
956 GL_state.Texture.Enable(1, GL_TEXTURE_2D, Scene_depth_texture);
957 }
958 }
opengl_tnl_set_material_batched(batched_bitmap_material * material_info)959 void opengl_tnl_set_material_batched(batched_bitmap_material* material_info)
960 {
961 // This material assumes that the array index is supplied via the vertex attributes
962 opengl_tnl_set_material(material_info, true);
963
964 opengl_set_generic_uniform_data<graphics::generic_data::batched_data>(
965 [&](graphics::generic_data::batched_data* data) {
966 data->intensity = material_info->get_color_scale();
967 data->color = material_info->get_color();
968 });
969
970 gr_matrix_set_uniforms();
971
972 Current_shader->program->Uniforms.setTextureUniform("baseMap", 0);
973 }
974
opengl_tnl_set_material_distortion(distortion_material * material_info)975 void opengl_tnl_set_material_distortion(distortion_material* material_info)
976 {
977 opengl_tnl_set_material(material_info, true);
978
979 gr_matrix_set_uniforms();
980
981 Current_shader->program->Uniforms.setTextureUniform("baseMap", 0);
982 Current_shader->program->Uniforms.setTextureUniform("depthMap", 1);
983
984 opengl_set_generic_uniform_data<graphics::generic_data::effect_distort_data>(
985 [&](graphics::generic_data::effect_distort_data* data) {
986 data->window_width = (float)gr_screen.max_w;
987 data->window_height = (float)gr_screen.max_h;
988
989 if (material_info->get_thruster_rendering()) {
990 data->use_offset = 1.0f;
991 } else {
992 data->use_offset = 0.0f;
993 }
994 });
995
996 Current_shader->program->Uniforms.setTextureUniform("frameBuffer", 2);
997 GL_state.Texture.Enable(2, GL_TEXTURE_2D, Scene_effect_texture);
998
999 Current_shader->program->Uniforms.setTextureUniform("distMap", 3);
1000 if (material_info->get_thruster_rendering()) {
1001 GL_state.Texture.Enable(3, GL_TEXTURE_2D, Distortion_texture[!Distortion_switch]);
1002 } else {
1003 // Disable this texture unit
1004 GL_state.Texture.Enable(3, GL_TEXTURE_2D, 0);
1005 }
1006
1007 Assert(Scene_depth_texture != 0);
1008
1009 GL_state.Texture.Enable(1, GL_TEXTURE_2D, Scene_depth_texture);
1010 }
1011
opengl_tnl_set_material_movie(movie_material * material_info)1012 void opengl_tnl_set_material_movie(movie_material* material_info) {
1013 opengl_tnl_set_material(material_info, false);
1014
1015 gr_matrix_set_uniforms();
1016
1017 Current_shader->program->Uniforms.setTextureUniform("ytex", 0);
1018 Current_shader->program->Uniforms.setTextureUniform("utex", 1);
1019 Current_shader->program->Uniforms.setTextureUniform("vtex", 2);
1020
1021 float u_scale, v_scale;
1022 uint32_t index;
1023 if ( !gr_opengl_tcache_set(material_info->getYtex(), material_info->get_texture_type(), &u_scale, &v_scale, &index, 0) ) {
1024 mprintf(("WARNING: Error setting bitmap texture (%i)!\n", material_info->getYtex()));
1025 }
1026 if ( !gr_opengl_tcache_set(material_info->getUtex(), material_info->get_texture_type(), &u_scale, &v_scale, &index, 1) ) {
1027 mprintf(("WARNING: Error setting bitmap texture (%i)!\n", material_info->getUtex()));
1028 }
1029 if ( !gr_opengl_tcache_set(material_info->getVtex(), material_info->get_texture_type(), &u_scale, &v_scale, &index, 2) ) {
1030 mprintf(("WARNING: Error setting bitmap texture (%i)!\n", material_info->getVtex()));
1031 }
1032 }
opengl_tnl_set_material_nanovg(nanovg_material * material_info)1033 void opengl_tnl_set_material_nanovg(nanovg_material* material_info) {
1034 opengl_tnl_set_material(material_info, true);
1035
1036 Current_shader->program->Uniforms.setTextureUniform("nvg_tex", 0);
1037 }
1038
opengl_tnl_set_material_decal(decal_material * material_info)1039 void opengl_tnl_set_material_decal(decal_material* material_info) {
1040 opengl_tnl_set_material(material_info, false);
1041
1042 float u_scale, v_scale;
1043 uint32_t array_index;
1044
1045 if (gr_opengl_tcache_set(material_info->get_texture_map(TM_BASE_TYPE),
1046 material_info->get_texture_type(),
1047 &u_scale,
1048 &v_scale,
1049 &array_index,
1050 0)) {
1051 Current_shader->program->Uniforms.setTextureUniform("diffuseMap", 0);
1052 }
1053
1054 if (gr_opengl_tcache_set(material_info->get_texture_map(TM_GLOW_TYPE),
1055 material_info->get_texture_type(),
1056 &u_scale,
1057 &v_scale,
1058 &array_index,
1059 1)) {
1060 Current_shader->program->Uniforms.setTextureUniform("glowMap", 1);
1061 }
1062
1063 if (gr_opengl_tcache_set(material_info->get_texture_map(TM_NORMAL_TYPE),
1064 material_info->get_texture_type(),
1065 &u_scale,
1066 &v_scale,
1067 &array_index,
1068 2)) {
1069 Current_shader->program->Uniforms.setTextureUniform("normalMap", 2);
1070 }
1071
1072 GL_state.Texture.Enable(3, GL_TEXTURE_2D, Scene_depth_texture);
1073 Current_shader->program->Uniforms.setTextureUniform("gDepthBuffer", 3);
1074
1075 if (Current_shader->flags & SDR_FLAG_DECAL_USE_NORMAL_MAP) {
1076 GL_state.Texture.Enable(4, GL_TEXTURE_2D, Scene_normal_texture);
1077 Current_shader->program->Uniforms.setTextureUniform("gNormalBuffer", 4);
1078 }
1079 }
1080
opengl_tnl_set_rocketui_material(interface_material * material_info)1081 void opengl_tnl_set_rocketui_material(interface_material* material_info)
1082 {
1083 opengl_tnl_set_material(material_info, false);
1084
1085 Current_shader->program->Uniforms.setTextureUniform("baseMap", 0);
1086
1087 uint32_t baseMapIndex = 0;
1088 if (material_info->is_textured()) {
1089 float u_scale, v_scale;
1090 if (!gr_opengl_tcache_set(material_info->get_texture_map(TM_BASE_TYPE), material_info->get_texture_type(),
1091 &u_scale, &v_scale, &baseMapIndex)) {
1092 mprintf(("WARNING: Error setting bitmap texture (%i)!\n", material_info->get_texture_map(TM_BASE_TYPE)));
1093 }
1094 }
1095
1096 const vec2d& offset = material_info->get_offset();
1097 opengl_set_generic_uniform_data<graphics::generic_data::rocketui_data>(
1098 [&](graphics::generic_data::rocketui_data* data) {
1099 data->projMatrix = gr_projection_matrix;
1100
1101 data->offset = offset;
1102 data->textured = material_info->is_textured() ? GL_TRUE : GL_FALSE;
1103 data->baseMapIndex = baseMapIndex;
1104
1105 data->horizontalSwipeOffset = material_info->get_horizontal_swipe();
1106 });
1107 }
1108
gr_opengl_set_viewport(int x,int y,int width,int height)1109 void gr_opengl_set_viewport(int x, int y, int width, int height) {
1110 glViewport(x, y, width, height);
1111 }
1112
opengl_bind_vertex_component(const vertex_format_data & vert_component,size_t base_offset)1113 void opengl_bind_vertex_component(const vertex_format_data &vert_component, size_t base_offset)
1114 {
1115 opengl_vertex_bind &bind_info = GL_array_binding_data[vert_component.format_type];
1116 opengl_vert_attrib &attrib_info = GL_vertex_attrib_info[bind_info.attribute_id];
1117
1118 Assert(bind_info.attribute_id == attrib_info.attribute_id);
1119
1120 GLubyte *data_src = reinterpret_cast<GLubyte*>(base_offset) + vert_component.offset;
1121
1122 if ( Current_shader != NULL ) {
1123 // grabbing a vertex attribute is dependent on what current shader has been set. i hope no one calls opengl_bind_vertex_layout before opengl_set_current_shader
1124 GLint index = opengl_shader_get_attribute(attrib_info.attribute_id);
1125
1126 if ( index >= 0 ) {
1127 GL_state.Array.EnableVertexAttrib(index);
1128 GL_state.Array.VertexAttribPointer(index, bind_info.size, bind_info.data_type, bind_info.normalized, (GLsizei)vert_component.stride, data_src);
1129 }
1130 }
1131 }
1132
opengl_bind_dynamic_layout(vertex_layout & layout,size_t base_offset)1133 void opengl_bind_dynamic_layout(vertex_layout& layout, size_t base_offset) {
1134 GL_state.BindVertexArray(GL_vao);
1135 GL_state.Array.BindPointersBegin();
1136
1137 size_t num_vertex_bindings = layout.get_num_vertex_components();
1138
1139 for ( size_t i = 0; i < num_vertex_bindings; ++i ) {
1140 opengl_bind_vertex_component(*layout.get_vertex_component(i), base_offset);
1141 }
1142
1143 GL_state.Array.BindPointersEnd();
1144 }
1145
opengl_bind_vertex_array(const vertex_layout & layout)1146 void opengl_bind_vertex_array(const vertex_layout& layout) {
1147 auto iter = Stored_vertex_arrays.find(layout);
1148 if (iter != Stored_vertex_arrays.end()) {
1149 // Found existing vertex array!
1150 GL_state.BindVertexArray(iter->second);
1151 return;
1152 }
1153
1154 GR_DEBUG_SCOPE("Create Vertex array");
1155
1156 GLuint vao;
1157 glGenVertexArrays(1, &vao);
1158 GL_state.BindVertexArray(vao);
1159
1160 for (size_t i = 0; i < layout.get_num_vertex_components(); ++i) {
1161 auto component = layout.get_vertex_component(i);
1162
1163 auto& bind_info = GL_array_binding_data[component->format_type];
1164 auto& attrib_info = GL_vertex_attrib_info[bind_info.attribute_id];
1165
1166 auto attribIndex = attrib_info.attribute_id;
1167
1168 glEnableVertexAttribArray(attribIndex);
1169 glVertexAttribFormat(attribIndex,
1170 bind_info.size,
1171 bind_info.data_type,
1172 bind_info.normalized,
1173 static_cast<GLuint>(component->offset));
1174
1175 // Currently, all vertex data comes from one buffer.
1176 glVertexAttribBinding(attribIndex, 0);
1177 }
1178
1179 Stored_vertex_arrays.insert(std::make_pair(layout, vao));
1180 }
opengl_bind_vertex_layout(vertex_layout & layout,GLuint vertexBuffer,GLuint indexBuffer,size_t base_offset)1181 void opengl_bind_vertex_layout(vertex_layout &layout, GLuint vertexBuffer, GLuint indexBuffer, size_t base_offset)
1182 {
1183 GR_DEBUG_SCOPE("Bind vertex layout");
1184
1185 if (!GLAD_GL_ARB_vertex_attrib_binding) {
1186 // We don't have support for the new vertex binding functions so fall back to the single VAO implementation
1187 GL_state.Array.BindArrayBuffer(vertexBuffer);
1188 GL_state.Array.BindElementBuffer(indexBuffer);
1189
1190 opengl_bind_dynamic_layout(layout, base_offset);
1191 return;
1192 }
1193
1194 opengl_bind_vertex_array(layout);
1195
1196 GL_state.Array.BindVertexBuffer(0,
1197 vertexBuffer,
1198 static_cast<GLintptr>(base_offset),
1199 static_cast<GLsizei>(layout.get_vertex_stride()));
1200 GL_state.Array.BindElementBuffer(indexBuffer);
1201 }
1202