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