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 #ifndef _GRAPHICS_H
11 #define _GRAPHICS_H
12 
13 #include "globalincs/flagset.h"
14 #include "globalincs/pstypes.h"
15 
16 #include "bmpman/bmpman.h"
17 #include "cfile/cfile.h"
18 #include "graphics/grinternal.h"
19 #include "graphics/tmapper.h"
20 #include "io/cursor.h"
21 #include "math/vecmat.h"
22 #include "osapi/osapi.h"
23 #include "utils/id.h"
24 
25 // Forward definition
26 namespace graphics {
27 namespace util {
28 class UniformBuffer;
29 class GPUMemoryHeap;
30 } // namespace util
31 } // namespace graphics
32 namespace scripting {
33 class OverridableHook;
34 }
35 
36 extern const float Default_min_draw_distance;
37 extern const float Default_max_draw_distance;
38 extern float Min_draw_distance;
39 extern float Max_draw_distance;
40 extern int Gr_inited;
41 
42 // z-buffering stuff
43 extern int gr_zbuffering, gr_zbuffering_mode;
44 extern int gr_global_zbuffering;
45 
46 extern bool Gr_enable_soft_particles;
47 
FLAG_LIST(FramebufferEffects)48 FLAG_LIST(FramebufferEffects){Thrusters = 0, Shockwaves, NUM_VALUES};
49 extern flagset<FramebufferEffects> Gr_framebuffer_effects;
50 
51 enum class AntiAliasMode {
52 	None = 0,
53 
54 	FXAA_Low = 1,
55 	FXAA_Medium = 2,
56 	FXAA_High = 3,
57 
58 	SMAA_Low = 4,
59 	SMAA_Medium = 5,
60 	SMAA_High = 6,
61 	SMAA_Ultra = 7,
62 };
63 extern AntiAliasMode Gr_aa_mode;
64 extern AntiAliasMode Gr_aa_mode_last_frame;
65 
66 bool gr_is_fxaa_mode(AntiAliasMode mode);
67 bool gr_is_smaa_mode(AntiAliasMode mode);
68 
69 extern bool Gr_post_processing_enabled;
70 
71 extern bool Gr_enable_vsync;
72 
73 extern bool Deferred_lighting;
74 extern bool High_dynamic_range;
75 
76 extern os::ViewportState Gr_configured_window_state;
77 
78 extern const std::shared_ptr<scripting::OverridableHook> OnFrameHook;
79 
80 class material;
81 class model_material;
82 class particle_material;
83 class distortion_material;
84 class shield_material;
85 class movie_material;
86 class batched_bitmap_material;
87 class nanovg_material;
88 class decal_material;
89 class interface_material;
90 
91 class transform_stack {
92 
93 	matrix4 Current_transform;
94 	SCP_vector<matrix4> Stack;
95 public:
transform_stack()96 	transform_stack()
97 	{
98 		vm_matrix4_set_identity(&Current_transform);
99 
100 		Stack.clear();
101 		Stack.push_back(Current_transform);
102 	}
103 
get_transform()104 	matrix4 &get_transform()
105 	{
106 		return Current_transform;
107 	}
108 
clear()109 	void clear()
110 	{
111 		vm_matrix4_set_identity(&Current_transform);
112 
113 		Stack.clear();
114 		Stack.push_back(Current_transform);
115 	}
116 
push_and_replace(matrix4 new_transform)117 	void push_and_replace(matrix4 new_transform)
118 	{
119 		Current_transform = new_transform;
120 		Stack.push_back(Current_transform);
121 	}
122 
123 	void push(const vec3d *pos, const matrix *orient, const vec3d *scale = NULL)
124 	{
125 		vec3d new_scale = SCALE_IDENTITY_VECTOR;
126 		matrix new_orient = IDENTITY_MATRIX;
127 		vec3d new_pos = ZERO_VECTOR;
128 
129 		matrix4 current_transform_copy = Current_transform;
130 		matrix4 new_transform;
131 
132 		if ( pos != NULL ) {
133 			new_pos = *pos;
134 		}
135 
136 		if ( orient != NULL ) {
137 			new_orient = *orient;
138 		}
139 
140 		if ( scale != NULL ) {
141 			new_scale = *scale;
142 		}
143 
144 		vm_vec_scale(&new_orient.vec.rvec, new_scale.xyz.x);
145 		vm_vec_scale(&new_orient.vec.uvec, new_scale.xyz.y);
146 		vm_vec_scale(&new_orient.vec.fvec, new_scale.xyz.z);
147 
148 		vm_matrix4_set_transform(&new_transform, &new_orient, &new_pos);
149 
150 		vm_matrix4_x_matrix4(&Current_transform, &current_transform_copy, &new_transform);
151 		Stack.push_back(Current_transform);
152 	}
153 
pop()154 	void pop()
155 	{
156 		if ( Stack.size() > 1 ) {
157 			Stack.pop_back();
158 		}
159 
160 		Current_transform = Stack.back();
161 	}
162 
depth()163 	size_t depth() {
164 		return Stack.size();
165 	}
166 };
167 
168 enum primitive_type {
169 	PRIM_TYPE_POINTS,
170 	PRIM_TYPE_LINES,
171 	PRIM_TYPE_LINESTRIP,
172 	PRIM_TYPE_TRIS,
173 	PRIM_TYPE_TRISTRIP,
174 	PRIM_TYPE_TRIFAN,
175 };
176 
177 enum shader_type {
178 	SDR_TYPE_NONE = -1,
179 	SDR_TYPE_MODEL,
180 	SDR_TYPE_EFFECT_PARTICLE,
181 	SDR_TYPE_EFFECT_DISTORTION,
182 	SDR_TYPE_POST_PROCESS_MAIN,
183 	SDR_TYPE_POST_PROCESS_BLUR,
184 	SDR_TYPE_POST_PROCESS_BLOOM_COMP,
185 	SDR_TYPE_POST_PROCESS_BRIGHTPASS,
186 	SDR_TYPE_POST_PROCESS_FXAA,
187 	SDR_TYPE_POST_PROCESS_FXAA_PREPASS,
188 	SDR_TYPE_POST_PROCESS_LIGHTSHAFTS,
189 	SDR_TYPE_POST_PROCESS_TONEMAPPING,
190 	SDR_TYPE_DEFERRED_LIGHTING,
191 	SDR_TYPE_DEFERRED_CLEAR,
192 	SDR_TYPE_VIDEO_PROCESS,
193 	SDR_TYPE_PASSTHROUGH_RENDER, //!< Shader for doing the old style fixed-function rendering. Only used internally, use
194 	                             //!< SDR_TYPE_DEFAULT_MATERIAL.
195 	SDR_TYPE_SHIELD_DECAL,
196 	SDR_TYPE_BATCHED_BITMAP,
197 	SDR_TYPE_DEFAULT_MATERIAL,
198 	SDR_TYPE_NANOVG,
199 	SDR_TYPE_DECAL,
200 	SDR_TYPE_SCENE_FOG,
201 	SDR_TYPE_ROCKET_UI,
202 
203 	SDR_TYPE_POST_PROCESS_SMAA_EDGE,
204 	SDR_TYPE_POST_PROCESS_SMAA_BLENDING_WEIGHT,
205 	SDR_TYPE_POST_PROCESS_SMAA_NEIGHBORHOOD_BLENDING,
206 
207 	NUM_SHADER_TYPES
208 };
209 
210 // Shader flags
211 #define SDR_FLAG_MODEL_LIGHT		(1<<0)
212 #define SDR_FLAG_MODEL_FOG			(1<<1)
213 #define SDR_FLAG_MODEL_DIFFUSE_MAP	(1<<2)
214 #define SDR_FLAG_MODEL_GLOW_MAP		(1<<3)
215 #define SDR_FLAG_MODEL_SPEC_MAP		(1<<4)
216 #define SDR_FLAG_MODEL_NORMAL_MAP	(1<<5)
217 #define SDR_FLAG_MODEL_HEIGHT_MAP	(1<<6)
218 #define SDR_FLAG_MODEL_ENV_MAP		(1<<7)
219 #define SDR_FLAG_MODEL_ANIMATED		(1<<8)
220 #define SDR_FLAG_MODEL_MISC_MAP		(1<<9)
221 #define SDR_FLAG_MODEL_TEAMCOLOR	(1<<10)
222 #define SDR_FLAG_MODEL_TRANSFORM	(1<<11)
223 #define SDR_FLAG_MODEL_DEFERRED		(1<<12)
224 #define SDR_FLAG_MODEL_SHADOW_MAP	(1<<13)
225 #define SDR_FLAG_MODEL_GEOMETRY		(1<<14)
226 #define SDR_FLAG_MODEL_SHADOWS		(1<<15)
227 #define SDR_FLAG_MODEL_THRUSTER		(1<<16)
228 #define SDR_FLAG_MODEL_CLIP			(1<<17)
229 #define SDR_FLAG_MODEL_HDR			(1<<18)
230 #define SDR_FLAG_MODEL_AMBIENT_MAP	(1<<19)
231 #define SDR_FLAG_MODEL_NORMAL_ALPHA	(1<<20)
232 #define SDR_FLAG_MODEL_THICK_OUTLINES (1<<21) // Renders the model geometry as an outline with configurable line width
233 
234 #define SDR_FLAG_PARTICLE_POINT_GEN			(1<<0)
235 
236 #define SDR_FLAG_BLUR_HORIZONTAL			(1<<0)
237 #define SDR_FLAG_BLUR_VERTICAL				(1<<1)
238 
239 #define SDR_FLAG_NANOVG_EDGE_AA		(1<<0)
240 
241 #define SDR_FLAG_DECAL_USE_NORMAL_MAP (1<<0)
242 
243 enum class uniform_block_type {
244 	Lights = 0,
245 	ModelData = 1,
246 	NanoVGData = 2,
247 	DecalInfo = 3,
248 	DecalGlobals = 4,
249 	DeferredGlobals = 5,
250 	Matrices = 6,
251 	GenericData = 7,
252 
253 	NUM_BLOCK_TYPES
254 };
255 
256 struct vertex_format_data
257 {
258 	enum vertex_format {
259 		POSITION4,
260 		POSITION3,
261 		POSITION2,
262 		SCREEN_POS,
263 		COLOR3,
264 		COLOR4,
265 		COLOR4F,
266 		TEX_COORD2,
267 		TEX_COORD3,
268 		NORMAL,
269 		TANGENT,
270 		MODEL_ID,
271 		RADIUS,
272 		UVEC,
273 	};
274 
275 	vertex_format format_type;
276 	size_t stride;
277 	size_t offset;
278 
vertex_format_datavertex_format_data279 	vertex_format_data(vertex_format i_format_type, size_t i_stride, size_t i_offset) :
280 	format_type(i_format_type), stride(i_stride), offset(i_offset) {}
281 
maskvertex_format_data282 	static inline uint mask(vertex_format v_format) { return 1 << v_format; }
283 
284 	bool operator==(const vertex_format_data& other) const {
285 		return format_type == other.format_type && stride == other.stride && offset == other.offset;
286 	}
287 };
288 class vertex_layout
289 {
290 	SCP_vector<vertex_format_data> Vertex_components;
291 
292 	uint Vertex_mask = 0;
293 	size_t Vertex_stride = 0;
294 public:
vertex_layout()295 	vertex_layout() {}
296 
get_num_vertex_components()297 	size_t get_num_vertex_components() const { return Vertex_components.size(); }
298 
get_vertex_component(size_t index)299 	const vertex_format_data* get_vertex_component(size_t index) const { return &Vertex_components[index]; }
300 
301 	bool resident_vertex_format(vertex_format_data::vertex_format format_type) const;
302 
303 	void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset);
304 
get_vertex_stride()305 	size_t get_vertex_stride() { return Vertex_stride; }
306 
307 	bool operator==(const vertex_layout& other) const;
308 
309 	size_t hash() const;
310 };
311 namespace std {
312 template<> struct hash<vertex_format_data> {
313 	size_t operator()(const vertex_format_data& data) const;
314 };
315 template<> struct hash<vertex_layout> {
316 	size_t operator()(const vertex_layout& data) const;
317 };
318 }
319 
320 typedef enum gr_capability {
321 	CAPABILITY_ENVIRONMENT_MAP,
322 	CAPABILITY_NORMAL_MAP,
323 	CAPABILITY_HEIGHT_MAP,
324 	CAPABILITY_SOFT_PARTICLES,
325 	CAPABILITY_DISTORTION,
326 	CAPABILITY_POST_PROCESSING,
327 	CAPABILITY_DEFERRED_LIGHTING,
328 	CAPABILITY_SHADOWS,
329 	CAPABILITY_BATCHED_SUBMODELS,
330 	CAPABILITY_POINT_PARTICLES,
331 	CAPABILITY_TIMESTAMP_QUERY,
332 	CAPABILITY_SEPARATE_BLEND_FUNCTIONS,
333 	CAPABILITY_PERSISTENT_BUFFER_MAPPING,
334 	CAPABILITY_BPTC
335 } gr_capability;
336 
337 enum class gr_property
338 {
339 	UNIFORM_BUFFER_OFFSET_ALIGNMENT,
340 	UNIFORM_BUFFER_MAX_SIZE,
341 	MAX_ANISOTROPY
342 };
343 
344 struct gr_buffer_handle_tag {
345 };
346 using gr_buffer_handle = ::util::ID<gr_buffer_handle_tag, int, -1>;
347 
348 // stencil buffering stuff
349 extern int gr_stencil_mode;
350 
351 /**
352  * This is a structure used by the shader to keep track
353  * of the values you want to use in the shade primitive.
354  */
355 typedef struct shader {
356 	uint screen_sig;  // current mode this is in
357 	ubyte r, g, b, c; // factors and constant
358 	ubyte lookup[256];
359 } shader;
360 
361 #define AC_TYPE_NONE		0		// Not an alphacolor
362 #define AC_TYPE_HUD		1		// Doesn't change hue depending on background.  Used for HUD stuff.
363 #define AC_TYPE_BLEND	2		// Changes hue depending on background.  Used for stars, etc.
364 
365 // NEVER REFERENCE THESE VALUES OUTSIDE OF THE GRAPHICS LIBRARY!!!
366 // If you need to get the rgb values of a "color" struct call
367 // gr_get_colors after calling gr_set_colors_fast.
368 typedef struct color {
369 	uint		screen_sig;
370 	int		is_alphacolor;
371 	int		alphacolor;
372 	int		magic;
373 	ubyte		red;
374 	ubyte		green;
375 	ubyte		blue;
376 	ubyte		alpha;
377 	ubyte		ac_type;							// The type of alphacolor.  See AC_TYPE_??? defines
378 	ubyte		raw8;
379 } color;
380 
381 // Used by the team coloring code
382 typedef struct team_color {
383 	struct {
384 		float r, g, b;
385 	} base;
386 	struct {
387 		float r, g, b;
388 	} stripe;
389 } team_color;
390 
391 
392 
393 typedef struct tsb_t {
394 	vec3d tangent;
395 	float scaler;
396 } tsb_t;
397 
398 /**
399  * This should be basicly just like it is in the VB
400  * a list of triangles and their associated normals
401  */
402 class poly_list {
403 	// helper function struct that let's us sort the indices.
404 	// an instance is fed into std::sort and std::lower_bound.
405 	// overloaded operator() is used for the comparison function.
406 	struct finder {
407 		poly_list* search_list;
408 		bool compare_indices;
409 		vertex* vert_to_find;
410 		vec3d* norm_to_find;
411 
412 		finder(poly_list* _search_list): search_list(_search_list), compare_indices(true), vert_to_find(NULL), norm_to_find(NULL) {}
413 		finder(poly_list* _search_list, vertex* _vert, vec3d* _norm): search_list(_search_list), compare_indices(false), vert_to_find(_vert), norm_to_find(_norm) {}
414 
415 		bool operator()(const uint a, const uint b);
416 	};
417 public:
418 	poly_list(): n_verts(0), vert(NULL), norm(NULL), tsb(NULL), submodels(NULL), sorted_indices(NULL), currently_allocated(0) {}
419 	~poly_list();
420 	poly_list& operator=(const poly_list&);
421 
422 	void allocate(int size);
423 	void make_index_buffer(SCP_vector<int> &vertex_list);
424 	void calculate_tangent();
425 	int n_verts;
426 	vertex *vert;
427 	vec3d *norm;
428 	tsb_t *tsb;
429 	int *submodels;
430 
431 	uint *sorted_indices;
432 
433 	int find_index(poly_list *plist, int idx);
434 	int find_index_fast(poly_list *plist, int idx);
435 private:
436 	int currently_allocated;
437 	int find_first_vertex(int idx);
438 	int find_first_vertex_fast(int idx);
439 	void generate_sorted_index_list();
440 };
441 
442 class buffer_data
443 {
444 public:
445 	int flags;
446 
447 	int texture;		// this is the texture the vertex buffer will use
448 	size_t n_verts;
449 
450 	size_t index_offset;
451 
452 	const uint *get_index() const
453 	{
454 		return index;
455 	}
456 
457         uint i_first, i_last;
458 
459 	void release()
460 	{
461 		if (index) {
462 			delete [] index;
463 			index = NULL;
464 		}
465 	}
466 
467 	void assign(size_t i, uint j)
468 	{
469 		const_cast<uint *>(index)[i] = j;
470 		if (i_first > i_last)
471 			i_first = i_last = j;
472 		else if (i_first > j)
473 			i_first = j;
474 		else if (i_last < j)
475 			i_last = j;
476 	}
477 
478 	// Constructor
479 
480 	buffer_data() :
481 	flags(0), texture(-1), n_verts(0), index_offset(0),
482 		i_first(1), i_last(0), index(NULL)
483 	{
484 	}
485 
486 	explicit buffer_data(size_t n_vrts) :
487 		flags(0), texture(-1), n_verts(n_vrts), index_offset(0),
488 		i_first(1), i_last(0), index(NULL)
489 	{
490 		if ( n_verts > 0 ) {
491 			index = new(std::nothrow) uint[n_verts];
492 		} else {
493 			index = NULL;
494 		}
495 	}
496 
497 	// Copy-constructor
498 	buffer_data(const buffer_data& other)
499 	{
500 		if ( other.index ) {
501 			index = new(std::nothrow) uint[other.n_verts];
502 			for (size_t i=0; i < other.n_verts; i++)
503 			{
504 				index[i] = other.index[i];
505 			}
506 		} else {
507 			index = NULL;
508 		}
509 
510 		flags   = other.flags;
511 		texture = other.texture;
512 		n_verts = other.n_verts;
513 
514 		i_first = other.i_first;
515 		i_last  = other.i_last;
516 
517 		index_offset = other.index_offset;
518 	}
519 
520 	// Copy-assignment operator
521 	buffer_data& operator=(const buffer_data& rhs)
522 	{
523 		if (this != &rhs)
524 		{
525 			if ( index ) {
526 				delete [] index;
527 			}
528 
529 			if ( rhs.index && rhs.n_verts > 0 ) {
530 				index = new(std::nothrow) uint[rhs.n_verts];
531 				for (size_t i=0; i < rhs.n_verts; i++)
532 				{
533 					index[i] = rhs.index[i];
534 				}
535 			}
536 
537 			flags   = rhs.flags;
538 			texture = rhs.texture;
539 			n_verts = rhs.n_verts;
540 
541 			i_first = rhs.i_first;
542 			i_last  = rhs.i_last;
543 
544 			index_offset = rhs.index_offset;
545 		}
546 		return *this;
547 	}
548 
549 	// Destructor
550 	~buffer_data()
551 	{
552 		release();
553 	}
554 
555 private:
556 	uint *index;
557 };
558 
559 class vertex_buffer
560 {
561 public:
562 	int flags;
563 
564 	size_t stride;
565 	size_t vertex_offset;
566 	size_t vertex_num_offset;
567 
568 	poly_list *model_list;
569 
570 	SCP_vector<buffer_data> tex_buf;
571 
572 	vertex_layout layout;
573 
574 	vertex_buffer() :
575 		flags(0), stride(0), vertex_offset(0), vertex_num_offset(0), model_list(NULL)
576 	{
577 	}
578 
579 	~vertex_buffer()
580 	{
581 		clear();
582 	}
583 
584 	void release()
585 	{
586 		if (model_list) {
587 			delete model_list;
588 			model_list = NULL;
589 		}
590 
591 		for (SCP_vector<buffer_data>::iterator tbi = tex_buf.begin(); tbi != tex_buf.end(); ++tbi) {
592 			tbi->release();
593 		}
594 	}
595 
596 	void clear()
597 	{
598 		release();
599 		tex_buf.clear();
600 	}
601 };
602 
603 struct indexed_vertex_source {
604 	void* Vertex_list = nullptr;
605 	void* Index_list = nullptr;
606 
607 	gr_buffer_handle Vbuffer_handle;
608 	size_t Vertex_offset = 0;
609 	size_t Base_vertex_offset = 0;
610 
611 	gr_buffer_handle Ibuffer_handle;
612 	size_t Index_offset = 0;
613 
614 	uint Vertex_list_size = 0;
615 	uint Index_list_size = 0;
616 };
617 
618 struct light;
619 
620 #define FIND_SCALED_NUM(x, x0, x1, y0, y1) ( ((((x) - (x0)) * ((y1) - (y0))) / ((x1) - (x0))) + (y0) )
621 
622 #define GR_ALPHABLEND_NONE			0		// no blending
623 #define GR_ALPHABLEND_FILTER		1		// 50/50 mix of foreground, background, using intensity as alpha
624 
625 #define GR_BITBLT_MODE_NORMAL		0		// Normal bitblting
626 #define GR_BITBLT_MODE_RLE			1		// RLE would be faster
627 
628 // fog modes
629 #define GR_FOGMODE_NONE				0		// set this to turn off fog
630 #define GR_FOGMODE_FOG				1		// linear fog
631 
632 enum class QueryType {
633 	Timestamp
634 };
635 
636 enum class BufferType {
637 	Vertex,
638 	Index,
639 	Uniform
640 };
641 
642 enum class BufferUsageHint { Static, Dynamic, Streaming, PersistentMapping };
643 
644 /**
645  * @brief Type of a graphics sync object
646  */
647 typedef void* gr_sync;
648 
649 typedef struct screen {
650 	uint signature = 0;       // changes when mode or palette or width or height changes
651 	int max_w = 0, max_h = 0; // Width and height
652 	int max_w_unscaled = 0, max_h_unscaled = 0;
653 	int max_w_unscaled_zoomed = 0, max_h_unscaled_zoomed = 0;
654 	int center_w = 0, center_h = 0; // Width and height of center monitor
655 	int center_offset_x = 0, center_offset_y = 0;
656 	int save_max_w = 0, save_max_h = 0; // Width and height
657 	int save_max_w_unscaled = 0, save_max_h_unscaled = 0;
658 	int save_max_w_unscaled_zoomed = 0, save_max_h_unscaled_zoomed = 0;
659 	int save_center_w = 0, save_center_h = 0; // Width and height of center monitor
660 	int save_center_offset_x = 0, save_center_offset_y = 0;
661 	int res = 0;                             // GR_640 or GR_1024
662 	int mode = 0;                            // What mode gr_init was called with.
663 	float aspect = 0.0f, clip_aspect = 0.0f; // Aspect ratio = 0, aspect of clip_width/clip_height
664 	int rowsize = 0;                         // What you need to add to go to next row (includes bytes_per_pixel)
665 	int bits_per_pixel = 0;                  // How many bits per pixel it is. (7,8,15,16,24,32)
666 	int bytes_per_pixel = 0;                 // How many bytes per pixel (1,2,3,4)
667 	int offset_x = 0, offset_y = 0;          // The offsets into the screen
668 	int offset_x_unscaled = 0, offset_y_unscaled = 0; // Offsets into the screen, in unscaled dimensions
669 	int clip_width = 0, clip_height = 0;
670 	int clip_width_unscaled = 0, clip_height_unscaled = 0; // Height and width of clip aread, in unscaled dimensions
671 	// center of clip area
672 	float clip_center_x = 0.0f, clip_center_y = 0.0f;
673 
674 	float fog_near = 0.0f, fog_far = 0.0f;
675 
676 	// the clip_l,r,t,b are used internally.  left and top are
677 	// actually always 0, but it's nice to have the code work with
678 	// arbitrary clipping regions.
679 	int clip_left = 0, clip_right = 0, clip_top = 0, clip_bottom = 0;
680 	// same as above except in unscaled dimensions
681 	int clip_left_unscaled = 0, clip_right_unscaled = 0, clip_top_unscaled = 0, clip_bottom_unscaled = 0;
682 
683 	int current_alphablend_mode = 0; // See GR_ALPHABLEND defines above
684 	int current_bitblt_mode = 0;     // See GR_BITBLT_MODE defines above
685 	int current_bitmap = 0;
686 	color current_color{};
687 	color current_fog_color{};   // current fog color
688 	color current_clear_color{}; // current clear color
689 	shader current_shader{};
690 	float current_alpha = 0.0f;
691 
692 	bool custom_size = false;
693 	int rendering_to_texture = 0; // wich texture we are rendering to, -1 if the back buffer
694 	int rendering_to_face = 0;    // wich face of the texture we are rendering to, -1 if the back buffer
695 
696 	int envmap_render_target = 0;
697 
698 	float line_width = 0.0f;
699 
700 	// switch onscreen, offscreen
701 	std::function<void()> gf_flip;
702 
703 	// sets the clipping region
704 	std::function<void(int x, int y, int w, int h, int resize_mode)> gf_set_clip;
705 
706 	// resets the clipping region to entire screen
707 	std::function<void()> gf_reset_clip;
708 
709 	// clears entire clipping region to current color
710 	std::function<void()> gf_clear;
711 
712 	// dumps the current screen to a file
713 	std::function<void(const char* filename)> gf_print_screen;
714 
715 	// Retrieves the zbuffer mode.
716 	std::function<int()> gf_zbuffer_get;
717 
718 	// Sets mode.  Returns previous mode.
719 	std::function<int(int mode)> gf_zbuffer_set;
720 
721 	// Clears the zbuffer.  If use_zbuffer is FALSE, then zbuffering mode is ignored and zbuffer is always off.
722 	std::function<void(int use_zbuffer)> gf_zbuffer_clear;
723 
724 	// Set the stencil buffer mode. Returns previous mode
725 	std::function<int(int mode)> gf_stencil_set;
726 
727 	// Clears the stencil buffer.
728 	std::function<void()> gf_stencil_clear;
729 
730 	std::function<int(int mode, float alpha)> gf_alpha_mask_set;
731 
732 	// Saves screen. Returns an id you pass to restore and free.
733 	std::function<int()> gf_save_screen;
734 
735 	// Resets clip region and copies entire saved screen to the screen.
736 	std::function<void(int id)> gf_restore_screen;
737 
738 	// Frees up a saved screen.
739 	std::function<void(int id)> gf_free_screen;
740 
741 	// grab a region of the screen. assumes data is large enough
742 	std::function<void(int front, int w, int h, ubyte* data)> gf_get_region;
743 
744 	// poly culling
745 	std::function<int(int cull)> gf_set_cull;
746 
747 	// color buffer writes
748 	std::function<int(int mode)> gf_set_color_buffer;
749 
750 	// preload a bitmap into texture memory
751 	std::function<int(int bitmap_num, int is_aabitmap)> gf_preload;
752 
753 	// set the color to be used when clearing the background
754 	std::function<void(int r, int g, int b)> gf_set_clear_color;
755 
756 	// Here be the bitmap functions
757 	std::function<void(bitmap_slot* slot, bool release)> gf_bm_free_data;
758 	std::function<void(bitmap_slot* slot)> gf_bm_create;
759 	std::function<void(bitmap_slot* slot)> gf_bm_init;
760 	std::function<void()> gf_bm_page_in_start;
761 	std::function<bool(int handle, bitmap* bm)> gf_bm_data;
762 
763 	std::function<int(int handle, int* width, int* height, int* bpp, int* mm_lvl, int flags)> gf_bm_make_render_target;
764 	std::function<int(int handle, int face)> gf_bm_set_render_target;
765 
766 	std::function<void(int)> gf_set_texture_addressing;
767 
768 	std::function<gr_buffer_handle(BufferType type, BufferUsageHint usage)> gf_create_buffer;
769 	std::function<void(gr_buffer_handle handle)> gf_delete_buffer;
770 
771 	std::function<void(gr_buffer_handle handle, size_t size, const void* data)> gf_update_buffer_data;
772 	std::function<void(gr_buffer_handle handle, size_t offset, size_t size, const void* data)>
773 		gf_update_buffer_data_offset;
774 	std::function<void*(gr_buffer_handle handle)> gf_map_buffer;
775 	std::function<void(gr_buffer_handle handle, size_t offset, size_t size)> gf_flush_mapped_buffer;
776 	std::function<void(void* data, size_t size)> gf_update_transform_buffer;
777 
778 	// postprocessing effects
779 	std::function<void(const char*, int, const vec3d*)> gf_post_process_set_effect;
780 	std::function<void()> gf_post_process_set_defaults;
781 
782 	std::function<void()> gf_post_process_begin;
783 	std::function<void()> gf_post_process_end;
784 	std::function<void()> gf_post_process_save_zbuffer;
785 	std::function<void()> gf_post_process_restore_zbuffer;
786 
787 	std::function<void()> gf_deferred_lighting_begin;
788 	std::function<void()> gf_deferred_lighting_end;
789 	std::function<void()> gf_deferred_lighting_finish;
790 
791 	std::function<void()> gf_scene_texture_begin;
792 	std::function<void()> gf_scene_texture_end;
793 	std::function<void()> gf_copy_effect_texture;
794 
795 	std::function<void(int zbias)> gf_zbias;
796 
797 	std::function<void(int)> gf_set_fill_mode;
798 
799 	std::function<void(float width)> gf_set_line_width;
800 
801 	std::function<void(material* material_def, float rad)> gf_sphere;
802 
803 	std::function<int(shader_type type, unsigned int flags)> gf_maybe_create_shader;
804 	std::function<void(const std::function<void(size_t, size_t)>& progress_callback)> gf_recompile_all_shaders;
805 
806 	std::function<void()> gf_clear_states;
807 
808 	std::function<void(int bitmap_handle, int bpp, const ubyte* data, int width, int height)> gf_update_texture;
809 	std::function<void(void* data_out, int bitmap_num)> gf_get_bitmap_from_texture;
810 
811 	std::function<void(matrix4* shadow_view_matrix, const matrix* light_matrix, vec3d* eye_pos)> gf_shadow_map_start;
812 	std::function<void()> gf_shadow_map_end;
813 
814 	std::function<void()> gf_start_decal_pass;
815 	std::function<void()> gf_stop_decal_pass;
816 
817 	// new drawing functions
818 	std::function<
819 		void(model_material* material_info, indexed_vertex_source* vert_source, vertex_buffer* bufferp, size_t texi)>
820 		gf_render_model;
821 	std::function<void(shield_material* material_info,
822 		primitive_type prim_type,
823 		vertex_layout* layout,
824 		gr_buffer_handle buffer_handle,
825 		int n_verts)>
826 		gf_render_shield_impact;
827 	std::function<void(material* material_info,
828 		primitive_type prim_type,
829 		vertex_layout* layout,
830 		int offset,
831 		int n_verts,
832 		gr_buffer_handle buffer_handle,
833 		size_t buffer_offset)>
834 		gf_render_primitives;
835 	std::function<void(particle_material* material_info,
836 		primitive_type prim_type,
837 		vertex_layout* layout,
838 		int offset,
839 		int n_verts,
840 		gr_buffer_handle buffer_handle)>
841 		gf_render_primitives_particle;
842 	std::function<void(distortion_material* material_info,
843 		primitive_type prim_type,
844 		vertex_layout* layout,
845 		int offset,
846 		int n_verts,
847 		gr_buffer_handle buffer_handle)>
848 		gf_render_primitives_distortion;
849 	std::function<void(movie_material* material_info,
850 		primitive_type prim_type,
851 		vertex_layout* layout,
852 		int n_verts,
853 		gr_buffer_handle buffer,
854 		size_t buffer_offset)>
855 		gf_render_movie;
856 	std::function<void(batched_bitmap_material* material_info,
857 		primitive_type prim_type,
858 		vertex_layout* layout,
859 		int offset,
860 		int n_verts,
861 		gr_buffer_handle buffer_handle)>
862 		gf_render_primitives_batched;
863 	std::function<void(nanovg_material* material_info,
864 		primitive_type prim_type,
865 		vertex_layout* layout,
866 		int offset,
867 		int n_verts,
868 		gr_buffer_handle buffer_handle)>
869 		gf_render_nanovg;
870 	std::function<void(decal_material* material_info,
871 		primitive_type prim_type,
872 		vertex_layout* layout,
873 		int num_elements,
874 		const indexed_vertex_source& buffers)>
875 		gf_render_decals;
876 	void (*gf_render_rocket_primitives)(interface_material* material_info,
877 		primitive_type prim_type,
878 		vertex_layout* layout,
879 		int n_indices,
880 		gr_buffer_handle vertex_buffer,
881 		gr_buffer_handle index_buffer);
882 
883 	std::function<bool(gr_capability capability)> gf_is_capable;
884 	std::function<bool(gr_property property, void* destination)> gf_get_property;
885 
886 	std::function<void(const char* name)> gf_push_debug_group;
887 	std::function<void()> gf_pop_debug_group;
888 
889 	std::function<int()> gf_create_query_object;
890 	std::function<void(int obj, QueryType type)> gf_query_value;
891 	std::function<bool(int obj)> gf_query_value_available;
892 	std::function<uint64_t(int obj)> gf_get_query_value;
893 	std::function<void(int obj)> gf_delete_query_object;
894 
895 	std::unique_ptr<os::Viewport> (*gf_create_viewport)(const os::ViewPortProperties& props);
896 	std::function<void(os::Viewport* view)> gf_use_viewport;
897 
898 	std::function<void(uniform_block_type bind_point, size_t offset, size_t size, gr_buffer_handle buffer)>
899 		gf_bind_uniform_buffer;
900 
901 	std::function<gr_sync()> gf_sync_fence;
902 	std::function<bool(gr_sync sync, uint64_t timeoutns)> gf_sync_wait;
903 	std::function<void(gr_sync sync)> gf_sync_delete;
904 
905 	std::function<void(int x, int y, int width, int height)> gf_set_viewport;
906 } screen;
907 
908 // handy macro
909 #define GR_MAYBE_CLEAR_RES(bmap)		do  { int bmw = -1; int bmh = -1; if(bmap != -1){ bm_get_info( bmap, &bmw, &bmh, NULL, NULL, NULL); if((bmw != gr_screen.max_w) || (bmh != gr_screen.max_h)){gr_clear();} } else {gr_clear();} } while(false);
910 
911 //Window's interface to set up graphics:
912 //--------------------------------------
913 // Call this at application startup
914 
915 // # Software Re-added by Kazan --- THIS HAS TO STAY -- It is used by standalone!
916 #define GR_DEFAULT				(-1)		// set to use default settings
917 #define GR_STUB					(100)
918 #define GR_OPENGL (104) // Use OpenGl hardware renderer
919 #define GR_VULKAN (105) // Use Vulkan hardware renderer
920 
921 // resolution constants   - always keep resolutions in ascending order and starting from 0
922 #define GR_NUM_RESOLUTIONS			2
923 #define GR_640							0		// 640 x 480
924 #define GR_1024						1		// 1024 x 768
925 
926 #define GR_1024_THRESHOLD_WIDTH		1024
927 #define GR_1024_THRESHOLD_HEIGHT	600
928 
929 extern const char *Resolution_prefixes[GR_NUM_RESOLUTIONS];
930 
931 extern bool gr_init(std::unique_ptr<os::GraphicsOperations>&& graphicsOps, int d_mode = GR_DEFAULT,
932 					int d_width = GR_DEFAULT, int d_height = GR_DEFAULT, int d_depth = GR_DEFAULT);
933 
934 extern void gr_screen_resize(int width, int height);
935 extern int gr_get_resolution_class(int width, int height);
936 
937 // Call this when your app ends.
938 extern void gr_close();
939 
940 extern screen gr_screen;
941 
942 #define GR_FILL_MODE_WIRE 1
943 #define GR_FILL_MODE_SOLID 2
944 
945 #define GR_ZBUFF_NONE	0
946 #define GR_ZBUFF_WRITE	(1<<0)
947 #define GR_ZBUFF_READ	(1<<1)
948 #define GR_ZBUFF_FULL	(GR_ZBUFF_WRITE|GR_ZBUFF_READ)
949 
950 #define GR_STENCIL_NONE		0
951 #define GR_STENCIL_READ		1
952 #define GR_STENCIL_WRITE	2
953 
954 #define GR_RESIZE_NONE				0
955 #define GR_RESIZE_FULL				1
956 #define GR_RESIZE_FULL_CENTER		2
957 #define GR_RESIZE_MENU				3
958 #define GR_RESIZE_MENU_ZOOMED		4
959 #define GR_RESIZE_MENU_NO_OFFSET	5
960 
961 void gr_set_screen_scale(int x, int y, int zoom_x = -1, int zoom_y = -1, int max_x = gr_screen.max_w, int max_y = gr_screen.max_h, int center_x = gr_screen.center_w, int center_y = gr_screen.center_h, bool force_stretch = false);
962 void gr_reset_screen_scale();
963 bool gr_unsize_screen_pos(int *x, int *y, int *w = NULL, int *h = NULL, int resize_mode = GR_RESIZE_FULL);
964 bool gr_resize_screen_pos(int *x, int *y, int *w = NULL, int *h = NULL, int resize_mode = GR_RESIZE_FULL);
965 bool gr_unsize_screen_posf(float *x, float *y, float *w = NULL, float *h = NULL, int resize_mode = GR_RESIZE_FULL);
966 bool gr_resize_screen_posf(float *x, float *y, float *w = NULL, float *h = NULL, int resize_mode = GR_RESIZE_FULL);
967 
968 // Does formatted printing.  This calls gr_string after formatting,
969 // so if you don't need to format the string, then call gr_string
970 // directly.
971 extern void gr_printf( int x, int y, const char * format, SCP_FORMAT_STRING ... ) SCP_FORMAT_STRING_ARGS(3, 4);
972 // same as gr_printf but positions text correctly in menus
973 extern void gr_printf_menu( int x, int y, const char * format, SCP_FORMAT_STRING ... )  SCP_FORMAT_STRING_ARGS(3, 4);
974 // same as gr_printf_menu but accounts for menu zooming
975 extern void gr_printf_menu_zoomed( int x, int y, const char * format, SCP_FORMAT_STRING ... )  SCP_FORMAT_STRING_ARGS(3, 4);
976 // same as gr_printf but doesn't resize for non-standard resolutions
977 extern void gr_printf_no_resize( int x, int y, const char * format, SCP_FORMAT_STRING ... )  SCP_FORMAT_STRING_ARGS(3, 4);
978 
979 // Returns the size of the string in pixels in w and h
980 extern void gr_get_string_size( int *w, int *h, const char * text, int len = 9999 );
981 
982 // Returns the height of the current font
983 extern int gr_get_font_height();
984 
985 extern io::mouse::Cursor* Web_cursor;
986 
987 // Called by OS when application gets/looses focus
988 extern void gr_activate(int active);
989 
990 #define GR_CALL(x) (x)
991 
992 // These macros make the function indirection look like the
993 // old Descent-style gr_xxx calls.
994 
995 #define gr_print_screen		GR_CALL(gr_screen.gf_print_screen)
996 
997 //#define gr_flip				GR_CALL(gr_screen.gf_flip)
998 void gr_flip(bool execute_scripting = true);
999 
1000 //#define gr_set_clip			GR_CALL(gr_screen.gf_set_clip)
1001 inline void gr_set_clip(int x, int y, int w, int h, int resize_mode=GR_RESIZE_FULL)
1002 {
1003 	gr_screen.gf_set_clip(x, y, w, h, resize_mode);
1004 }
1005 #define gr_reset_clip		GR_CALL(gr_screen.gf_reset_clip)
1006 
1007 void gr_set_bitmap(int bitmap_num, int alphablend = GR_ALPHABLEND_NONE, int bitbltmode = GR_BITBLT_MODE_NORMAL, float alpha = 1.0f);
1008 
1009 #define gr_clear				GR_CALL(gr_screen.gf_clear)
1010 
1011 #define gr_zbuffer_get		GR_CALL(gr_screen.gf_zbuffer_get)
1012 #define gr_zbuffer_set		GR_CALL(gr_screen.gf_zbuffer_set)
1013 #define gr_zbuffer_clear	GR_CALL(gr_screen.gf_zbuffer_clear)
1014 
1015 #define gr_stencil_set		GR_CALL(gr_screen.gf_stencil_set)
1016 #define gr_stencil_clear	GR_CALL(gr_screen.gf_stencil_clear)
1017 
1018 #define gr_alpha_mask_set	GR_CALL(gr_screen.gf_alpha_mask_set)
1019 
1020 #define gr_save_screen		GR_CALL(gr_screen.gf_save_screen)
1021 #define gr_restore_screen	GR_CALL(gr_screen.gf_restore_screen)
1022 #define gr_free_screen		GR_CALL(gr_screen.gf_free_screen)
1023 
1024 #define gr_get_region		GR_CALL(gr_screen.gf_get_region)
1025 
1026 #define gr_set_cull			GR_CALL(gr_screen.gf_set_cull)
1027 #define gr_set_color_buffer	GR_CALL(gr_screen.gf_set_color_buffer)
1028 
1029 
1030 #define gr_preload			GR_CALL(gr_screen.gf_preload)
1031 
1032 #define gr_set_clear_color	GR_CALL(gr_screen.gf_set_clear_color)
1033 
1034 // Here be the bitmap functions
1035 #define gr_bm_free_data				GR_CALL(gr_screen.gf_bm_free_data)
1036 #define gr_bm_create				GR_CALL(gr_screen.gf_bm_create)
1037 #define gr_bm_init					GR_CALL(gr_screen.gf_bm_init)
1038 #define gr_bm_page_in_start			GR_CALL(gr_screen.gf_bm_page_in_start)
1039 #define gr_bm_data					GR_CALL(gr_screen.gf_bm_data)
1040 
1041 #define gr_bm_make_render_target					GR_CALL(gr_screen.gf_bm_make_render_target)
1042 
1043 inline int gr_bm_set_render_target(int n, int face = -1)
1044 {
1045 	return gr_screen.gf_bm_set_render_target(n, face);
1046 }
1047 
1048 #define gr_set_texture_addressing GR_CALL(gr_screen.gf_set_texture_addressing)
1049 
1050 inline gr_buffer_handle gr_create_buffer(BufferType type, BufferUsageHint usage)
1051 {
1052 	return gr_screen.gf_create_buffer(type, usage);
1053 }
1054 
1055 #define gr_delete_buffer GR_CALL(gr_screen.gf_delete_buffer)
1056 #define gr_update_buffer_data GR_CALL(gr_screen.gf_update_buffer_data)
1057 #define gr_update_buffer_data_offset GR_CALL(gr_screen.gf_update_buffer_data_offset)
1058 inline void* gr_map_buffer(gr_buffer_handle handle)
1059 {
1060 	return gr_screen.gf_map_buffer(handle);
1061 }
1062 inline void gr_flush_mapped_buffer(gr_buffer_handle handle, size_t offset, size_t size)
1063 {
1064 	gr_screen.gf_flush_mapped_buffer(handle, offset, size);
1065 }
1066 #define gr_update_transform_buffer GR_CALL(gr_screen.gf_update_transform_buffer)
1067 
1068 #define gr_scene_texture_begin GR_CALL(gr_screen.gf_scene_texture_begin)
1069 #define gr_scene_texture_end GR_CALL(gr_screen.gf_scene_texture_end)
1070 #define gr_copy_effect_texture GR_CALL(gr_screen.gf_copy_effect_texture)
1071 
1072 #define gr_post_process_set_effect GR_CALL(gr_screen.gf_post_process_set_effect)
1073 #define gr_post_process_set_defaults GR_CALL(gr_screen.gf_post_process_set_defaults)
1074 #define gr_post_process_begin GR_CALL(gr_screen.gf_post_process_begin)
1075 #define gr_post_process_end GR_CALL(gr_screen.gf_post_process_end)
1076 #define gr_post_process_save_zbuffer GR_CALL(gr_screen.gf_post_process_save_zbuffer)
1077 inline void gr_post_process_restore_zbuffer()
1078 {
1079 	gr_screen.gf_post_process_restore_zbuffer();
1080 }
1081 
1082 #define gr_deferred_lighting_begin		GR_CALL(gr_screen.gf_deferred_lighting_begin)
1083 #define gr_deferred_lighting_end		GR_CALL(gr_screen.gf_deferred_lighting_end)
1084 #define gr_deferred_lighting_finish		GR_CALL(gr_screen.gf_deferred_lighting_finish)
1085 
1086 #define	gr_zbias						GR_CALL(gr_screen.gf_zbias)
1087 #define	gr_set_fill_mode				GR_CALL(gr_screen.gf_set_fill_mode)
1088 
1089 #define gr_set_line_width				GR_CALL(gr_screen.gf_set_line_width)
1090 
1091 #define gr_sphere						GR_CALL(gr_screen.gf_sphere)
1092 
1093 #define gr_maybe_create_shader			GR_CALL(gr_screen.gf_maybe_create_shader)
1094 #define gr_recompile_all_shaders		GR_CALL(gr_screen.gf_recompile_all_shaders)
1095 
1096 #define gr_clear_states					GR_CALL(gr_screen.gf_clear_states)
1097 
1098 #define gr_update_texture				GR_CALL(gr_screen.gf_update_texture)
1099 #define gr_get_bitmap_from_texture		GR_CALL(gr_screen.gf_get_bitmap_from_texture)
1100 
1101 #define gr_shadow_map_start				GR_CALL(gr_screen.gf_shadow_map_start)
1102 #define gr_shadow_map_end				GR_CALL(gr_screen.gf_shadow_map_end)
1103 #define gr_render_shield_impact			GR_CALL(gr_screen.gf_render_shield_impact)
1104 
1105 inline void gr_render_primitives(material* material_info,
1106 	primitive_type prim_type,
1107 	vertex_layout* layout,
1108 	int vert_offset,
1109 	int n_verts,
1110 	gr_buffer_handle buffer_handle = gr_buffer_handle(),
1111 	size_t buffer_offset = 0)
1112 {
1113 	gr_screen
1114 		.gf_render_primitives(material_info, prim_type, layout, vert_offset, n_verts, buffer_handle, buffer_offset);
1115 }
1116 
1117 inline void gr_render_primitives_particle(particle_material* material_info,
1118 	primitive_type prim_type,
1119 	vertex_layout* layout,
1120 	int offset,
1121 	int n_verts,
1122 	gr_buffer_handle buffer_handle = gr_buffer_handle())
1123 {
1124 	gr_screen.gf_render_primitives_particle(material_info, prim_type, layout, offset, n_verts, buffer_handle);
1125 }
1126 
1127 inline void gr_render_primitives_batched(batched_bitmap_material* material_info,
1128 	primitive_type prim_type,
1129 	vertex_layout* layout,
1130 	int offset,
1131 	int n_verts,
1132 	gr_buffer_handle buffer_handle = gr_buffer_handle())
1133 {
1134 	gr_screen.gf_render_primitives_batched(material_info, prim_type, layout, offset, n_verts, buffer_handle);
1135 }
1136 
1137 inline void gr_render_nanovg(nanovg_material* material_info,
1138 	primitive_type prim_type,
1139 	vertex_layout* layout,
1140 	int offset,
1141 	int n_verts,
1142 	gr_buffer_handle buffer_handle)
1143 {
1144 	gr_screen.gf_render_nanovg(material_info, prim_type, layout, offset, n_verts, buffer_handle);
1145 }
1146 
1147 inline void gr_render_primitives_distortion(distortion_material* material_info,
1148 	primitive_type prim_type,
1149 	vertex_layout* layout,
1150 	int offset,
1151 	int n_verts,
1152 	gr_buffer_handle buffer_handle = gr_buffer_handle())
1153 {
1154 	gr_screen.gf_render_primitives_distortion(material_info, prim_type, layout, offset, n_verts, buffer_handle);
1155 }
1156 
1157 inline void gr_render_movie(movie_material* material_info,
1158 	primitive_type prim_type,
1159 	vertex_layout* layout,
1160 	int n_verts,
1161 	gr_buffer_handle buffer,
1162 	size_t buffer_offset = 0)
1163 {
1164 	gr_screen.gf_render_movie(material_info, prim_type, layout, n_verts, buffer, buffer_offset);
1165 }
1166 
1167 inline void gr_render_model(model_material* material_info, indexed_vertex_source *vert_source, vertex_buffer* bufferp, size_t texi)
1168 {
1169 	gr_screen.gf_render_model(material_info, vert_source, bufferp, texi);
1170 }
1171 
1172 inline void gr_render_rocket_primitives(interface_material* material_info,
1173 	primitive_type prim_type,
1174 	vertex_layout* layout,
1175 	int n_indices,
1176 	gr_buffer_handle vertex_buffer,
1177 	gr_buffer_handle index_buffer)
1178 {
1179 	gr_screen.gf_render_rocket_primitives(material_info, prim_type, layout, n_indices, vertex_buffer, index_buffer);
1180 }
1181 
1182 inline bool gr_is_capable(gr_capability capability)
1183 {
1184 	return gr_screen.gf_is_capable(capability);
1185 }
1186 
1187 inline bool gr_get_property(gr_property property, void* destination)
1188 {
1189 	return gr_screen.gf_get_property(property, destination);
1190 }
1191 
1192 inline void gr_push_debug_group(const char* name)
1193 {
1194 	gr_screen.gf_push_debug_group(name);
1195 }
1196 
1197 inline void gr_pop_debug_group()
1198 {
1199 	gr_screen.gf_pop_debug_group();
1200 }
1201 
1202 inline int gr_create_query_object()
1203 {
1204 	return gr_screen.gf_create_query_object();
1205 }
1206 
1207 inline void gr_query_value(int obj, QueryType type)
1208 {
1209 	gr_screen.gf_query_value(obj, type);
1210 }
1211 
1212 inline bool gr_query_value_available(int obj)
1213 {
1214 	return gr_screen.gf_query_value_available(obj);
1215 }
1216 
1217 inline std::uint64_t gr_get_query_value(int obj)
1218 {
1219 	return gr_screen.gf_get_query_value(obj);
1220 }
1221 
1222 inline void gr_delete_query_object(int obj)
1223 {
1224 	gr_screen.gf_delete_query_object(obj);
1225 }
1226 
1227 inline std::unique_ptr<os::Viewport> gr_create_viewport(const os::ViewPortProperties& props)
1228 {
1229 	return gr_screen.gf_create_viewport(props);
1230 }
1231 inline void gr_use_viewport(os::Viewport* view)
1232 {
1233 	gr_screen.gf_use_viewport(view);
1234 }
1235 inline void gr_set_viewport(int x, int y, int width, int height)
1236 {
1237 	gr_screen.gf_set_viewport(x, y, width, height);
1238 }
1239 
1240 inline void gr_bind_uniform_buffer(uniform_block_type bind_point, size_t offset, size_t size, gr_buffer_handle buffer)
1241 {
1242 	gr_screen.gf_bind_uniform_buffer(bind_point, offset, size, buffer);
1243 }
1244 
1245 inline gr_sync gr_sync_fence()
1246 {
1247 	return gr_screen.gf_sync_fence();
1248 }
1249 inline bool gr_sync_wait(gr_sync sync, uint64_t timeoutns)
1250 {
1251 	return gr_screen.gf_sync_wait(sync, timeoutns);
1252 }
1253 inline void gr_sync_delete(gr_sync sync)
1254 {
1255 	gr_screen.gf_sync_delete(sync);
1256 }
1257 
1258 // color functions
1259 void gr_init_color(color *c, int r, int g, int b);
1260 void gr_init_alphacolor( color *clr, int r, int g, int b, int alpha, int type = AC_TYPE_HUD );
1261 void gr_set_color( int r, int g, int b );
1262 void gr_set_color_fast(color *dst);
1263 
1264 // shader functions
1265 void gr_create_shader(shader *shade, ubyte r, ubyte g, ubyte b, ubyte c);
1266 void gr_set_shader(shader *shade);
1267 
1268 // new bitmap functions
1269 void gr_bitmap(int x, int y, int resize_mode = GR_RESIZE_FULL);
1270 void gr_bitmap_uv(int _x, int _y, int _w, int _h, float _u0, float _v0, float _u1, float _v1, int resize_mode = GR_RESIZE_FULL);
1271 
1272 // special function for drawing polylines. this function is specifically intended for
1273 // polylines where each section is no more than 90 degrees away from a previous section.
1274 // Moreover, it is _really_ intended for use with 45 degree angles.
1275 void gr_pline_special(SCP_vector<vec3d> *pts, int thickness,int resize_mode=GR_RESIZE_FULL);
1276 
1277 #define VB_FLAG_POSITION	(1<<0)
1278 #define VB_FLAG_RHW			(1<<1)	//incompatable with the next normal
1279 #define VB_FLAG_NORMAL		(1<<2)
1280 #define VB_FLAG_DIFUSE		(1<<3)
1281 #define VB_FLAG_SPECULAR	(1<<4)
1282 #define VB_FLAG_UV1			(1<<5)	//how many UV coords, only use one of these
1283 #define VB_FLAG_UV2			(1<<6)
1284 #define VB_FLAG_UV3			(1<<7)
1285 #define VB_FLAG_UV4			(1<<8)
1286 #define VB_FLAG_TANGENT		(1<<9)
1287 #define VB_FLAG_LARGE_INDEX	(1<<10)
1288 #define VB_FLAG_MODEL_ID	(1<<11)
1289 #define VB_FLAG_TRANS		(1<<12)
1290 
1291 /**
1292 * @brief Prints the current time
1293 *
1294 * Draws the timestamp of the current #Missiontime in the format @c h:mm:ss at the specified coordinates
1295 *
1296 * @param x The x position where the timestamp should be draw
1297 * @param y The y position where the timestamp should be draw
1298 * @param timestamp The timestamp (in 65536ths of a second) to be printed
1299 * @param resize_mode The resize mode to use
1300 */
1301 void gr_print_timestamp(int x, int y, fix timestamp, int resize_mode);
1302 
1303 namespace graphics {
1304 class DebugScope {
1305  public:
1306 	explicit DebugScope(const char* name) {
1307 		gr_push_debug_group(name);
1308 	}
1309 	~DebugScope() {
1310 		gr_pop_debug_group();
1311 	}
1312 };
1313 }
1314 
1315 #ifndef NDEBUG
1316 #define GR_DEBUG_SCOPE(name) ::graphics::DebugScope SCP_TOKEN_CONCAT(gr_scope, __LINE__)(name)
1317 #else
1318 #define GR_DEBUG_SCOPE(name) do {} while(false)
1319 #endif
1320 
1321 enum AnimatedShader {
1322 	ANIMATED_SHADER_LOADOUTSELECT_FS1= 0,
1323 	ANIMATED_SHADER_LOADOUTSELECT_FS2= 1,
1324 	ANIMATED_SHADER_CLOAK = 2,
1325 };
1326 
1327 /**
1328  * @brief Retreives a uniform buffer for storing uniform block data
1329  * @param type The type of uniform data that will be stored in the buffer
1330  * @param num_elements The number of elements that will be used in the buffer
1331  * @param element_size_override Override what the size of the element should be instead of relying on the preconfigured
1332  * size for that block type
1333  * @return A structure which gives access to a memory buffer where the uniform data can be stored
1334  */
1335 graphics::util::UniformBuffer gr_get_uniform_buffer(uniform_block_type type, size_t num_elements,
1336                                                     size_t element_size_override = 0);
1337 
1338 struct VideoModeData {
1339 	uint32_t width = 0;
1340 	uint32_t height = 0;
1341 	uint32_t bit_depth = 0;
1342 };
1343 
1344 struct DisplayData {
1345 	uint32_t index;
1346 	SCP_string name;
1347 
1348 	int32_t x = 0;
1349 	int32_t y = 0;
1350 	int32_t width = 0;
1351 	int32_t height = 0;
1352 
1353 	SCP_vector<VideoModeData> video_modes;
1354 };
1355 
1356 SCP_vector<DisplayData> gr_enumerate_displays();
1357 
1358 enum class GpuHeap {
1359 	ModelVertex = 0,
1360 	ModelIndex,
1361 
1362 	NUM_VALUES
1363 };
1364 
1365 /**
1366  * @brief Allocates storage on the specified GPU heap and stores data in that storage
1367  * @param heap_type The heap type to store this memory on
1368  * @param size The size of the data
1369  * @param data A pointer to the data
1370  * @param[out] offset_out The offset at which the data is stored in the buffer
1371  * @param[out] handle_out The handle of the buffer object this data is stored in
1372  */
1373 void gr_heap_allocate(GpuHeap heap_type, size_t size, void* data, size_t& offset_out, gr_buffer_handle& handle_out);
1374 
1375 /**
1376  * @brief Deallocates memory previously allocated with gr_heap_allocate.
1377  * @param heap_type The heap type to deallocate this memory from
1378  * @param data_offset The offset at which the data is stored.
1379  */
1380 void gr_heap_deallocate(GpuHeap heap_type, size_t data_offset);
1381 
1382 void gr_set_gamma(float gamma);
1383 
1384 void gr_get_post_process_effect_names(SCP_vector<SCP_string> &names);
1385 
1386 // Include this last to make the 2D rendering function available everywhere
1387 #include "graphics/render.h"
1388 
1389 #endif
1390