/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ #ifndef _GRAPHICS_H #define _GRAPHICS_H #include "globalincs/flagset.h" #include "globalincs/pstypes.h" #include "bmpman/bmpman.h" #include "cfile/cfile.h" #include "graphics/grinternal.h" #include "graphics/tmapper.h" #include "io/cursor.h" #include "math/vecmat.h" #include "osapi/osapi.h" #include "utils/id.h" // Forward definition namespace graphics { namespace util { class UniformBuffer; class GPUMemoryHeap; } // namespace util } // namespace graphics namespace scripting { template class OverridableHook; } extern const float Default_min_draw_distance; extern const float Default_max_draw_distance; extern float Min_draw_distance_cockpit; extern float Min_draw_distance; extern float Max_draw_distance; extern int Gr_inited; // # Software Re-added by Kazan --- THIS HAS TO STAY -- It is used by standalone! enum class GraphicsAPI : uint8_t { Default, Stub, OpenGL, Vulkan }; // z-buffering stuff extern int gr_zbuffering, gr_zbuffering_mode; extern int gr_global_zbuffering; extern bool Gr_enable_soft_particles; FLAG_LIST(FramebufferEffects){Thrusters = 0, Shockwaves, NUM_VALUES}; extern flagset Gr_framebuffer_effects; enum class AntiAliasMode { None = 0, FXAA_Low = 1, FXAA_Medium = 2, FXAA_High = 3, SMAA_Low = 4, SMAA_Medium = 5, SMAA_High = 6, SMAA_Ultra = 7, }; extern AntiAliasMode Gr_aa_mode; extern AntiAliasMode Gr_aa_mode_last_frame; bool gr_is_fxaa_mode(AntiAliasMode mode); bool gr_is_smaa_mode(AntiAliasMode mode); extern bool Gr_post_processing_enabled; extern bool Gr_enable_vsync; // HDR10 (PQ/ST.2084 + BT.2020) output. Currently only honored by the Vulkan renderer. extern bool Gr_enable_hdr; // True once the renderer has actually negotiated an HDR10 swap chain (read-only, // set by the active renderer). Distinct from Gr_enable_hdr, which is the request. extern bool Gr_hdr_output_active; // Reference white luminance in nits (the brightness of SDR "paper white" / UI when HDR is active). extern float Gr_hdr_paperwhite_nits; // Display peak luminance in nits used for tone curve clamping and HDR10 metadata. extern float Gr_hdr_peak_nits; extern bool Deferred_lighting; extern bool High_dynamic_range; extern os::ViewportState Gr_configured_window_state; extern const std::shared_ptr> OnFrameHook; class material; class model_material; class particle_material; class distortion_material; class shield_material; class movie_material; class batched_bitmap_material; class nanovg_material; class decal_material; class interface_material; class transform_stack { matrix4 Current_transform; SCP_vector Stack; public: transform_stack() { vm_matrix4_set_identity(&Current_transform); Stack.clear(); Stack.push_back(Current_transform); } const matrix4 &get_transform() const { return Current_transform; } void clear() { vm_matrix4_set_identity(&Current_transform); Stack.clear(); Stack.push_back(Current_transform); } void push_and_replace(const matrix4 &new_transform) { Current_transform = new_transform; Stack.push_back(Current_transform); } void push(const vec3d *pos, const matrix *orient, const vec3d *scale = NULL) { vec3d new_scale = SCALE_IDENTITY_VECTOR; matrix new_orient = IDENTITY_MATRIX; vec3d new_pos = ZERO_VECTOR; matrix4 current_transform_copy = Current_transform; matrix4 new_transform; if ( pos != NULL ) { new_pos = *pos; } if ( orient != NULL ) { new_orient = *orient; } if ( scale != NULL ) { new_scale = *scale; } vm_vec_scale(&new_orient.vec.rvec, new_scale.xyz.x); vm_vec_scale(&new_orient.vec.uvec, new_scale.xyz.y); vm_vec_scale(&new_orient.vec.fvec, new_scale.xyz.z); vm_matrix4_set_transform(&new_transform, &new_orient, &new_pos); vm_matrix4_x_matrix4(&Current_transform, ¤t_transform_copy, &new_transform); Stack.push_back(Current_transform); } void pop() { if ( Stack.size() > 1 ) { Stack.pop_back(); } Current_transform = Stack.back(); } size_t depth() { return Stack.size(); } }; enum primitive_type { PRIM_TYPE_POINTS, PRIM_TYPE_LINES, PRIM_TYPE_LINESTRIP, PRIM_TYPE_TRIS, PRIM_TYPE_TRISTRIP, PRIM_TYPE_TRIFAN, }; enum shader_type { SDR_TYPE_NONE = -1, SDR_TYPE_MODEL, SDR_TYPE_EFFECT_PARTICLE, SDR_TYPE_EFFECT_DISTORTION, SDR_TYPE_POST_PROCESS_MAIN, SDR_TYPE_POST_PROCESS_BLUR, SDR_TYPE_POST_PROCESS_BLOOM_COMP, SDR_TYPE_POST_PROCESS_BRIGHTPASS, SDR_TYPE_POST_PROCESS_FXAA, SDR_TYPE_POST_PROCESS_FXAA_PREPASS, SDR_TYPE_POST_PROCESS_LIGHTSHAFTS, SDR_TYPE_POST_PROCESS_TONEMAPPING, SDR_TYPE_DEFERRED_LIGHTING, SDR_TYPE_DEFERRED_CLEAR, SDR_TYPE_VIDEO_PROCESS, SDR_TYPE_PASSTHROUGH_RENDER, //!< Shader for doing the old style fixed-function rendering. Only used internally, use //!< SDR_TYPE_DEFAULT_MATERIAL. SDR_TYPE_SHIELD_DECAL, SDR_TYPE_BATCHED_BITMAP, SDR_TYPE_DEFAULT_MATERIAL, SDR_TYPE_NANOVG, SDR_TYPE_DECAL, SDR_TYPE_SCENE_FOG, SDR_TYPE_VOLUMETRIC_FOG, SDR_TYPE_ROCKET_UI, SDR_TYPE_COPY, SDR_TYPE_COPY_WORLD, SDR_TYPE_MSAA_RESOLVE, SDR_TYPE_POST_PROCESS_SMAA_EDGE, SDR_TYPE_POST_PROCESS_SMAA_BLENDING_WEIGHT, SDR_TYPE_POST_PROCESS_SMAA_NEIGHBORHOOD_BLENDING, SDR_TYPE_POST_PROCESS_SMAA_RESOLVE, SDR_TYPE_ENVMAP_SPHERE_WARP, SDR_TYPE_IRRADIANCE_MAP_GEN, SDR_TYPE_SHADOW_MAP_GEN, SDR_TYPE_GAMMA_BLIT, NUM_SHADER_TYPES }; // Shader flags #define SDR_FLAG_PARTICLE_POINT_GEN (1<<0) #define SDR_FLAG_BLUR_HORIZONTAL (1<<0) #define SDR_FLAG_BLUR_VERTICAL (1<<1) #define SDR_FLAG_NANOVG_EDGE_AA (1<<0) #define SDR_FLAG_DECAL_USE_NORMAL_MAP (1<<0) #define SDR_FLAG_MSAA_SAMPLES_4 (1 << 0) #define SDR_FLAG_MSAA_SAMPLES_8 (1 << 1) #define SDR_FLAG_MSAA_SAMPLES_16 (1 << 2) #define SDR_FLAG_VOLUMETRICS_DO_EDGE_SMOOTHING (1<<0) #define SDR_FLAG_VOLUMETRICS_NOISE (1<<1) #define SDR_FLAG_COPY_FROM_ARRAY (1 << 0) #define SDR_FLAG_COPY_CLAMP01 (1 << 1) #define SDR_FLAG_TONEMAPPING_LINEAR_OUT (1 << 0) #define SDR_FLAG_GAMMA_HDR10 (1 << 0) #define SDR_FLAG_ENV_MAP (1 << 0) #define SDR_FLAG_DEFERRED_RT_SHADOWS (1 << 1) #define SDR_FLAG_SHADOW_FALLBACK (1 << 0) #define SDR_FLAG_SHADOW_FALLBACK (1 << 0) enum class uniform_block_type { Lights = 0, ModelData = 1, NanoVGData = 2, DecalInfo = 3, DecalGlobals = 4, DeferredGlobals = 5, Matrices = 6, MovieData = 7, GenericData = 8, ShadowMapData = 9, ShadowCascadeParams = 10, NUM_BLOCK_TYPES }; struct vertex_format_data { enum vertex_format { POSITION4, POSITION3, POSITION2, COLOR3, COLOR4, COLOR4F, TEX_COORD2, TEX_COORD4, NORMAL, TANGENT, MODEL_ID, RADIUS, UVEC, MATRIX4, }; vertex_format format_type; size_t stride; size_t offset; size_t divisor; size_t buffer_number; vertex_format_data(vertex_format i_format_type, size_t i_stride, size_t i_offset, size_t i_divisor, size_t i_buffer_number) : format_type(i_format_type), stride(i_stride), offset(i_offset), divisor(i_divisor), buffer_number(i_buffer_number) {} static inline uint mask(vertex_format v_format) { return 1 << v_format; } bool operator==(const vertex_format_data& other) const { return format_type == other.format_type && stride == other.stride && offset == other.offset; } }; class vertex_layout { SCP_vector Vertex_components; uint Vertex_mask = 0; SCP_unordered_map Vertex_stride; public: vertex_layout() {} size_t get_num_vertex_components() const { return Vertex_components.size(); } const vertex_format_data* get_vertex_component(size_t index) const { return &Vertex_components[index]; } bool resident_vertex_format(vertex_format_data::vertex_format format_type) const; void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset, size_t divisor = 0, size_t buffer_number = 0); size_t get_vertex_stride(size_t buffer_number = 0) const { return Vertex_stride.at(buffer_number); } bool operator==(const vertex_layout& other) const; size_t hash() const; }; namespace std { template<> struct hash { size_t operator()(const vertex_format_data& data) const; }; template<> struct hash { size_t operator()(const vertex_layout& data) const; }; } enum class gr_capability { CAPABILITY_ENVIRONMENT_MAP, CAPABILITY_NORMAL_MAP, CAPABILITY_HEIGHT_MAP, CAPABILITY_SOFT_PARTICLES, CAPABILITY_DISTORTION, CAPABILITY_POST_PROCESSING, CAPABILITY_DEFERRED_LIGHTING, CAPABILITY_SHADOWS, CAPABILITY_THICK_OUTLINE, CAPABILITY_BATCHED_SUBMODELS, CAPABILITY_TIMESTAMP_QUERY, CAPABILITY_SEPARATE_BLEND_FUNCTIONS, CAPABILITY_PERSISTENT_BUFFER_MAPPING, CAPABILITY_BPTC, CAPABILITY_S3TC, CAPABILITY_LARGE_SHADER, CAPABILITY_INSTANCED_RENDERING, CAPABILITY_FAST_SHADOWS, CAPABILITY_QUERIES_REUSABLE, CAPABILITY_RAYTRACED_SHADOWS }; struct gr_capability_def { gr_capability capability; const char* parse_name; }; extern gr_capability_def gr_capabilities[]; extern const size_t gr_capabilities_num; enum class gr_property { UNIFORM_BUFFER_OFFSET_ALIGNMENT, UNIFORM_BUFFER_MAX_SIZE, MAX_ANISOTROPY }; struct gr_buffer_handle_tag { }; using gr_buffer_handle = ::util::ID; // stencil buffering stuff extern int gr_stencil_mode; /** * This is a structure used by the shader to keep track * of the values you want to use in the shade primitive. */ typedef struct shader { ubyte r, g, b, c; // factors and constant ubyte lookup[256]; } shader; #define AC_TYPE_NONE 0 // Not an alphacolor #define AC_TYPE_HUD 1 // Doesn't change hue depending on background. Used for HUD stuff. #define AC_TYPE_BLEND 2 // Changes hue depending on background. Used for stars, etc. // NEVER REFERENCE THESE VALUES OUTSIDE OF THE GRAPHICS LIBRARY!!! // If you need to get the rgb values of a "color" struct call // gr_get_colors after calling gr_set_colors_fast. typedef struct color { int is_alphacolor; int alphacolor; int magic; ubyte red; ubyte green; ubyte blue; ubyte alpha; ubyte ac_type; // The type of alphacolor. See AC_TYPE_??? defines ubyte raw8; } color; // Used by the team coloring code typedef struct team_color { struct { float r, g, b; } base; struct { float r, g, b; } stripe; } team_color; typedef struct tsb_t { vec3d tangent; float scaler; } tsb_t; /** * This should be basicly just like it is in the VB * a list of triangles and their associated normals */ class poly_list { // helper function struct that let's us sort the indices. // an instance is fed into std::sort and std::lower_bound. // overloaded operator() is used for the comparison function. struct finder { poly_list* search_list; bool compare_indices; vertex* vert_to_find; vec3d* norm_to_find; finder(poly_list* _search_list): search_list(_search_list), compare_indices(true), vert_to_find(NULL), norm_to_find(NULL) {} finder(poly_list* _search_list, vertex* _vert, vec3d* _norm): search_list(_search_list), compare_indices(false), vert_to_find(_vert), norm_to_find(_norm) {} bool operator()(const uint a, const uint b); }; public: poly_list(): n_verts(0), vert(NULL), norm(NULL), tsb(NULL), submodels(NULL), sorted_indices(NULL), currently_allocated(0) {} ~poly_list(); poly_list& operator=(const poly_list&); void allocate(int size); void make_index_buffer(SCP_vector &vertex_list); void calculate_tangent(); int n_verts; vertex *vert; vec3d *norm; tsb_t *tsb; int *submodels; uint *sorted_indices; int find_index(poly_list *plist, int idx); int find_index_fast(poly_list *plist, int idx); private: int currently_allocated; int find_first_vertex(int idx); int find_first_vertex_fast(int idx); void generate_sorted_index_list(); }; class buffer_data { public: int flags; int texture; // this is the texture the vertex buffer will use size_t n_verts; size_t index_offset; const uint *get_index() const { return index; } uint i_first, i_last; void release() { if (index) { delete [] index; index = NULL; } } void assign(size_t i, uint j) { const_cast(index)[i] = j; if (i_first > i_last) i_first = i_last = j; else if (i_first > j) i_first = j; else if (i_last < j) i_last = j; } // Constructor buffer_data() : flags(0), texture(-1), n_verts(0), index_offset(0), i_first(1), i_last(0), index(NULL) { } explicit buffer_data(size_t n_vrts) : flags(0), texture(-1), n_verts(n_vrts), index_offset(0), i_first(1), i_last(0), index(NULL) { if ( n_verts > 0 ) { index = new(std::nothrow) uint[n_verts]; } else { index = NULL; } } // Copy-constructor buffer_data(const buffer_data& other) { if ( other.index ) { index = new(std::nothrow) uint[other.n_verts]; for (size_t i=0; i < other.n_verts; i++) { index[i] = other.index[i]; } } else { index = NULL; } flags = other.flags; texture = other.texture; n_verts = other.n_verts; i_first = other.i_first; i_last = other.i_last; index_offset = other.index_offset; } // Copy-assignment operator buffer_data& operator=(const buffer_data& rhs) { if (this != &rhs) { if ( index ) { delete [] index; } if ( rhs.index && rhs.n_verts > 0 ) { index = new(std::nothrow) uint[rhs.n_verts]; for (size_t i=0; i < rhs.n_verts; i++) { index[i] = rhs.index[i]; } } flags = rhs.flags; texture = rhs.texture; n_verts = rhs.n_verts; i_first = rhs.i_first; i_last = rhs.i_last; index_offset = rhs.index_offset; } return *this; } // Destructor ~buffer_data() { release(); } private: uint *index; }; class vertex_buffer { public: int flags; size_t stride; size_t vertex_offset; size_t vertex_num_offset; poly_list *model_list; SCP_vector tex_buf; vertex_layout layout; vertex_buffer() : flags(0), stride(0), vertex_offset(0), vertex_num_offset(0), model_list(NULL) { } ~vertex_buffer() { clear(); } void release() { if (model_list) { delete model_list; model_list = NULL; } for (SCP_vector::iterator tbi = tex_buf.begin(); tbi != tex_buf.end(); ++tbi) { tbi->release(); } } void clear() { release(); tex_buf.clear(); } }; struct indexed_vertex_source { std::shared_ptr Vertex_list = nullptr; std::shared_ptr Index_list = nullptr; gr_buffer_handle Vbuffer_handle; size_t Vertex_offset = 0; size_t Base_vertex_offset = 0; gr_buffer_handle Ibuffer_handle; size_t Index_offset = 0; uint Vertex_list_size = 0; uint Index_list_size = 0; }; struct light; #define FIND_SCALED_NUM(x, x0, x1, y0, y1) ( ((((x) - (x0)) * ((y1) - (y0))) / ((x1) - (x0))) + (y0) ) #define GR_ALPHABLEND_NONE 0 // no blending #define GR_ALPHABLEND_FILTER 1 // 50/50 mix of foreground, background, using intensity as alpha #define GR_BITBLT_MODE_NORMAL 0 // Normal bitblting #define GR_BITBLT_MODE_RLE 1 // RLE would be faster // fog modes #define GR_FOGMODE_NONE 0 // set this to turn off fog #define GR_FOGMODE_FOG 1 // linear fog enum class QueryType { Timestamp }; enum class BufferType { Vertex, Index, Uniform }; enum class BufferUsageHint { Static, Dynamic, Streaming, PersistentMapping }; /** * @brief Type of a graphics sync object */ typedef void* gr_sync; typedef struct screen { int max_w = 0, max_h = 0; // Width and height int max_w_unscaled = 0, max_h_unscaled = 0; int max_w_unscaled_zoomed = 0, max_h_unscaled_zoomed = 0; int center_w = 0, center_h = 0; // Width and height of center monitor int center_offset_x = 0, center_offset_y = 0; int save_max_w = 0, save_max_h = 0; // Width and height int save_max_w_unscaled = 0, save_max_h_unscaled = 0; int save_max_w_unscaled_zoomed = 0, save_max_h_unscaled_zoomed = 0; int save_center_w = 0, save_center_h = 0; // Width and height of center monitor int save_center_offset_x = 0, save_center_offset_y = 0; int res = 0; // GR_640 or GR_1024 GraphicsAPI mode = GraphicsAPI::Default; // What mode gr_init was called with. float aspect = 0.0f, clip_aspect = 0.0f; // Aspect ratio = 0, aspect of clip_width/clip_height int rowsize = 0; // What you need to add to go to next row (includes bytes_per_pixel) int bits_per_pixel = 0; // How many bits per pixel it is. (7,8,15,16,24,32) int bytes_per_pixel = 0; // How many bytes per pixel (1,2,3,4) int offset_x = 0, offset_y = 0; // The offsets into the screen int offset_x_unscaled = 0, offset_y_unscaled = 0; // Offsets into the screen, in unscaled dimensions int clip_width = 0, clip_height = 0; int clip_width_unscaled = 0, clip_height_unscaled = 0; // Height and width of clip aread, in unscaled dimensions // center of clip area float clip_center_x = 0.0f, clip_center_y = 0.0f; float fog_near = 0.0f, fog_far = 0.0f; // the clip_l,r,t,b are used internally. left and top are // actually always 0, but it's nice to have the code work with // arbitrary clipping regions. int clip_left = 0, clip_right = 0, clip_top = 0, clip_bottom = 0; // same as above except in unscaled dimensions int clip_left_unscaled = 0, clip_right_unscaled = 0, clip_top_unscaled = 0, clip_bottom_unscaled = 0; int current_alphablend_mode = 0; // See GR_ALPHABLEND defines above int current_bitblt_mode = 0; // See GR_BITBLT_MODE defines above int current_bitmap = 0; color current_color{}; color current_fog_color{}; // current fog color color current_clear_color{}; // current clear color shader current_shader{}; float current_alpha = 0.0f; bool custom_size = false; int rendering_to_texture = 0; // wich texture we are rendering to, -1 if the back buffer int rendering_to_face = 0; // wich face of the texture we are rendering to, -1 if the back buffer int envmap_render_target = 0; int irrmap_render_target = -1; // Irradiance map for diffuse env lighting. float line_width = 0.0f; // switch onscreen, offscreen std::function gf_flip; std::function gf_setup_frame; // sets the clipping region std::function gf_set_clip; // resets the clipping region to entire screen std::function gf_reset_clip; // clears entire clipping region to current color std::function gf_clear; // dumps the current screen to a file std::function gf_print_screen; // dumps the current screen to a html blob string std::function gf_blob_screen; // transforms and dumps the current environment map to a file std::function gf_dump_envmap; // generate diffuse irradiance cubemap for IBL. std::function gf_calculate_irrmap; // Retrieves the zbuffer mode. std::function gf_zbuffer_get; // Sets mode. Returns previous mode. std::function gf_zbuffer_set; // Clears the zbuffer. If use_zbuffer is FALSE, then zbuffering mode is ignored and zbuffer is always off. std::function gf_zbuffer_clear; // Set the stencil buffer mode. Returns previous mode std::function gf_stencil_set; // Clears the stencil buffer. std::function gf_stencil_clear; std::function gf_alpha_mask_set; // Saves screen. Returns an id you pass to restore and free. std::function gf_save_screen; // Resets clip region and copies entire saved screen to the screen. std::function gf_restore_screen; // Frees up a saved screen. std::function gf_free_screen; // grab a region of the screen. assumes data is large enough std::function gf_get_region; // poly culling std::function gf_set_cull; // color buffer writes std::function gf_set_color_buffer; // preload a bitmap into texture memory std::function gf_preload; // set the color to be used when clearing the background std::function gf_set_clear_color; // Here be the bitmap functions std::function gf_bm_free_data; std::function gf_bm_create; std::function gf_bm_init; std::function gf_bm_page_in_start; std::function gf_bm_data; std::function gf_bm_make_render_target; std::function gf_bm_set_render_target; std::function gf_set_texture_addressing; std::function gf_create_buffer; std::function gf_delete_buffer; // Optional lifecycle hooks for backends that maintain auxiliary per-model GPU // state (e.g. Vulkan's raytraced-shadow BLAS cache). Default to no-ops so // backends that don't need them (OpenGL, stub) don't have to assign anything. std::function gf_model_loaded = [](int) {}; std::function gf_model_unloaded = [](int) {}; // Rebuilds the raytraced-shadow top-level acceleration structure for the // current frame from the live shadow-casting object set. Called once per // frame from shadows_render_all(), alongside the cascaded shadow map pass -- // the shading pass picks between the two per shadows_use_raytracing(). // No-op default. std::function gf_build_shadow_tlas = []() {}; std::function gf_update_buffer_data; std::function gf_update_buffer_data_offset; std::function gf_map_buffer; std::function gf_flush_mapped_buffer; std::function gf_update_transform_buffer; // postprocessing effects std::function gf_post_process_set_effect; std::function gf_post_process_set_defaults; std::function gf_post_process_begin; std::function gf_post_process_end; std::function gf_post_process_save_zbuffer; std::function gf_post_process_restore_zbuffer; std::function gf_deferred_lighting_begin; std::function gf_deferred_lighting_msaa; std::function gf_deferred_lighting_end; std::function gf_deferred_lighting_finish; std::function gf_scene_texture_begin; std::function gf_scene_texture_end; std::function gf_copy_effect_texture; std::function gf_zbias; std::function gf_set_fill_mode; std::function gf_set_line_width; std::function gf_sphere; std::function gf_maybe_create_shader; std::function& progress_callback)> gf_recompile_all_shaders; std::function gf_clear_states; std::function gf_update_texture; // Reads the texture uploaded for a bitmap back from graphics memory. Returns a vm_malloc'd buffer // (freed by the caller with vm_free) and reports the dimensions of the returned data, which may be // smaller than the bitmap if the texture was culled at upload; returns nullptr on failure. std::function gf_get_bitmap_from_texture; std::function gf_shadow_map_start; std::function gf_shadow_map_end; std::function gf_start_decal_pass; std::function gf_stop_decal_pass; // new drawing functions std::function< void(model_material* material_info, indexed_vertex_source* vert_source, vertex_buffer* bufferp, size_t texi)> gf_render_model; std::function gf_render_shadow_draw; std::function gf_render_shield_impact; std::function gf_render_primitives; std::function gf_render_primitives_particle; std::function gf_render_primitives_distortion; std::function gf_render_movie; std::function gf_render_primitives_batched; std::function gf_render_nanovg; std::function gf_render_decals; void (*gf_render_rocket_primitives)(interface_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_indices, gr_buffer_handle vertex_buffer, gr_buffer_handle index_buffer); std::function gf_is_capable; std::function gf_get_property; std::function gf_push_debug_group; std::function gf_pop_debug_group; std::function gf_create_query_object; std::function gf_query_value; std::function gf_query_value_available; std::function gf_get_query_value; std::function gf_delete_query_object; std::unique_ptr (*gf_create_viewport)(const os::ViewPortProperties& props); std::function gf_use_viewport; std::function gf_bind_uniform_buffer; std::function gf_sync_fence; std::function gf_sync_wait; std::function gf_sync_delete; std::function gf_set_viewport; std::function gf_override_fog; // ImGui backend integration std::function gf_imgui_new_frame; std::function gf_imgui_render_draw_data; //OpenXR functions std::function()> gf_openxr_get_extensions; std::function gf_openxr_test_capabilities; std::function gf_openxr_create_session; std::function&)> gf_openxr_get_swapchain_format; std::function gf_openxr_acquire_swapchain_buffers; std::function gf_openxr_flip; } screen; /** * @brief Scripting context render values */ typedef struct lua_screen { bool active = false; bool force_fso_context = false; color current_color = { 0, // is_alphacolor 0, // alphacolor 0, // magic 255, // red 255, // green 255, // blue 255, // alpha 0, // ac_type 0 // raw8 }; float line_width = 1.0f; int current_font_index = 0; } lua_screen; extern lua_screen gr_lua_screen; bool gr_lua_context_active(); // Macros to easily choose been which context to use for color and line width // Note that font is handled slightly differently for the normal game context by using it's own global in the FontManager namespace // So FontManager::getCurrentFontIndex() is effectively its own macro // Gets the current color between the game context and the lua context if active #define GR_CURRENT_COLOR (gr_lua_context_active() ? gr_lua_screen.current_color : gr_screen.current_color) // Gets the current line width between the game context and the lua contet if active #define GR_CURRENT_LINE_WIDTH (gr_lua_context_active() ? gr_lua_screen.line_width : gr_screen.line_width) // handy macro #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); //Window's interface to set up graphics: //-------------------------------------- // Call this at application startup #define GR_DEFAULT (-1) // resolution constants - always keep resolutions in ascending order and starting from 0 #define GR_NUM_RESOLUTIONS 2 #define GR_640 0 // 640 x 480 #define GR_1024 1 // 1024 x 768 #define GR_1024_THRESHOLD_WIDTH 1024 #define GR_1024_THRESHOLD_HEIGHT 600 extern const char *Resolution_prefixes[GR_NUM_RESOLUTIONS]; extern bool gr_init(std::unique_ptr&& graphicsOps, GraphicsAPI d_mode = GraphicsAPI::Default, int d_width = GR_DEFAULT, int d_height = GR_DEFAULT, int d_depth = GR_DEFAULT); // The render API (GraphicsAPI::OpenGL/GraphicsAPI::Vulkan) selected via the "Graphics.RenderAPI" in-game option (or a mod's // default settings table). The -vulkan/-opengl command line flags still win over this; see Cmdline_graphics_api. extern GraphicsAPI gr_get_configured_render_api(); // The display name of a render API, e.g. "OpenGL". Returns "Unknown???" for GraphicsAPI values that are not // a real backend, such as GraphicsAPI::Stub. extern const char* gr_render_api_name(GraphicsAPI api); extern void gr_screen_resize(int width, int height); extern int gr_get_resolution_class(int width, int height); /** * @brief Converts a position or delta from OS window pixels into internal render-target pixels * * @details When -window_res is in effect the frame is rendered into an offscreen buffer sized * gr_screen.max_w/max_h and only stretched to the window when we flip, so everything the engine * draws lives in render space while SDL reports input in window space. These are pure scale * factors with no offset, so they are equally valid for absolute positions and for deltas. * * Note that this is unrelated to the gr_resize_screen_pos() family, which handles the retail * 640/1024 menu coordinate system. */ void gr_window_to_render_pos(float& x, float& y); /** * @brief Converts a position or delta from internal render-target pixels into OS window pixels * * @see gr_window_to_render_pos */ void gr_render_to_window_pos(float& x, float& y); // Call this when your app ends. extern void gr_close(); extern screen gr_screen; #define GR_FILL_MODE_WIRE 1 #define GR_FILL_MODE_SOLID 2 #define GR_ZBUFF_NONE 0 #define GR_ZBUFF_WRITE (1<<0) #define GR_ZBUFF_READ (1<<1) #define GR_ZBUFF_FULL (GR_ZBUFF_WRITE|GR_ZBUFF_READ) #define GR_STENCIL_NONE 0 #define GR_STENCIL_READ 1 #define GR_STENCIL_WRITE 2 #define GR_RESIZE_NONE 0 #define GR_RESIZE_FULL 1 #define GR_RESIZE_FULL_CENTER 2 #define GR_RESIZE_MENU 3 #define GR_RESIZE_MENU_ZOOMED 4 #define GR_RESIZE_MENU_NO_OFFSET 5 #define GR_RESIZE_REPLACE 6 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); void gr_reset_screen_scale(); bool gr_unsize_screen_pos(int *x, int *y, int *w = NULL, int *h = NULL, int resize_mode = GR_RESIZE_FULL); bool gr_resize_screen_pos(int *x, int *y, int *w = NULL, int *h = NULL, int resize_mode = GR_RESIZE_FULL); bool gr_unsize_screen_posf(float *x, float *y, float *w = NULL, float *h = NULL, int resize_mode = GR_RESIZE_FULL); bool gr_resize_screen_posf(float *x, float *y, float *w = NULL, float *h = NULL, int resize_mode = GR_RESIZE_FULL); // Does formatted printing. This calls gr_string after formatting, // so if you don't need to format the string, then call gr_string // directly. extern void gr_printf(int x, int y, SCP_FORMAT_STRING const char *format, ...) SCP_FORMAT_STRING_ARGS(3, 4); extern void gr_printf(int x, int y, size_t len, SCP_FORMAT_STRING const char *format, ...) SCP_FORMAT_STRING_ARGS(4, 5); // same as gr_printf but positions text correctly in menus extern void gr_printf_menu(int x, int y, SCP_FORMAT_STRING const char *format, ...) SCP_FORMAT_STRING_ARGS(3, 4); extern void gr_printf_menu(int x, int y, size_t len, SCP_FORMAT_STRING const char *format, ...) SCP_FORMAT_STRING_ARGS(4, 5); // same as gr_printf_menu but accounts for menu zooming extern void gr_printf_menu_zoomed(int x, int y, SCP_FORMAT_STRING const char *format, ...) SCP_FORMAT_STRING_ARGS(3, 4); extern void gr_printf_menu_zoomed(int x, int y, size_t len, SCP_FORMAT_STRING const char *format, ...) SCP_FORMAT_STRING_ARGS(4, 5); // same as gr_printf but doesn't resize for non-standard resolutions extern void gr_printf_no_resize(int x, int y, SCP_FORMAT_STRING const char *format, ...) SCP_FORMAT_STRING_ARGS(3, 4); extern void gr_printf_no_resize(int x, int y, size_t len, SCP_FORMAT_STRING const char *format, ...) SCP_FORMAT_STRING_ARGS(4, 5); // Returns the size of the string in pixels in w and h extern void gr_get_string_size( int *w, int *h, const char * text, float scaleMultiplier = 1.0f, size_t len = std::string::npos); // Returns the height of the current font extern int gr_get_font_height(); // Returns a scaled amount of lines per the current font --wookieejedi extern int gr_get_dynamic_font_lines(int number_default_lines); extern io::mouse::Cursor* Web_cursor; // Called by OS when application gets/looses focus extern void gr_activate(bool active); #define GR_CALL(x) (x) // These macros make the function indirection look like the // old Descent-style gr_xxx calls. #define gr_print_screen GR_CALL(gr_screen.gf_print_screen) #define gr_blob_screen GR_CALL(gr_screen.gf_blob_screen) #define gr_dump_envmap GR_CALL(gr_screen.gf_dump_envmap) void gr_request_screenshot(const char* filename); bool gr_is_screenshot_requested(); //#define gr_flip GR_CALL(gr_screen.gf_flip) void gr_flip(bool execute_scripting = true); inline void gr_setup_frame() { gr_screen.gf_setup_frame(); } //#define gr_set_clip GR_CALL(gr_screen.gf_set_clip) inline void gr_set_clip(int x, int y, int w, int h, int resize_mode=GR_RESIZE_FULL) { gr_screen.gf_set_clip(x, y, w, h, resize_mode); } #define gr_reset_clip GR_CALL(gr_screen.gf_reset_clip) void gr_set_bitmap(int bitmap_num, int alphablend = GR_ALPHABLEND_NONE, int bitbltmode = GR_BITBLT_MODE_NORMAL, float alpha = 1.0f); #define gr_clear GR_CALL(gr_screen.gf_clear) #define gr_zbuffer_get GR_CALL(gr_screen.gf_zbuffer_get) #define gr_zbuffer_set GR_CALL(gr_screen.gf_zbuffer_set) #define gr_zbuffer_clear GR_CALL(gr_screen.gf_zbuffer_clear) #define gr_stencil_set GR_CALL(gr_screen.gf_stencil_set) #define gr_stencil_clear GR_CALL(gr_screen.gf_stencil_clear) #define gr_alpha_mask_set GR_CALL(gr_screen.gf_alpha_mask_set) #define gr_save_screen GR_CALL(gr_screen.gf_save_screen) #define gr_restore_screen GR_CALL(gr_screen.gf_restore_screen) #define gr_free_screen GR_CALL(gr_screen.gf_free_screen) #define gr_get_region GR_CALL(gr_screen.gf_get_region) #define gr_set_cull GR_CALL(gr_screen.gf_set_cull) #define gr_set_color_buffer GR_CALL(gr_screen.gf_set_color_buffer) #define gr_preload GR_CALL(gr_screen.gf_preload) #define gr_set_clear_color GR_CALL(gr_screen.gf_set_clear_color) // Here be the bitmap functions #define gr_bm_free_data GR_CALL(gr_screen.gf_bm_free_data) #define gr_bm_create GR_CALL(gr_screen.gf_bm_create) #define gr_bm_init GR_CALL(gr_screen.gf_bm_init) #define gr_bm_page_in_start GR_CALL(gr_screen.gf_bm_page_in_start) #define gr_bm_data GR_CALL(gr_screen.gf_bm_data) #define gr_bm_make_render_target GR_CALL(gr_screen.gf_bm_make_render_target) inline int gr_bm_set_render_target(int n, int face = -1) { return gr_screen.gf_bm_set_render_target(n, face); } #define gr_set_texture_addressing GR_CALL(gr_screen.gf_set_texture_addressing) /** * @brief Create a GPU buffer * @param type The buffer type (Vertex, Index, Uniform) * @param usage Usage hint for optimization * @param rt_capable If true (Vulkan only), the buffer is created with the extra * usage flags (VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT and * VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR) * needed to use it as acceleration structure geometry input. Ignored by * backends without raytraced shadow support. */ inline gr_buffer_handle gr_create_buffer(BufferType type, BufferUsageHint usage, bool rt_capable = false) { return gr_screen.gf_create_buffer(type, usage, rt_capable); } #define gr_delete_buffer GR_CALL(gr_screen.gf_delete_buffer) /** * @brief Notify the graphics backend that a model finished loading (its GPU * vertex/index buffers are already uploaded at this point). No-op on backends * that don't need per-model GPU state. */ inline void gr_model_loaded(int pm_id) { gr_screen.gf_model_loaded(pm_id); } /** * @brief Notify the graphics backend that a model is about to be freed, so it * can release any auxiliary per-model GPU state before the model's own GPU * buffers are destroyed. */ inline void gr_model_unloaded(int pm_id) { gr_screen.gf_model_unloaded(pm_id); } #define gr_build_shadow_tlas GR_CALL(gr_screen.gf_build_shadow_tlas) #define gr_update_buffer_data GR_CALL(gr_screen.gf_update_buffer_data) #define gr_update_buffer_data_offset GR_CALL(gr_screen.gf_update_buffer_data_offset) inline void* gr_map_buffer(gr_buffer_handle handle) { return gr_screen.gf_map_buffer(handle); } inline void gr_flush_mapped_buffer(gr_buffer_handle handle, size_t offset, size_t size) { gr_screen.gf_flush_mapped_buffer(handle, offset, size); } #define gr_update_transform_buffer GR_CALL(gr_screen.gf_update_transform_buffer) #define gr_scene_texture_begin GR_CALL(gr_screen.gf_scene_texture_begin) #define gr_scene_texture_end GR_CALL(gr_screen.gf_scene_texture_end) #define gr_copy_effect_texture GR_CALL(gr_screen.gf_copy_effect_texture) #define gr_post_process_set_effect GR_CALL(gr_screen.gf_post_process_set_effect) #define gr_post_process_set_defaults GR_CALL(gr_screen.gf_post_process_set_defaults) #define gr_post_process_begin GR_CALL(gr_screen.gf_post_process_begin) #define gr_post_process_end GR_CALL(gr_screen.gf_post_process_end) #define gr_post_process_save_zbuffer GR_CALL(gr_screen.gf_post_process_save_zbuffer) inline void gr_post_process_restore_zbuffer() { gr_screen.gf_post_process_restore_zbuffer(); } #define gr_deferred_lighting_begin GR_CALL(gr_screen.gf_deferred_lighting_begin) #define gr_deferred_lighting_msaa GR_CALL(gr_screen.gf_deferred_lighting_msaa) #define gr_deferred_lighting_end GR_CALL(gr_screen.gf_deferred_lighting_end) #define gr_deferred_lighting_finish GR_CALL(gr_screen.gf_deferred_lighting_finish) #define gr_zbias GR_CALL(gr_screen.gf_zbias) #define gr_set_fill_mode GR_CALL(gr_screen.gf_set_fill_mode) #define gr_set_line_width GR_CALL(gr_screen.gf_set_line_width) #define gr_sphere GR_CALL(gr_screen.gf_sphere) #define gr_maybe_create_shader GR_CALL(gr_screen.gf_maybe_create_shader) #define gr_recompile_all_shaders GR_CALL(gr_screen.gf_recompile_all_shaders) #define gr_clear_states GR_CALL(gr_screen.gf_clear_states) #define gr_update_texture GR_CALL(gr_screen.gf_update_texture) #define gr_get_bitmap_from_texture GR_CALL(gr_screen.gf_get_bitmap_from_texture) #define gr_shadow_map_start GR_CALL(gr_screen.gf_shadow_map_start) #define gr_shadow_map_end GR_CALL(gr_screen.gf_shadow_map_end) #define gr_render_shield_impact GR_CALL(gr_screen.gf_render_shield_impact) #define gr_override_fog GR_CALL(gr_screen.gf_override_fog) #define gr_imgui_new_frame GR_CALL(gr_screen.gf_imgui_new_frame) #define gr_imgui_render_draw_data GR_CALL(gr_screen.gf_imgui_render_draw_data) /** * @brief Starts an ImGui frame, sized to the render target rather than to the OS window * * @details Drives the renderer backend, the SDL platform backend and ImGui itself, then corrects * the display size the platform backend derived from the window. Must be paired with * ImGui::Render() and gr_imgui_render_draw_data(). */ void gr_imgui_begin_frame(); inline void gr_render_primitives(material* material_info, primitive_type prim_type, vertex_layout* layout, int vert_offset, int n_verts, gr_buffer_handle buffer_handle = gr_buffer_handle(), size_t buffer_offset = 0) { gr_screen .gf_render_primitives(material_info, prim_type, layout, vert_offset, n_verts, buffer_handle, buffer_offset); } inline void gr_render_primitives_particle(particle_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, gr_buffer_handle buffer_handle = gr_buffer_handle()) { gr_screen.gf_render_primitives_particle(material_info, prim_type, layout, offset, n_verts, buffer_handle); } inline void gr_render_primitives_batched(batched_bitmap_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, gr_buffer_handle buffer_handle = gr_buffer_handle()) { gr_screen.gf_render_primitives_batched(material_info, prim_type, layout, offset, n_verts, buffer_handle); } inline void gr_render_nanovg(nanovg_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, gr_buffer_handle buffer_handle) { gr_screen.gf_render_nanovg(material_info, prim_type, layout, offset, n_verts, buffer_handle); } inline void gr_render_primitives_distortion(distortion_material* material_info, primitive_type prim_type, vertex_layout* layout, int offset, int n_verts, gr_buffer_handle buffer_handle = gr_buffer_handle()) { gr_screen.gf_render_primitives_distortion(material_info, prim_type, layout, offset, n_verts, buffer_handle); } inline void gr_render_movie(movie_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_verts, gr_buffer_handle buffer, size_t buffer_offset = 0) { gr_screen.gf_render_movie(material_info, prim_type, layout, n_verts, buffer, buffer_offset); } inline void gr_render_model(model_material* material_info, indexed_vertex_source *vert_source, vertex_buffer* bufferp, size_t texi) { gr_screen.gf_render_model(material_info, vert_source, bufferp, texi); } inline void gr_render_shadow_draw(gr_buffer_handle ubo_handle, size_t ubo_offset, size_t ubo_size, vertex_buffer* buffer, indexed_vertex_source* vert_src, size_t texi) { gr_screen.gf_render_shadow_draw(ubo_handle, ubo_offset, ubo_size, buffer, vert_src, texi); } inline void gr_render_rocket_primitives(interface_material* material_info, primitive_type prim_type, vertex_layout* layout, int n_indices, gr_buffer_handle vertex_buffer, gr_buffer_handle index_buffer) { gr_screen.gf_render_rocket_primitives(material_info, prim_type, layout, n_indices, vertex_buffer, index_buffer); } inline bool gr_is_capable(gr_capability capability) { return gr_screen.gf_is_capable(capability); } inline bool gr_get_property(gr_property property, void* destination) { return gr_screen.gf_get_property(property, destination); } inline void gr_push_debug_group(const char* name) { gr_screen.gf_push_debug_group(name); } inline void gr_pop_debug_group() { gr_screen.gf_pop_debug_group(); } inline int gr_create_query_object() { return gr_screen.gf_create_query_object(); } inline void gr_query_value(int obj, QueryType type) { gr_screen.gf_query_value(obj, type); } inline bool gr_query_value_available(int obj) { return gr_screen.gf_query_value_available(obj); } inline std::uint64_t gr_get_query_value(int obj) { return gr_screen.gf_get_query_value(obj); } inline void gr_delete_query_object(int obj) { gr_screen.gf_delete_query_object(obj); } inline std::unique_ptr gr_create_viewport(const os::ViewPortProperties& props) { return gr_screen.gf_create_viewport(props); } inline void gr_use_viewport(os::Viewport* view) { gr_screen.gf_use_viewport(view); } inline void gr_set_viewport(int x, int y, int width, int height) { gr_screen.gf_set_viewport(x, y, width, height); } inline void gr_bind_uniform_buffer(uniform_block_type bind_point, size_t offset, size_t size, gr_buffer_handle buffer) { gr_screen.gf_bind_uniform_buffer(bind_point, offset, size, buffer); } inline gr_sync gr_sync_fence() { return gr_screen.gf_sync_fence(); } inline bool gr_sync_wait(gr_sync sync, uint64_t timeoutns) { return gr_screen.gf_sync_wait(sync, timeoutns); } inline void gr_sync_delete(gr_sync sync) { gr_screen.gf_sync_delete(sync); } //OpenXR #define gr_openxr_get_extensions GR_CALL(gr_screen.gf_openxr_get_extensions) #define gr_openxr_test_capabilities GR_CALL(gr_screen.gf_openxr_test_capabilities) #define gr_openxr_create_session GR_CALL(gr_screen.gf_openxr_create_session) #define gr_openxr_get_swapchain_format GR_CALL(gr_screen.gf_openxr_get_swapchain_format) #define gr_openxr_acquire_swapchain_buffers GR_CALL(gr_screen.gf_openxr_acquire_swapchain_buffers) #define gr_openxr_flip GR_CALL(gr_screen.gf_openxr_flip) // color functions void gr_init_color(color *c, int r, int g, int b); void gr_init_alphacolor( color *clr, int r, int g, int b, int alpha, int type = AC_TYPE_HUD ); void gr_set_color( int r, int g, int b ); void gr_set_color_fast(const color *dst); bool gr_compare_color_values(const color& clr1, const color& clr2); // shader functions void gr_create_shader(shader *shade, ubyte r, ubyte g, ubyte b, ubyte c); void gr_set_shader(shader *shade); // new bitmap functions void gr_bitmap(int x, int y, int resize_mode = GR_RESIZE_FULL, bool mirror = false, float scale_factor = 1.0f); 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); // special function for drawing polylines. this function is specifically intended for // polylines where each section is no more than 90 degrees away from a previous section. // Moreover, it is _really_ intended for use with 45 degree angles. void gr_pline_special(SCP_vector *pts, int thickness,int resize_mode=GR_RESIZE_FULL); #define VB_FLAG_POSITION (1<<0) #define VB_FLAG_RHW (1<<1) //incompatable with the next normal #define VB_FLAG_NORMAL (1<<2) #define VB_FLAG_DIFUSE (1<<3) #define VB_FLAG_SPECULAR (1<<4) #define VB_FLAG_UV1 (1<<5) //how many UV coords, only use one of these #define VB_FLAG_UV2 (1<<6) #define VB_FLAG_UV3 (1<<7) #define VB_FLAG_UV4 (1<<8) #define VB_FLAG_TANGENT (1<<9) #define VB_FLAG_LARGE_INDEX (1<<10) #define VB_FLAG_MODEL_ID (1<<11) #define VB_FLAG_TRANS (1<<12) /** * @brief Prints the current time * * Draws the timestamp of the current #Missiontime in the format @c h:mm:ss at the specified coordinates * * @param x The x position where the timestamp should be draw * @param y The y position where the timestamp should be draw * @param timestamp The timestamp (in 65536ths of a second) to be printed * @param resize_mode The resize mode to use */ void gr_print_timestamp(int x, int y, fix timestamp, int resize_mode); namespace graphics { class DebugScope { public: explicit DebugScope(const char* name) { gr_push_debug_group(name); } ~DebugScope() { gr_pop_debug_group(); } }; } #if !defined(NDEBUG) || defined(FS_OPENGL_DEBUG) #define GR_DEBUG_SCOPE(name) ::graphics::DebugScope SCP_TOKEN_CONCAT(gr_scope, __LINE__)(name) #else #define GR_DEBUG_SCOPE(name) do {} while(false) #endif enum AnimatedShader { ANIMATED_SHADER_LOADOUTSELECT_FS1= 0, ANIMATED_SHADER_LOADOUTSELECT_FS2= 1, ANIMATED_SHADER_CLOAK = 2, }; /** * @brief Retreives a uniform buffer for storing uniform block data * @param type The type of uniform data that will be stored in the buffer * @param num_elements The number of elements that will be used in the buffer * @param element_size_override Override what the size of the element should be instead of relying on the preconfigured * size for that block type * @return A structure which gives access to a memory buffer where the uniform data can be stored */ graphics::util::UniformBuffer gr_get_uniform_buffer(uniform_block_type type, size_t num_elements, size_t element_size_override = 0); struct VideoModeData { uint32_t width = 0; uint32_t height = 0; uint32_t bit_depth = 0; }; struct DisplayData { uint32_t index; SCP_string name; int32_t x = 0; int32_t y = 0; int32_t width = 0; int32_t height = 0; SCP_vector video_modes; }; SCP_vector gr_enumerate_displays(); enum class GpuHeap { ModelVertex = 0, ModelIndex, NUM_VALUES }; /** * @brief Allocates storage on the specified GPU heap and stores data in that storage * @param heap_type The heap type to store this memory on * @param size The size of the data * @param data A pointer to the data * @param[out] offset_out The offset at which the data is stored in the buffer * @param[out] handle_out The handle of the buffer object this data is stored in */ void gr_heap_allocate(GpuHeap heap_type, size_t size, void* data, size_t& offset_out, gr_buffer_handle& handle_out); /** * @brief Deallocates memory previously allocated with gr_heap_allocate. * @param heap_type The heap type to deallocate this memory from * @param data_offset The offset at which the data is stored. */ void gr_heap_deallocate(GpuHeap heap_type, size_t data_offset); void gr_set_gamma(float gamma); void gr_get_post_process_effect_names(SCP_vector &names); bool gr_is_viewport_window(); void gr_uniform_buffer_managers_init(); SDL_DisplayID gr_get_preferred_display(); // Include this last to make the 2D rendering function available everywhere #include "graphics/render.h" #endif