2023-08-25 14:38:06 -07:00
# include "RendererBackend.h"
2024-03-23 18:41:26 -07:00
# include <assets/assets.h>
2023-08-25 14:38:06 -07:00
# include <vector>
# include "IconsForkAwesome.h"
# include "config.h"
# include <SDL_image.h>
# include <string>
2024-04-28 12:31:40 -07:00
# include <tuple>
# include <initializer_list>
2023-08-25 14:38:06 -07:00
# include "theme.h"
# include "imgui_stdlib.h"
# include "imgui_impl_sdl2.h"
2024-04-28 12:31:40 -07:00
# include "imgui_impl_sdlrenderer2.h"
2023-08-25 14:38:06 -07:00
# include "base85.h"
# include <thread>
2024-04-25 11:23:38 -07:00
# include <translation.hpp>
2024-03-23 18:41:26 -07:00
# include <log.hpp>
2024-04-28 12:31:40 -07:00
# include <options.hpp>
2024-05-02 14:52:11 -07:00
# include <web_functions.hpp>
2023-08-25 14:38:06 -07:00
using std : : vector ;
2024-04-28 12:31:40 -07:00
using namespace Looper : : Options ;
2024-04-24 09:59:51 -07:00
void RendererBackend : : on_resize ( ) {
# ifdef __EMSCRIPTEN__
int32_t x , y ;
get_size ( & x , & y ) ;
SDL_SetWindowSize ( window , ( int ) x , ( int ) y ) ;
2024-04-28 12:31:40 -07:00
UpdateScale ( ) ;
2024-04-24 09:59:51 -07:00
# endif
}
static RendererBackend * renderer_backend ;
void RendererBackend : : resize_static ( ) {
renderer_backend - > resize_needed = true ;
}
void main_loop ( ) {
2024-05-02 14:52:11 -07:00
# ifdef __EMSCRIPTEN__
2024-05-01 09:07:08 -07:00
if ( ! renderer_backend - > started ) {
2024-05-02 14:52:11 -07:00
renderer_backend - > BackendInit ( ) ;
2024-05-01 09:07:08 -07:00
}
2024-05-02 14:52:11 -07:00
# endif
2024-04-24 09:59:51 -07:00
renderer_backend - > LoopFunction ( ) ;
# ifdef __EMSCRIPTEN__
if ( renderer_backend - > done ) {
renderer_backend - > BackendDeinit ( ) ;
emscripten_cancel_main_loop ( ) ;
}
# endif
}
2024-04-28 12:31:40 -07:00
struct FontData {
const ImWchar * ranges ;
std : : map < std : : string , std : : pair < const char * , double > > data ;
void Init ( const ImWchar * ranges_in , std : : map < std : : string , std : : pair < const char * , double > > data_in ) {
ranges = ranges_in ;
data = data_in ;
}
FontData ( const ImWchar * ranges , std : : initializer_list < std : : pair < std : : string , std : : pair < const char * , double > > > data ) {
std : : map < std : : string , std : : pair < const char * , double > > out_data ;
for ( auto pair : data ) {
out_data [ pair . first ] = pair . second ;
}
Init ( ranges , out_data ) ;
}
FontData ( const ImWchar * ranges , std : : initializer_list < std : : tuple < std : : string , const char * , double > > data ) {
std : : map < std : : string , std : : pair < const char * , double > > out_data ;
for ( auto tuple : data ) {
std : : pair < const char * , double > outPair = { std : : get < 1 > ( tuple ) , std : : get < 2 > ( tuple ) } ;
out_data [ std : : get < 0 > ( tuple ) ] = outPair ;
}
Init ( ranges , out_data ) ;
}
FontData ( const ImWchar * ranges , std : : map < std : : string , std : : pair < const char * , double > > data ) {
Init ( ranges , data ) ;
}
} ;
2024-04-24 09:59:51 -07:00
void RendererBackend : : BackendDeinit ( ) {
ImGuiIO & io = ImGui : : GetIO ( ) ; ( void ) io ;
2024-08-08 13:12:37 -07:00
void * IniFilename = ( void * ) io . IniFilename ;
2024-04-24 09:59:51 -07:00
// Cleanup
2024-04-28 12:31:40 -07:00
ImGui_ImplSDLRenderer2_Shutdown ( ) ;
2024-04-24 09:59:51 -07:00
ImGui_ImplSDL2_Shutdown ( ) ;
ImGui : : DestroyContext ( ) ;
2024-04-28 12:31:40 -07:00
SDL_DestroyRenderer ( rend ) ;
2024-04-24 09:59:51 -07:00
SDL_DestroyWindow ( window ) ;
IMG_Quit ( ) ;
SDL_Quit ( ) ;
2024-08-08 13:12:37 -07:00
free ( IniFilename ) ;
2024-04-24 09:59:51 -07:00
Deinit ( ) ;
renderer_backend = nullptr ;
}
2024-04-28 12:31:40 -07:00
bool RendererBackend : : isTouchScreenMode ( ) {
return touchScreenModeOverride . value_or ( SDL_GetNumTouchDevices ( ) > 0 ) ;
}
2024-05-01 09:07:08 -07:00
void RendererBackend : : QueueUpdateScale ( ) {
update_scale = true ;
}
2024-04-24 09:59:51 -07:00
void RendererBackend : : LoopFunction ( ) {
2024-05-01 09:07:08 -07:00
if ( update_scale ) {
UpdateScale ( ) ;
update_scale = false ;
}
# ifndef __EMSCRIPTEN__
2024-04-28 12:31:40 -07:00
SDL_RenderSetVSync ( rend , vsync ? 1 : 0 ) ;
2024-05-01 09:07:08 -07:00
# endif
2024-04-24 09:59:51 -07:00
ImGuiIO & io = ImGui : : GetIO ( ) ; ( void ) io ;
if ( resize_needed ) {
on_resize ( ) ;
}
2024-05-02 14:52:11 -07:00
auto next_frame = std : : chrono : : steady_clock : : now ( ) + std : : chrono : : milliseconds ( 1000 / ( framerate = = 0 ? 60 : framerate ) ) ;
2024-04-24 09:59:51 -07:00
// Poll and handle events (inputs, window resize, etc.)
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
SDL_Event event ;
while ( SDL_PollEvent ( & event ) )
{
ImGui_ImplSDL2_ProcessEvent ( & event ) ;
if ( event . type = = SDL_QUIT )
done = true ;
if ( event . type = = SDL_WINDOWEVENT ) {
if ( event . window . event = = SDL_WINDOWEVENT_RESIZED ) {
window_width = event . window . data1 / scale ;
window_height = event . window . data2 / scale ;
//SDL_GetWindowSize(window, &window_width, &window_height);
}
if ( event . window . event = = SDL_WINDOWEVENT_DISPLAY_CHANGED ) {
UpdateScale ( ) ;
}
if ( event . window . event = = SDL_WINDOWEVENT_CLOSE & & event . window . windowID = = SDL_GetWindowID ( window ) ) {
done = true ;
}
}
if ( event . type = = SDL_DROPFILE ) {
if ( event . drop . file ! = NULL ) {
Drop ( std : : string ( event . drop . file ) ) ;
free ( event . drop . file ) ;
}
}
}
2024-04-28 12:31:40 -07:00
bool touchScreenMode = isTouchScreenMode ( ) ;
if ( touchScreenMode ) {
io . ConfigFlags | = ImGuiConfigFlags_IsTouchScreen ;
} else {
io . ConfigFlags & = ~ ImGuiConfigFlags_IsTouchScreen ;
}
2024-04-24 09:59:51 -07:00
// Start the Dear ImGui frame
2024-04-28 12:31:40 -07:00
ImGui_ImplSDLRenderer2_NewFrame ( ) ;
2024-04-24 09:59:51 -07:00
ImGui_ImplSDL2_NewFrame ( ) ;
ImGui : : NewFrame ( ) ;
// Run the GUI
GuiFunction ( ) ;
// Rendering
ImGui : : Render ( ) ;
2024-04-28 12:31:40 -07:00
SDL_SetRenderDrawColor ( rend , ( Uint8 ) ( clear_color . x * clear_color . w * 255 ) , ( Uint8 ) ( clear_color . y * clear_color . w * 255 ) , ( Uint8 ) ( clear_color . z * clear_color . w * 255 ) , ( Uint8 ) ( clear_color . w * 255 ) ) ;
SDL_RenderClear ( rend ) ;
2024-04-24 09:59:51 -07:00
// Tell ImGui to render.
2024-04-28 12:31:40 -07:00
ImGui_ImplSDLRenderer2_RenderDrawData ( ImGui : : GetDrawData ( ) ) ;
2023-08-25 14:38:06 -07:00
2024-04-24 09:59:51 -07:00
// Swap the buffers, and do VSync if enabled.
2024-04-28 12:31:40 -07:00
SDL_RenderPresent ( rend ) ;
2024-04-24 09:59:51 -07:00
// If not doing VSync, wait until the next frame needs to be rendered.
if ( ! vsync ) {
std : : this_thread : : sleep_until ( next_frame ) ;
}
}
2023-08-25 14:38:06 -07:00
2024-04-28 12:31:40 -07:00
std : : map < std : : string , ImFont * > add_font ( FontData data_vec , double scale ) {
2023-08-25 14:38:06 -07:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
2024-04-28 12:31:40 -07:00
std : : map < std : : string , ImFont * > output ;
for ( auto value : data_vec . data ) {
ImFont * font = nullptr ;
std : : string id = value . first ;
const char * data = value . second . first ;
double size = value . second . second * scale ;
{
ImFontConfig font_cfg = ImFontConfig ( ) ;
font_cfg . SizePixels = size ;
font_cfg . OversampleH = font_cfg . OversampleV = 1 ;
font_cfg . PixelSnapH = true ;
if ( font_cfg . SizePixels < = 0.0f )
font_cfg . SizePixels = 13.0f * 1.0f ;
//font_cfg.EllipsisChar = (ImWchar)0x0085;
//font_cfg.GlyphOffset.y = 1.0f * IM_FLOOR(font_cfg.SizePixels / 13.0f); // Add +1 offset per 13 units
2023-08-25 14:38:06 -07:00
2024-04-28 12:31:40 -07:00
const char * ttf_compressed_base85 = data ;
const ImWchar * glyph_ranges = data_vec . ranges ;
font = io . Fonts - > AddFontFromMemoryCompressedBase85TTF ( ttf_compressed_base85 ,
font_cfg . SizePixels ,
& font_cfg , glyph_ranges ) ;
}
{
ImFontConfig config ;
config . MergeMode = true ;
config . GlyphMinAdvanceX = size ;
config . SizePixels = size ;
config . DstFont = font ;
static const ImWchar icon_ranges [ ] = { ICON_MIN_FK , ICON_MAX_FK , 0 } ;
io . Fonts - > AddFontFromMemoryCompressedBase85TTF ( forkawesome_compressed_data_base85 ,
float ( size ) , & config , icon_ranges ) ;
}
output [ id ] = font ;
2023-08-25 14:38:06 -07:00
}
2024-04-28 12:31:40 -07:00
return output ;
2023-08-25 14:38:06 -07:00
}
RendererBackend : : RendererBackend ( ) {
}
RendererBackend : : ~ RendererBackend ( ) {
2024-05-02 14:52:11 -07:00
DEBUG . writeln ( " Renderer backend destructor run. " ) ;
renderer_backend = nullptr ;
2023-08-25 14:38:06 -07:00
}
void RendererBackend : : SetWindowTitle ( const char * title ) {
SDL_SetWindowTitle ( window , title ) ;
}
void RendererBackend : : GuiFunction ( ) {
// Do nothing by default.
}
2023-09-03 11:54:07 -07:00
void RendererBackend : : UpdateScale ( ) {
double prevScale = scale ;
const double defaultDPI =
# ifdef __APPLE__
72.0 ;
# else
96.0 ;
# endif
2024-05-01 09:07:08 -07:00
if ( scaleOverride . has_value ( ) ) {
scale = scaleOverride . value ( ) ;
} else {
2024-04-28 12:31:40 -07:00
# ifdef __EMSCRIPTEN__
2024-05-01 09:07:08 -07:00
scale = get_dpi ( ) ;
2024-04-28 12:31:40 -07:00
# else
2024-05-01 09:07:08 -07:00
float dpi = defaultDPI ;
if ( SDL_GetDisplayDPI ( SDL_GetWindowDisplayIndex ( window ) , NULL , & dpi , NULL ) = = 0 ) {
scale = dpi / defaultDPI ;
} else {
WARNING . writeln ( " DPI couldn't be determined! " ) ;
scale = 1.0 ;
}
2024-04-28 12:31:40 -07:00
# ifndef __ANDROID__
2024-05-01 09:07:08 -07:00
SDL_SetWindowSize ( window , window_width * scale , window_height * scale ) ;
2024-04-28 12:31:40 -07:00
# endif
# endif
2024-05-01 09:07:08 -07:00
}
2023-09-03 11:54:07 -07:00
AddFonts ( ) ;
2024-05-01 09:07:08 -07:00
OnScale ( ( float ) scale ) ;
}
void RendererBackend : : OnScale ( float scale ) {
theme - > Apply ( accent_color , scale ) ;
2023-09-03 11:54:07 -07:00
}
void RendererBackend : : SetWindowSize ( int w , int h ) {
2024-04-28 12:31:40 -07:00
# if !(defined(__ANDROID__) || defined(__EMSCRIPTEN__))
2023-09-03 11:54:07 -07:00
window_width = w ;
window_height = h ;
SDL_SetWindowSize ( window , w * scale , h * scale ) ;
2024-04-28 12:31:40 -07:00
# endif
2023-09-03 11:54:07 -07:00
}
void RendererBackend : : GetWindowsize ( int * w , int * h ) {
int ww , wh ;
SDL_GetWindowSize ( window , & ww , & wh ) ;
ww / = scale ;
wh / = scale ;
if ( w ) * w = ww ;
if ( h ) * h = wh ;
}
void RendererBackend : : AddFonts ( ) {
2024-04-28 12:31:40 -07:00
ImGui_ImplSDLRenderer2_DestroyFontsTexture ( ) ;
2023-09-03 11:54:07 -07:00
auto & io = ImGui : : GetIO ( ) ; ( void ) io ;
io . Fonts - > Clear ( ) ;
2024-04-28 12:31:40 -07:00
std : : string font_type = get_option < std : : string > ( " font_type " , " default " ) ;
std : : string default_font = " default " ;
std : : string jp_font = " japanese " ;
auto glyph_ranges_default = io . Fonts - > GetGlyphRangesDefault ( ) ;
auto glyph_ranges_jp = io . Fonts - > GetGlyphRangesJapanese ( ) ;
FontData latin ( glyph_ranges_default , { { " normal " , notosans_regular_compressed_data_base85 , 13 } , { " title " , notosans_thin_compressed_data_base85 , 32 } } ) ;
FontData jp ( glyph_ranges_jp , { { " normal " , notosansjp_regular_compressed_data_base85 , 13 } , { " title " , notosansjp_thin_compressed_data_base85 , 32 } } ) ;
std : : map < std : : string , ImFont * > font_map ;
if ( font_type = = jp_font ) {
font_map = add_font ( jp , scale ) ;
} else {
font_map = add_font ( latin , scale ) ;
}
title = font_map [ " title " ] ;
io . FontDefault = font_map [ " normal " ] ;
ImGui_ImplSDLRenderer2_CreateFontsTexture ( ) ;
2023-09-03 11:54:07 -07:00
}
2024-04-24 10:05:02 -07:00
# ifdef __EMSCRIPTEN__
2024-04-24 09:59:51 -07:00
static EM_BOOL resize_callback ( int event_type , const EmscriptenUiEvent * event , void * userdata ) {
RendererBackend : : resize_static ( ) ;
2024-05-01 09:07:08 -07:00
return EM_FALSE ;
2024-04-24 09:59:51 -07:00
}
2024-04-24 10:05:02 -07:00
# endif
2024-05-02 14:52:11 -07:00
void RendererBackend : : BackendInit ( ) {
2024-04-25 11:23:38 -07:00
setup_locale ( " neko_player " ) ;
2024-03-23 18:41:26 -07:00
DEBUG . writefln ( " Loaded locale '%s' from '%s'... " , CURRENT_LANGUAGE , LOCALE_DIR ) ;
DEBUG . writefln ( " Locale name: %s " , _TR_CTX ( " Language name " , " English (United States) " ) ) ;
2023-08-25 14:38:06 -07:00
bool enable_kms = std : : getenv ( " LAP_KMS " ) ! = nullptr ;
SDL_SetHint ( SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR , " false " ) ;
SDL_SetHint ( SDL_HINT_APP_NAME , NAME ) ;
// Setup SDL
if ( SDL_Init ( SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER ) ! = 0 )
{
2024-03-23 18:41:26 -07:00
ERROR . writefln ( " Error: %s " , SDL_GetError ( ) ) ;
2024-05-02 14:52:11 -07:00
throw std : : exception ( ) ;
2023-08-25 14:38:06 -07:00
}
if ( std : : string ( SDL_GetCurrentVideoDriver ( ) ) = = " KMSDRM " ) {
enable_kms = true ;
}
IMG_Init ( IMG_INIT_PNG | IMG_INIT_WEBP ) ;
2024-04-25 11:23:38 -07:00
# ifdef __ANDROID__
prefPath = SDL_AndroidGetInternalStoragePath ( ) ;
# else
2023-08-25 14:38:06 -07:00
prefPath = SDL_GetPrefPath ( " Catmeow72 " , NAME ) ;
2024-04-25 11:23:38 -07:00
# endif
2023-08-25 14:38:06 -07:00
Theme : : prefPath = prefPath ;
// From 2.0.18: Enable native IME.
# ifdef SDL_HINT_IME_SHOW_UI
SDL_SetHint ( SDL_HINT_IME_SHOW_UI , " 1 " ) ;
2024-05-01 09:07:08 -07:00
# endif
2024-04-28 12:31:40 -07:00
SDL_WindowFlags window_flags = ( SDL_WindowFlags ) ( SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN ) ;
SDL_CreateWindowAndRenderer ( window_width , window_height , window_flags , & window , & rend ) ;
# ifndef __ANDROID__
2023-08-25 14:38:06 -07:00
SDL_SetWindowMinimumSize ( window , window_width , window_height ) ;
if ( enable_kms ) {
SDL_SetWindowFullscreen ( window , SDL_WINDOW_FULLSCREEN_DESKTOP ) ;
}
2024-04-28 12:31:40 -07:00
# endif
2023-10-16 10:44:25 -07:00
SDL_EventState ( SDL_DROPFILE , SDL_ENABLE ) ;
2023-08-25 14:38:06 -07:00
const vector < unsigned char > icon_data = DecodeBase85 ( icon_compressed_data_base85 ) ;
SDL_Surface * icon = IMG_Load_RW ( SDL_RWFromConstMem ( icon_data . data ( ) , icon_data . size ( ) ) , 1 ) ;
SDL_SetWindowIcon ( window , icon ) ;
// Setup Dear ImGui context
IMGUI_CHECKVERSION ( ) ;
ImGui : : CreateContext ( ) ;
ImGuiIO & io = ImGui : : GetIO ( ) ; ( void ) io ;
io . ConfigFlags | = ImGuiConfigFlags_NavEnableKeyboard ; // Enable Keyboard Controls
io . ConfigFlags | = ImGuiConfigFlags_NavEnableGamepad ; // Enable Gamepad Controls
io . ConfigFlags | = ImGuiConfigFlags_DockingEnable ;
2024-04-28 12:31:40 -07:00
if ( SDL_GetNumTouchDevices ( ) > 0 ) {
io . ConfigFlags | = ImGuiConfigFlags_IsTouchScreen ;
}
2023-08-25 14:38:06 -07:00
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
io . IniFilename = strdup ( ( std : : string ( prefPath ) + " imgui.ini " ) . c_str ( ) ) ;
if ( enable_kms ) {
io . MouseDrawCursor = true ;
}
//io.ConfigViewportsNoAutoMerge = true;
//io.ConfigViewportsNoTaskBarIcon = true;
//ImGui::StyleColorsLight();
// Setup Platform/Renderer backends
2024-04-28 12:31:40 -07:00
ImGui_ImplSDL2_InitForSDLRenderer ( window , rend ) ;
ImGui_ImplSDLRenderer2_Init ( rend ) ;
2023-08-25 14:38:06 -07:00
// Load Fonts
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
// - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple.
// - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit).
// - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call.
// - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering.
// - Read 'docs/FONTS.md' for more instructions and details.
// - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
//io.Fonts->AddFontDefault();
//io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
//io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
//ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese());
//IM_ASSERT(font != nullptr);
2024-05-01 09:07:08 -07:00
theme = new Theme ( false ) ;
2023-08-25 14:38:06 -07:00
2024-05-01 09:07:08 -07:00
UpdateScale ( ) ;
2024-08-08 13:12:37 -07:00
2024-04-25 11:23:38 -07:00
# ifdef __ANDROID__
userdir = SDL_AndroidGetExternalStoragePath ( ) ;
# else
2023-08-25 14:38:06 -07:00
userdir = std : : getenv (
# ifdef _WIN32
" UserProfile "
# else
" HOME "
# endif
) ;
2024-04-25 11:23:38 -07:00
# endif
2024-05-01 09:07:08 -07:00
# ifndef __EMSCRIPTEN__
2024-04-28 12:31:40 -07:00
SDL_RenderSetVSync ( rend , vsync ? 1 : 0 ) ;
2024-05-01 09:07:08 -07:00
# endif
theme - > Apply ( accent_color , ( float ) scale ) ;
2023-08-25 14:38:06 -07:00
Init ( ) ;
2023-10-16 10:44:25 -07:00
SDL_ShowWindow ( window ) ;
2024-05-01 09:07:08 -07:00
started = true ;
2024-05-02 14:52:11 -07:00
}
int RendererBackend : : Run ( ) {
framerate = 60 ;
started = false ;
renderer_backend = this ;
# ifdef __EMSCRIPTEN__
emscripten_set_main_loop ( & main_loop , 0 , 1 ) ;
2023-08-25 14:38:06 -07:00
# else
2024-05-02 14:52:11 -07:00
try {
BackendInit ( ) ;
} catch ( std : : exception ) {
return - 1 ;
}
2024-05-01 09:07:08 -07:00
started = true ;
2023-08-25 14:38:06 -07:00
while ( ! done )
{
2024-04-24 09:59:51 -07:00
LoopFunction ( ) ;
2023-08-25 14:38:06 -07:00
}
2024-04-24 09:59:51 -07:00
BackendDeinit ( ) ;
2023-08-25 14:38:06 -07:00
# endif
return 0 ;
}
void RendererBackend : : Init ( ) {
// Do nothing by default.
}
void RendererBackend : : Deinit ( ) {
// Do nothing by default.
2023-10-16 10:44:25 -07:00
}
void RendererBackend : : Drop ( std : : string file ) {
// Do nothing by default.
2024-08-08 13:12:37 -07:00
}