diff --git a/MAKE.bat b/MAKE.bat
index 7ce5957..02d9a6e 100644
--- a/MAKE.bat
+++ b/MAKE.bat
@@ -324,6 +324,7 @@ if "%1"=="fwk_prep" (
xcopy /y "engine\split\3rd_*" "_fwk\engine\split"
xcopy /y "engine\art\shaders\*" "_fwk\engine\art\shaders"
xcopy /y "demos" "_fwk\demos"
+ xcopy /y "engine\editor.c" "_fwk\engine\editor.c"
rem xcopy /y/E "tools "_fwk\tools"
for %%f in ("engine\split\v4k*") do (
set "filename=%%~nf"
@@ -371,6 +372,10 @@ if "%1"=="back" (
xcopy /y "_fwk\engine\split\3rd_*" "engine\split"
xcopy /y "_fwk\engine\art\shaders\*" "engine\art\shaders"
xcopy /y "_fwk\demos" "demos"
+ xcopy /y "_fwk\engine\editor.c" "engine\editor.c"
+ tools\fwkren.exe "engine\editor.c" to
+ tools\fwkren.exe "hello.c" to
+
rem xcopy /y/E "_fwk\tools "tools"
for %%f in ("_fwk\engine\split\fwk*") do (
set "filename=%%~nf"
@@ -804,7 +809,8 @@ if "!v4k!"=="yes" (
rem editor
if "!editor!"=="yes" (
set edit=-DCOOK_ON_DEMAND
-!echo! editor && !cc! !o! editor.exe tools\editor\editor.c !edit! -Iengine/joint !args! || set rc=1
+rem set edit=-DUI_LESSER_SPACING -DUI_ICONS_SMALL !edit!
+!echo! editor && !cc! !o! editor.exe engine\editor.c !edit! -Iengine/joint !args! || set rc=1
rem if "!cc!"=="cl" (
rem set plug_export=/LD
diff --git a/demos/01-demo2d.c b/demos/01-demo2d.c
index 7dc45f6..854280b 100644
--- a/demos/01-demo2d.c
+++ b/demos/01-demo2d.c
@@ -32,7 +32,7 @@ void demo_kids(vec3 offs) {
spritesheet, // num_frame in a 4x4 spritesheet
position, 0, // position(x,y,depth:sort-by-Y), angle
offset, scale, // offset(x,y), scale(x,y)
- false, WHITE, false // is_additive, tint color, resolution-independent
+ WHITE, 0 // tint_color, no flags
);
}
}
@@ -43,7 +43,7 @@ void demo_hud() {
float spritesheet[3] = {17,34,24}, offset[2] = {0, - 2*absf(sin(window_time()*5))}; // sprite cell and animation
float scale[2] = {3, 3}, tile_w = 16 * scale[0], tile_h = 16 * scale[1]; // scaling
float position[3] = {window_width() - tile_w, window_height() - tile_h, window_height() }; // position in screen-coordinates (x,y,z-index)
- sprite_sheet(inputs, spritesheet, position, 0/*deg*/, offset, scale, false, WHITE, 1);
+ sprite_sheet(inputs, spritesheet, position, 0/*deg*/, offset, scale, WHITE, SPRITE_RESOLUTION_INDEPENDANT);
}
int main() {
@@ -140,7 +140,7 @@ int main() {
ui_panel_end();
}
/*if( ui_panel("Spine", 0)) {
- spine_ui(spn);
+ ui_spine(spn);
ui_panel_end();
}*/
}
diff --git a/demos/01-ui.c b/demos/01-ui.c
new file mode 100644
index 0000000..7035670
--- /dev/null
+++ b/demos/01-ui.c
@@ -0,0 +1,86 @@
+// hello ui: config, window, system, ui, video
+// - rlyeh, public domain.
+//
+// Compile with:
+// `make demos\01-ui.c` (windows)
+// `sh MAKE.bat demos/01-ui.c` (linux, osx)
+
+#include "v4k.h"
+
+int main() {
+ float app_volume = 1.00f;
+ unsigned app_size = flag("--fullscreen") ? 100 : 75;
+ unsigned app_flags = flag("--msaa") ? WINDOW_MSAA4 : 0;
+ unsigned app_target_fps = optioni("--fps", 60); // --fps=30, --fps=45, etc. defaults to 60.
+
+ // window api (fullscreen or 75% sized, optional MSAA flags)
+ window_create(app_size, app_flags);
+ window_title(__FILE__);
+ window_fps_lock(app_target_fps);
+
+ // load video
+ video_t *v = video( "pexels-pachon-in-motion-17486489.mp4", VIDEO_RGB | VIDEO_LOOP );
+
+ // app loop
+ while( window_swap() ) {
+ // input controls
+ if( input(KEY_ESC) ) break;
+
+ // profile api
+ texture_t *textures;
+ profile( "Video decoder" ) {
+ // video api: decode frame and get associated textures (audio is sent to audiomixer automatically)
+ textures = video_decode( v );
+ // fullscreen video
+ // if(video_is_rgb(v)) fullscreen_quad_rgb( textures[0], 1.3f );
+ // else fullscreen_quad_ycbcr( textures, 1.3f );
+ }
+
+ // create menubar on top
+ int choice1 = ui_menu("File;Shell;Exit");
+ int choice2 = ui_menu("Help;About");
+ if( choice1 == 1 ) system(ifdef(win32, "start \"\" cmd", ifdef(osx, "open sh", "xdg-open sh")));
+ if( choice1 == 2 ) exit(0);
+
+ // showcase a few ui widgets
+ ui_demo(0);
+
+ // create ui panel
+ if( ui_panel("myPanel", PANEL_OPEN) ) {
+ // Print some numbers
+ ui_section("Stats");
+ ui_label2("FPS", va("%5.2f", window_fps()));
+ ui_separator();
+
+ // add some buttons
+ ui_section("Buttons");
+ if( ui_button("Screenshot") ) window_screenshot(__FILE__ ".png"), ui_notify(0,ICON_MD_WARNING "Screenshot");
+ if( ui_button("Record Video") ) window_record(__FILE__ ".mp4"), ui_notify(0,ICON_MD_WARNING "Recoding video");
+ if( ui_button("Toggle fullscreen") ) window_fullscreen( !window_has_fullscreen() );
+ ui_separator();
+
+ // some more video controls
+ ui_section("Video");
+ if( ui_button("Rewind") ) video_seek(v, video_position(v) - 3);
+ if( ui_button("Pause") ) video_pause(v, video_is_paused(v) ^ 1);
+ if( ui_button("Forward") ) video_seek(v, video_position(v) + 3);
+ if( ui_slider2("Volume", &app_volume, va("%.2f", app_volume))) audio_volume_master(app_volume);
+
+ // end of panel. must be enclosed within same if() branch.
+ ui_panel_end();
+ }
+
+ // create window
+ static int open = 1;
+ if( ui_window("myWindow", &open) ) {
+ // present decoded texture in a widget, without any label (NULL)
+ ui_texture( NULL, textures[0] );
+ // end of window. must be enclosed within same if() branch.
+ ui_window_end();
+ }
+ }
+}
+
+// this demo supersedes following old sources:
+// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-hello.c
+// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-video.c
diff --git a/demos/06-scene.c b/demos/06-scene.c
new file mode 100644
index 0000000..8bcd5a4
--- /dev/null
+++ b/demos/06-scene.c
@@ -0,0 +1,216 @@
+// scene demo
+// - rlyeh, public domain
+
+#include "v4k.h"
+
+int main() {
+ // options
+ bool do_twosided = 1;
+ bool do_wireframe = 0;
+ bool do_billboard_x = 0, do_billboard_y = 0, do_billboard_z = 0;
+
+ // window (80% sized, MSAA x4 flag)
+ window_create(80, WINDOW_MSAA4);
+ window_title(__FILE__);
+
+ // load all postfx files in all subdirs
+ fx_load("fx**.fs");
+
+ // scene loading
+ #define SCENE(...) #__VA_ARGS__
+ const char *my_scene = SCENE([
+ {
+ skybox: 'cubemaps/stardust/',
+ },
+ {
+ position:[-5.0,-2.0,2.0],
+ rotation: [90.0,0.0,180.0],
+ scale:0.20,
+ //anchor/pivot:[],
+ // vertex:'p3 t2',
+ mesh:'models/witch/witch.obj',
+ texture:'models/witch/witch_diffuse.tga.png',
+// swapzy:true,
+ flipuv:false,
+ },
+ {
+ position:[-5.0,-2.0,2.0],
+ rotation: [90.0,0.0,180.0],
+ scale:2.20,
+ //anchor/pivot:[],
+ // vertex:'p3 t2',
+ mesh:'models/witch/witch_object.obj',
+ texture:'models/witch/witch_object_diffuse.tga.png',
+// swapzy:true,
+ flipuv:false,
+ },
+ ]);
+ int num_spawned = scene_merge(my_scene);
+ object_t *obj1 = scene_index(0);
+ object_t *obj2 = scene_index(1);
+
+ // manual spawn & loading
+ model_t m1 = model("kgirl/kgirls01.fbx", 0); //MODEL_NO_ANIMS);
+ texture_t t1 = texture("kgirl/g01_texture.png", TEXTURE_RGB);
+ object_t* obj3 = scene_spawn();
+ object_model(obj3, m1);
+ object_diffuse(obj3, t1);
+ object_scale(obj3, vec3(3,3,3));
+ object_move(obj3, vec3(-10,0,-10));
+ object_pivot(obj3, vec3(-90+180,180,0));
+
+ // camera
+ camera_t cam = camera();
+
+ // demo loop
+ while (window_swap())
+ {
+ // input
+ if( input_down(KEY_ESC) ) break;
+
+ // fps camera
+ bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
+ window_cursor( !active );
+
+ if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
+ vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
+ vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed);
+ camera_moveby(&cam, wasdecq);
+ camera_fps(&cam, mouse.x,mouse.y);
+
+ // queue model scale bounces
+ float t = fmod(window_time(), 0.3) / 0.3;
+ float s = 0.01f * ease_ping_pong(t, EASE_IN|EASE_CUBIC,EASE_OUT|EASE_CUBIC);
+ object_scale(obj1, vec3(0.20f - s,0.20f + s,0.20f - s));
+ object_scale(obj2, vec3(0.20f - s,0.20f + s,0.20f - s));
+
+ // queue model billboard
+ object_billboard(obj1, (do_billboard_x << 2)|(do_billboard_y << 1)|(do_billboard_z << 0));
+ object_billboard(obj2, (do_billboard_x << 2)|(do_billboard_y << 1)|(do_billboard_z << 0));
+
+ // queue model rotation
+ //object_rotate(obj3, vec3(0,1*window_time() * 20,0));
+
+ // flush render scene (background objects: skybox)
+ profile("Scene background") {
+ scene_render(SCENE_BACKGROUND);
+ }
+
+ // queue debug drawcalls
+ profile("Debugdraw") {
+ ddraw_ground(0);
+ ddraw_color(YELLOW);
+ ddraw_text(vec3(+1,+1,-1), 0.04f, va("(%f,%f,%f)", cam.position.x,cam.position.y,cam.position.z));
+ ddraw_color(YELLOW);
+ ddraw_flush();
+ }
+
+ // apply post-fxs from here
+ fx_begin();
+
+ // render scene (foreground objects) with post-effects
+ profile("Scene foreground") {
+ int scene_flags = 0;
+ scene_flags |= do_wireframe ? SCENE_WIREFRAME : 0;
+ scene_flags |= do_twosided ? 0 : SCENE_CULLFACE;
+ scene_render(SCENE_FOREGROUND | scene_flags);
+ }
+
+ profile("Skeletal update") if(!window_has_pause()) {
+ float delta = window_delta() * 30 ; // 30fps anim
+ m1.curframe = model_animate(m1, m1.curframe + delta);
+
+ ddraw_text(vec3(-10,5,-10), 0.05, va("Frame: %.1f", m1.curframe));
+ }
+
+ // post-fxs end here
+ fx_end();
+
+ // queue ui
+ if( ui_panel("Scene", 0)) {
+ if(ui_toggle("Billboard X", &do_billboard_x)) {}
+ if(ui_toggle("Billboard Y", &do_billboard_y)) {}
+ if(ui_toggle("Billboard Z", &do_billboard_z)) {}
+ if(ui_separator()) {}
+ if(ui_bool("Wireframe", &do_wireframe)) {}
+ if(ui_bool("Two sided", &do_twosided)) {}
+ ui_panel_end();
+ }
+ }
+}
+
+#if 0
+
+// ----------------------------------------------------------------------------
+// material demo
+// - rlyeh, public domain
+//
+// @todo: object_print(obj, "");
+
+// create camera
+camera_t cam = camera();
+// load video, RGB texture, no audio
+video_t *v = video( "pexels-pachon-in-motion-17486489.mp4", VIDEO_RGB | VIDEO_NO_AUDIO | VIDEO_LOOP ); video_seek(v, 30);
+// load texture
+texture_t t1 = texture("kgirl/g01_texture.png", TEXTURE_RGB);
+texture_t t2 = texture("matcaps/material3", 0);
+// load model
+model_t m1 = model("suzanne.obj", MODEL_NO_ANIMATIONS);
+model_t m2 = model("suzanne.obj", MODEL_NO_ANIMATIONS|MODEL_MATCAPS);
+
+// spawn object1 (diffuse)
+object_t* obj1 = scene_spawn();
+object_model(obj1, m1);
+object_diffuse(obj1, t1);
+object_scale(obj1, vec3(3,3,3));
+object_move(obj1, vec3(-10+5*0,0,-10));
+object_pivot(obj1, vec3(0,90,0));
+
+// spawn object2 (matcap)
+object_t* obj2 = scene_spawn();
+object_model(obj2, m2);
+object_diffuse(obj2, t2);
+object_scale(obj2, vec3(3,3,3));
+object_move(obj2, vec3(-10+5*2,0,-10));
+object_pivot(obj2, vec3(0,90,0));
+
+// spawn object2 (video)
+object_t* obj3 = scene_spawn();
+object_model(obj3, m1);
+object_diffuse(obj3, video_textures(v)[0]);
+object_scale(obj3, vec3(3,3,3));
+object_move(obj3, vec3(-10+5*1,0,-10));
+object_pivot(obj3, vec3(0,90,0));
+
+// @todo: add shadertoy material
+ static model_t cube; do_once cube = model("cube.obj", 0);
+ static shadertoy_t s; do_once s = shadertoy("shadertoys/4ttGWM.fs", 256);
+ model_set_texture(cube, shadertoy_render(&s, window_delta())->tx);
+ model_render(cube, cam.proj, cam.view, cube.pivot, 0);
+
+while(window_swap() && !input(KEY_ESC)) {
+ // draw environment
+ viewport_color( RGB3(22,22,32) );
+ ddraw_grid(0);
+ ddraw_flush();
+
+ // update video
+ video_decode( v );
+
+ // draw scene
+ scene_render(SCENE_FOREGROUND);
+}
+
+// load static scene
+// model_t sponza = model("sponza.obj", MODEL_MATCAPS);
+// model_set_texture(sponza, texture("matcaps/normals", 0));
+// translation44(sponza.pivot, 0,-1,0);
+// rotate44(sponza.pivot, -90,1,0,0);
+// scale44(sponza.pivot, 10,10,10);
+ // model_render(sponza, cam.proj, cam.view, sponza.pivot, 0);
+
+// this demo supersedes following old sources:
+// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-material.c
+// https://github.com/r-lyeh/V4K/blob/45e34d7890b2b8fe1f4994f4b76e496280d83cb6/demos/00-shadertoy.c
+
+#endif
diff --git a/demos/99-controller.c b/demos/99-controller.c
new file mode 100644
index 0000000..faf5a98
--- /dev/null
+++ b/demos/99-controller.c
@@ -0,0 +1,280 @@
+// full controller demo: anims, input, collide; @todo: gamepad, input opts, easing on hits, notify on gamepad connect
+// - rlyeh, public domain.
+//
+// Compile with:
+// `make demos\99-controller.c` (windows)
+// `sh MAKE.bat demos/99-controller.c` (linux, osx)
+
+#include "v4k.h"
+
+int main() {
+ // 75% window, MSAAx2 flag
+ window_create(75, WINDOW_MSAA2);
+
+ // fx: load all post fx files in all subdirs
+ fx_load("fx**.fs");
+
+ // create a camera
+ camera_t cam = camera();
+ camera_enable(&cam);
+
+ // config 3d model #1
+ model_t witch = model("witch/witch.obj", 0);
+ model_set_texture(witch, texture("witch/witch_diffuse.tga.png", 0));
+ mat44 witch_pivot; vec3 witch_p = {-5,0,-5}, witch_r={-180,180,0}, witch_s={0.1,-0.1,0.1};
+
+ // config 3d model #2
+ model_t girl = model("kgirl/kgirls01.fbx", 0);
+ mat44 girl_pivot; vec3 girl_p = {0,0,0}, girl_r = {270,0,0}, girl_s = {2,2,2};
+
+ // skybox
+ skybox_t sky = skybox("cubemaps/stardust", 0);
+
+ // BGM
+ audio_play( audio_stream("waterworld-map.fur"), 0 );
+
+ // editor loop
+ while( window_swap() ) {
+
+ // game camera
+ profile("Game.Camera") {
+ camera_t *cam = camera_get_active();
+
+ static vec3 source;
+ do_once source = cam->position;
+
+ vec3 target = add3(girl_p, vec3(0,10,0));
+ target = add3(target, scale3(norm3(sub3(source, target)), 10.0));
+ source = mix3(source, target, 1-0.99f);
+
+ camera_teleport(cam, source);
+ camera_lookat(cam, vec3(girl_p.x,0,girl_p.z));
+ }
+
+ // render begin (postfx)
+ fx_begin();
+
+ // skybox
+ skybox_render(&sky, cam.proj, cam.view);
+
+ // world
+ ddraw_grid(0);
+ ddraw_flush();
+
+ // models
+ compose44(girl.pivot, girl_p, eulerq(girl_r), girl_s);
+ model_render(girl, cam.proj, cam.view, girl.pivot, 0);
+
+ compose44(witch.pivot, witch_p, eulerq(witch_r), witch_s);
+ model_render(witch, cam.proj, cam.view, witch.pivot, 0);
+
+ // render end (postfx)
+ fx_end();
+
+ // input controllers
+
+ double GAME_JUMP_DOWN = input_down(KEY_Z);
+ double GAME_FIRE_DOWN = input_down(KEY_X);
+ double GAME_JUMP = input(KEY_Z);
+ double GAME_FIRE = input(KEY_X);
+ double GAME_LEFT = input(KEY_J);
+ double GAME_RIGHT = input(KEY_L);
+ double GAME_UP = input(KEY_I);
+ double GAME_DOWN = input(KEY_K);
+ double GAME_AXISX = input(KEY_L) - input(KEY_J);
+ double GAME_AXISY = input(KEY_I) - input(KEY_K);
+
+ if( !input_anykey() ) {
+ if( input(GAMEPAD_CONNECTED) ) {
+ vec2 filtered_lpad = input_filter_deadzone(input2(GAMEPAD_LPAD), 0.15f /*15% deadzone*/);
+ GAME_JUMP_DOWN = input_down(GAMEPAD_A);
+ GAME_FIRE_DOWN = input_down(GAMEPAD_B) || input_down(GAMEPAD_X) || input_down(GAMEPAD_Y);
+ GAME_JUMP = input(GAMEPAD_A);
+ GAME_FIRE = input(GAMEPAD_B) || input(GAMEPAD_X) || input(GAMEPAD_Y);
+ GAME_AXISX = filtered_lpad.x;
+ GAME_AXISY = filtered_lpad.y;
+ }
+ }
+
+ // animation controllers
+
+ profile("Game.Animate scene") if( !window_has_pause() ) {
+ float delta = window_delta() * 30; // 30fps anim
+
+ // animate girl
+ girl.curframe = model_animate(girl, girl.curframe + delta);
+
+ // jump controller: jump duration=1.5s, jump height=6 units, anims (expo->circ)
+ float jump_delta = 1.0;
+ static double jump_timer = 0, jump_ss = 1.5, jump_h = 6;
+ if( GAME_JUMP_DOWN ) if( jump_timer == 0 ) jump_timer = time_ss();
+ jump_delta = clampf(time_ss() - jump_timer, 0, jump_ss) * (1.0/jump_ss);
+ if( jump_delta >= 1 ) { jump_timer = 0; }
+ float y = ease_ping_pong( jump_delta, EASE_OUT|EASE_EXPO, EASE_OUT|EASE_CIRC);
+ girl_p.y = y * jump_h;
+
+ // punch controller
+ float punch_delta = 1;
+ if( jump_delta >= 1 ) {
+ static vec3 origin;
+ static double punch_timer = 0, punch_ss = 0.5;
+ if( GAME_FIRE_DOWN ) if( punch_timer == 0 ) punch_timer = time_ss(), origin = girl_p;
+ punch_delta = clampf(time_ss() - punch_timer, 0, punch_ss) * (1.0/punch_ss);
+ if( punch_delta >= 1 ) { punch_timer = 0; }
+ else {
+ float x = ease_out_expo( punch_delta );
+ vec3 fwd = rotate3q(vec3(0,0,1), eulerq(vec3(girl_r.x - 170,girl_r.y,girl_r.z)));
+ vec3 mix = mix3(girl_p, add3(origin,scale3(fwd,x*2)), x);
+ girl_p.x = mix.x, girl_p.z = mix.z;
+ }
+ }
+
+ int modern_controller = 1;
+ int running = 0;
+
+ // girl controller
+
+ // locomotion vars
+ float speed = 0.2f * delta;
+ float yaw_boost = GAME_AXISY > 0 ? 1.0 : 1.75;
+ if(punch_delta < 1) yaw_boost = 0.0; // if firing...
+ else if(punch_delta <= 0.1) yaw_boost = 4.0; // unless initial punch chaining, extra yaw
+
+ // old fashioned locomotion controller (boat controller)
+ if(!modern_controller) {
+ running = GAME_AXISY > 0;
+
+ girl_r.x -= 170;
+ quat q = eulerq(girl_r); // += custom.pivot
+ vec3 rgt = rotate3q(vec3(1,0,0), q);
+ vec3 up = rotate3q(vec3(0,1,0), q);
+ vec3 fwd = rotate3q(vec3(0,0,1), q);
+ vec3 dir = scale3(fwd, speed * GAME_AXISY * (GAME_AXISY > 0 ? 2.0 : 0.5));
+ girl_r.x += speed * 20.0 * yaw_boost * GAME_AXISX; // yaw
+ girl_p = add3(girl_p, dir);
+ girl_r.x += 170;
+ }
+
+ // modern locomotion controller (mario 3d)
+ if(modern_controller) {
+ running = GAME_AXISX != 0 || GAME_AXISY != 0;
+
+ camera_t *cam = camera_get_active();
+ vec3 fwd = sub3(girl_p, cam->position); fwd.y = 0; fwd = norm3(fwd);
+ vec3 rgt = norm3(cross3(fwd, vec3(0,1,0)));
+
+ // target
+ vec3 dir = add3(
+ scale3(fwd, GAME_AXISY),
+ scale3(rgt, GAME_AXISX)
+ ); dir.y = 0; dir = norm3(dir);
+
+ // smoothing
+ static vec3 olddir; do_once olddir = dir;
+ dir = mix3(dir, olddir, 1 - (yaw_boost / 4.0) * 0.85);
+ olddir = dir;
+
+ // vis
+ // ddraw_arrow(girl_p, add3(girl_p,scale3(dir,10)));
+
+ // apply direction
+ girl_p = add3(girl_p, scale3(dir, speed * 2));
+
+ // apply rotation
+ {
+ girl_r.x -= 170;
+ quat q = eulerq(girl_r);
+ vec3 fwdg = rotate3q(vec3(0,0,1), q);
+ girl_r.x += 170;
+
+ //float cosAngle = dot3(dir,fwdg);
+ //float angle = acos(cosAngle) * TO_DEG;
+ float angle = TO_DEG * ( atan2(fwdg.z, fwdg.x) - atan2(dir.z, dir.x));
+
+ if( !isnan(angle) ) {
+ girl_r.x -= angle;
+ while(girl_r.x> 180) girl_r.x-=360;
+ while(girl_r.x<-180) girl_r.x+=360;
+ }
+ }
+ }
+
+ // anim loops
+ if( jump_delta < 1 ) { // jump/kick anim
+#if 0
+ girl.curframe = clampf(girl.curframe, 184, 202);
+ if( girl.curframe > 202-4 && GAME_FIRE_DOWN ) girl.curframe = 184+4;
+#else
+ #define loopf(frame, min, max) (frame < min ? min : frame > max ? min + frame - max : frame)
+ if(girl.curframe >= 203)
+ girl.curframe = loopf(girl.curframe, 203, 220);
+ else
+ girl.curframe = clampf(girl.curframe, 184, 202);
+ if( girl.curframe > 202-4 && girl.curframe < 208 && GAME_FIRE_DOWN ) girl.curframe = 203;
+#endif
+ }
+ else if( punch_delta < 1 ) { // punch anim
+ girl.curframe = clampf(girl.curframe, 90, 101);
+ if( girl.curframe > 101-6 && GAME_FIRE_DOWN ) girl.curframe = 101-6;
+ }
+ else if( running ) {
+ // loop running anim
+ if( girl.curframe < 65 ) girl.curframe = 65;
+ if( girl.curframe > 85 ) girl.curframe = 65;
+ }
+ else { // loop idle anim
+ if( girl.curframe > 59 ) girl.curframe = 0;
+ }
+ }
+
+ // Game collisions
+
+ profile("Game.collisions") {
+ bool punching = girl.curframe >= 90 && girl.curframe < 101;
+ bool air_kicking = girl.curframe >= 184 && girl.curframe < 202;
+ bool jump_kicking = girl.curframe >= 203 && girl.curframe < 220;
+ bool attacking = punching || air_kicking || jump_kicking;
+
+ if( attacking ) {
+ aabb boxg = model_aabb(girl, girl_pivot);
+ aabb boxw = model_aabb(witch, witch_pivot);
+#if 0 // halve aabb. ok
+ {
+ vec3 diag = sub3(boxg.max, boxg.min);
+ vec3 halve = scale3(diag, 0.25);
+ vec3 center = scale3(add3(boxg.min, boxg.max), 0.5);
+ boxg.min = sub3(center, halve);
+ boxg.max = add3(center, halve);
+ }
+#endif
+ hit* h = aabb_hit_aabb(boxg, boxw);
+ if( h && GAME_FIRE ) {
+ vec3 dir = norm3(sub3(witch_p, girl_p));
+ witch_p = add3(witch_p, mul3(dir,vec3(1,0,1)));
+ }
+ }
+ }
+
+ // ui
+ if( ui_panel("Input", 0) ) { // @todo: showcase input binding
+ ui_section("Controllers");
+ ui_label("Gamepad #1");
+ ui_label("Keys I/J/K/L + Z/X");
+ ui_panel_end();
+ }
+ }
+}
+
+// vec2 do_gamepad_polarity = vec2(+1,+1);
+// vec2 do_gamepad_sensitivity = vec2(0.1f,0.1f);
+// vec2 do_mouse_polarity = vec2(+1,-1);
+// vec2 do_mouse_sensitivity = vec2(0.2f,0.2f);
+// float do_gamepad_deadzone = 0.15f;//
+//
+// if(ui_separator()) {}
+// if(ui_slider("Gamepad deadzone", &do_gamepad_deadzone)) {}
+// if(ui_float2("Gamepad polarity", do_gamepad_polarity.v2)) {}
+// if(ui_float2("Gamepad sensitivity", do_gamepad_sensitivity.v2)) {}
+// if(ui_separator()) {}
+// if(ui_float2("Mouse polarity", do_mouse_polarity.v2)) {}
+// if(ui_float2("Mouse sensitivity", do_mouse_sensitivity.v2)) {}//
diff --git a/demos/99-lod.c b/demos/99-lod.c
new file mode 100644
index 0000000..99bfe91
--- /dev/null
+++ b/demos/99-lod.c
@@ -0,0 +1,234 @@
+// LOD demo, based on Polygon Reduction Demo by Stan Melax (PD)
+// - rlyeh, public domain.
+
+#include "v4k.h"
+
+vec2 world2screen(vec3 p) {
+ vec4 clip_pos = transform444(camera_get_active()->proj, transform444(camera_get_active()->view, vec4(p.x,p.y,p.z,1.0)));
+ vec4 ndc_pos = scale4(clip_pos, 1.0 / (clip_pos.w + !clip_pos.w)); // [-1..1]
+ vec2 screen_pos = vec2( window_width() * (ndc_pos.x + 1) / 2.0, window_height() * (1 - ndc_pos.y) / 2.0 );
+ return screen_pos;
+}
+
+float mesh_area(mesh_t *m) {
+ // @fixme: return 0 if mesh is out of frustum, or window is minimized
+
+ aabb box = mesh_bounds(m);
+ ddraw_aabb(box.min, box.max);
+
+ vec2 A = world2screen(vec3(box.min.x,box.min.y,box.min.z)); ddraw_text2d(A, va("A: %5.2f,%5.2f", A.x, A.y));
+ vec2 B = world2screen(vec3(box.min.x,box.min.y,box.max.z)); ddraw_text2d(B, va("B: %5.2f,%5.2f", B.x, B.y));
+ vec2 C = world2screen(vec3(box.min.x,box.max.y,box.min.z)); ddraw_text2d(C, va("C: %5.2f,%5.2f", C.x, C.y));
+ vec2 D = world2screen(vec3(box.min.x,box.max.y,box.max.z)); ddraw_text2d(D, va("D: %5.2f,%5.2f", D.x, D.y));
+ vec2 E = world2screen(vec3(box.max.x,box.min.y,box.min.z)); ddraw_text2d(E, va("E: %5.2f,%5.2f", E.x, E.y));
+ vec2 F = world2screen(vec3(box.max.x,box.min.y,box.max.z)); ddraw_text2d(F, va("F: %5.2f,%5.2f", F.x, F.y));
+ vec2 G = world2screen(vec3(box.max.x,box.max.y,box.min.z)); ddraw_text2d(G, va("G: %5.2f,%5.2f", G.x, G.y));
+ vec2 H = world2screen(vec3(box.max.x,box.max.y,box.max.z)); ddraw_text2d(H, va("H: %5.2f,%5.2f", H.x, H.y));
+
+ vec2 O = min2(min2(min2(min2(min2(min2(min2(A,B),C),D),E),F),G),H); ddraw_text2d(O, "|\\");
+ vec2 P = max2(max2(max2(max2(max2(max2(max2(A,B),C),D),E),F),G),H); ddraw_text2d(P, "\\|");
+
+ float area = (P.x-O.x) * (P.y-O.y); // len2(sub2(P,O));
+ float pct = area / (float)(window_height() * window_width());
+
+ font_print(va(FONT_RIGHT "area: %5.2f%%", pct*100));
+ return pct;
+}
+
+
+API void ProgressiveMesh(int vert_n, int vert_stride, const float *v, int tri_n, const int *tri, int *map, int *permutation);
+
+// Map()
+//
+// Note that the use of the Map() function and the collapse_map Array isn't part of the polygon reduction
+// algorithm. We set up the function here so that we could retrieve the model at any desired vertex count.
+//
+// When the model is rendered using a maximum of mx vertices then it is vertices 0 through mx-1 that are used.
+// We are able to do this because the vertex Array gets sorted according to the collapse order.
+// The Map() routine takes a vertex number 'n' and the maximum number of vertices 'mx' and returns the
+// appropriate vertex in the range 0 to mx-1. When 'n' is greater than 'mx' the Map() routine follows the
+// chain of edge collapses until a vertex within the limit is reached.
+// An example to make this clear: assume there is a triangle with vertices 1, 3 and 12. But when
+// rendering the model we limit ourselves to 10 vertices. In that case we find out how vertex 12 was
+// removed by the polygon reduction algorithm. i.e. which edge was collapsed. Lets say that vertex 12 was
+// collapsed to vertex number 7. This number would have been stored in the collapse_map array (i.e.
+// collapse_map[12]==7). Since vertex 7 is in range (less than max of 10) we will want to render the
+// triangle 1,3,7. Pretend now that we want to limit ourselves to 5 vertices. and vertex 7 was collapsed
+// to vertex 3 (i.e. collapse_map[7]==3). Then triangle 1,3,12 would now be triangle 1,3,3. i.e. this
+// polygon was removed by the progressive mesh polygon reduction algorithm by the time it had gotten down
+// to 5 vertices. No need to draw a one dimensional polygon. :-)
+
+static inline int MapReduce(array(int) collapse_map, int n, int mx) {
+ while( n >= mx ) n = collapse_map[n];
+ return n;
+}
+
+mesh_t *ReduceModel(mesh_t *m, float lo_detail, float hi_detail, float morph) {
+ int max_verts_to_render = hi_detail * array_count(m->in_vertex3);
+ int min_verts_to_render = lo_detail * array_count(m->in_vertex3);
+
+ if( max_verts_to_render <= 0 || min_verts_to_render <= 0 )
+ return m;
+
+ array_resize(m->out_index3, 0);
+ array_resize(m->out_vertex3, 0);
+
+ ASSERT(array_count(m->lod_collapse_map));
+ for( unsigned int i = 0; i < array_count(m->in_index3); i++ ) {
+ int p0 = MapReduce(m->lod_collapse_map, m->in_index3[i].x, max_verts_to_render);
+ int p1 = MapReduce(m->lod_collapse_map, m->in_index3[i].y, max_verts_to_render);
+ int p2 = MapReduce(m->lod_collapse_map, m->in_index3[i].z, max_verts_to_render);
+ // @fixme: serious optimization opportunity here,
+ // by sorting the triangles the following "continue"
+ // could have been made into a "break" statement.
+ if(p0==p1 || p0==p2 || p1==p2) continue;
+ // if we are not currenly morphing between 2 levels of detail
+ // (i.e. if morph=1.0) then q0,q1, and q2 may not be necessary
+ int q0 = MapReduce(m->lod_collapse_map, p0, min_verts_to_render);
+ int q1 = MapReduce(m->lod_collapse_map, p1, min_verts_to_render);
+ int q2 = MapReduce(m->lod_collapse_map, p2, min_verts_to_render);
+ vec3 v0, v1, v2;
+ v0 = mix3(m->in_vertex3[p0], m->in_vertex3[q0], (1-morph));
+ v1 = mix3(m->in_vertex3[p1], m->in_vertex3[q1], (1-morph));
+ v2 = mix3(m->in_vertex3[p2], m->in_vertex3[q2], (1-morph));
+ vec3 normal = norm3(cross3(sub3(v1,v0),sub3(v2,v1)));
+ array_push(m->out_vertex3, v0);
+ array_push(m->out_vertex3, normal);
+ array_push(m->out_vertex3, v1);
+ array_push(m->out_vertex3, normal);
+ array_push(m->out_vertex3, v2);
+ array_push(m->out_vertex3, normal);
+
+ int idx = array_count(m->out_vertex3) / 2;
+ array_push(m->out_index3, vec3i(idx-3,idx-2,idx-1));
+ }
+
+ return m;
+}
+
+void DrawModel(mesh_t *m) {
+ static mat44 M; do_once id44(M);
+ static mat44 VP; multiply44x2(VP, camera_get_active()->proj, camera_get_active()->view);
+
+ static const char *vs =
+ "#version 130\n"
+ "//" FILELINE "\n"
+ "uniform mat4 M,VP;\n"
+ "in vec3 att_position;\n"
+ "in vec3 att_normal;\n"
+ "out vec3 v_normal;\n"
+ "void main() {\n"
+ " v_normal = normalize(att_normal);\n"
+ " gl_Position = M * VP * vec4( att_position, 1.0 );\n"
+ "}\n";
+ static const char *fs =
+ "#version 130\n"
+ "//" FILELINE "\n"
+ "in vec3 v_normal;\n"
+ "out vec4 fragcolor;\n"
+ "void main() {\n"
+ "fragcolor = vec4(v_normal, 1.0);\n" // diffuse
+ "}";
+
+ static unsigned program; do_once program = shader(vs, fs, "att_position,att_normal", "fragcolor", NULL);
+ shader_bind(program);
+ shader_mat44("VP", VP);
+ shader_mat44("M", M);
+
+ mesh_update(m, "p3 n3", 0,array_count(m->out_vertex3)/2,m->out_vertex3, array_count(m->out_index3)*3,m->out_index3,0);
+ mesh_render(m);
+}
+
+void InitModel(mesh_t *m) {
+ static const double verts[]={-0.334392,+0.133007,+0.062259,-0.350189,+0.150354,-0.147769,-0.234201,+0.343811,-0.174307,-0.200259,+0.285207,+0.093749,+0.003520,+0.475208,-0.159365,+0.001856,+0.419203,+0.098582,-0.252802,+0.093666,+0.237538,-0.162901,+0.237984,+0.206905,+0.000865,+0.318141,+0.235370,-0.414624,+0.164083,-0.278254,-0.262213,+0.357334,-0.293246,+0.004628,+0.482694,-0.338626,-0.402162,+0.133528,-0.443247,-0.243781,+0.324275,-0.436763,+0.005293,+0.437592,-0.458332,-0.339884,-0.041150,-0.668211,-0.248382,+0.255825,-0.627493,+0.006261,+0.376103,-0.631506,-0.216201,-0.126776,-0.886936,-0.171075,+0.011544,-0.881386,-0.181074,+0.098223,-0.814779,-0.119891,+0.218786,-0.760153,-0.078895,+0.276780,-0.739281,+0.006801,+0.310959,-0.735661,-0.168842,+0.102387,-0.920381,-0.104072,+0.177278,-0.952530,-0.129704,+0.211848,-0.836678,-0.099875,+0.310931,-0.799381,+0.007237,+0.361687,-0.794439,-0.077913,+0.258753,-0.921640,+0.007957,+0.282241,-0.931680,-0.252222,-0.550401,-0.557810,-0.267633,-0.603419,-0.655209,-0.446838,-0.118517,-0.466159,-0.459488,-0.093017,-0.311341,-0.370645,-0.100108,-0.159454,-0.371984,-0.091991,-0.011044,-0.328945,-0.098269,+0.088659,-0.282452,-0.018862,+0.311501,-0.352403,-0.131341,+0.144902,-0.364126,-0.200299,+0.202388,-0.283965,-0.231869,+0.023668,-0.298943,-0.155218,+0.369716,-0.293787,-0.121856,+0.419097,-0.290163,-0.290797,+0.107824,-0.264165,-0.272849,+0.036347,-0.228567,-0.372573,+0.290309,-0.190431,-0.286997,+0.421917,-0.191039,-0.240973,+0.507118,-0.287272,-0.276431,-0.065444,-0.295675,-0.280818,-0.174200,-0.399537,-0.313131,-0.376167,-0.392666,-0.488581,-0.427494,-0.331669,-0.570185,-0.466054,-0.282290,-0.618140,-0.589220,-0.374238,-0.594882,-0.323298,-0.381071,-0.629723,-0.350777,-0.382112,-0.624060,-0.221577,-0.272701,-0.566522,+0.259157,-0.256702,-0.663406,+0.286079,-0.280948,-0.428359,+0.055790,-0.184974,-0.508894,+0.326265,-0.279971,-0.526918,+0.395319,-0.282599,-0.663393,+0.412411,-0.188329,-0.475093,+0.417954,-0.263384,-0.663396,+0.466604,-0.209063,-0.663393,+0.509344,-0.002044,-0.319624,+0.553078,-0.001266,-0.371260,+0.413296,-0.219753,-0.339762,-0.040921,-0.256986,-0.282511,-0.006349,-0.271706,-0.260881,+0.001764,-0.091191,-0.419184,-0.045912,-0.114944,-0.429752,-0.124739,-0.113970,-0.382987,-0.188540,-0.243012,-0.464942,-0.242850,-0.314815,-0.505402,-0.324768,+0.002774,-0.437526,-0.262766,-0.072625,-0.417748,-0.221440,-0.160112,-0.476932,-0.293450,+0.003859,-0.453425,-0.443916,-0.120363,-0.581567,-0.438689,-0.091499,-0.584191,-0.294511,-0.116469,-0.599861,-0.188308,-0.208032,-0.513640,-0.134649,-0.235749,-0.610017,-0.040939,-0.344916,-0.622487,-0.085380,-0.336401,-0.531864,-0.212298,+0.001961,-0.459550,-0.135547,-0.058296,-0.430536,-0.043440,+0.001378,-0.449511,-0.037762,-0.130135,-0.510222,+0.079144,+0.000142,-0.477549,+0.157064,-0.114284,-0.453206,+0.304397,-0.000592,-0.443558,+0.285401,-0.056215,-0.663402,+0.326073,-0.026248,-0.568010,+0.273318,-0.049261,-0.531064,+0.389854,-0.127096,-0.663398,+0.479316,-0.058384,-0.663401,+0.372891,-0.303961,+0.054199,+0.625921,-0.268594,+0.193403,+0.502766,-0.277159,+0.126123,+0.443289,-0.287605,-0.005722,+0.531844,-0.231396,-0.121289,+0.587387,-0.253475,-0.081797,+0.756541,-0.195164,-0.137969,+0.728011,-0.167673,-0.156573,+0.609388,-0.145917,-0.169029,+0.697600,-0.077776,-0.214247,+0.622586,-0.076873,-0.214971,+0.696301,-0.002341,-0.233135,+0.622859,-0.002730,-0.213526,+0.691267,-0.003136,-0.192628,+0.762731,-0.056136,-0.201222,+0.763806,-0.114589,-0.166192,+0.770723,-0.155145,-0.129632,+0.791738,-0.183611,-0.058705,+0.847012,-0.165562,+0.001980,+0.833386,-0.220084,+0.019914,+0.768935,-0.255730,+0.090306,+0.670782,-0.255594,+0.113833,+0.663389,-0.226380,+0.212655,+0.617740,-0.003367,-0.195342,+0.799680,-0.029743,-0.210508,+0.827180,-0.003818,-0.194783,+0.873636,-0.004116,-0.157907,+0.931268,-0.031280,-0.184555,+0.889476,-0.059885,-0.184448,+0.841330,-0.135333,-0.164332,+0.878200,-0.085574,-0.170948,+0.925547,-0.163833,-0.094170,+0.897114,-0.138444,-0.104250,+0.945975,-0.083497,-0.084934,+0.979607,-0.004433,-0.146642,+0.985872,-0.150715,+0.032650,+0.884111,-0.135892,-0.035520,+0.945455,-0.070612,+0.036849,+0.975733,-0.004458,-0.042526,+1.015670,-0.004249,+0.046042,+1.003240,-0.086969,+0.133224,+0.947633,-0.003873,+0.161605,+0.970499,-0.125544,+0.140012,+0.917678,-0.125651,+0.250246,+0.857602,-0.003127,+0.284070,+0.878870,-0.159174,+0.125726,+0.888878,-0.183807,+0.196970,+0.844480,-0.159890,+0.291736,+0.732480,-0.199495,+0.207230,+0.779864,-0.206182,+0.164608,+0.693257,-0.186315,+0.160689,+0.817193,-0.192827,+0.166706,+0.782271,-0.175112,+0.110008,+0.860621,-0.161022,+0.057420,+0.855111,-0.172319,+0.036155,+0.816189,-0.190318,+0.064083,+0.760605,-0.195072,+0.129179,+0.731104,-0.203126,+0.410287,+0.680536,-0.216677,+0.309274,+0.642272,-0.241515,+0.311485,+0.587832,-0.002209,+0.366663,+0.749413,-0.088230,+0.396265,+0.678635,-0.170147,+0.109517,+0.840784,-0.160521,+0.067766,+0.830650,-0.181546,+0.139805,+0.812146,-0.180495,+0.148568,+0.776087,-0.180255,+0.129125,+0.744192,-0.186298,+0.078308,+0.769352,-0.167622,+0.060539,+0.806675,-0.189876,+0.102760,+0.802582,-0.108340,+0.455446,+0.657174,-0.241585,+0.527592,+0.669296,-0.265676,+0.513366,+0.634594,-0.203073,+0.478550,+0.581526,-0.266772,+0.642330,+0.602061,-0.216961,+0.564846,+0.535435,-0.202210,+0.525495,+0.475944,-0.193888,+0.467925,+0.520606,-0.265837,+0.757267,+0.500933,-0.240306,+0.653440,+0.463215,-0.309239,+0.776868,+0.304726,-0.271009,+0.683094,+0.382018,-0.312111,+0.671099,+0.286687,-0.268791,+0.624342,+0.377231,-0.302457,+0.533996,+0.360289,-0.263656,+0.529310,+0.412564,-0.282311,+0.415167,+0.447666,-0.239201,+0.442096,+0.495604,-0.220043,+0.569026,+0.445877,-0.001263,+0.395631,+0.602029,-0.057345,+0.442535,+0.572224,-0.088927,+0.506333,+0.529106,-0.125738,+0.535076,+0.612913,-0.126251,+0.577170,+0.483159,-0.149594,+0.611520,+0.557731,-0.163188,+0.660791,+0.491080,-0.172482,+0.663387,+0.415416,-0.160464,+0.591710,+0.370659,-0.156445,+0.536396,+0.378302,-0.136496,+0.444358,+0.425226,-0.095564,+0.373768,+0.473659,-0.104146,+0.315912,+0.498104,-0.000496,+0.384194,+0.473817,-0.000183,+0.297770,+0.401486,-0.129042,+0.270145,+0.434495,+0.000100,+0.272963,+0.349138,-0.113060,+0.236984,+0.385554,+0.007260,+0.016311,-0.883396,+0.007865,+0.122104,-0.956137,-0.032842,+0.115282,-0.953252,-0.089115,+0.108449,-0.950317,-0.047440,+0.014729,-0.882756,-0.104458,+0.013137,-0.882070,-0.086439,-0.584866,-0.608343,-0.115026,-0.662605,-0.436732,-0.071683,-0.665372,-0.606385,-0.257884,-0.665381,-0.658052,-0.272542,-0.665381,-0.592063,-0.371322,-0.665382,-0.353620,-0.372362,-0.665381,-0.224420,-0.335166,-0.665380,-0.078623,-0.225999,-0.665375,-0.038981,-0.106719,-0.665374,-0.186351,-0.081749,-0.665372,-0.292554,+0.006943,-0.091505,-0.858354,+0.006117,-0.280985,-0.769967,+0.004495,-0.502360,-0.559799,-0.198638,-0.302135,-0.845816,-0.237395,-0.542544,-0.587188,-0.270001,-0.279489,-0.669861,-0.134547,-0.119852,-0.959004,-0.052088,-0.122463,-0.944549,-0.124463,-0.293508,-0.899566,-0.047616,-0.289643,-0.879292,-0.168595,-0.529132,-0.654931,-0.099793,-0.515719,-0.645873,-0.186168,-0.605282,-0.724690,-0.112970,-0.583097,-0.707469,-0.108152,-0.665375,-0.700408,-0.183019,-0.665378,-0.717630,-0.349529,-0.334459,-0.511985,-0.141182,-0.437705,-0.798194,-0.212670,-0.448725,-0.737447,-0.261111,-0.414945,-0.613835,-0.077364,-0.431480,-0.778113,+0.005174,-0.425277,-0.651592,+0.089236,-0.431732,-0.777093,+0.271006,-0.415749,-0.610577,+0.223981,-0.449384,-0.734774,+0.153275,-0.438150,-0.796391,+0.358414,-0.335529,-0.507649,+0.193434,-0.665946,-0.715325,+0.118363,-0.665717,-0.699021,+0.123515,-0.583454,-0.706020,+0.196851,-0.605860,-0.722345,+0.109788,-0.516035,-0.644590,+0.178656,-0.529656,-0.652804,+0.061157,-0.289807,-0.878626,+0.138234,-0.293905,-0.897958,+0.066933,-0.122643,-0.943820,+0.149571,-0.120281,-0.957264,+0.280989,-0.280321,-0.666487,+0.246581,-0.543275,-0.584224,+0.211720,-0.302754,-0.843303,+0.086966,-0.665627,-0.291520,+0.110634,-0.665702,-0.185021,+0.228099,-0.666061,-0.036201,+0.337743,-0.666396,-0.074503,+0.376722,-0.666513,-0.219833,+0.377265,-0.666513,-0.349036,+0.281411,-0.666217,-0.588670,+0.267564,-0.666174,-0.654834,+0.080745,-0.665602,-0.605452,+0.122016,-0.662963,-0.435280,+0.095767,-0.585141,-0.607228,+0.118944,+0.012799,-0.880702,+0.061944,+0.014564,-0.882086,+0.104725,+0.108156,-0.949130,+0.048513,+0.115159,-0.952753,+0.112696,+0.236643,+0.386937,+0.128177,+0.269757,+0.436071,+0.102643,+0.315600,+0.499370,+0.094535,+0.373481,+0.474824,+0.136270,+0.443946,+0.426895,+0.157071,+0.535923,+0.380222,+0.161350,+0.591224,+0.372630,+0.173035,+0.662865,+0.417531,+0.162808,+0.660299,+0.493077,+0.148250,+0.611070,+0.559555,+0.125719,+0.576790,+0.484702,+0.123489,+0.534699,+0.614440,+0.087621,+0.506066,+0.530188,+0.055321,+0.442365,+0.572915,+0.219936,+0.568361,+0.448571,+0.238099,+0.441375,+0.498528,+0.281711,+0.414315,+0.451121,+0.263833,+0.528513,+0.415794,+0.303284,+0.533081,+0.363998,+0.269687,+0.623528,+0.380528,+0.314255,+0.670153,+0.290524,+0.272023,+0.682273,+0.385343,+0.311480,+0.775931,+0.308527,+0.240239,+0.652714,+0.466159,+0.265619,+0.756464,+0.504187,+0.192562,+0.467341,+0.522972,+0.201605,+0.524885,+0.478417,+0.215743,+0.564193,+0.538084,+0.264969,+0.641527,+0.605317,+0.201031,+0.477940,+0.584002,+0.263086,+0.512567,+0.637832,+0.238615,+0.526867,+0.672237,+0.105309,+0.455123,+0.658482,+0.183993,+0.102195,+0.804872,+0.161563,+0.060042,+0.808692,+0.180748,+0.077754,+0.771600,+0.175168,+0.128588,+0.746368,+0.175075,+0.148030,+0.778264,+0.175658,+0.139265,+0.814333,+0.154191,+0.067291,+0.832578,+0.163818,+0.109013,+0.842830,+0.084760,+0.396004,+0.679695,+0.238888,+0.310760,+0.590775,+0.213380,+0.308625,+0.644905,+0.199666,+0.409678,+0.683003,+0.190143,+0.128597,+0.733463,+0.184833,+0.063516,+0.762902,+0.166070,+0.035644,+0.818261,+0.154361,+0.056943,+0.857042,+0.168542,+0.109489,+0.862725,+0.187387,+0.166131,+0.784599,+0.180428,+0.160135,+0.819438,+0.201823,+0.163991,+0.695756,+0.194206,+0.206635,+0.782275,+0.155438,+0.291260,+0.734412,+0.177696,+0.196424,+0.846693,+0.152305,+0.125256,+0.890786,+0.119546,+0.249876,+0.859104,+0.118369,+0.139643,+0.919173,+0.079410,+0.132973,+0.948652,+0.062419,+0.036648,+0.976547,+0.127847,-0.035919,+0.947070,+0.143624,+0.032206,+0.885913,+0.074888,-0.085173,+0.980577,+0.130184,-0.104656,+0.947620,+0.156201,-0.094653,+0.899074,+0.077366,-0.171194,+0.926545,+0.127722,-0.164729,+0.879810,+0.052670,-0.184618,+0.842019,+0.023477,-0.184638,+0.889811,+0.022626,-0.210587,+0.827500,+0.223089,+0.211976,+0.620493,+0.251444,+0.113067,+0.666494,+0.251419,+0.089540,+0.673887,+0.214360,+0.019258,+0.771595,+0.158999,+0.001490,+0.835374,+0.176696,-0.059249,+0.849218,+0.148696,-0.130091,+0.793599,+0.108290,-0.166528,+0.772088,+0.049820,-0.201382,+0.764454,+0.071341,-0.215195,+0.697209,+0.073148,-0.214475,+0.623510,+0.140502,-0.169461,+0.699354,+0.163374,-0.157073,+0.611416,+0.189466,-0.138550,+0.730366,+0.247593,-0.082554,+0.759610,+0.227468,-0.121982,+0.590197,+0.284702,-0.006586,+0.535347,+0.275741,+0.125287,+0.446676,+0.266650,+0.192594,+0.506044,+0.300086,+0.053287,+0.629620,+0.055450,-0.663935,+0.375065,+0.122854,-0.664138,+0.482323,+0.046520,-0.531571,+0.391918,+0.024824,-0.568450,+0.275106,+0.053855,-0.663931,+0.328224,+0.112829,-0.453549,+0.305788,+0.131265,-0.510617,+0.080746,+0.061174,-0.430716,-0.042710,+0.341019,-0.532887,-0.208150,+0.347705,-0.623533,-0.081139,+0.238040,-0.610732,-0.038037,+0.211764,-0.514274,-0.132078,+0.120605,-0.600219,-0.186856,+0.096985,-0.584476,-0.293357,+0.127621,-0.581941,-0.437170,+0.165902,-0.477425,-0.291453,+0.077720,-0.417975,-0.220519,+0.320892,-0.506363,-0.320874,+0.248214,-0.465684,-0.239842,+0.118764,-0.383338,-0.187114,+0.118816,-0.430106,-0.123307,+0.094131,-0.419464,-0.044777,+0.274526,-0.261706,+0.005110,+0.259842,-0.283292,-0.003185,+0.222861,-0.340431,-0.038210,+0.204445,-0.664380,+0.513353,+0.259286,-0.664547,+0.471281,+0.185402,-0.476020,+0.421718,+0.279163,-0.664604,+0.417328,+0.277157,-0.528122,+0.400208,+0.183069,-0.509812,+0.329995,+0.282599,-0.429210,+0.059242,+0.254816,-0.664541,+0.290687,+0.271436,-0.567707,+0.263966,+0.386561,-0.625221,-0.216870,+0.387086,-0.630883,-0.346073,+0.380021,-0.596021,-0.318679,+0.291269,-0.619007,-0.585707,+0.339280,-0.571198,-0.461946,+0.400045,-0.489778,-0.422640,+0.406817,-0.314349,-0.371230,+0.300588,-0.281718,-0.170549,+0.290866,-0.277304,-0.061905,+0.187735,-0.241545,+0.509437,+0.188032,-0.287569,+0.424234,+0.227520,-0.373262,+0.293102,+0.266526,-0.273650,+0.039597,+0.291592,-0.291676,+0.111386,+0.291914,-0.122741,+0.422683,+0.297574,-0.156119,+0.373368,+0.286603,-0.232731,+0.027162,+0.364663,-0.201399,+0.206850,+0.353855,-0.132408,+0.149228,+0.282208,-0.019715,+0.314960,+0.331187,-0.099266,+0.092701,+0.375463,-0.093120,-0.006467,+0.375917,-0.101236,-0.154882,+0.466635,-0.094416,-0.305669,+0.455805,-0.119881,-0.460632,+0.277465,-0.604242,-0.651871,+0.261022,-0.551176,-0.554667,+0.093627,+0.258494,-0.920589,+0.114248,+0.310608,-0.798070,+0.144232,+0.211434,-0.835001,+0.119916,+0.176940,-0.951159,+0.184061,+0.101854,-0.918220,+0.092431,+0.276521,-0.738231,+0.133504,+0.218403,-0.758602,+0.194987,+0.097655,-0.812476,+0.185542,+0.011005,-0.879202,+0.230315,-0.127450,-0.884202,+0.260471,+0.255056,-0.624378,+0.351567,-0.042194,-0.663976,+0.253742,+0.323524,-0.433716,+0.411612,+0.132299,-0.438264,+0.270513,+0.356530,-0.289984,+0.422146,+0.162819,-0.273130,+0.164724,+0.237490,+0.208912,+0.253806,+0.092900,+0.240640,+0.203608,+0.284597,+0.096223,+0.241006,+0.343093,-0.171396,+0.356076,+0.149288,-0.143443,+0.337656,+0.131992,+0.066374,};
+ static const int tris[]={126,134,133,342,138,134,133,134,138,126,342,134,312,316,317,169,163,162,312,317,319,312,319,318,169,162,164,169,168,163,312,314,315,169,164,165,169,167,168,312,315,316,312,313,314,169,165,166,169,166,167,312,318,313,308,304,305,308,305,306,179,181,188,177,173,175,177,175,176,302,293,300,322,294,304,188,176,175,188,175,179,158,177,187,305,293,302,305,302,306,322,304,308,188,181,183,158,173,177,293,298,300,304,294,296,304,296,305,185,176,188,185,188,183,187,177,176,187,176,185,305,296,298,305,298,293,436,432, 28,436, 28, 23,434,278,431, 30,208,209, 30,209, 29, 19, 20, 24,208,207,211,208,211,209, 19,210,212,433,434,431,433,431,432,433,432,436,436,437,433,277,275,276,277,276,278,209,210, 25, 21, 26, 24, 21, 24, 20, 25, 26, 27, 25, 27, 29,435,439,277,439,275,277,432,431, 30,432, 30, 28,433,437,438,433,438,435,434,277,278, 24, 25,210, 24, 26, 25, 29, 27, 28, 29, 28, 30, 19, 24,210,208, 30,431,208,431,278,435,434,433,435,277,434, 25, 29,209, 27, 22, 23, 27, 23, 28, 26, 22, 27, 26, 21, 22,212,210,209,212,209,211,207,208,278,207,278,276,439,435,438, 12, 9, 10, 12, 10, 13, 2, 3, 5, 2, 5, 4, 16, 13, 14, 16, 14, 17, 22, 21, 16, 13, 10, 11, 13, 11, 14, 1, 0, 3, 1, 3, 2, 15, 12, 16, 19, 18, 15, 19, 15, 16, 19, 16, 20, 9, 1, 2, 9, 2, 10, 3, 7, 8, 3, 8, 5, 16, 17, 23, 16, 23, 22, 21, 20, 16, 10, 2, 4, 10, 4, 11, 0, 6, 7, 0, 7, 3, 12, 13, 16,451,446,445,451,445,450,442,440,439,442,439,438,442,438,441,421,420,422,412,411,426,412,426,425,408,405,407,413, 67, 68,413, 68,414,391,390,412, 80,384,386,404,406,378,390,391,377,390,377, 88,400,415,375,398,396,395,398,395,371,398,371,370,112,359,358,112,358,113,351,352,369,125,349,348,345,343,342,342,340,339,341,335,337,328,341,327,331,323,333,331,322,323,327,318,319,327,319,328,315,314,324,302,300,301,302,301,303,320,311,292,285,284,289,310,307,288,310,288,290,321,350,281,321,281,282,423,448,367,272,273,384,272,384,274,264,265,382,264,382,383,440,442,261,440,261,263,252,253,254,252,254,251,262,256,249,262,249,248,228,243,242,228, 31,243,213,215,238,213,238,237, 19,212,230,224,225,233,224,233,231,217,218, 56,217, 56, 54,217,216,239,217,239,238,217,238,215,218,217,215,218,215,214, 6,102,206,186,199,200,197,182,180,170,171,157,201,200,189,170,190,191,170,191,192,175,174,178,175,178,179,168,167,155,122,149,158,122,158,159,135,153,154,135,154,118,143,140,141,143,141,144,132,133,136,130,126,133,124,125,127,122,101,100,122,100,121,110,108,107,110,107,109, 98, 99, 97, 98, 97, 64, 98, 64, 66, 87, 55, 57, 83, 82, 79, 83, 79, 84, 78, 74, 50, 49, 71, 41, 49, 41, 37, 49, 37, 36, 58, 44, 60, 60, 59, 58, 51, 34, 33, 39, 40, 42, 39, 42, 38,243,240, 33,243, 33,229, 39, 38, 6, 44, 46, 40, 55, 56, 57, 64, 62, 65, 64, 65, 66, 41, 71, 45, 75, 50, 51, 81, 79, 82, 77, 88, 73, 93, 92, 94, 68, 47, 46, 96, 97, 99, 96, 99, 95,110,109,111,111,112,110,114,113,123,114,123,124,132,131,129,133,137,136,135,142,145,145,152,135,149,147,157,157,158,149,164,150,151,153,163,168,153,168,154,185,183,182,185,182,184,161,189,190,200,199,191,200,191,190,180,178,195,180,195,196,102,101,204,102,204,206, 43, 48,104, 43,104,103,216,217, 54,216, 54, 32,207,224,231,230,212,211,230,211,231,227,232,241,227,241,242,235,234,241,235,241,244,430,248,247,272,274,253,272,253,252,439,260,275,225,224,259,225,259,257,269,270,407,269,407,405,270,269,273,270,273,272,273,269,268,273,268,267,273,267,266,273,266,265,273,265,264,448,279,367,281,350,368,285,286,301,290,323,310,290,311,323,282,281,189,292,311,290,292,290,291,307,306,302,307,302,303,316,315,324,316,324,329,331,351,350,330,334,335,330,335,328,341,337,338,344,355,354,346,345,348,346,348,347,364,369,352,364,352,353,365,363,361,365,361,362,376,401,402,373,372,397,373,397,400,376, 92,377,381,378,387,381,387,385,386, 77, 80,390,389,412,416,417,401,403,417,415,408,429,430,419,423,418,427,428,444,427,444,446,437,436,441,450,445, 11,450, 11, 4,447,449, 5,447, 5, 8,441,438,437,425,426,451,425,451,452,417,421,415,408,407,429,399,403,400,399,400,397,394,393,416,389,411,412,386,383,385,408,387,378,408,378,406,377,391,376, 94,375,415,372,373,374,372,374,370,359,111,360,359,112,111,113,358,349,113,349,123,346,343,345,343,340,342,338,336,144,338,144,141,327,341,354,327,354,326,331,350,321,331,321,322,314,313,326,314,326,325,300,298,299,300,299,301,288,287,289,189,292,282,287,288,303,284,285,297,368,280,281,448,447,279,274,226,255,267,268,404,267,404,379,429,262,430,439,440,260,257,258,249,257,249,246,430,262,248,234,228,242,234,242,241,237,238,239,237,239,236, 15, 18,227, 15,227,229,222,223, 82,222, 82, 83,214,215,213,214,213, 81, 38,102, 6,122,159,200,122,200,201,174,171,192,174,192,194,197,193,198,190,170,161,181,179,178,181,178,180,166,156,155,163,153,152,163,152,162,120,156,149,120,149,121,152,153,135,140,143,142,135,131,132,135,132,136,130,129,128,130,128,127,100,105,119,100,119,120,106,104,107,106,107,108, 91, 95, 59, 93, 94, 68, 91, 89, 92, 76, 53, 55, 76, 55, 87, 81, 78, 79, 74, 73, 49, 69, 60, 45, 58, 62, 64, 58, 64, 61, 53, 31, 32, 32, 54, 53, 42, 43, 38, 35, 36, 0, 35, 0, 1, 34, 35, 1, 34, 1, 9, 44, 40, 41, 44, 41, 45, 33,240, 51, 63, 62, 58, 63, 58, 59, 45, 71, 70, 76, 75, 51, 76, 51, 52, 86, 85, 84, 86, 84, 87, 89, 72, 73, 89, 73, 88, 91, 92, 96, 91, 96, 95, 72, 91, 60, 72, 60, 69,104,106,105,119,105,117,119,117,118,124,127,128,117,116,129,117,129,131,118,117,131,135,140,142,146,150,152,146,152,145,149,122,121,166,165,151,166,151,156,158,172,173,161,160,189,199,198,193,199,193,191,204,201,202,178,174,194,200,159,186,109, 48, 67, 48,107,104,216, 32,236,216,236,239,223,214, 81,223, 81, 82, 33, 12, 15, 32,228,234, 32,234,236,240, 31, 52,256,255,246,256,246,249,258,263,248,258,248,249,275,260,259,275,259,276,207,276,259,270,271,429,270,429,407,413,418,366,413,366,365,368,367,279,368,279,280,303,301,286,303,286,287,283,282,292,283,292,291,320,292,189,298,296,297,298,297,299,318,327,326,318,326,313,329,330,317,336,333,320,326,354,353,334,332,333,334,333,336,342,339,139,342,139,138,345,342,126,347,357,356,369,368,351,363,356,357,363,357,361,366,367,368,366,368,369,375,373,400, 92, 90,377,409,387,408,386,385,387,386,387,388,412,394,391,396,398,399,408,406,405,415,421,419,415,419,414,425,452,448,425,448,424,444,441,443,448,452,449,448,449,447,446,444,443,446,443,445,250,247,261,250,261,428,421,422,423,421,423,419,427,410,250,417,403,401,403,402,401,420,392,412,420,412,425,420,425,424,386,411,389,383,382,381,383,381,385,378,379,404,372,371,395,372,395,397,371,372,370,361,359,360,361,360,362,368,350,351,349,347,348,356,355,344,356,344,346,344,341,340,344,340,343,338,337,336,328,335,341,324,352,351,324,351,331,320,144,336,314,325,324,322,308,309,310,309,307,287,286,289,203,280,279,203,279,205,297,295,283,297,283,284,447,205,279,274,384, 80,274, 80,226,266,267,379,266,379,380,225,257,246,225,246,245,256,254,253,256,253,255,430,247,250,226,235,244,226,244,245,232,233,244,232,244,241,230, 18, 19, 32, 31,228,219,220, 86,219, 86, 57,226,213,235,206, 7, 6,122,201,101,201,204,101,180,196,197,170,192,171,200,190,189,194,193,195,183,181,180,183,180,182,155,154,168,149,156,151,149,151,148,155,156,120,145,142,143,145,143,146,136,137,140,133,132,130,128,129,116,100,120,121,110,112,113,110,113,114, 66, 65, 63, 66, 63, 99, 66, 99, 98, 96, 46, 61, 89, 88, 90, 86, 87, 57, 80, 78, 81, 72, 69, 49, 67, 48, 47, 67, 47, 68, 56, 55, 53, 50, 49, 36, 50, 36, 35, 40, 39, 41,242,243,229,242,229,227, 6, 37, 39, 42, 47, 48, 42, 48, 43, 61, 46, 44, 45, 70, 69, 69, 70, 71, 69, 71, 49, 74, 78, 77, 83, 84, 85, 73, 74, 77, 93, 96, 92, 68, 46, 93, 95, 99, 63, 95, 63, 59,115,108,110,115,110,114,125,126,127,129,130,132,137,133,138,137,138,139,148,146,143,148,143,147,119,118,154,161,147,143,165,164,151,158,157,171,158,171,172,159,158,187,159,187,186,194,192,191,194,191,193,189,202,201,182,197,184,205, 8, 7, 48,109,107,218,219, 57,218, 57, 56,207,231,211,232,230,231,232,231,233, 53, 52, 31,388,411,386,409,430,250,262,429,254,262,254,256,442,444,428,273,264,383,273,383,384,429,271,251,429,251,254,413,365,362, 67,413,360,282,283,295,285,301,299,202,281,280,284,283,291,284,291,289,320,189,160,308,306,307,307,309,308,319,317,330,319,330,328,353,352,324,332,331,333,340,341,338,354,341,344,349,358,357,349,357,347,364,355,356,364,356,363,364,365,366,364,366,369,374,376,402,375, 92,373, 77,389,390,382,380,381,389, 77,386,393,394,412,393,412,392,401,394,416,415,400,403,411,410,427,411,427,426,422,420,424,247,248,263,247,263,261,445,443, 14,445, 14, 11,449,450, 4,449, 4, 5,443,441, 17,443, 17, 14,436, 23, 17,436, 17,441,424,448,422,448,423,422,414,419,418,414,418,413,406,404,405,399,397,395,399,395,396,420,416,392,388,410,411,386,384,383,390, 88, 77,375, 94, 92,415,414, 68,415, 68, 94,370,374,402,370,402,398,361,357,358,361,358,359,125,348,126,346,344,343,340,338,339,337,335,334,337,334,336,325,353,324,324,331,332,324,332,329,323,322,309,323,309,310,294,295,297,294,297,296,289,286,285,202,280,203,288,307,303,282,295,321, 67,360,111,418,423,367,418,367,366,272,252,251,272,251,271,272,271,270,255,253,274,265,266,380,265,380,382,442,428,261,440,263,258,440,258,260,409,250,410,255,226,245,255,245,246, 31,240,243,236,234,235,236,235,237,233,225,245,233,245,244,220,221, 85,220, 85, 86, 81,213,226, 81,226, 80, 7,206,205,186,184,198,186,198,199,204,203,205,204,205,206,195,193,196,171,174,172,173,174,175,173,172,174,155,167,166,160,161,143,160,143,144,119,154,155,148,151,150,148,150,146,140,137,139,140,139,141,127,126,130,114,124,128,114,128,115,117,105,106,117,106,116,104,105,100,104,100,103, 59, 60, 91, 97, 96, 61, 97, 61, 64, 91, 72, 89, 87, 84, 79, 87, 79, 76, 78, 80, 77, 49, 50, 74, 60, 44, 45, 61, 44, 58, 51, 50, 35, 51, 35, 34, 39, 37, 41, 33, 34, 9, 33, 9, 12, 0, 36, 37, 0, 37, 6, 40, 46, 47, 40, 47, 42, 53, 54, 56, 65, 62, 63, 72, 49, 73, 79, 78, 75, 79, 75, 76, 52, 53, 76, 92, 89, 90, 96, 93, 46,102,103,100,102,100,101,116,106,108,116,108,115,123,125,124,116,115,128,118,131,135,140,135,136,148,147,149,120,119,155,164,162,152,164,152,150,157,147,161,157,161,170,186,187,185,186,185,184,193,197,196,202,203,204,194,195,178,198,184,197, 67,111,109, 38, 43,103, 38,103,102,214,223,222,214,222,221,214,221,220,214,220,219,214,219,218,213,237,235,221,222, 83,221, 83, 85, 15,229, 33,227, 18,230,227,230,232, 52, 51,240, 75, 78, 50,408,430,409,260,258,257,260,257,259,224,207,259,268,269,405,268,405,404,413,362,360,447, 8,205,299,297,285,189,281,202,290,288,289,290,289,291,322,321,295,322,295,294,333,323,311,333,311,320,317,316,329,320,160,144,353,325,326,329,332,334,329,334,330,339,338,141,339,141,139,348,345,126,347,356,346,123,349,125,364,353,354,364,354,355,365,364,363,376,391,394,376,394,401, 92,376,374, 92,374,373,377, 90, 88,380,379,378,380,378,381,388,387,409,388,409,410,416,393,392,399,398,402,399,402,403,250,428,427,421,417,416,421,416,420,426,427,446,426,446,451,444,442,441,452,451,450,452,450,449,};
+ enum { NUM_VERTS = countof(verts) / 3, NUM_TRIS = countof(tris) / 3 };
+
+ // Copy the geometry from the arrays of data into the arrays which we send to the reduction routine
+ for(int i = 0; i < NUM_VERTS; i++ ) {
+ const double *vp = &verts[i*3];
+ array_push(m->in_vertex3, vec3(vp[0],vp[1],vp[2]));
+ }
+ for(int i = 0; i < NUM_TRIS; i++ ) {
+ const int *td = &tris[i*3];
+ array_push(m->in_index3, vec3i(td[0],td[1],td[2]));
+ }
+
+ int tri_n = array_count(m->in_index3);
+ int vert_n = array_count(m->in_vertex3);
+ int vert_stride = sizeof(float) * 3;
+ array(int) permutation = 0;
+ array_resize(m->lod_collapse_map, vert_n);
+ array_resize(permutation, vert_n);
+ ProgressiveMesh(vert_n, vert_stride, (const float *)m->in_vertex3, tri_n, (const int *)m->in_index3, m->lod_collapse_map, permutation);
+ // PermuteVertices {
+ ASSERT(array_count(permutation) == array_count(m->in_vertex3));
+ // rearrange the vertex Array
+ array(vec3) tmp = 0;
+ for(int i = 0; i < array_count(m->in_vertex3); i++) array_push(tmp, m->in_vertex3[i]);
+ for(int i = 0; i < array_count(m->in_vertex3); i++) m->in_vertex3[permutation[i]]=tmp[i];
+ // update the changes in the entries in the triangle Array
+ for (int i = 0; i < array_count(m->in_index3); i++) {
+ m->in_index3[i].x = permutation[m->in_index3[i].x];
+ m->in_index3[i].y = permutation[m->in_index3[i].y];
+ m->in_index3[i].z = permutation[m->in_index3[i].z];
+ }
+ array_free(tmp);
+ // } PermuteVertices
+ array_free(permutation);
+}
+
+int main() {
+ window_create(0.75, 0);
+ window_color(PURPLE);
+
+ camera_t cam = camera();
+ cam.speed /= 4;
+ cam.position = vec3(1.667,0.503,2.417);
+ camera_lookat(&cam, vec3(0,0,0));
+
+ mesh_t m = mesh();
+ InitModel(&m);
+
+ float lo_detail=0.25f;
+ float hi_detail=1.00f;
+ float morph=0.75f;
+
+ while( window_swap() && !input(KEY_ESC) ) {
+ if( input(KEY_LALT) && input_down(KEY_Z) ) window_record(__FILE__ ".mp4");
+
+ // fps camera
+ if( input(GAMEPAD_CONNECTED) ) {
+ vec2 filtered_lpad = input_filter_deadzone(input2(GAMEPAD_LPAD), 0.15f/*do_gamepad_deadzone*/ + 1e-3 );
+ vec2 filtered_rpad = input_filter_deadzone(input2(GAMEPAD_RPAD), 0.15f/*do_gamepad_deadzone*/ + 1e-3 );
+ vec2 mouse = scale2(vec2(filtered_rpad.x, filtered_rpad.y), 1.0f);
+ vec3 wasdec = scale3(vec3(filtered_lpad.x, input(GAMEPAD_LT) - input(GAMEPAD_RT), filtered_lpad.y), 1.0f);
+ camera_moveby(&cam, wasdec);
+ camera_fps(&cam, mouse.x,mouse.y);
+ window_cursor( true );
+ } else {
+ bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
+ if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
+ vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
+ vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed);
+ camera_moveby(&cam, wasdecq);
+ camera_fps(&cam, mouse.x,mouse.y);
+ window_cursor( !active );
+ }
+
+ profile("LOD generation") {
+ ReduceModel(&m, lo_detail, hi_detail, morph);
+ mesh_area(&m);
+ }
+
+ DrawModel(&m);
+
+ if( ui_panel("LODs", PANEL_OPEN) ) {
+ ui_label(va("Polys: %d/%d Vertices: %d/%d", array_count(m.out_index3), array_count(m.in_index3), (int)(lo_detail * array_count(m.in_vertex3)), (int)(hi_detail * array_count(m.in_vertex3))));
+ if(ui_slider("Lo detail", &lo_detail)) { lo_detail = clampf(lo_detail, 0.01f, 1.0f); if(lo_detail > hi_detail) hi_detail = lo_detail; }
+ if(ui_slider("Hi detail", &hi_detail)) { hi_detail = clampf(hi_detail, 0.01f, 1.0f); if(hi_detail < lo_detail) lo_detail = hi_detail; }
+ ui_slider("Morph", &morph);
+ ui_panel_end();
+ }
+ }
+}
diff --git a/demos/99-spine.c b/demos/99-spine.c
index 5f2454b..5ea8812 100644
--- a/demos/99-spine.c
+++ b/demos/99-spine.c
@@ -394,8 +394,8 @@ void spine_render(spine_t *p, vec3 offset, unsigned flags) {
float offsy = 0; // /*-(rect.z * p->texture.h)*2*/ -p->atlas[self->atlas_id].h - (self->rect_id ? p->skins[p->skin].rects[self->rect_id].h/2 : 0);
float deg_rect = self->rect_id ? p->skins[p->skin].rects[self->rect_id].deg : 0;
float tilt = p->atlas[self->atlas_id].deg + self->deg2 - deg_rect; // + self->deg2 + deg_rect + p->atlas[self->atlas_id].deg
- unsigned tint = ~0u;
- sprite_rect(p->texture, rect, zindex, add4(vec4(target.x,target.y,1,1),vec4(offsx,offsy,0,0)), tilt, tint);
+ unsigned tint = ~0u, flags = 0;
+ sprite_rect(p->texture, rect, vec4(target.x,target.y,0,zindex), vec4(1,1,offsx,offsy), tilt, tint, flags);
}
}
@@ -510,12 +510,9 @@ void ui_spine(spine_t *p) {
spine_atlas_t *r = p->atlas + b->atlas_id;
sprite_flush();
camera_get_active()->position = vec3(0,0,2);
- vec4 rect = ptr4(&r->x); float zindex = 0; vec3 xy_zoom = vec3(0,0,0); unsigned tint = ~0u;
- sprite_rect(p->texture,
- // rect: vec4(r->x*1.0/p->texture.w,r->y*1.0/p->texture.h,(r->x+r->w)*1.0/p->texture.w,(r->y+r->h)*1.0/p->texture.h),
- ptr4(&r->x), // atlas
- 0, vec4(0,0,1,1), r->deg + tilt, tint);
- sprite_flush();
+ vec4 rect = ptr4(&r->x); float zindex = 0; vec4 scale_offset = vec4(1,1,0,0);
+ sprite_rect(p->texture, ptr4(&r->x), vec4(0,0,0,zindex), scale_offset, r->deg + tilt, ~0u, 0);
+ sprite_flush();
camera_get_active()->position = vec3(+window_width()/3,window_height()/2.25,2);
}
}
diff --git a/demos/99-sprite.c b/demos/99-sprite.c
new file mode 100644
index 0000000..65c1acc
--- /dev/null
+++ b/demos/99-sprite.c
@@ -0,0 +1,218 @@
+// sprite routines
+// - rlyeh,
+//
+// credits: original lovely demo by rxi (MIT License).
+// see https://github.com/rxi/autobatch/tree/master/demo/cats
+
+#include "v4k.h"
+
+texture_t kids, catImage, shadowImage, inputs;
+int NUM_SPRITES = 100, NUM_SPRITES_CHANGED = 1;
+
+typedef struct Cat {
+ int cat, flip;
+ double x, y;
+ double vx, vy;
+ double animSpeed;
+ double moveTimer;
+ double elapsed;
+} Cat;
+
+void demo_cats() {
+ static array(Cat) cats = 0;
+
+ // init
+ if( NUM_SPRITES_CHANGED ) {
+ NUM_SPRITES_CHANGED = 0;
+
+ array_resize(cats, NUM_SPRITES); int i = 0;
+ for each_array_ptr(cats, Cat, c) {
+ randset(i++);
+ c->x = randf() * window_width();
+ c->y = randf() * window_height();
+ c->vx = c->vy = 0;
+ c->cat = randi(0, 4);
+ c->flip = randf() < 0.5;
+ c->animSpeed = 0.8 + randf() * 0.3;
+ c->moveTimer = 0;
+ c->elapsed = 0;
+ }
+ }
+
+ // move
+ const float dt = 1/120.f;
+ const int appw = window_width(), apph = window_height();
+
+ enum { yscale = 1 };
+ for( int i = 0; i < NUM_SPRITES; ++i ) {
+ Cat *c = &cats[i];
+ // Add velocity to position //and wrap to screen
+ c->x += yscale * c->vx * dt; // % ;
+ c->y += yscale * c->vy * dt; // % (int)window_height();
+ if( c->x < 0 ) c->x += appw; else if( c->x > appw ) c->x -= appw;
+ if( c->y < 0 ) c->y += apph; else if( c->y > apph ) c->y -= apph;
+ // Faster animation if walking
+ int boost = c->vx == 0 && c->vy == 0 ? 1 : 3;
+ // Update elapsed time
+ c->elapsed += dt * boost;
+ // Update move timer -- if we hit zero then change or zero velocity
+ c->moveTimer -= dt * boost;
+ if (c->moveTimer < 0) {
+ if (randf() < .2) {
+ c->vx = (randf() * 2 - 1) * 30 * 2;
+ c->vy = (randf() * 2 - 1) * 15 * 2;
+ c->flip = c->vx < 0;
+ } else {
+ c->vx = c->vy = 0;
+ }
+ c->moveTimer = 1 + randf() * 5;
+ }
+ }
+
+ // render
+ uint32_t white = rgba(255,255,255,255);
+ uint32_t alpha = rgba(255,255,255,255*0.6);
+ for( int i = 0; i < NUM_SPRITES; ++i ) {
+ Cat *c = &cats[i];
+ // Get current animation frame (8x4 tilesheet)
+ double e = c->elapsed * c->animSpeed;
+ double frame_num = c->cat * 8 + floor( ((int)(e * 8)) % 4 );
+ frame_num = c->vx != 0 || c->vy != 0 ? frame_num + 4 : frame_num;
+ // Get x scale based on flip flag
+ int xscale = yscale * (c->flip ? -1 : 1);
+ // Draw
+ float angle = 0; //fmod(window_time()*360/5, 360);
+ float scale[2] = { 2*xscale, 2*yscale };
+ float position[3] = { c->x,c->y,c->y }, no_offset[2] = {0,0}, spritesheet[3] = { frame_num,8,4 };
+ sprite_sheet(catImage,
+ spritesheet, // frame_number in a 8x4 spritesheet
+ position, angle, // position(x,y,depth: sort by Y), angle
+ no_offset, scale, // offset(x,y), scale(x,y)
+ white,0 // tint_color, flags
+ );
+ float position_neg_sort[3] = { c->x,c->y,-c->y }, offset[2] = {-1,5}, no_spritesheet[3] = {0,0,0};
+ sprite_sheet(shadowImage,
+ no_spritesheet, // no frame_number (0x0 spritesheet)
+ position_neg_sort, angle, // position(x,y,depth: sort by Y), angle
+ offset, scale, // offset(x,y), scale(x,y)
+ alpha,0 // tint_color, flags
+ );
+ }
+}
+
+void demo_kids() {
+ static int angle; //++angle;
+ static int *x, *y, *v;
+
+ // init
+ if( NUM_SPRITES_CHANGED ) {
+ NUM_SPRITES_CHANGED = 0;
+
+ y = (int*)REALLOC(y, 0 );
+ x = (int*)REALLOC(x, NUM_SPRITES * sizeof(int) );
+ y = (int*)REALLOC(y, NUM_SPRITES * sizeof(int) );
+ v = (int*)REALLOC(v, NUM_SPRITES * sizeof(int) );
+ for( int i = 0; i < NUM_SPRITES; ++i ) {
+ randset(i);
+ x[i] = randi(0, window_width());
+ y[i] = randi(0, window_height());
+ v[i] = randi(1, 3);
+ }
+ }
+
+ // config
+ const int appw = window_width(), apph = window_height();
+
+ // move & render
+ for( int i = 0; i < NUM_SPRITES; ++i ) {
+ y[i] = (y[i] + v[i]) % (apph + 128);
+ int col = ((x[i] / 10) % 4); // 4x4 tilesheet
+ int row = ((y[i] / 10) % 4);
+ int num_frame = col * 4 + row;
+ float position[3] = {x[i],y[i],y[i]}, offset[2]={0,0}, scale[2]={1,1}, spritesheet[3]={num_frame,4,4};
+ sprite_sheet(kids,
+ spritesheet, // num_frame in a 4x4 spritesheet
+ position, angle, // position(x,y,depth: sort by Y), angle
+ offset, scale, // offset(x,y), scale(x,y)
+ ~0u, 0 // tint color, flags
+ );
+ }
+}
+
+int main(int argc, char **argv) {
+ window_create(75.f, 0);
+ window_title("V4K - Sprite");
+ window_color( SILVER );
+
+ // options
+ int do_cats = 1;
+ NUM_SPRITES = optioni("--num_sprites,-N", NUM_SPRITES);
+ if(do_cats) NUM_SPRITES/=2; // cat-sprite+cat-shadow == 2 sprites
+
+ // load sprites and sheets
+ kids = texture( "spriteSheetExample.png", TEXTURE_LINEAR );
+ catImage = texture( "cat.png", TEXTURE_LINEAR ); //
+ shadowImage = texture( "cat-shadow.png", TEXTURE_LINEAR );
+ inputs = texture( "prompts_tilemap_34x24_16x16x1.png", TEXTURE_LINEAR );
+
+ // load all fx files, including subdirs
+ fx_load("fx**.fs");
+
+ // init camera (x,y) (z = zoom)
+ camera_t cam = camera();
+ cam.position = vec3(window_width()/2,window_height()/2,1);
+ camera_enable(&cam);
+
+ while(window_swap()) {
+ if( input(KEY_F5)) window_reload();
+ if( input(KEY_F11)) window_fullscreen( window_has_fullscreen() ^ 1);
+ if( input(KEY_ESC) ) break;
+
+ // camera panning (x,y) & zooming (z)
+ if( !ui_hover() && !ui_active() ) {
+ if( input(MOUSE_L) ) cam.position.x -= input_diff(MOUSE_X);
+ if( input(MOUSE_L) ) cam.position.y -= input_diff(MOUSE_Y);
+ cam.position.z += input_diff(MOUSE_W) * 0.1; // cam.p.z += 0.001f; for tests
+ }
+
+ // apply post-fxs from here
+ fx_begin();
+
+ profile("Sprite batching") {
+ if(do_cats) demo_cats(); else demo_kids();
+ }
+
+ // flush retained renderer, so we ensure the fbos are up to date before fx_end()
+ profile("Sprite flushing") {
+ sprite_flush();
+ }
+
+ // post-fxs end here
+ fx_end();
+
+ // draw pixel-art hud, 16x16 ui element, scaled and positioned in resolution-independant way
+ {
+ vec3 old_pos = camera_get_active()->position;
+
+ sprite_flush();
+ camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
+
+ float zindex = window_height(); // large number, on top
+ float spritesheet[3] = {17,34,24}, offset[2] = {0, - 2*absf(sin(window_time()*5))}; // sprite cell and animation
+ float scale[2] = {3, 3}, tile_w = 16 * scale[0], tile_h = 16 * scale[1]; // scaling
+ float position[3] = {window_width() - tile_w, window_height() - tile_h, zindex }; // position in screen-coordinates
+ sprite_sheet(inputs, spritesheet, position, 0/*rotation*/, offset, scale, WHITE, SPRITE_RESOLUTION_INDEPENDANT);
+
+ sprite_flush();
+ camera_get_active()->position = old_pos;
+ }
+
+ if( ui_panel("Sprite", 0) ) {
+ const char *labels[] = {"Kids","Cats"};
+ if( ui_list("Sprite type", labels, countof(labels), &do_cats) ) NUM_SPRITES_CHANGED = 1;
+ if( ui_int("Number of Sprites", &NUM_SPRITES) ) NUM_SPRITES_CHANGED = 1;
+ if( ui_clampf("Zoom", &cam.position.z, 0.1, 10));
+ ui_panel_end();
+ }
+ }
+}
diff --git a/demos/99-sprite2.c b/demos/99-sprite2.c
new file mode 100644
index 0000000..13caa01
--- /dev/null
+++ b/demos/99-sprite2.c
@@ -0,0 +1,118 @@
+#include "v4k.h"
+
+void game(unsigned frame) {
+ static camera_t cam2d,cam3d;
+ static sprite_t *s1 = 0;
+ static sprite_t *s2 = 0;
+ static sprite_t *s3 = 0;
+ static sprite_t *s4 = 0;
+ if( !frame ) {
+ cam3d = camera();
+ cam3d.damping = true;
+
+ // camera center(x,y) zoom(z)
+ cam2d = camera();
+ cam2d.position = vec3(window_width()/2,window_height()/2,8);
+ camera_enable(&cam2d);
+
+ sprite_del(s1);
+ sprite_del(s2);
+ sprite_del(s3);
+ sprite_del(s4);
+
+ s1 = sprite_new("Captain Clown Nose.ase", (int[6]){KEY_UP,KEY_DOWN,KEY_LEFT,KEY_RIGHT,KEY_A,KEY_S});
+ s2 = sprite_new("Crew-Crabby.ase", (int[6]){KEY_I,KEY_K,KEY_J,KEY_L} );
+ s3 = sprite_new("Props-Shooter Traps.ase", (int[6]){0} );
+ s4 = sprite_new("Crew-Fierce Tooth.ase", (int[6]){0,0,KEY_N,KEY_M} );
+
+ obj_setname(s1, "Cap");
+ obj_setname(s2, "Crab");
+ obj_setname(s3, "Cannon");
+ obj_setname(s4, "Shark");
+
+ // 2d pos and z-order
+ // s1->pos = vec3(window_width()/2, window_height()/2, 2);
+ // s2->pos = vec3(window_width()/2, window_height()/2, 1);
+ // s3->pos = vec3(window_width()/2, window_height()/2, 1);
+ // s4->pos = vec3(window_width()/2, window_height()/2, 1);
+
+ // 3d position+scale
+ s1->pos = s2->pos = s3->pos = s4->pos = vec4(0,1.5,0,0);
+ s1->sca = s2->sca = s3->sca = s4->sca = vec2(0.125,0.125);
+ // 3d zindex
+ s1->pos.w = 0; s2->pos.w = 0.1; s3->pos.w = 0.2; s4->pos.w = 0.3;
+
+ s4->flipped ^= 1;
+ }
+
+ // draw world
+ camera_enable(&cam3d);
+ ddraw_grid(0);
+ ddraw_flush();
+
+ // camera logic
+ enum { is_editing = 0 };
+ if( is_editing ) {
+ if( !ui_hover() && !ui_active() ) {
+ // camera panning (x,y) & zooming (z)
+ if( input(MOUSE_L) ) cam2d.position.x -= input_diff(MOUSE_X);
+ if( input(MOUSE_L) ) cam2d.position.y -= input_diff(MOUSE_Y);
+ cam2d.position.z += input_diff(MOUSE_W) * 0.1; // cam2d.p.z += 0.001f; for tests
+ }
+ camera_enable(&cam2d);
+ } else {
+
+ // fps camera
+ bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
+ if( active ) {
+ cam3d.speed = clampf(cam3d.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
+ vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
+ vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam3d.speed);
+ camera_moveby(&cam3d, wasdecq);
+ camera_fps(&cam3d, mouse.x,mouse.y);
+ } else {
+ camera_teleport(&cam3d, add3(s1->pos.xyz, vec3(0,10,20)));
+ camera_lookat(&cam3d, s1->pos.xyz);
+ }
+
+ window_cursor( !active );
+ }
+
+ obj_tick(s1);
+ obj_draw(s1);
+
+ obj_tick(s2);
+ obj_draw(s2);
+
+ obj_tick(s3);
+ obj_draw(s3);
+
+ obj_tick(s4);
+ obj_draw(s4);
+
+ if( ui_panel("Help", 0) ) {
+ ui_label2("Freecam", ICON_MD_MOUSE " RMB");
+ ui_label2("Captain", ICON_MD_KEYBOARD " Cursor keys");
+ ui_label2("Crab", ICON_MD_KEYBOARD " I/K/J/L keys");
+ ui_label2("Shark", ICON_MD_KEYBOARD " N/M");
+ ui_panel_end();
+ }
+
+ if( ui_panel("Sprites", PANEL_OPEN)) {
+ obj_edit(s1);
+ obj_edit(s2);
+ obj_edit(s3);
+ obj_edit(s4);
+ ui_panel_end();
+ }
+}
+
+int main() {
+ unsigned frame = 0;
+
+ for( window_create(0.75, 0); window_swap(); ) {
+ if( input_down(KEY_Z) && input(KEY_ALT) ) window_record(file_counter(va("%s.mp4",app_name())));
+ if( input_down(KEY_F5) ) frame = 0;
+ game( frame++ );
+ }
+}
\ No newline at end of file
diff --git a/tools/editor/art/fx/editorOutline.fs b/engine/art/editor/fx/editorOutline.fs
similarity index 100%
rename from tools/editor/art/fx/editorOutline.fs
rename to engine/art/editor/fx/editorOutline.fs
diff --git a/tools/editor/art/icons/logo.ai b/engine/art/editor/icons/logo.ai
similarity index 100%
rename from tools/editor/art/icons/logo.ai
rename to engine/art/editor/icons/logo.ai
diff --git a/tools/editor/art/icons/logo.ico b/engine/art/editor/icons/logo.ico
similarity index 100%
rename from tools/editor/art/icons/logo.ico
rename to engine/art/editor/icons/logo.ico
diff --git a/tools/editor/art/icons/logo.license b/engine/art/editor/icons/logo.license
similarity index 100%
rename from tools/editor/art/icons/logo.license
rename to engine/art/editor/icons/logo.license
diff --git a/tools/editor/art/icons/logo.png b/engine/art/editor/icons/logo.png
similarity index 100%
rename from tools/editor/art/icons/logo.png
rename to engine/art/editor/icons/logo.png
diff --git a/tools/editor/art/icons/scale-ruler-icon.license b/engine/art/editor/icons/scale-ruler-icon.license
similarity index 100%
rename from tools/editor/art/icons/scale-ruler-icon.license
rename to engine/art/editor/icons/scale-ruler-icon.license
diff --git a/tools/editor/art/icons/scale-ruler-icon.png b/engine/art/editor/icons/scale-ruler-icon.png
similarity index 100%
rename from tools/editor/art/icons/scale-ruler-icon.png
rename to engine/art/editor/icons/scale-ruler-icon.png
diff --git a/tools/editor/art/icons/scale-ruler-icon.svg b/engine/art/editor/icons/scale-ruler-icon.svg
similarity index 100%
rename from tools/editor/art/icons/scale-ruler-icon.svg
rename to engine/art/editor/icons/scale-ruler-icon.svg
diff --git a/tools/editor/art/lite/data/core/command.lua b/engine/art/editor/lite/data/core/command.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/command.lua
rename to engine/art/editor/lite/data/core/command.lua
diff --git a/tools/editor/art/lite/data/core/commands/command.lua b/engine/art/editor/lite/data/core/commands/command.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/commands/command.lua
rename to engine/art/editor/lite/data/core/commands/command.lua
diff --git a/tools/editor/art/lite/data/core/commands/core.lua b/engine/art/editor/lite/data/core/commands/core.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/commands/core.lua
rename to engine/art/editor/lite/data/core/commands/core.lua
diff --git a/tools/editor/art/lite/data/core/commands/doc.lua b/engine/art/editor/lite/data/core/commands/doc.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/commands/doc.lua
rename to engine/art/editor/lite/data/core/commands/doc.lua
diff --git a/tools/editor/art/lite/data/core/commands/findreplace.lua b/engine/art/editor/lite/data/core/commands/findreplace.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/commands/findreplace.lua
rename to engine/art/editor/lite/data/core/commands/findreplace.lua
diff --git a/tools/editor/art/lite/data/core/commands/root.lua b/engine/art/editor/lite/data/core/commands/root.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/commands/root.lua
rename to engine/art/editor/lite/data/core/commands/root.lua
diff --git a/tools/editor/art/lite/data/core/commandview.lua b/engine/art/editor/lite/data/core/commandview.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/commandview.lua
rename to engine/art/editor/lite/data/core/commandview.lua
diff --git a/tools/editor/art/lite/data/core/common.lua b/engine/art/editor/lite/data/core/common.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/common.lua
rename to engine/art/editor/lite/data/core/common.lua
diff --git a/tools/editor/art/lite/data/core/config.lua b/engine/art/editor/lite/data/core/config.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/config.lua
rename to engine/art/editor/lite/data/core/config.lua
diff --git a/tools/editor/art/lite/data/core/doc/highlighter.lua b/engine/art/editor/lite/data/core/doc/highlighter.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/doc/highlighter.lua
rename to engine/art/editor/lite/data/core/doc/highlighter.lua
diff --git a/tools/editor/art/lite/data/core/doc/init.lua b/engine/art/editor/lite/data/core/doc/init.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/doc/init.lua
rename to engine/art/editor/lite/data/core/doc/init.lua
diff --git a/tools/editor/art/lite/data/core/doc/search.lua b/engine/art/editor/lite/data/core/doc/search.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/doc/search.lua
rename to engine/art/editor/lite/data/core/doc/search.lua
diff --git a/tools/editor/art/lite/data/core/doc/translate.lua b/engine/art/editor/lite/data/core/doc/translate.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/doc/translate.lua
rename to engine/art/editor/lite/data/core/doc/translate.lua
diff --git a/tools/editor/art/lite/data/core/docview.lua b/engine/art/editor/lite/data/core/docview.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/docview.lua
rename to engine/art/editor/lite/data/core/docview.lua
diff --git a/tools/editor/art/lite/data/core/init.lua b/engine/art/editor/lite/data/core/init.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/init.lua
rename to engine/art/editor/lite/data/core/init.lua
diff --git a/tools/editor/art/lite/data/core/keymap.lua b/engine/art/editor/lite/data/core/keymap.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/keymap.lua
rename to engine/art/editor/lite/data/core/keymap.lua
diff --git a/tools/editor/art/lite/data/core/logview.lua b/engine/art/editor/lite/data/core/logview.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/logview.lua
rename to engine/art/editor/lite/data/core/logview.lua
diff --git a/tools/editor/art/lite/data/core/node.lua b/engine/art/editor/lite/data/core/node.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/node.lua
rename to engine/art/editor/lite/data/core/node.lua
diff --git a/tools/editor/art/lite/data/core/object.lua b/engine/art/editor/lite/data/core/object.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/object.lua
rename to engine/art/editor/lite/data/core/object.lua
diff --git a/tools/editor/art/lite/data/core/rootview.lua b/engine/art/editor/lite/data/core/rootview.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/rootview.lua
rename to engine/art/editor/lite/data/core/rootview.lua
diff --git a/tools/editor/art/lite/data/core/statusview.lua b/engine/art/editor/lite/data/core/statusview.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/statusview.lua
rename to engine/art/editor/lite/data/core/statusview.lua
diff --git a/tools/editor/art/lite/data/core/strict.lua b/engine/art/editor/lite/data/core/strict.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/strict.lua
rename to engine/art/editor/lite/data/core/strict.lua
diff --git a/tools/editor/art/lite/data/core/style.lua b/engine/art/editor/lite/data/core/style.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/style.lua
rename to engine/art/editor/lite/data/core/style.lua
diff --git a/tools/editor/art/lite/data/core/syntax.lua b/engine/art/editor/lite/data/core/syntax.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/syntax.lua
rename to engine/art/editor/lite/data/core/syntax.lua
diff --git a/tools/editor/art/lite/data/core/tokenizer.lua b/engine/art/editor/lite/data/core/tokenizer.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/tokenizer.lua
rename to engine/art/editor/lite/data/core/tokenizer.lua
diff --git a/tools/editor/art/lite/data/core/view.lua b/engine/art/editor/lite/data/core/view.lua
similarity index 100%
rename from tools/editor/art/lite/data/core/view.lua
rename to engine/art/editor/lite/data/core/view.lua
diff --git a/tools/editor/art/lite/data/fonts/font.ttf b/engine/art/editor/lite/data/fonts/font.ttf
similarity index 100%
rename from tools/editor/art/lite/data/fonts/font.ttf
rename to engine/art/editor/lite/data/fonts/font.ttf
diff --git a/tools/editor/art/lite/data/fonts/icons.ttf b/engine/art/editor/lite/data/fonts/icons.ttf
similarity index 100%
rename from tools/editor/art/lite/data/fonts/icons.ttf
rename to engine/art/editor/lite/data/fonts/icons.ttf
diff --git a/tools/editor/art/lite/data/fonts/monospace.ttf b/engine/art/editor/lite/data/fonts/monospace.ttf
similarity index 100%
rename from tools/editor/art/lite/data/fonts/monospace.ttf
rename to engine/art/editor/lite/data/fonts/monospace.ttf
diff --git a/tools/editor/art/lite/data/languages/language_bat.lua b/engine/art/editor/lite/data/languages/language_bat.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_bat.lua
rename to engine/art/editor/lite/data/languages/language_bat.lua
diff --git a/tools/editor/art/lite/data/languages/language_batch.lua b/engine/art/editor/lite/data/languages/language_batch.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_batch.lua
rename to engine/art/editor/lite/data/languages/language_batch.lua
diff --git a/tools/editor/art/lite/data/languages/language_c.lua b/engine/art/editor/lite/data/languages/language_c.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_c.lua
rename to engine/art/editor/lite/data/languages/language_c.lua
diff --git a/tools/editor/art/lite/data/languages/language_cpp.lua b/engine/art/editor/lite/data/languages/language_cpp.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_cpp.lua
rename to engine/art/editor/lite/data/languages/language_cpp.lua
diff --git a/tools/editor/art/lite/data/languages/language_csharp.lua b/engine/art/editor/lite/data/languages/language_csharp.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_csharp.lua
rename to engine/art/editor/lite/data/languages/language_csharp.lua
diff --git a/tools/editor/art/lite/data/languages/language_css.lua b/engine/art/editor/lite/data/languages/language_css.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_css.lua
rename to engine/art/editor/lite/data/languages/language_css.lua
diff --git a/tools/editor/art/lite/data/languages/language_glsl.lua b/engine/art/editor/lite/data/languages/language_glsl.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_glsl.lua
rename to engine/art/editor/lite/data/languages/language_glsl.lua
diff --git a/tools/editor/art/lite/data/languages/language_hlsl.lua b/engine/art/editor/lite/data/languages/language_hlsl.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_hlsl.lua
rename to engine/art/editor/lite/data/languages/language_hlsl.lua
diff --git a/tools/editor/art/lite/data/languages/language_js.lua b/engine/art/editor/lite/data/languages/language_js.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_js.lua
rename to engine/art/editor/lite/data/languages/language_js.lua
diff --git a/tools/editor/art/lite/data/languages/language_lua.lua b/engine/art/editor/lite/data/languages/language_lua.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_lua.lua
rename to engine/art/editor/lite/data/languages/language_lua.lua
diff --git a/tools/editor/art/lite/data/languages/language_md.lua b/engine/art/editor/lite/data/languages/language_md.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_md.lua
rename to engine/art/editor/lite/data/languages/language_md.lua
diff --git a/tools/editor/art/lite/data/languages/language_moon.lua b/engine/art/editor/lite/data/languages/language_moon.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_moon.lua
rename to engine/art/editor/lite/data/languages/language_moon.lua
diff --git a/tools/editor/art/lite/data/languages/language_nim.lua b/engine/art/editor/lite/data/languages/language_nim.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_nim.lua
rename to engine/art/editor/lite/data/languages/language_nim.lua
diff --git a/tools/editor/art/lite/data/languages/language_odin.lua b/engine/art/editor/lite/data/languages/language_odin.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_odin.lua
rename to engine/art/editor/lite/data/languages/language_odin.lua
diff --git a/tools/editor/art/lite/data/languages/language_python.lua b/engine/art/editor/lite/data/languages/language_python.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_python.lua
rename to engine/art/editor/lite/data/languages/language_python.lua
diff --git a/tools/editor/art/lite/data/languages/language_teal.lua b/engine/art/editor/lite/data/languages/language_teal.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_teal.lua
rename to engine/art/editor/lite/data/languages/language_teal.lua
diff --git a/tools/editor/art/lite/data/languages/language_ts.lua b/engine/art/editor/lite/data/languages/language_ts.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_ts.lua
rename to engine/art/editor/lite/data/languages/language_ts.lua
diff --git a/tools/editor/art/lite/data/languages/language_wren.lua b/engine/art/editor/lite/data/languages/language_wren.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_wren.lua
rename to engine/art/editor/lite/data/languages/language_wren.lua
diff --git a/tools/editor/art/lite/data/languages/language_xml.lua b/engine/art/editor/lite/data/languages/language_xml.lua
similarity index 100%
rename from tools/editor/art/lite/data/languages/language_xml.lua
rename to engine/art/editor/lite/data/languages/language_xml.lua
diff --git a/tools/editor/art/lite/data/lite.license b/engine/art/editor/lite/data/lite.license
similarity index 100%
rename from tools/editor/art/lite/data/lite.license
rename to engine/art/editor/lite/data/lite.license
diff --git a/tools/editor/art/lite/data/lite.readme b/engine/art/editor/lite/data/lite.readme
similarity index 100%
rename from tools/editor/art/lite/data/lite.readme
rename to engine/art/editor/lite/data/lite.readme
diff --git a/tools/editor/art/lite/data/lite.usage b/engine/art/editor/lite/data/lite.usage
similarity index 100%
rename from tools/editor/art/lite/data/lite.usage
rename to engine/art/editor/lite/data/lite.usage
diff --git a/engine/art/editor/lite/data/plugins/autocomplete.lua b/engine/art/editor/lite/data/plugins/autocomplete.lua
new file mode 100644
index 0000000..79e4513
--- /dev/null
+++ b/engine/art/editor/lite/data/plugins/autocomplete.lua
@@ -0,0 +1,284 @@
+local core = require "core"
+local common = require "core.common"
+local config = require "core.config"
+local command = require "core.command"
+local style = require "core.style"
+local keymap = require "core.keymap"
+local translate = require "core.doc.translate"
+local RootView = require "core.rootview"
+local DocView = require "core.docview"
+
+config.autocomplete_max_suggestions = 6
+
+local autocomplete = {}
+autocomplete.map = {}
+
+
+local mt = { __tostring = function(t) return t.text end }
+
+function autocomplete.add(t)
+ local items = {}
+ for text, info in pairs(t.items) do
+ info = (type(info) == "string") and info
+ table.insert(items, setmetatable({ text = text, info = info }, mt))
+ end
+ autocomplete.map[t.name] = { files = t.files or ".*", items = items }
+end
+
+
+core.add_thread(function()
+ local cache = setmetatable({}, { __mode = "k" })
+
+ local function get_symbols(doc)
+ local i = 1
+ local s = {}
+ while i < #doc.lines do
+ for sym in doc.lines[i]:gmatch(config.symbol_pattern) do
+ s[sym] = true
+ end
+ i = i + 1
+ if i % 100 == 0 then coroutine.yield() end
+ end
+ return s
+ end
+
+ local function cache_is_valid(doc)
+ local c = cache[doc]
+ return c and c.last_change_id == doc:get_change_id()
+ end
+
+ while true do
+ local symbols = {}
+
+ -- lift all symbols from all docs
+ for _, doc in ipairs(core.docs) do
+ -- update the cache if the doc has changed since the last iteration
+ if not cache_is_valid(doc) then
+ cache[doc] = {
+ last_change_id = doc:get_change_id(),
+ symbols = get_symbols(doc)
+ }
+ end
+ -- update symbol set with doc's symbol set
+ for sym in pairs(cache[doc].symbols) do
+ symbols[sym] = true
+ end
+ coroutine.yield()
+ end
+
+ -- update symbols list
+ autocomplete.add { name = "open-docs", items = symbols }
+
+ -- wait for next scan
+ local valid = true
+ while valid do
+ coroutine.yield(1)
+ for _, doc in ipairs(core.docs) do
+ if not cache_is_valid(doc) then
+ valid = false
+ end
+ end
+ end
+
+ end
+end)
+
+
+local partial = ""
+local suggestions_idx = 1
+local suggestions = {}
+local last_line, last_col
+
+
+local function reset_suggestions()
+ suggestions_idx = 1
+ suggestions = {}
+end
+
+
+local function update_suggestions()
+ local doc = core.active_view.doc
+ local filename = doc and doc.filename or ""
+
+ -- get all relevant suggestions for given filename
+ local items = {}
+ for _, v in pairs(autocomplete.map) do
+ if common.match_pattern(filename, v.files) then
+ for _, item in pairs(v.items) do
+ table.insert(items, item)
+ end
+ end
+ end
+
+ -- fuzzy match, remove duplicates and store
+ items = common.fuzzy_match(items, partial)
+ local j = 1
+ for i = 1, config.autocomplete_max_suggestions do
+ suggestions[i] = items[j]
+ while items[j] and items[i].text == items[j].text do
+ items[i].info = items[i].info or items[j].info
+ j = j + 1
+ end
+ end
+end
+
+
+local function get_partial_symbol()
+ local doc = core.active_view.doc
+ local line2, col2 = doc:get_selection()
+ local line1, col1 = doc:position_offset(line2, col2, translate.start_of_word)
+ return doc:get_text(line1, col1, line2, col2)
+end
+
+
+local function get_active_view()
+ if getmetatable(core.active_view) == DocView then
+ return core.active_view
+ end
+end
+
+
+local function get_suggestions_rect(av)
+ if #suggestions == 0 then
+ return 0, 0, 0, 0
+ end
+
+ local line, col = av.doc:get_selection()
+ local x, y = av:get_line_screen_position(line)
+ x = x + av:get_col_x_offset(line, col - #partial)
+ y = y + av:get_line_height() + style.padding.y
+ local font = av:get_font()
+ local th = font:get_height()
+
+ local max_width = 0
+ for _, s in ipairs(suggestions) do
+ local w = font:get_width(s.text)
+ if s.info then
+ w = w + style.font:get_width(s.info) + style.padding.x
+ end
+ max_width = math.max(max_width, w)
+ end
+
+ return
+ x - style.padding.x,
+ y - style.padding.y,
+ max_width + style.padding.x * 2,
+ #suggestions * (th + style.padding.y) + style.padding.y
+end
+
+
+local function draw_suggestions_box(av)
+ -- draw background rect
+ local rx, ry, rw, rh = get_suggestions_rect(av)
+ renderer.draw_rect(rx, ry, rw, rh, style.background3)
+
+ -- draw text
+ local font = av:get_font()
+ local lh = font:get_height() + style.padding.y
+ local y = ry + style.padding.y / 2
+ for i, s in ipairs(suggestions) do
+ local color = (i == suggestions_idx) and style.accent or style.text
+ common.draw_text(font, color, s.text, "left", rx + style.padding.x, y, rw, lh)
+ if s.info then
+ color = (i == suggestions_idx) and style.text or style.dim
+ common.draw_text(style.font, color, s.info, "right", rx, y, rw - style.padding.x, lh)
+ end
+ y = y + lh
+ end
+end
+
+
+-- patch event logic into RootView
+local on_text_input = RootView.on_text_input
+local update = RootView.update
+local draw = RootView.draw
+
+
+RootView.on_text_input = function(...)
+ on_text_input(...)
+
+ local av = get_active_view()
+ if av then
+ -- update partial symbol and suggestions
+ partial = get_partial_symbol()
+ if #partial >= 3 then
+ update_suggestions()
+ last_line, last_col = av.doc:get_selection()
+ else
+ reset_suggestions()
+ end
+
+ -- scroll if rect is out of bounds of view
+ local _, y, _, h = get_suggestions_rect(av)
+ local limit = av.position.y + av.size.y
+ if y + h > limit then
+ av.scroll.to.y = av.scroll.y + y + h - limit
+ end
+ end
+end
+
+
+RootView.update = function(...)
+ update(...)
+
+ local av = get_active_view()
+ if av then
+ -- reset suggestions if caret was moved
+ local line, col = av.doc:get_selection()
+ if line ~= last_line or col ~= last_col then
+ reset_suggestions()
+ end
+ end
+end
+
+
+RootView.draw = function(...)
+ draw(...)
+
+ local av = get_active_view()
+ if av then
+ -- draw suggestions box after everything else
+ core.root_view:defer_draw(draw_suggestions_box, av)
+ end
+end
+
+
+local function predicate()
+ return get_active_view() and #suggestions > 0
+end
+
+
+command.add(predicate, {
+ ["autocomplete:complete"] = function()
+ local doc = core.active_view.doc
+ local line, col = doc:get_selection()
+ local text = suggestions[suggestions_idx].text
+ doc:insert(line, col, text)
+ doc:remove(line, col, line, col - #partial)
+ doc:set_selection(line, col + #text - #partial)
+ reset_suggestions()
+ end,
+
+ ["autocomplete:previous"] = function()
+ suggestions_idx = math.max(suggestions_idx - 1, 1)
+ end,
+
+ ["autocomplete:next"] = function()
+ suggestions_idx = math.min(suggestions_idx + 1, #suggestions)
+ end,
+
+ ["autocomplete:cancel"] = function()
+ reset_suggestions()
+ end,
+})
+
+
+keymap.add {
+ ["tab"] = "autocomplete:complete",
+ ["up"] = "autocomplete:previous",
+ ["down"] = "autocomplete:next",
+ ["escape"] = "autocomplete:cancel",
+}
+
+
+return autocomplete
diff --git a/tools/editor/art/lite/data/plugins/autoinsert.lua b/engine/art/editor/lite/data/plugins/autoinsert.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/autoinsert.lua
rename to engine/art/editor/lite/data/plugins/autoinsert.lua
diff --git a/engine/art/editor/lite/data/plugins/autoreload.lua b/engine/art/editor/lite/data/plugins/autoreload.lua
new file mode 100644
index 0000000..a077b6d
--- /dev/null
+++ b/engine/art/editor/lite/data/plugins/autoreload.lua
@@ -0,0 +1,61 @@
+local core = require "core"
+local config = require "core.config"
+local Doc = require "core.doc"
+
+
+local times = setmetatable({}, { __mode = "k" })
+
+local function update_time(doc)
+ local info = system.get_file_info(doc.filename)
+ times[doc] = info.modified
+end
+
+
+local function reload_doc(doc)
+ local fp = io.open(doc.filename, "r")
+ local text = fp:read("*a")
+ fp:close()
+
+ local sel = { doc:get_selection() }
+ doc:remove(1, 1, math.huge, math.huge)
+ doc:insert(1, 1, text:gsub("\r", ""):gsub("\n$", ""))
+ doc:set_selection(table.unpack(sel))
+
+ update_time(doc)
+ doc:clean()
+ core.log_quiet("Auto-reloaded doc \"%s\"", doc.filename)
+end
+
+
+core.add_thread(function()
+ while true do
+ -- check all doc modified times
+ for _, doc in ipairs(core.docs) do
+ local info = system.get_file_info(doc.filename or "")
+ if info and times[doc] ~= info.modified then
+ reload_doc(doc)
+ end
+ coroutine.yield()
+ end
+
+ -- wait for next scan
+ coroutine.yield(config.project_scan_rate)
+ end
+end)
+
+
+-- patch `Doc.save|load` to store modified time
+local load = Doc.load
+local save = Doc.save
+
+Doc.load = function(self, ...)
+ local res = load(self, ...)
+ update_time(self)
+ return res
+end
+
+Doc.save = function(self, ...)
+ local res = save(self, ...)
+ update_time(self)
+ return res
+end
diff --git a/tools/editor/art/lite/data/plugins/autowrap.lua b/engine/art/editor/lite/data/plugins/autowrap.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/autowrap.lua
rename to engine/art/editor/lite/data/plugins/autowrap.lua
diff --git a/tools/editor/art/lite/data/plugins/bracketmatch.lua b/engine/art/editor/lite/data/plugins/bracketmatch.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/bracketmatch.lua
rename to engine/art/editor/lite/data/plugins/bracketmatch.lua
diff --git a/tools/editor/art/lite/data/plugins/closeconfirmx.lua b/engine/art/editor/lite/data/plugins/closeconfirmx.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/closeconfirmx.lua
rename to engine/art/editor/lite/data/plugins/closeconfirmx.lua
diff --git a/tools/editor/art/lite/data/plugins/colorpreview.lua b/engine/art/editor/lite/data/plugins/colorpreview.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/colorpreview.lua
rename to engine/art/editor/lite/data/plugins/colorpreview.lua
diff --git a/tools/editor/art/lite/data/plugins/console.lua b/engine/art/editor/lite/data/plugins/console.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/console.lua
rename to engine/art/editor/lite/data/plugins/console.lua
diff --git a/tools/editor/art/lite/data/plugins/contextmenu.lua b/engine/art/editor/lite/data/plugins/contextmenu.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/contextmenu.lua
rename to engine/art/editor/lite/data/plugins/contextmenu.lua
diff --git a/tools/editor/art/lite/data/plugins/detectindent.lua b/engine/art/editor/lite/data/plugins/detectindent.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/detectindent.lua
rename to engine/art/editor/lite/data/plugins/detectindent.lua
diff --git a/tools/editor/art/lite/data/plugins/drawwhitespace.lua b/engine/art/editor/lite/data/plugins/drawwhitespace.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/drawwhitespace.lua
rename to engine/art/editor/lite/data/plugins/drawwhitespace.lua
diff --git a/tools/editor/art/lite/data/plugins/eofnewline.lua b/engine/art/editor/lite/data/plugins/eofnewline.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/eofnewline.lua
rename to engine/art/editor/lite/data/plugins/eofnewline.lua
diff --git a/tools/editor/art/lite/data/plugins/fsutils.lua b/engine/art/editor/lite/data/plugins/fsutils.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/fsutils.lua
rename to engine/art/editor/lite/data/plugins/fsutils.lua
diff --git a/tools/editor/art/lite/data/plugins/indentguide.lua b/engine/art/editor/lite/data/plugins/indentguide.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/indentguide.lua
rename to engine/art/editor/lite/data/plugins/indentguide.lua
diff --git a/tools/editor/art/lite/data/plugins/lfautoinsert.lua b/engine/art/editor/lite/data/plugins/lfautoinsert.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/lfautoinsert.lua
rename to engine/art/editor/lite/data/plugins/lfautoinsert.lua
diff --git a/tools/editor/art/lite/data/plugins/lineguide.lua b/engine/art/editor/lite/data/plugins/lineguide.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/lineguide.lua
rename to engine/art/editor/lite/data/plugins/lineguide.lua
diff --git a/tools/editor/art/lite/data/plugins/macro.lua b/engine/art/editor/lite/data/plugins/macro.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/macro.lua
rename to engine/art/editor/lite/data/plugins/macro.lua
diff --git a/tools/editor/art/lite/data/plugins/markers.lua b/engine/art/editor/lite/data/plugins/markers.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/markers.lua
rename to engine/art/editor/lite/data/plugins/markers.lua
diff --git a/tools/editor/art/lite/data/plugins/minimap.lua b/engine/art/editor/lite/data/plugins/minimap.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/minimap.lua
rename to engine/art/editor/lite/data/plugins/minimap.lua
diff --git a/tools/editor/art/lite/data/plugins/motiontrail.lua b/engine/art/editor/lite/data/plugins/motiontrail.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/motiontrail.lua
rename to engine/art/editor/lite/data/plugins/motiontrail.lua
diff --git a/tools/editor/art/lite/data/plugins/openfilelocation.lua b/engine/art/editor/lite/data/plugins/openfilelocation.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/openfilelocation.lua
rename to engine/art/editor/lite/data/plugins/openfilelocation.lua
diff --git a/tools/editor/art/lite/data/plugins/projectsearch.lua b/engine/art/editor/lite/data/plugins/projectsearch.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/projectsearch.lua
rename to engine/art/editor/lite/data/plugins/projectsearch.lua
diff --git a/tools/editor/art/lite/data/plugins/quote.lua b/engine/art/editor/lite/data/plugins/quote.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/quote.lua
rename to engine/art/editor/lite/data/plugins/quote.lua
diff --git a/tools/editor/art/lite/data/plugins/rainbowparen.lua b/engine/art/editor/lite/data/plugins/rainbowparen.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/rainbowparen.lua
rename to engine/art/editor/lite/data/plugins/rainbowparen.lua
diff --git a/tools/editor/art/lite/data/plugins/reflow.lua b/engine/art/editor/lite/data/plugins/reflow.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/reflow.lua
rename to engine/art/editor/lite/data/plugins/reflow.lua
diff --git a/tools/editor/art/lite/data/plugins/scale.lua b/engine/art/editor/lite/data/plugins/scale.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/scale.lua
rename to engine/art/editor/lite/data/plugins/scale.lua
diff --git a/tools/editor/art/lite/data/plugins/scalestatus.lua b/engine/art/editor/lite/data/plugins/scalestatus.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/scalestatus.lua
rename to engine/art/editor/lite/data/plugins/scalestatus.lua
diff --git a/tools/editor/art/lite/data/plugins/selectionhighlight.lua b/engine/art/editor/lite/data/plugins/selectionhighlight.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/selectionhighlight.lua
rename to engine/art/editor/lite/data/plugins/selectionhighlight.lua
diff --git a/tools/editor/art/lite/data/plugins/sort.lua b/engine/art/editor/lite/data/plugins/sort.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/sort.lua
rename to engine/art/editor/lite/data/plugins/sort.lua
diff --git a/tools/editor/art/lite/data/plugins/tabularize.lua b/engine/art/editor/lite/data/plugins/tabularize.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/tabularize.lua
rename to engine/art/editor/lite/data/plugins/tabularize.lua
diff --git a/tools/editor/art/lite/data/plugins/todotreeview.lua b/engine/art/editor/lite/data/plugins/todotreeview.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/todotreeview.lua
rename to engine/art/editor/lite/data/plugins/todotreeview.lua
diff --git a/tools/editor/art/lite/data/plugins/treeview.lua b/engine/art/editor/lite/data/plugins/treeview.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/treeview.lua
rename to engine/art/editor/lite/data/plugins/treeview.lua
diff --git a/tools/editor/art/lite/data/plugins/trimwhitespace.lua b/engine/art/editor/lite/data/plugins/trimwhitespace.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/trimwhitespace.lua
rename to engine/art/editor/lite/data/plugins/trimwhitespace.lua
diff --git a/tools/editor/art/lite/data/plugins/workspace.lua b/engine/art/editor/lite/data/plugins/workspace.lua
similarity index 100%
rename from tools/editor/art/lite/data/plugins/workspace.lua
rename to engine/art/editor/lite/data/plugins/workspace.lua
diff --git a/tools/editor/art/lite/data/themes/abyss.lua b/engine/art/editor/lite/data/themes/abyss.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/abyss.lua
rename to engine/art/editor/lite/data/themes/abyss.lua
diff --git a/tools/editor/art/lite/data/themes/cold_lime.lua b/engine/art/editor/lite/data/themes/cold_lime.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/cold_lime.lua
rename to engine/art/editor/lite/data/themes/cold_lime.lua
diff --git a/tools/editor/art/lite/data/themes/dracula.lua b/engine/art/editor/lite/data/themes/dracula.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/dracula.lua
rename to engine/art/editor/lite/data/themes/dracula.lua
diff --git a/tools/editor/art/lite/data/themes/duorand.lua b/engine/art/editor/lite/data/themes/duorand.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/duorand.lua
rename to engine/art/editor/lite/data/themes/duorand.lua
diff --git a/tools/editor/art/lite/data/themes/duotone.lua b/engine/art/editor/lite/data/themes/duotone.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/duotone.lua
rename to engine/art/editor/lite/data/themes/duotone.lua
diff --git a/tools/editor/art/lite/data/themes/fall.lua b/engine/art/editor/lite/data/themes/fall.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/fall.lua
rename to engine/art/editor/lite/data/themes/fall.lua
diff --git a/tools/editor/art/lite/data/themes/fwk.lua b/engine/art/editor/lite/data/themes/fwk.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/fwk.lua
rename to engine/art/editor/lite/data/themes/fwk.lua
diff --git a/tools/editor/art/lite/data/themes/github.lua b/engine/art/editor/lite/data/themes/github.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/github.lua
rename to engine/art/editor/lite/data/themes/github.lua
diff --git a/tools/editor/art/lite/data/themes/gruvbox_dark.lua b/engine/art/editor/lite/data/themes/gruvbox_dark.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/gruvbox_dark.lua
rename to engine/art/editor/lite/data/themes/gruvbox_dark.lua
diff --git a/tools/editor/art/lite/data/themes/liqube.lua b/engine/art/editor/lite/data/themes/liqube.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/liqube.lua
rename to engine/art/editor/lite/data/themes/liqube.lua
diff --git a/tools/editor/art/lite/data/themes/moe.lua b/engine/art/editor/lite/data/themes/moe.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/moe.lua
rename to engine/art/editor/lite/data/themes/moe.lua
diff --git a/tools/editor/art/lite/data/themes/monodark.lua b/engine/art/editor/lite/data/themes/monodark.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/monodark.lua
rename to engine/art/editor/lite/data/themes/monodark.lua
diff --git a/tools/editor/art/lite/data/themes/monokai.lua b/engine/art/editor/lite/data/themes/monokai.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/monokai.lua
rename to engine/art/editor/lite/data/themes/monokai.lua
diff --git a/tools/editor/art/lite/data/themes/nord.lua b/engine/art/editor/lite/data/themes/nord.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/nord.lua
rename to engine/art/editor/lite/data/themes/nord.lua
diff --git a/tools/editor/art/lite/data/themes/onedark.lua b/engine/art/editor/lite/data/themes/onedark.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/onedark.lua
rename to engine/art/editor/lite/data/themes/onedark.lua
diff --git a/tools/editor/art/lite/data/themes/only_dark.lua b/engine/art/editor/lite/data/themes/only_dark.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/only_dark.lua
rename to engine/art/editor/lite/data/themes/only_dark.lua
diff --git a/tools/editor/art/lite/data/themes/solarized_light.lua b/engine/art/editor/lite/data/themes/solarized_light.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/solarized_light.lua
rename to engine/art/editor/lite/data/themes/solarized_light.lua
diff --git a/tools/editor/art/lite/data/themes/solarobj.lua b/engine/art/editor/lite/data/themes/solarobj.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/solarobj.lua
rename to engine/art/editor/lite/data/themes/solarobj.lua
diff --git a/tools/editor/art/lite/data/themes/summer.lua b/engine/art/editor/lite/data/themes/summer.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/summer.lua
rename to engine/art/editor/lite/data/themes/summer.lua
diff --git a/tools/editor/art/lite/data/themes/vscode-dark.lua b/engine/art/editor/lite/data/themes/vscode-dark.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/vscode-dark.lua
rename to engine/art/editor/lite/data/themes/vscode-dark.lua
diff --git a/tools/editor/art/lite/data/themes/winter.lua b/engine/art/editor/lite/data/themes/winter.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/winter.lua
rename to engine/art/editor/lite/data/themes/winter.lua
diff --git a/tools/editor/art/lite/data/themes/zenburn.lua b/engine/art/editor/lite/data/themes/zenburn.lua
similarity index 100%
rename from tools/editor/art/lite/data/themes/zenburn.lua
rename to engine/art/editor/lite/data/themes/zenburn.lua
diff --git a/tools/editor/art/lite/data/user/init.lua b/engine/art/editor/lite/data/user/init.lua
similarity index 88%
rename from tools/editor/art/lite/data/user/init.lua
rename to engine/art/editor/lite/data/user/init.lua
index 689c60e..173f73d 100644
--- a/tools/editor/art/lite/data/user/init.lua
+++ b/engine/art/editor/lite/data/user/init.lua
@@ -7,7 +7,7 @@ local style = require "core.style"
-- light theme:
-- require "themes.summer"
-require "themes.fwk" -- monokai, dracula
+--require "themes.fwk" -- monokai, dracula
-- key binding:
-- keymap.add { ["ctrl+escape"] = "core:quit" }
diff --git a/tools/editor/art/materialdesignicons-webfont.license b/engine/art/editor/materialdesignicons-webfont.license
similarity index 100%
rename from tools/editor/art/materialdesignicons-webfont.license
rename to engine/art/editor/materialdesignicons-webfont.license
diff --git a/tools/editor/art/materialdesignicons-webfont.ttf b/engine/art/editor/materialdesignicons-webfont.ttf
similarity index 100%
rename from tools/editor/art/materialdesignicons-webfont.ttf
rename to engine/art/editor/materialdesignicons-webfont.ttf
diff --git a/tools/editor/plugins/.gitkeep b/engine/art/editor/plugins/.gitkeep
similarity index 100%
rename from tools/editor/plugins/.gitkeep
rename to engine/art/editor/plugins/.gitkeep
diff --git a/tools/editor/art/scripts/inspect.lua b/engine/art/editor/scripts/inspect.lua
similarity index 100%
rename from tools/editor/art/scripts/inspect.lua
rename to engine/art/editor/scripts/inspect.lua
diff --git a/tools/editor/editor.c b/engine/editor.c
similarity index 90%
rename from tools/editor/editor.c
rename to engine/editor.c
index c92f010..c00a656 100644
--- a/tools/editor/editor.c
+++ b/engine/editor.c
@@ -1,11 +1,13 @@
#define COOK_ON_DEMAND 1 // @fixme: these directives should be on client, not within v4k.dll
#define ENABLE_AUTOTESTS 1
-#define V4K_IMPLEMENTATION
-#include "v4k.h"
-#include "objtests.h"
+#include "v4k.c"
+//#include "../tools/labs/objtests.h"
// ----------------------------------------------------------------------------
+TODO("editor_load_on_boot()");
+TODO("editor_save_on_quit()");
+
TODO("file_id: glow.hdr vs glow.png");
TODO("reflect: iterate components+metas on REFLECT too, so they're properly saved/loaded");
@@ -54,7 +56,7 @@ TODO("obj: free obj_components()/payload2");
TODO("pack: mp2json, json2mp");
TODO("pack: simplify msgpack API, make it growth similar to va()")
-#if 0 // v4k_pack proposal
+#if 0 // fwk_pack proposal
static __thread char* mpin;
static __thread unsigned mpinlen;
static __thread char mpinbuf[256];
@@ -65,8 +67,28 @@ static __thread char mpoutbuf[256];
#define UNPACKMSG(ptr,fmt,...) (mpin = (char*)ptr, mpinlen = strlen(ptr), mpout = mpoutbuf, mpoutlen = sizeof(mpoutbuf), mpoutlen = cobs_decode(mpin, mpinlen, mpout, mpoutlen), msgunpack_new(mpout, mpoutlen) && msgunpack(fmt, __VA_ARGS__))
#endif
-#include "3rd_icon_mdi.h"
-#include "v4k_editor.h"
+TODO("serialize array(types)")
+TODO("serialize map(char*,types)")
+TODO("serialize map(int,types)")
+TODO("sprite: solid platforms, one-way platforms")
+TODO("sprite: shake left-right, up-down")
+TODO("sprite: coyote time")
+TODO("sprite: jump buffering before grounded")
+TODO("sprite: double jump, wall sliding, wall climbing")
+TODO("sprite: hitbox for enemies -> wall detection")
+
+TODO("new: integrate with Art/ browser")
+TODO("bug: lite key bindings are being sent to editor")
+TODO("bug: not sending quit signal to lite neither at window close nor editor close (see: temporary files)")
+TODO("bug: missing search results window")
+TODO("bug: missing code completions popup")
+// TODO("eval: https://github.com/drmargarido/linters")
+// TODO("eval: https://github.com/monolifed/theme16")
+// TODO("eval: https://github.com/vincens2005/lite-formatters")
+// https://github.com/takase1121/lite-xl-img
+// https://github.com/takase1121/lite-xl-finder
+// https://github.com/rxi/lite/commit/236a585756cb9fa70130eee6c9a604780aced424 > suru.png
+// https://github.com/rxi/lite/commit/f90b00748e1fe1cd2340aaa06d2526a1b2ea54ec
void editor_gizmos(int dim) {
// debugdraw
@@ -247,8 +269,8 @@ void kid_draw(kid *obj) {
float position[3] = {obj->pos.x,obj->pos.y,obj->pos.y}; // position(x,y,depth: sort by Y)
float offset[2]={0,0}, scale[2]={1,1};
float coords[3]={col * 4 + row,4,4}; // num_frame(x) in a 4x4(y,z) spritesheet
- sprite_sheet(obj->texture_, coords, position, obj->angle*TO_DEG, offset, scale,
- 0, obj->color, 0); // is_additive, tint color, resolution independant
+ unsigned flags = 0;
+ sprite_sheet(obj->texture_, coords, position, obj->angle*TO_DEG, offset, scale, obj->color, flags);
}
int kid_aabb(kid *obj, aabb *box) {
*box = aabb( vec3(obj->pos.x-16,obj->pos.y-16,0), vec3(obj->pos.x+16,obj->pos.y+16,1) );
@@ -399,7 +421,7 @@ int main(){
if( flag("--transparent") )
window_create(101, 0);
else
- window_create(80, flag("--borderless") ? WINDOW_BORDERLESS : 0);
+ window_create(80, flag("--windowed") ? 0 : WINDOW_BORDERLESS);
window_icon("scale-ruler-icon.png");
while( window_swap() ) {
diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h
index 2ac99e0..9878932 100644
--- a/engine/joint/v4k.h
+++ b/engine/joint/v4k.h
@@ -14028,7 +14028,7 @@ extern "C" {
//-----------------------------------------------------------------------------
// Headers
-#line 1 "engine/split/v4k_config.h"
+#line 1 "v4k_config.h"
// -----------------------------------------------------------------------------
// config directives
@@ -14443,7 +14443,7 @@ typedef char bool;
#endif
#line 0
-#line 1 "engine/split/v4k_ds.h"
+#line 1 "v4k_ds.h"
// data structures and utils: array, set, map, hash, sort.
// - rlyeh, public domain
@@ -14882,7 +14882,7 @@ API bool (map_sort)(map* m);
API void (map_clear)(map* m);
#line 0
-#line 1 "engine/split/v4k_math.h"
+#line 1 "v4k_math.h"
// -----------------------------------------------------------------------------
// math framework: rand, ease, vec2, vec3, vec4, quat, mat2, mat33, mat34, mat4
// - rlyeh, public domain
@@ -15163,7 +15163,7 @@ API void print34( float *m );
API void print44( float *m );
#line 0
-#line 1 "engine/split/v4k_obj.h"
+#line 1 "v4k_obj.h"
// -----------------------------------------------------------------------------
// factory of handle ids
@@ -15327,6 +15327,7 @@ void* obj_free(void *o);
// --- syntax sugars
#define obj_extend(T,method) (obj_##method[OBJTYPE(T)] = (void*)T##_##method)
+#define obj_extend_t(T,method) (obj_##method[OBJTYPE(T##_t)] = (void*)T##_##method)
#define obj_method(method,o,...) (obj_##method[((struct obj*)(o))->objtype](o,##__VA_ARGS__)) // (obj_##method[((struct obj*)(o))->objtype]((o), ##__VA_ARGS__))
#define obj_hasmethod(o,method) (obj_typeid(o)[obj_##method])
@@ -15349,6 +15350,17 @@ void* obj_free(void *o);
#define EXTEND9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8)
#define EXTEND10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8), obj_extend(o,F9)
+#define EXTEND_T(...) EXPAND(EXTEND_T, __VA_ARGS__)
+#define EXTEND_T2(o,F1) obj_extend_t(o,F1)
+#define EXTEND_T3(o,F1,F2) obj_extend_t(o,F1), obj_extend_t(o,F2)
+#define EXTEND_T4(o,F1,F2,F3) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3)
+#define EXTEND_T5(o,F1,F2,F3,F4) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4)
+#define EXTEND_T6(o,F1,F2,F3,F4,F5) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5)
+#define EXTEND_T7(o,F1,F2,F3,F4,F5,F6) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6)
+#define EXTEND_T8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7)
+#define EXTEND_T9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8)
+#define EXTEND_T10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8), obj_extend_t(o,F9)
+
// --- declare vtables
API extern void (*obj_ctor[256])(); ///-
@@ -15367,6 +15379,8 @@ API extern int (*obj_lerp[256])(); ///-
API extern int (*obj_edit[256])(); ///-
API extern int (*obj_aabb[256])(); ///-
+API extern const char*OBJTYPES[256]; /// -
+
// ----------------------------------------------------------------------------
// core
@@ -15511,7 +15525,7 @@ typedef enum OBJTYPE_BUILTINS {
#line 0
-#line 1 "engine/split/v4k_ai.h"
+#line 1 "v4k_ai.h"
// AI framework
// - rlyeh, public domain.
//
@@ -15596,7 +15610,7 @@ API void swarm_update_acceleration_and_velocity_only(swarm_t *self, float del
API int ui_swarm(swarm_t *self);
#line 0
-#line 1 "engine/split/v4k_audio.h"
+#line 1 "v4k_audio.h"
// -----------------------------------------------------------------------------
// audio framework
// - rlyeh, public domain
@@ -15657,7 +15671,7 @@ enum AUDIO_FLAGS {
API int audio_queue( const void *samples, int num_samples, int flags );
#line 0
-#line 1 "engine/split/v4k_collide.h"
+#line 1 "v4k_collide.h"
// -----------------------------------------------------------------------------
// original code by @vurtun (PD) and @barerose (CC0).
// [src] https://gist.github.com/vurtun/95f088e4889da2474ad1ce82d7911fee
@@ -15818,7 +15832,7 @@ API poly diamond(vec3 from, vec3 to, float size); // poly_free() required
API void collide_demo(); // debug draw collisions
#line 0
-#line 1 "engine/split/v4k_cook.h"
+#line 1 "v4k_cook.h"
// -----------------------------------------------------------------------------
// asset pipeline framework
// - rlyeh, public domain.
@@ -15854,7 +15868,7 @@ API int cook_progress(); // [0..100]
API bool have_tools();
#line 0
-#line 1 "engine/split/v4k_data.h"
+#line 1 "v4k_data.h"
// -----------------------------------------------------------------------------
// data framework (json5, xml, compression) @todo:kvdb
// - rlyeh, public domain
@@ -15893,7 +15907,7 @@ API void xml_pop();
API bool data_tests();
#line 0
-#line 1 "engine/split/v4k_extend.h"
+#line 1 "v4k_extend.h"
// dll ------------------------------------------------------------------------
/// !!! `filename` must contain extension
@@ -15930,54 +15944,7 @@ enum {
API void *script_init_env(unsigned flags);
#line 0
-#line 1 "engine/split/v4k_editor.h"
-// -----------------------------------------------------------------------------
-// in-game editor
-// - rlyeh, public domain.
-//
-// @todo: merge editor1.c and editor3.c internals into this api
-
-//API void editor();
-//API bool editor_active();
-API vec3 editor_pick(float mouse_x, float mouse_y);
-API char* editor_path(const char *path);
-
-API float* engine_getf(const char *key);
-API int* engine_geti(const char *key);
-API char** engine_gets(const char *key);
-API int engine_send(const char *cmd, const char *optional_value);
-
-API int ui_debug();
-
-// open file dialog
-
-API char* dialog_load();
-API char* dialog_save();
-
-// transform gizmos
-
-API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca);
-API bool gizmo_active();
-API bool gizmo_hover();
-
-// localization kit (I18N, L10N)
-
-API bool kit_load( const char *filename ); // load translations file (xlsx)
-API bool kit_merge( const char *filename ); // merge translations file into existing context
-API void kit_insert( const char *id, const char *translation ); // insert single translation unit
-API void kit_clear(); // delete all translations
-
-API void kit_set( const char *variable, const char *value ); // set context variable
-API void kit_reset(); // reset all variables in context
-API void kit_dump_state( FILE *fp ); // debug
-
-API char* kit_translate2( const char *id, const char *langcode_iso639_1 ); // perform a translation given explicit locale
-
-API void kit_locale( const char *langcode_iso639_1 ); // set current locale: enUS, ptBR, esES, ...
-API char* kit_translate( const char *id ); // perform a translation, given current locale
-#line 0
-
-#line 1 "engine/split/v4k_file.h"
+#line 1 "v4k_file.h"
// -----------------------------------------------------------------------------
// files, cache and virtual filesystem (registered directories and/or compressed zip archives).
// - rlyeh, public domain.
@@ -16077,7 +16044,7 @@ API void ini_destroy(ini_t);
API bool ini_write(const char *filename, const char *section, const char *key, const char *value);
#line 0
-#line 1 "engine/split/v4k_font.h"
+#line 1 "v4k_font.h"
// -----------------------------------------------------------------------------
// font framework
// - rlyeh, public domain
@@ -16169,7 +16136,7 @@ API void* font_colorize(const char *text, const char *comma_types, const char *c
API vec2 font_highlight(const char *text, const void *colors);
#line 0
-#line 1 "engine/split/v4k_input.h"
+#line 1 "v4k_input.h"
// -----------------------------------------------------------------------------
// input framework
// - rlyeh, public domain
@@ -16296,7 +16263,7 @@ enum INPUT_ALIASES {
};
#line 0
-#line 1 "engine/split/v4k_memory.h"
+#line 1 "v4k_memory.h"
// -----------------------------------------------------------------------------
// memory framework
// - rlyeh, public domain
@@ -16336,7 +16303,7 @@ static FORCE_INLINE void *(CALLOC_)(size_t m, size_t n) { return n *= m, memset(
static FORCE_INLINE char *(STRDUP_)(const char *s) { size_t n = strlen(s)+1; return ((char*)memcpy(REALLOC(0,n), s, n)); } ///-
#line 0
-#line 1 "engine/split/v4k_network.h"
+#line 1 "v4k_network.h"
// -----------------------------------------------------------------------------
// network framework
// - rlyeh, public domain
@@ -16388,7 +16355,7 @@ API int tcp_debug(int); // toggle traffic monitoring on/off for given socket
//API int tcp_crypt(int,uint64_t); // set shared secret
#line 0
-#line 1 "engine/split/v4k_track.h"
+#line 1 "v4k_track.h"
#ifndef TRACK_SEND_BUFSIZE
#define TRACK_SEND_BUFSIZE 576
#endif
@@ -16449,7 +16416,7 @@ typedef struct track_prop {
API int track_event_props(char const *event_id, char const *user_id, const track_prop *props);
#line 0
-#line 1 "engine/split/v4k_netsync.h"
+#line 1 "v4k_netsync.h"
// high-level, socket-less networking api. inspired by Quake, MPI and RenderBuckets theories.
// - rlyeh, public domain
//
@@ -16535,7 +16502,7 @@ API int64_t client_join(const char *ip, int port);
#define LOCALHOST_IPV6 "::1"
#line 0
-#line 1 "engine/split/v4k_pack.h"
+#line 1 "v4k_pack.h"
// ----------------------------------------------------------------------------
// compression api
@@ -16664,25 +16631,25 @@ typedef struct double2 { double x,y; } double2;
typedef struct double3 { double x,y,z; } double3;
typedef struct double4 { double x,y,z,w; } double4;
-#define byte2(x,y) M_CAST(byte2, (uint8_t)(x), (uint8_t)(y) )
-#define byte3(x,y,z) M_CAST(byte3, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z) )
-#define byte4(x,y,z,w) M_CAST(byte4, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z), (uint8_t)(w) )
+#define byte2(x,y) C_CAST(byte2, (uint8_t)(x), (uint8_t)(y) )
+#define byte3(x,y,z) C_CAST(byte3, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z) )
+#define byte4(x,y,z,w) C_CAST(byte4, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z), (uint8_t)(w) )
-#define int2(x,y) M_CAST(int2, (int)(x), (int)(y) )
-#define int3(x,y,z) M_CAST(int3, (int)(x), (int)(y), (int)(z) )
-#define int4(x,y,z,w) M_CAST(int4, (int)(x), (int)(y), (int)(z), (int)(w) )
+#define int2(x,y) C_CAST(int2, (int)(x), (int)(y) )
+#define int3(x,y,z) C_CAST(int3, (int)(x), (int)(y), (int)(z) )
+#define int4(x,y,z,w) C_CAST(int4, (int)(x), (int)(y), (int)(z), (int)(w) )
-#define uint2(x,y) M_CAST(uint2, (unsigned)(x), (unsigned)(y) )
-#define uint3(x,y,z) M_CAST(uint3, (unsigned)(x), (unsigned)(y), (unsigned)(z) )
-#define uint4(x,y,z,w) M_CAST(uint4, (unsigned)(x), (unsigned)(y), (unsigned)(z), (unsigned)(w) )
+#define uint2(x,y) C_CAST(uint2, (unsigned)(x), (unsigned)(y) )
+#define uint3(x,y,z) C_CAST(uint3, (unsigned)(x), (unsigned)(y), (unsigned)(z) )
+#define uint4(x,y,z,w) C_CAST(uint4, (unsigned)(x), (unsigned)(y), (unsigned)(z), (unsigned)(w) )
-#define float2(x,y) M_CAST(float2, (float)(x), (float)(y) )
-#define float3(x,y,z) M_CAST(float3, (float)(x), (float)(y), (float)(z) )
-#define float4(x,y,z,w) M_CAST(float4, (float)(x), (float)(y), (float)(z), (float)(w) )
+#define float2(x,y) C_CAST(float2, (float)(x), (float)(y) )
+#define float3(x,y,z) C_CAST(float3, (float)(x), (float)(y), (float)(z) )
+#define float4(x,y,z,w) C_CAST(float4, (float)(x), (float)(y), (float)(z), (float)(w) )
-#define double2(x,y) M_CAST(double2, (double)(x), (double)(y) )
-#define double3(x,y,z) M_CAST(double3, (double)(x), (double)(y), (double)(z) )
-#define double4(x,y,z,w) M_CAST(double4, (double)(x), (double)(y), (double)(z), (double)(w) )
+#define double2(x,y) C_CAST(double2, (double)(x), (double)(y) )
+#define double3(x,y,z) C_CAST(double3, (double)(x), (double)(y), (double)(z) )
+#define double4(x,y,z,w) C_CAST(double4, (double)(x), (double)(y), (double)(z), (double)(w) )
// -----------------------------------------------------------------------------
// compile-time fourcc, eightcc
@@ -16927,7 +16894,7 @@ API int loadb(const unsigned char *buf, const char *format, ...);
#line 0
-#line 1 "engine/split/v4k_profile.h"
+#line 1 "v4k_profile.h"
// -----------------------------------------------------------------------------
// profiler & stats (@fixme: threadsafe)
@@ -16959,7 +16926,7 @@ extern API int profiler_enabled; ///-
#endif
#line 0
-#line 1 "engine/split/v4k_reflect.h"
+#line 1 "v4k_reflect.h"
// C reflection: enums, functions, structs, members and anotations.
// - rlyeh, public domain
//
@@ -17026,7 +16993,7 @@ API const char* symbol_naked(const char *s);
API int ui_reflect(const char *mask); // *, model* or NULL
#line 0
-#line 1 "engine/split/v4k_render.h"
+#line 1 "v4k_render.h"
// -----------------------------------------------------------------------------
// naive rendering framework
// - rlyeh, public domain
@@ -17212,82 +17179,6 @@ API void fullscreen_quad_rgb_flipped( texture_t texture, float gamma );
API void fullscreen_quad_ycbcr( texture_t texture_YCbCr[3], float gamma );
API void fullscreen_quad_ycbcr_flipped( texture_t texture_YCbCr[3], float gamma );
-// -----------------------------------------------------------------------------
-// sprites
-
-// texture id, position(x,y,depth sort), tint color, rotation angle
-API void sprite( texture_t texture, float position[3], float rotation /*0*/, uint32_t color /*~0u*/);
-
-// texture id, rect(x,y,w,h) is [0..1] normalized, z-index, pos(xy,scale.xy), rotation (degrees), color (rgba)
-API void sprite_rect( texture_t t, vec4 rect, float zindex, vec4 pos, float tilt_deg, unsigned tint_rgba);
-
-// texture id, sheet(frameNumber,X,Y) (frame in a X*Y spritesheet), position(x,y,depth sort), rotation angle, offset(x,y), scale(x,y), is_additive, tint color
-API void sprite_sheet( texture_t texture, float sheet[3], float position[3], float rotation, float offset[2], float scale[2], int is_additive, uint32_t rgba, int resolution_independant);
-
-API void sprite_flush();
-
-// -----------------------------------------------------------------------------
-// tilemaps
-
-typedef struct tileset_t {
- texture_t tex; // spritesheet
- unsigned tile_w, tile_h; // dimensions per tile in pixels
- unsigned cols, rows; // tileset num_cols, num_rows
- unsigned selected; // active tile (while editing)
-} tileset_t;
-
-API tileset_t tileset(texture_t tex, unsigned tile_w, unsigned tile_h, unsigned cols, unsigned rows);
-
-API int ui_tileset( tileset_t t );
-
-typedef struct tilemap_t {
- int blank_chr; // transparent tile
- unsigned cols, rows; // map dimensions (in tiles)
- array(int) map;
-
- vec3 position; // x,y,scale
- float zindex;
- float tilt;
- unsigned tint;
- bool is_additive;
-} tilemap_t;
-
-API tilemap_t tilemap(const char *map, int blank_chr, int linefeed_chr);
-API void tilemap_render( tilemap_t m, tileset_t style );
-API void tilemap_render_ext( tilemap_t m, tileset_t style, float zindex, float xy_zoom[3], float tilt, unsigned tint, bool is_additive );
-
-// -----------------------------------------------------------------------------
-// tiled maps
-
-typedef struct tiled_t {
- char *map_name;
- unsigned first_gid, tilew, tileh, w, h;
-
- bool parallax;
- vec3 position;
- array(bool) visible;
- array(tilemap_t) layers;
- array(tileset_t) sets;
- array(char*) names;
-} tiled_t;
-
-API tiled_t tiled(const char *file_tmx);
-API void tiled_render(tiled_t tmx, vec3 pos);
-
-API void ui_tiled(tiled_t *t);
-
-// -----------------------------------------------------------------------------
-// spines
-
-typedef struct spine_t spine_t;
-
-API spine_t*spine(const char *file_json, const char *file_atlas, unsigned flags);
-API void spine_skin(spine_t *p, unsigned skin);
-API void spine_render(spine_t *p, vec3 offset, unsigned flags);
-API void spine_animate(spine_t *p, float delta);
-
-API void ui_spine(spine_t *p);
-
// -----------------------------------------------------------------------------
// cubemaps
@@ -17734,7 +17625,7 @@ API void* screenshot(int components); // 3 RGB, 4 RGBA, -3 BGR, -4 BGRA
API void* screenshot_async(int components); // 3 RGB, 4 RGBA, -3 BGR, -4 BGRA
#line 0
-#line 1 "engine/split/v4k_renderdd.h"
+#line 1 "v4k_renderdd.h"
// -----------------------------------------------------------------------------
// debugdraw framework
// - rlyeh, public domain.
@@ -17801,7 +17692,7 @@ API void ddraw_flush();
API void ddraw_flush_projview(mat44 proj, mat44 view);
#line 0
-#line 1 "engine/split/v4k_scene.h"
+#line 1 "v4k_scene.h"
// -----------------------------------------------------------------------------
// scene framework
// - rlyeh, public domain
@@ -17938,7 +17829,124 @@ API unsigned scene_count_light();
API light_t* scene_index_light(unsigned index);
#line 0
-#line 1 "engine/split/v4k_string.h"
+#line 1 "v4k_sprite.h"
+// -----------------------------------------------------------------------------
+// sprites
+
+typedef enum SPRITE_FLAGS {
+ SPRITE_PROJECTED = 1,
+ SPRITE_ADDITIVE = 2,
+ SPRITE_CENTERED = 4,
+ SPRITE_RESOLUTION_INDEPENDANT = 128,
+} SPRITE_FLAGS;
+
+// texture id, position(x,y,depth sort), tint color, rotation angle
+API void sprite( texture_t texture, float position[3], float rotation /*0*/, unsigned color /*~0u*/, unsigned flags);
+
+// texture id, rect(x,y,w,h) is [0..1] normalized, then: pos(xyz,z-index), (scale.xy,offset.xy), rotation (degrees), color (rgba)
+API void sprite_rect( texture_t t, vec4 rect, vec4 pos, vec4 scaleoff, float tilt_deg, unsigned tint_rgba, unsigned flags);
+
+// texture id, sheet(frameNumber,X,Y) (frame in a X*Y spritesheet), position(x,y,depth sort), rotation angle, offset(x,y), scale(x,y), is_additive, tint color
+API void sprite_sheet( texture_t texture, float sheet[3], float position[3], float rotation, float offset[2], float scale[2], unsigned rgba, unsigned flags);
+
+API void sprite_flush();
+
+// -----------------------------------------------------------------------------
+// tilemaps
+
+typedef struct tileset_t {
+ texture_t tex; // spritesheet
+ unsigned tile_w, tile_h; // dimensions per tile in pixels
+ unsigned cols, rows; // tileset num_cols, num_rows
+ unsigned selected; // active tile (while editing)
+} tileset_t;
+
+API tileset_t tileset(texture_t tex, unsigned tile_w, unsigned tile_h, unsigned cols, unsigned rows);
+
+API int ui_tileset( tileset_t t );
+
+typedef struct tilemap_t {
+ int blank_chr; // transparent tile
+ unsigned cols, rows; // map dimensions (in tiles)
+ array(int) map;
+
+ vec3 position; // x,y,scale
+ float zindex;
+ float tilt;
+ unsigned tint;
+ bool is_additive;
+} tilemap_t;
+
+API tilemap_t tilemap(const char *map, int blank_chr, int linefeed_chr);
+API void tilemap_render( tilemap_t m, tileset_t style );
+API void tilemap_render_ext( tilemap_t m, tileset_t style, float zindex, float xy_zoom[3], float tilt, unsigned tint, bool is_additive );
+
+// -----------------------------------------------------------------------------
+// tiled maps
+
+typedef struct tiled_t {
+ char *map_name;
+ unsigned first_gid, tilew, tileh, w, h;
+
+ bool parallax;
+ vec3 position;
+ array(bool) visible;
+ array(tilemap_t) layers;
+ array(tileset_t) sets;
+ array(char*) names;
+} tiled_t;
+
+API tiled_t tiled(const char *file_tmx);
+API void tiled_render(tiled_t tmx, vec3 pos);
+
+API void ui_tiled(tiled_t *t);
+
+// -----------------------------------------------------------------------------
+// spines
+
+typedef struct spine_t spine_t;
+
+API spine_t*spine(const char *file_json, const char *file_atlas, unsigned flags);
+API void spine_skin(spine_t *p, unsigned skin);
+API void spine_render(spine_t *p, vec3 offset, unsigned flags);
+API void spine_animate(spine_t *p, float delta);
+
+API void ui_spine(spine_t *p);
+
+// ----------------------------------------------------------------------------
+// sprite v2 api
+
+typedef struct sprite_t { OBJ
+ vec4 gamepad; // up,down,left,right
+ vec2 fire; // a,b
+
+ vec4 pos;
+ vec2 sca;
+ float tilt;
+ unsigned tint;
+ unsigned frame;
+ unsigned timer, timer_ms;
+ unsigned flip_, flipped;
+ unsigned play;
+ bool paused;
+ // array(unsigned) play_queue; or unsigned play_next;
+ struct atlas_t *a; // shared
+ //atlas_t own; // owned
+} sprite_t;
+
+OBJTYPEDEF(sprite_t,10);
+API void sprite_ctor(sprite_t *s);
+API void sprite_dtor(sprite_t *s);
+API void sprite_tick(sprite_t *s);
+API void sprite_draw(sprite_t *s);
+API void sprite_edit(sprite_t *s);
+
+API sprite_t*sprite_new(const char *ase, int bindings[6]);
+API void sprite_del(sprite_t *s);
+API void sprite_setanim(sprite_t *s, unsigned name);
+#line 0
+
+#line 1 "v4k_string.h"
// string framework
// - rlyeh, public domain
@@ -18031,9 +18039,26 @@ typedef struct quarks_db {
API unsigned quark_intern( quarks_db*, const char *string );
API const char *quark_string( quarks_db*, unsigned key );
+
+// -----------------------------------------------------------------------------
+// ## localization kit (I18N, L10N)
+
+API bool kit_load( const char *filename ); // load translations file (xlsx)
+API bool kit_merge( const char *filename ); // merge translations file into existing context
+API void kit_insert( const char *id, const char *translation ); // insert single translation unit
+API void kit_clear(); // delete all translations
+
+API void kit_set( const char *variable, const char *value ); // set context variable
+API void kit_reset(); // reset all variables in context
+API void kit_dump_state( FILE *fp ); // debug
+
+API char* kit_translate2( const char *id, const char *langcode_iso639_1 ); // perform a translation given explicit locale
+
+API void kit_locale( const char *langcode_iso639_1 ); // set current locale: enUS, ptBR, esES, ...
+API char* kit_translate( const char *id ); // perform a translation, given current locale
#line 0
-#line 1 "engine/split/v4k_system.h"
+#line 1 "v4k_system.h"
// -----------------------------------------------------------------------------
// system framework utils
// - rlyeh, public domain.
@@ -18120,7 +18145,7 @@ API int (test)(const char *file, int line, const char *expr, bool result);
#endif
#line 0
-#line 1 "engine/split/v4k_time.h"
+#line 1 "v4k_time.h"
// -----------------------------------------------------------------------------
// time framework utils
@@ -18279,7 +18304,7 @@ API vec3 curve_eval(curve_t *c, float dt, unsigned *color);
API void curve_destroy(curve_t *c);
#line 0
-#line 1 "engine/split/v4k_ui.h"
+#line 1 "v4k_ui.h"
// -----------------------------------------------------------------------------
// immediate ui framework
// - rlyeh, public domain
@@ -18373,7 +18398,7 @@ API int ui_demo(int do_windows);
API void *ui_handle();
#line 0
-#line 1 "engine/split/v4k_video.h"
+#line 1 "v4k_video.h"
// -----------------------------------------------------------------------------
// video decoder (mpeg)
// - rlyeh, public domain
@@ -18416,7 +18441,7 @@ API bool record_active();
API void record_stop(void);
#line 0
-#line 1 "engine/split/v4k_window.h"
+#line 1 "v4k_window.h"
// -----------------------------------------------------------------------------
// window framework
// - rlyeh, public domain
@@ -18520,6 +18545,39 @@ API void window_setclipboard(const char *text);
// ----
+#line 1 "v4k_editor.h"
+// -----------------------------------------------------------------------------
+// in-game editor
+// - rlyeh, public domain.
+
+API int editor_send(const char *command);
+
+//API void editor();
+//API bool editor_active();
+API vec3 editor_pick(float mouse_x, float mouse_y);
+API char* editor_path(const char *path);
+
+API float* engine_getf(const char *key);
+API int* engine_geti(const char *key);
+API char** engine_gets(const char *key);
+API int engine_send(const char *cmd, const char *optional_value);
+
+API int ui_debug();
+
+// open file dialog
+
+API char* dialog_load();
+API char* dialog_save();
+
+// transform gizmos
+
+API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca);
+API bool gizmo_active();
+API bool gizmo_hover();
+#line 0
+
+// ----
+
#if is(cpp)
} // extern "C"
#endif
@@ -18554,7 +18612,7 @@ API void window_setclipboard(const char *text);
#define GLAD_GL_IMPLEMENTATION // glad
#endif
-#line 1 "engine/split/3rd_glad.h"
+#line 1 "3rd_glad.h"
#ifndef __EMSCRIPTEN__
#ifndef _GNU_SOURCE // juicy linux headers
@@ -30236,7 +30294,7 @@ int gladLoadGL( GLADloadfunc load) {
#endif /* __EMSCRIPTEN__ */
#line 0
-#line 1 "engine/split/3rd_icon_md.h"
+#line 1 "3rd_icon_md.h"
// Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py for languages C and C++
// from https://github.com/google/material-design-icons/raw/master/font/MaterialIcons-Regular.codepoints
// for use with https://github.com/google/material-design-icons/blob/master/font/MaterialIcons-Regular.ttf
@@ -32580,7 +32638,7 @@ errno_t fopen_s(
#endif
//---
-#line 1 "engine/split/3rd_glfw3.h"
+#line 1 "3rd_glfw3.h"
#ifndef __EMSCRIPTEN__
// forked from https://github.com/SasLuca/glfw-single-header (CC0-1.0 licensed)
@@ -71777,7 +71835,7 @@ uint32_t _glfwKeySym2Unicode(unsigned int keysym)
#line 0
#undef timeGetTime
//---
-#line 1 "engine/split/3rd_swrap.h"
+#line 1 "3rd_swrap.h"
// https://github.com/BareRose/swrap/blob/master/swrap.h
/*
@@ -72070,7 +72128,7 @@ SWDEF int swrapMultiSelect (int* socks, size_t socks_size, double timeout) {
#endif //SWRAP_H
#line 0
//---
-#line 1 "engine/split/3rd_jo_mp1.h"
+#line 1 "3rd_jo_mp1.h"
/* public domain Simple, Minimalistic MPEG Layer 1 decoder - http://jonolick.com
*
* Revision History:
@@ -72481,7 +72539,7 @@ bool jo_read_mp1(const void *input, int inputSize, short **output_, int *outputS
#line 0
#define get_bits stb_vorbis_get_bits
#define error stb_vorbis_error
-#line 1 "engine/split/3rd_stb_vorbis.h"
+#line 1 "3rd_stb_vorbis.h"
// Ogg Vorbis audio decoder - v1.22 - public domain
// http://nothings.org/stb_vorbis/
//
@@ -78069,7 +78127,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#line 0
#undef error
#undef DEBUG
-#line 1 "engine/split/3rd_sts_mixer.h"
+#line 1 "3rd_sts_mixer.h"
///////////////////////////////////////////////////////////////////////////////
// sts_mixer.h - v0.02
// written 2016 by Sebastian Steinhauer
@@ -78582,7 +78640,7 @@ int main(int argc, char *argv[]) {
For more information, please refer to
*/
#line 0
-#line 1 "engine/split/3rd_miniaudio.h"
+#line 1 "3rd_miniaudio.h"
/*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.11.18 - 2023-08-07
@@ -171127,12 +171185,12 @@ SOFTWARE.
#undef R
#define error l_error
#define panic l_panic
-#line 1 "engine/split/3rd_lua.h"
+#line 1 "3rd_lua.h"
/*
minilua.h -- Lua in a single header
Project URL: https://github.com/edubart/minilua
- This is Lua 5.4.4 contained in a single header to be bundled in C/C++ applications with ease.
+ This is Lua 5.4.6 contained in a single header to be bundled in C/C++ applications with ease.
Lua is a powerful, efficient, lightweight, embeddable scripting language.
Do the following in *one* C file to create the implementation:
@@ -171152,7 +171210,7 @@ SOFTWARE.
*/
/* detect system platform */
-#if !defined(LUA_USE_WINDOWS) && !defined(LUA_USE_LINUX) && !defined(LUA_USE_MACOSX) && !defined(LUA_USE_POSIX) && !defined(LUA_USE_C89)
+#if !defined(LUA_USE_WINDOWS) && !defined(LUA_USE_LINUX) && !defined(LUA_USE_MACOSX) && !defined(LUA_USE_POSIX) && !defined(LUA_USE_C89) && !defined(LUA_USE_IOS)
#if defined(_WIN32)
#define LUA_USE_WINDOWS
#elif defined(__linux__)
@@ -171288,6 +171346,12 @@ extern "C" {
#endif
+#if defined(LUA_USE_IOS)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN
+#endif
+
+
/*
@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.
*/
@@ -171946,7 +172010,7 @@ extern "C" {
** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices).
-** (It must fit into max(size_t)/32.)
+** (It must fit into max(size_t)/32 and max(int)/2.)
*/
#if LUAI_IS32INT
#define LUAI_MAXSTACK 1000000
@@ -171965,14 +172029,15 @@ extern "C" {
/*
@@ LUA_IDSIZE gives the maximum size for the description of the source
-@@ of a function in debug information.
+** of a function in debug information.
** CHANGE it if you want a different size.
*/
#define LUA_IDSIZE 60
/*
-@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
+@@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
+** buffer system.
*/
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
@@ -172022,14 +172087,14 @@ extern "C" {
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4"
-#define LUA_VERSION_RELEASE "4"
+#define LUA_VERSION_RELEASE "6"
#define LUA_VERSION_NUM 504
-#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 4)
+#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
-#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 Lua.org, PUC-Rio"
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -172135,6 +172200,16 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
+/*
+** Type used by the debug API to collect debug information
+*/
+typedef struct lua_Debug lua_Debug;
+
+
+/*
+** Functions to be called by the debugger in specific events
+*/
+typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
/*
@@ -172157,7 +172232,8 @@ extern const char lua_ident[];
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
-LUA_API int (lua_resetthread) (lua_State *L);
+LUA_API int (lua_closethread) (lua_State *L, lua_State *from);
+LUA_API int (lua_resetthread) (lua_State *L); /* Deprecated! */
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
@@ -172446,12 +172522,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
-typedef struct lua_Debug lua_Debug; /* activation record */
-
-
-/* Functions to be called by the debugger in specific events */
-typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
-
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
@@ -172496,7 +172566,7 @@ struct lua_Debug {
/******************************************************************************
-* Copyright (C) 1994-2022 Lua.org, PUC-Rio.
+* Copyright (C) 1994-2023 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -172874,6 +172944,7 @@ LUALIB_API void (luaL_openlibs) (lua_State *L);
#endif
#ifdef LUA_IMPL
+typedef struct CallInfo CallInfo;
/*
** $Id: llimits.h $
** Limits, basic types, and some other 'installation-dependent' definitions
@@ -172947,11 +173018,24 @@ typedef signed char ls_byte;
/*
-** conversion of pointer to unsigned integer:
-** this is for hashing only; there is no problem if the integer
-** cannot hold the whole pointer value
+** conversion of pointer to unsigned integer: this is for hashing only;
+** there is no problem if the integer cannot hold the whole pointer
+** value. (In strict ISO C this may cause undefined behavior, but no
+** actual machine seems to bother.)
*/
-#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX))
+#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
+ __STDC_VERSION__ >= 199901L
+#include
+#if defined(UINTPTR_MAX) /* even in C99 this type is optional */
+#define L_P2I uintptr_t
+#else /* no 'intptr'? */
+#define L_P2I uintmax_t /* use the largest available integer */
+#endif
+#else /* C89 option */
+#define L_P2I size_t
+#endif
+
+#define point2uint(p) ((unsigned int)((L_P2I)(p) & UINT_MAX))
@@ -173295,6 +173379,8 @@ typedef union Value {
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
+ /* not used, but may avoid warnings for uninitialized value */
+ lu_byte ub;
} Value;
@@ -173398,6 +173484,17 @@ typedef union StackValue {
/* index to stack elements */
typedef StackValue *StkId;
+
+/*
+** When reallocating the stack, change all pointers to the stack into
+** proper offsets.
+*/
+typedef union {
+ StkId p; /* actual pointer */
+ ptrdiff_t offset; /* used while the stack is being reallocated */
+} StkIdRel;
+
+
/* convert a 'StackValue' to a 'TValue' */
#define s2v(o) (&(o)->val)
@@ -173858,8 +173955,10 @@ typedef struct Proto {
*/
typedef struct UpVal {
CommonHeader;
- lu_byte tbc; /* true if it represents a to-be-closed variable */
- TValue *v; /* points to stack or to its own value */
+ union {
+ TValue *p; /* points to stack or to its own value */
+ ptrdiff_t offset; /* used while the stack is being reallocated */
+ } v;
union {
struct { /* (when open) */
struct UpVal *next; /* linked list */
@@ -174145,6 +174244,7 @@ LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag);
/*#include "lobject.h"*/
+/*#include "lstate.h"*/
/*
@@ -174231,8 +174331,8 @@ LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
int inv, int isfloat, TMS event);
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
- struct CallInfo *ci, const Proto *p);
-LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
+ CallInfo *ci, const Proto *p);
+LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci,
StkId where, int wanted);
@@ -174248,6 +174348,11 @@ LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
/*#include "lua.h"*/
+
+/* Some header files included here need this definition */
+typedef struct CallInfo CallInfo;
+
+
/*#include "lobject.h"*/
/*#include "ltm.h"*/
/*#include "lzio.h"*/
@@ -174378,7 +174483,7 @@ struct lua_longjmp; /* defined in ldo.c */
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
-#define stacksize(th) cast_int((th)->stack_last - (th)->stack)
+#define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
/* kinds of Garbage Collection */
@@ -174408,9 +174513,9 @@ typedef struct stringtable {
** - field 'transferinfo' is used only during call/returnhooks,
** before the function starts or after it ends.
*/
-typedef struct CallInfo {
- StkId func; /* function index in the stack */
- StkId top; /* top for this function */
+struct CallInfo {
+ StkIdRel func; /* function index in the stack */
+ StkIdRel top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */
union {
struct { /* only for Lua functions */
@@ -174435,7 +174540,7 @@ typedef struct CallInfo {
} u2;
short nresults; /* expected number of results from this function */
unsigned short callstatus;
-} CallInfo;
+};
/*
@@ -174530,7 +174635,7 @@ typedef struct global_State {
struct lua_State *mainthread;
TString *memerrmsg; /* message for memory-allocation errors */
TString *tmname[TM_N]; /* array with tag-method names */
- struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
+ struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
lua_WarnFunction warnf; /* warning function */
void *ud_warn; /* auxiliary data to 'warnf' */
@@ -174545,13 +174650,13 @@ struct lua_State {
lu_byte status;
lu_byte allowhook;
unsigned short nci; /* number of items in 'ci' list */
- StkId top; /* first free slot in the stack */
+ StkIdRel top; /* first free slot in the stack */
global_State *l_G;
CallInfo *ci; /* call info for current function */
- StkId stack_last; /* end of stack (last element + 1) */
- StkId stack; /* stack base */
+ StkIdRel stack_last; /* end of stack (last element + 1) */
+ StkIdRel stack; /* stack base */
UpVal *openupval; /* list of open upvalues in this stack */
- StkId tbclist; /* list of to-be-closed variables */
+ StkIdRel tbclist; /* list of to-be-closed variables */
GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
@@ -174730,7 +174835,7 @@ iABC C(8) | B(8) |k| A(8) | Op(7) |
iABx Bx(17) | A(8) | Op(7) |
iAsBx sBx (signed)(17) | A(8) | Op(7) |
iAx Ax(25) | Op(7) |
-isJ sJ(25) | Op(7) |
+isJ sJ (signed)(25) | Op(7) |
A signed argument is represented in excess K: the represented value is
the written unsigned value minus K, where K is half the maximum for the
@@ -175129,7 +175234,7 @@ LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];)
/* Active Lua function (given call info) */
-#define ci_func(ci) (clLvalue(s2v((ci)->func)))
+#define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
#define resethookcount(L) (L->hookcount = L->basehookcount)
@@ -175185,6 +175290,7 @@ LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
#define ldo_h
+/*#include "llimits.h"*/
/*#include "lobject.h"*/
/*#include "lstate.h"*/
/*#include "lzio.h"*/
@@ -175200,7 +175306,7 @@ LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
** at every check.
*/
#define luaD_checkstackaux(L,n,pre,pos) \
- if (l_unlikely(L->stack_last - L->top <= (n))) \
+ if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
{ pre; luaD_growstack(L, n, 1); pos; } \
else { condmovestack(L,pre,pos); }
@@ -175209,11 +175315,18 @@ LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
-#define savestack(L,p) ((char *)(p) - (char *)L->stack)
-#define restorestack(L,n) ((StkId)((char *)L->stack + (n)))
+#define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
+#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
/* macro to check stack size, preserving 'p' */
+#define checkstackp(L,n,p) \
+ luaD_checkstackaux(L, n, \
+ ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
+ p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
+
+
+/* macro to check stack size and GC, preserving 'p' */
#define checkstackGCp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
@@ -175235,7 +175348,8 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
int fTransfer, int nTransfer);
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
-LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1, int delta);
+LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
+ int narg1, int delta);
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
@@ -175428,24 +175542,27 @@ LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
-#define luaC_barrier(L,p,v) ( \
- (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
- luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
-
-#define luaC_barrierback(L,p,v) ( \
- (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
- luaC_barrierback_(L,p) : cast_void(0))
-
#define luaC_objbarrier(L,p,o) ( \
(isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
+#define luaC_barrier(L,p,v) ( \
+ iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
+
+#define luaC_objbarrierback(L,p,o) ( \
+ (isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
+
+#define luaC_barrierback(L,p,v) ( \
+ iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
+
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
+LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz,
+ size_t offset);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
@@ -175484,10 +175601,10 @@ LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
#define MAXUPVAL 255
-#define upisopen(up) ((up)->v != &(up)->u.value)
+#define upisopen(up) ((up)->v.p != &(up)->u.value)
-#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v))
+#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
/*
@@ -175509,7 +175626,7 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
-LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
+LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy);
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
@@ -175624,23 +175741,26 @@ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
/*#include "lstate.h"*/
-/* Increments 'L->top', checking for stack overflows */
-#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
- "stack overflow");}
+/* Increments 'L->top.p', checking for stack overflows */
+#define api_incr_top(L) {L->top.p++; \
+ api_check(L, L->top.p <= L->ci->top.p, \
+ "stack overflow");}
/*
** If a call returns too many multiple returns, the callee may not have
** stack space to accommodate all results. In this case, this macro
-** increases its stack space ('L->ci->top').
+** increases its stack space ('L->ci->top.p').
*/
#define adjustresults(L,nres) \
- { if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
+ { if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
+ L->ci->top.p = L->top.p; }
/* Ensure the stack has at least 'n' elements */
-#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
- "not enough elements in the stack")
+#define api_checknelems(L,n) \
+ api_check(L, (n) < (L->top.p - L->ci->func.p), \
+ "not enough elements in the stack")
/*
@@ -175811,7 +175931,6 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t);
#if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
-LUAI_FUNC int luaH_isdummy (const Table *t);
#endif
@@ -176203,6 +176322,11 @@ typedef enum {
luaC_barrierback(L, gcvalue(t), v); }
+/*
+** Shift right is the same as shift left with a negative 'y'
+*/
+#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
+
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
@@ -176588,25 +176712,6 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
/*#include "lstate.h"*/
-#if defined(EMERGENCYGCTESTS)
-/*
-** First allocation will fail whenever not building initial state.
-** (This fail will trigger 'tryagain' and a full GC cycle at every
-** allocation.)
-*/
-static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
- if (completestate(g) && ns > 0) /* frees never fail */
- return NULL; /* fail */
- else /* normal allocation */
- return (*g->frealloc)(g->ud, block, os, ns);
-}
-#else
-#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
-#endif
-
-
-
-
/*
** About the realloc function:
@@ -176626,6 +176731,43 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
*/
+/*
+** Macro to call the allocation function.
+*/
+#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
+
+
+/*
+** When an allocation fails, it will try again after an emergency
+** collection, except when it cannot run a collection. The GC should
+** not be called while the state is not fully built, as the collector
+** is not yet fully initialized. Also, it should not be called when
+** 'gcstopem' is true, because then the interpreter is in the middle of
+** a collection step.
+*/
+#define cantryagain(g) (completestate(g) && !g->gcstopem)
+
+
+
+
+#if defined(EMERGENCYGCTESTS)
+/*
+** First allocation will fail except when freeing a block (frees never
+** fail) and when it cannot try again; this fail will trigger 'tryagain'
+** and a full GC cycle at every allocation.
+*/
+static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
+ if (ns > 0 && cantryagain(g))
+ return NULL; /* fail */
+ else /* normal allocation */
+ return callfrealloc(g, block, os, ns);
+}
+#else
+#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns)
+#endif
+
+
+
/*
@@ -176698,7 +176840,7 @@ l_noret luaM_toobig (lua_State *L) {
void luaM_free_ (lua_State *L, void *block, size_t osize) {
global_State *g = G(L);
lua_assert((osize == 0) == (block == NULL));
- (*g->frealloc)(g->ud, block, osize, 0);
+ callfrealloc(g, block, osize, 0);
g->GCdebt -= osize;
}
@@ -176706,19 +176848,15 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
/*
** In case of allocation fail, this function will do an emergency
** collection to free some memory and then try the allocation again.
-** The GC should not be called while state is not fully built, as the
-** collector is not yet fully initialized. Also, it should not be called
-** when 'gcstopem' is true, because then the interpreter is in the
-** middle of a collection step.
*/
static void *tryagain (lua_State *L, void *block,
size_t osize, size_t nsize) {
global_State *g = G(L);
- if (completestate(g) && !g->gcstopem) {
+ if (cantryagain(g)) {
luaC_fullgc(L, 1); /* try to free some memory... */
- return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
+ return callfrealloc(g, block, osize, nsize); /* try again */
}
- else return NULL; /* cannot free any memory without a full state */
+ else return NULL; /* cannot run an emergency collection */
}
@@ -176887,10 +177025,10 @@ static TString *loadStringN (LoadState *S, Proto *p) {
}
else { /* long string */
ts = luaS_createlngstrobj(L, size); /* create string */
- setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */
+ setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
luaD_inctop(L);
loadVector(S, getstr(ts), size); /* load directly in final place */
- L->top--; /* pop string */
+ L->top.p--; /* pop string */
}
luaC_objbarrier(L, p, ts);
return ts;
@@ -177015,6 +177153,8 @@ static void loadDebug (LoadState *S, Proto *f) {
f->locvars[i].endpc = loadInt(S);
}
n = loadInt(S);
+ if (n != 0) /* does it have debug information? */
+ n = f->sizeupvalues; /* must be this many */
for (i = 0; i < n; i++)
f->upvalues[i].name = loadStringN(S, f);
}
@@ -177088,7 +177228,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
S.Z = Z;
checkHeader(&S);
cl = luaF_newLclosure(L, loadByte(&S));
- setclLvalue2s(L, L->top, cl);
+ setclLvalue2s(L, L->top.p, cl);
luaD_inctop(L);
cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
@@ -177110,6 +177250,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
/*#include "lprefix.h"*/
+#include
#include
/*#include "lua.h"*/
@@ -177155,8 +177296,11 @@ static void dumpByte (DumpState *D, int y) {
}
-/* dumpInt Buff Size */
-#define DIBS ((sizeof(size_t) * 8 / 7) + 1)
+/*
+** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6"
+** rounds up the division.)
+*/
+#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7)
static void dumpSize (DumpState *D, size_t x) {
lu_byte buff[DIBS];
@@ -177506,33 +177650,33 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
static void stack_init (lua_State *L1, lua_State *L) {
int i; CallInfo *ci;
/* initialize stack array */
- L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
- L1->tbclist = L1->stack;
+ L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
+ L1->tbclist.p = L1->stack.p;
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
- setnilvalue(s2v(L1->stack + i)); /* erase new stack */
- L1->top = L1->stack;
- L1->stack_last = L1->stack + BASIC_STACK_SIZE;
+ setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
+ L1->top.p = L1->stack.p;
+ L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
/* initialize first ci */
ci = &L1->base_ci;
ci->next = ci->previous = NULL;
ci->callstatus = CIST_C;
- ci->func = L1->top;
+ ci->func.p = L1->top.p;
ci->u.c.k = NULL;
ci->nresults = 0;
- setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */
- L1->top++;
- ci->top = L1->top + LUA_MINSTACK;
+ setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */
+ L1->top.p++;
+ ci->top.p = L1->top.p + LUA_MINSTACK;
L1->ci = ci;
}
static void freestack (lua_State *L) {
- if (L->stack == NULL)
+ if (L->stack.p == NULL)
return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L);
lua_assert(L->nci == 0);
- luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK); /* free stack */
+ luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */
}
@@ -177574,7 +177718,7 @@ static void f_luaopen (lua_State *L, void *ud) {
*/
static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g;
- L->stack = NULL;
+ L->stack.p = NULL;
L->ci = NULL;
L->nci = 0;
L->twups = L; /* thread has no upvalues */
@@ -177610,20 +177754,16 @@ static void close_state (lua_State *L) {
LUA_API lua_State *lua_newthread (lua_State *L) {
- global_State *g;
+ global_State *g = G(L);
+ GCObject *o;
lua_State *L1;
lua_lock(L);
- g = G(L);
luaC_checkGC(L);
/* create new thread */
- L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
- L1->marked = luaC_white(g);
- L1->tt = LUA_VTHREAD;
- /* link it on list 'allgc' */
- L1->next = g->allgc;
- g->allgc = obj2gco(L1);
+ o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
+ L1 = gco2th(o);
/* anchor it on L stack */
- setthvalue2s(L, L->top, L1);
+ setthvalue2s(L, L->top.p, L1);
api_incr_top(L);
preinit_thread(L1, g);
L1->hookmask = L->hookmask;
@@ -177642,7 +177782,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1);
- luaF_closeupval(L1, L1->stack); /* close all upvalues */
+ luaF_closeupval(L1, L1->stack.p); /* close all upvalues */
lua_assert(L1->openupval == NULL);
luai_userstatefree(L, L1);
freestack(L1);
@@ -177652,32 +177792,41 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
int luaE_resetthread (lua_State *L, int status) {
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
- setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */
- ci->func = L->stack;
+ setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */
+ ci->func.p = L->stack.p;
ci->callstatus = CIST_C;
if (status == LUA_YIELD)
status = LUA_OK;
L->status = LUA_OK; /* so it can run __close metamethods */
status = luaD_closeprotected(L, 1, status);
if (status != LUA_OK) /* errors? */
- luaD_seterrorobj(L, status, L->stack + 1);
+ luaD_seterrorobj(L, status, L->stack.p + 1);
else
- L->top = L->stack + 1;
- ci->top = L->top + LUA_MINSTACK;
- luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
+ L->top.p = L->stack.p + 1;
+ ci->top.p = L->top.p + LUA_MINSTACK;
+ luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0);
return status;
}
-LUA_API int lua_resetthread (lua_State *L) {
+LUA_API int lua_closethread (lua_State *L, lua_State *from) {
int status;
lua_lock(L);
+ L->nCcalls = (from) ? getCcalls(from) : 0;
status = luaE_resetthread(L, L->status);
lua_unlock(L);
return status;
}
+/*
+** Deprecated! Use 'lua_closethread' instead.
+*/
+LUA_API int lua_resetthread (lua_State *L) {
+ return lua_closethread(L, NULL);
+}
+
+
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i;
lua_State *L;
@@ -177752,7 +177901,7 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
** Generate a warning from an error message
*/
void luaE_warnerror (lua_State *L, const char *where) {
- TValue *errobj = s2v(L->top - 1); /* error object */
+ TValue *errobj = s2v(L->top.p - 1); /* error object */
const char *msg = (ttisstring(errobj))
? svalue(errobj)
: "error object is not a string";
@@ -178018,12 +178167,13 @@ void luaC_fix (lua_State *L, GCObject *o) {
/*
-** create a new collectable object (with given type and size) and link
-** it to 'allgc' list.
+** create a new collectable object (with given type, size, and offset)
+** and link it to 'allgc' list.
*/
-GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
+GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
global_State *g = G(L);
- GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));
+ char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
+ GCObject *o = cast(GCObject *, p + offset);
o->marked = luaC_white(g);
o->tt = tt;
o->next = g->allgc;
@@ -178031,6 +178181,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return o;
}
+
+GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
+ return luaC_newobjdt(L, tt, sz, 0);
+}
+
/* }====================================================== */
@@ -178067,7 +178222,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
set2gray(uv); /* open upvalues are kept gray */
else
set2black(uv); /* closed upvalues are visited here */
- markvalue(g, uv->v); /* mark its content */
+ markvalue(g, uv->v.p); /* mark its content */
break;
}
case LUA_VUSERDATA: {
@@ -178142,7 +178297,7 @@ static int remarkupvals (global_State *g) {
work++;
if (!iswhite(uv)) { /* upvalue already visited? */
lua_assert(upisopen(uv) && isgray(uv));
- markvalue(g, uv->v); /* mark its value */
+ markvalue(g, uv->v.p); /* mark its value */
}
}
}
@@ -178386,19 +178541,19 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
*/
static int traversethread (global_State *g, lua_State *th) {
UpVal *uv;
- StkId o = th->stack;
+ StkId o = th->stack.p;
if (isold(th) || g->gcstate == GCSpropagate)
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
if (o == NULL)
return 1; /* stack not completely built yet */
lua_assert(g->gcstate == GCSatomic ||
th->openupval == NULL || isintwups(th));
- for (; o < th->top; o++) /* mark live elements in the stack */
+ for (; o < th->top.p; o++) /* mark live elements in the stack */
markvalue(g, s2v(o));
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
markobject(g, uv); /* open upvalues cannot be collected */
if (g->gcstate == GCSatomic) { /* final traversal? */
- for (; o < th->stack_last + EXTRA_STACK; o++)
+ for (; o < th->stack_last.p + EXTRA_STACK; o++)
setnilvalue(s2v(o)); /* clear dead stack slice */
/* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) {
@@ -178658,7 +178813,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) {
UNUSED(ud);
- luaD_callnoyield(L, L->top - 2, 0);
+ luaD_callnoyield(L, L->top.p - 2, 0);
}
@@ -178675,16 +178830,16 @@ static void GCTM (lua_State *L) {
int oldgcstp = g->gcstp;
g->gcstp |= GCSTPGC; /* avoid GC steps */
L->allowhook = 0; /* stop debug hooks during GC metamethod */
- setobj2s(L, L->top++, tm); /* push finalizer... */
- setobj2s(L, L->top++, &v); /* ... and its argument */
+ setobj2s(L, L->top.p++, tm); /* push finalizer... */
+ setobj2s(L, L->top.p++, &v); /* ... and its argument */
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
- status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
+ status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */
g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc");
- L->top--; /* pops error object */
+ L->top.p--; /* pops error object */
}
}
}
@@ -178807,7 +178962,25 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
** =======================================================
*/
-static void setpause (global_State *g);
+
+/*
+** Set the "time" to wait before starting a new GC cycle; cycle will
+** start when memory use hits the threshold of ('estimate' * pause /
+** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
+** because Lua cannot even start with less than PAUSEADJ bytes).
+*/
+static void setpause (global_State *g) {
+ l_mem threshold, debt;
+ int pause = getgcparam(g->gcpause);
+ l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
+ lua_assert(estimate > 0);
+ threshold = (pause < MAX_LMEM / estimate) /* overflow? */
+ ? estimate * pause /* no overflow */
+ : MAX_LMEM; /* overflow; truncate to maximum */
+ debt = gettotalbytes(g) - threshold;
+ if (debt > 0) debt = 0;
+ luaE_setdebt(g, debt);
+}
/*
@@ -179051,6 +179224,15 @@ static void atomic2gen (lua_State *L, global_State *g) {
}
+/*
+** Set debt for the next minor collection, which will happen when
+** memory grows 'genminormul'%.
+*/
+static void setminordebt (global_State *g) {
+ luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
+}
+
+
/*
** Enter generational mode. Must go until the end of an atomic cycle
** to ensure that all objects are correctly marked and weak tables
@@ -179063,6 +179245,7 @@ static lu_mem entergen (lua_State *L, global_State *g) {
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
numobjs = atomic(L); /* propagates all and then do the atomic stuff */
atomic2gen(L, g);
+ setminordebt(g); /* set debt assuming next cycle will be minor */
return numobjs;
}
@@ -179108,15 +179291,6 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
}
-/*
-** Set debt for the next minor collection, which will happen when
-** memory grows 'genminormul'%.
-*/
-static void setminordebt (global_State *g) {
- luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
-}
-
-
/*
** Does a major collection after last collection was a "bad collection".
**
@@ -179188,8 +179362,8 @@ static void genstep (lua_State *L, global_State *g) {
lu_mem numobjs = fullgen(L, g); /* do a major collection */
if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
/* collected at least half of memory growth since last major
- collection; keep doing minor collections */
- setminordebt(g);
+ collection; keep doing minor collections. */
+ lua_assert(g->lastatomic == 0);
}
else { /* bad collection */
g->lastatomic = numobjs; /* signal that last collection was bad */
@@ -179215,26 +179389,6 @@ static void genstep (lua_State *L, global_State *g) {
*/
-/*
-** Set the "time" to wait before starting a new GC cycle; cycle will
-** start when memory use hits the threshold of ('estimate' * pause /
-** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
-** because Lua cannot even start with less than PAUSEADJ bytes).
-*/
-static void setpause (global_State *g) {
- l_mem threshold, debt;
- int pause = getgcparam(g->gcpause);
- l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
- lua_assert(estimate > 0);
- threshold = (pause < MAX_LMEM / estimate) /* overflow? */
- ? estimate * pause /* no overflow */
- : MAX_LMEM; /* overflow; truncate to maximum */
- debt = gettotalbytes(g) - threshold;
- if (debt > 0) debt = 0;
- luaE_setdebt(g, debt);
-}
-
-
/*
** Enter first sweep phase.
** The call to 'sweeptolive' makes the pointer point to an object
@@ -179442,12 +179596,15 @@ static void incstep (lua_State *L, global_State *g) {
}
/*
-** performs a basic GC step if collector is running
+** Performs a basic GC step if collector is running. (If collector is
+** not running, set a reasonable debt to avoid it being called at
+** every single check.)
*/
void luaC_step (lua_State *L) {
global_State *g = G(L);
- lua_assert(!g->gcemergency);
- if (gcrunning(g)) { /* running? */
+ if (!gcrunning(g)) /* not running? */
+ luaE_setdebt(g, -2000);
+ else {
if(isdecGCmodegen(g))
genstep(L, g);
else
@@ -179625,7 +179782,7 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
** ensuring there is only one copy of each unique string. The table
** here is used as a set: the string enters as the key, while its value
** is irrelevant. We use the string itself as the value only because it
-** is a TValue readly available. Later, the code generation can change
+** is a TValue readily available. Later, the code generation can change
** this value.
*/
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
@@ -179635,12 +179792,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
if (!ttisnil(o)) /* string already present? */
ts = keystrval(nodefromval(o)); /* get saved copy */
else { /* not in use yet */
- TValue *stv = s2v(L->top++); /* reserve stack space for string */
+ TValue *stv = s2v(L->top.p++); /* reserve stack space for string */
setsvalue(L, stv, ts); /* temporarily anchor the string */
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
/* table is not a metatable, so it does not need to invalidate cache */
luaC_checkGC(L);
- L->top--; /* remove string from stack */
+ L->top.p--; /* remove string from stack */
}
return ts;
}
@@ -181429,6 +181586,35 @@ static int constfolding (FuncState *fs, int op, expdesc *e1,
}
+/*
+** Convert a BinOpr to an OpCode (ORDER OPR - ORDER OP)
+*/
+l_sinline OpCode binopr2op (BinOpr opr, BinOpr baser, OpCode base) {
+ lua_assert(baser <= opr &&
+ ((baser == OPR_ADD && opr <= OPR_SHR) ||
+ (baser == OPR_LT && opr <= OPR_LE)));
+ return cast(OpCode, (cast_int(opr) - cast_int(baser)) + cast_int(base));
+}
+
+
+/*
+** Convert a UnOpr to an OpCode (ORDER OPR - ORDER OP)
+*/
+l_sinline OpCode unopr2op (UnOpr opr) {
+ return cast(OpCode, (cast_int(opr) - cast_int(OPR_MINUS)) +
+ cast_int(OP_UNM));
+}
+
+
+/*
+** Convert a BinOpr to a tag method (ORDER OPR - ORDER TM)
+*/
+l_sinline TMS binopr2TM (BinOpr opr) {
+ lua_assert(OPR_ADD <= opr && opr <= OPR_SHR);
+ return cast(TMS, (cast_int(opr) - cast_int(OPR_ADD)) + cast_int(TM_ADD));
+}
+
+
/*
** Emit code for unary expressions that "produce values"
** (everything but 'not').
@@ -181467,12 +181653,15 @@ static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
** Emit code for binary expressions that "produce values" over
** two registers.
*/
-static void codebinexpval (FuncState *fs, OpCode op,
+static void codebinexpval (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) {
- int v2 = luaK_exp2anyreg(fs, e2); /* both operands are in registers */
+ OpCode op = binopr2op(opr, OPR_ADD, OP_ADD);
+ int v2 = luaK_exp2anyreg(fs, e2); /* make sure 'e2' is in a register */
+ /* 'e1' must be already in a register or it is a constant */
+ lua_assert((VNIL <= e1->k && e1->k <= VKSTR) ||
+ e1->k == VNONRELOC || e1->k == VRELOC);
lua_assert(OP_ADD <= op && op <= OP_SHR);
- finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN,
- cast(TMS, (op - OP_ADD) + TM_ADD));
+ finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, binopr2TM(opr));
}
@@ -181488,6 +181677,18 @@ static void codebini (FuncState *fs, OpCode op,
}
+/*
+** Code binary operators with K operand.
+*/
+static void codebinK (FuncState *fs, BinOpr opr,
+ expdesc *e1, expdesc *e2, int flip, int line) {
+ TMS event = binopr2TM(opr);
+ int v2 = e2->u.info; /* K index */
+ OpCode op = binopr2op(opr, OPR_ADD, OP_ADDK);
+ finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
+}
+
+
/* Try to code a binary operator negating its second operand.
** For the metamethod, 2nd operand must keep its original value.
*/
@@ -181515,24 +181716,27 @@ static void swapexps (expdesc *e1, expdesc *e2) {
}
+/*
+** Code binary operators with no constant operand.
+*/
+static void codebinNoK (FuncState *fs, BinOpr opr,
+ expdesc *e1, expdesc *e2, int flip, int line) {
+ if (flip)
+ swapexps(e1, e2); /* back to original order */
+ codebinexpval(fs, opr, e1, e2, line); /* use standard operators */
+}
+
+
/*
** Code arithmetic operators ('+', '-', ...). If second operand is a
** constant in the proper range, use variant opcodes with K operands.
*/
static void codearith (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
- TMS event = cast(TMS, opr + TM_ADD);
- if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */
- int v2 = e2->u.info; /* K index */
- OpCode op = cast(OpCode, opr + OP_ADDK);
- finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
- }
- else { /* 'e2' is neither an immediate nor a K operand */
- OpCode op = cast(OpCode, opr + OP_ADD);
- if (flip)
- swapexps(e1, e2); /* back to original order */
- codebinexpval(fs, op, e1, e2, line); /* use standard operators */
- }
+ if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) /* K operand? */
+ codebinK(fs, opr, e1, e2, flip, line);
+ else /* 'e2' is neither an immediate nor a K operand */
+ codebinNoK(fs, opr, e1, e2, flip, line);
}
@@ -181549,35 +181753,27 @@ static void codecommutative (FuncState *fs, BinOpr op,
flip = 1;
}
if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */
- codebini(fs, cast(OpCode, OP_ADDI), e1, e2, flip, line, TM_ADD);
+ codebini(fs, OP_ADDI, e1, e2, flip, line, TM_ADD);
else
codearith(fs, op, e1, e2, flip, line);
}
/*
-** Code bitwise operations; they are all associative, so the function
+** Code bitwise operations; they are all commutative, so the function
** tries to put an integer constant as the 2nd operand (a K operand).
*/
static void codebitwise (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) {
int flip = 0;
- int v2;
- OpCode op;
- if (e1->k == VKINT && luaK_exp2RK(fs, e1)) {
+ if (e1->k == VKINT) {
swapexps(e1, e2); /* 'e2' will be the constant operand */
flip = 1;
}
- else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) { /* no constants? */
- op = cast(OpCode, opr + OP_ADD);
- codebinexpval(fs, op, e1, e2, line); /* all-register opcodes */
- return;
- }
- v2 = e2->u.info; /* index in K array */
- op = cast(OpCode, opr + OP_ADDK);
- lua_assert(ttisinteger(&fs->f->k[v2]));
- finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK,
- cast(TMS, opr + TM_ADD));
+ if (e2->k == VKINT && luaK_exp2K(fs, e2)) /* K operand? */
+ codebinK(fs, opr, e1, e2, flip, line);
+ else /* no constants */
+ codebinNoK(fs, opr, e1, e2, flip, line);
}
@@ -181585,25 +181781,27 @@ static void codebitwise (FuncState *fs, BinOpr opr,
** Emit code for order comparisons. When using an immediate operand,
** 'isfloat' tells whether the original value was a float.
*/
-static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
+static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
int r1, r2;
int im;
int isfloat = 0;
+ OpCode op;
if (isSCnumber(e2, &im, &isfloat)) {
/* use immediate operand */
r1 = luaK_exp2anyreg(fs, e1);
r2 = im;
- op = cast(OpCode, (op - OP_LT) + OP_LTI);
+ op = binopr2op(opr, OPR_LT, OP_LTI);
}
else if (isSCnumber(e1, &im, &isfloat)) {
/* transform (A < B) to (B > A) and (A <= B) to (B >= A) */
r1 = luaK_exp2anyreg(fs, e2);
r2 = im;
- op = (op == OP_LT) ? OP_GTI : OP_GEI;
+ op = binopr2op(opr, OPR_LT, OP_GTI);
}
else { /* regular case, compare two registers */
r1 = luaK_exp2anyreg(fs, e1);
r2 = luaK_exp2anyreg(fs, e2);
+ op = binopr2op(opr, OPR_LT, OP_LT);
}
freeexps(fs, e1, e2);
e1->u.info = condjump(fs, op, r1, r2, isfloat, 1);
@@ -181629,7 +181827,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
op = OP_EQI;
r2 = im; /* immediate operand */
}
- else if (luaK_exp2RK(fs, e2)) { /* 1st expression is constant? */
+ else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */
op = OP_EQK;
r2 = e2->u.info; /* constant index */
}
@@ -181646,16 +181844,16 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
/*
** Apply prefix operation 'op' to expression 'e'.
*/
-void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
+void luaK_prefix (FuncState *fs, UnOpr opr, expdesc *e, int line) {
static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
luaK_dischargevars(fs, e);
- switch (op) {
+ switch (opr) {
case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
- if (constfolding(fs, op + LUA_OPUNM, e, &ef))
+ if (constfolding(fs, opr + LUA_OPUNM, e, &ef))
break;
/* else */ /* FALLTHROUGH */
case OPR_LEN:
- codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
+ codeunexpval(fs, unopr2op(opr), e, line);
break;
case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0);
@@ -181689,7 +181887,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
case OPR_SHL: case OPR_SHR: {
if (!tonumeral(v, NULL))
luaK_exp2anyreg(fs, v);
- /* else keep numeral, which may be folded with 2nd operand */
+ /* else keep numeral, which may be folded or used as an immediate
+ operand */
break;
}
case OPR_EQ: case OPR_NE: {
@@ -181784,30 +181983,27 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
/* coded as (r1 >> -I) */;
}
else /* regular case (two registers) */
- codebinexpval(fs, OP_SHL, e1, e2, line);
+ codebinexpval(fs, opr, e1, e2, line);
break;
}
case OPR_SHR: {
if (isSCint(e2))
codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */
else /* regular case (two registers) */
- codebinexpval(fs, OP_SHR, e1, e2, line);
+ codebinexpval(fs, opr, e1, e2, line);
break;
}
case OPR_EQ: case OPR_NE: {
codeeq(fs, opr, e1, e2);
break;
}
- case OPR_LT: case OPR_LE: {
- OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
- codeorder(fs, op, e1, e2);
- break;
- }
case OPR_GT: case OPR_GE: {
/* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */
- OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
swapexps(e1, e2);
- codeorder(fs, op, e1, e2);
+ opr = cast(BinOpr, (opr - OPR_GT) + OPR_LT);
+ } /* FALLTHROUGH */
+ case OPR_LT: case OPR_LE: {
+ codeorder(fs, opr, e1, e2);
break;
}
default: lua_assert(0);
@@ -182378,6 +182574,7 @@ static void singlevar (LexState *ls, expdesc *var) {
expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k != VVOID); /* this one must exist */
+ luaK_exp2anyregup(fs, var); /* but could be a constant */
codestring(&key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */
}
@@ -182430,12 +182627,12 @@ static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
/*
** Solves the goto at index 'g' to given 'label' and removes it
-** from the list of pending goto's.
+** from the list of pending gotos.
** If it jumps into the scope of some variable, raises an error.
*/
static void solvegoto (LexState *ls, int g, Labeldesc *label) {
int i;
- Labellist *gl = &ls->dyd->gt; /* list of goto's */
+ Labellist *gl = &ls->dyd->gt; /* list of gotos */
Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */
lua_assert(eqstr(gt->name, label->name));
if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
@@ -182489,7 +182686,7 @@ static int newgotoentry (LexState *ls, TString *name, int line, int pc) {
/*
** Solves forward jumps. Check whether new label 'lb' matches any
** pending gotos in current block and solves them. Return true
-** if any of the goto's need to close upvalues.
+** if any of the gotos need to close upvalues.
*/
static int solvegotos (LexState *ls, Labeldesc *lb) {
Labellist *gl = &ls->dyd->gt;
@@ -182510,7 +182707,7 @@ static int solvegotos (LexState *ls, Labeldesc *lb) {
/*
** Create a new label with the given 'name' at the given 'line'.
** 'last' tells whether label is the last non-op statement in its
-** block. Solves all pending goto's to this new label and adds
+** block. Solves all pending gotos to this new label and adds
** a close instruction if necessary.
** Returns true iff it added a close instruction.
*/
@@ -182583,19 +182780,19 @@ static void leaveblock (FuncState *fs) {
LexState *ls = fs->ls;
int hasclose = 0;
int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
- if (bl->isloop) /* fix pending breaks? */
+ removevars(fs, bl->nactvar); /* remove block locals */
+ lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */
+ if (bl->isloop) /* has to fix pending breaks? */
hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
- if (!hasclose && bl->previous && bl->upval)
+ if (!hasclose && bl->previous && bl->upval) /* still need a 'close'? */
luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
- fs->bl = bl->previous;
- removevars(fs, bl->nactvar);
- lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = stklevel; /* free registers */
ls->dyd->label.n = bl->firstlabel; /* remove local labels */
- if (bl->previous) /* inner block? */
- movegotosout(fs, bl); /* update pending gotos to outer block */
+ fs->bl = bl->previous; /* current block now is previous one */
+ if (bl->previous) /* was it a nested block? */
+ movegotosout(fs, bl); /* update pending gotos to enclosing block */
else {
- if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */
+ if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */
undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
}
}
@@ -183853,10 +184050,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
LexState lexstate;
FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
- setclLvalue2s(L, L->top, cl); /* anchor it (to avoid being collected) */
+ setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */
- sethvalue2s(L, L->top, lexstate.h); /* anchor it */
+ sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
@@ -183870,7 +184067,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
- L->top--; /* remove scanner's table */
+ L->top.p--; /* remove scanner's table */
return cl; /* closure is on the stack, too */
}
@@ -184058,10 +184255,10 @@ static const char *upvalname (const Proto *p, int uv) {
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
- if (clLvalue(s2v(ci->func))->p->is_vararg) {
+ if (clLvalue(s2v(ci->func.p))->p->is_vararg) {
int nextra = ci->u.l.nextraargs;
if (n >= -nextra) { /* 'n' is negative */
- *pos = ci->func - nextra - (n + 1);
+ *pos = ci->func.p - nextra - (n + 1);
return "(vararg)"; /* generic name for any vararg */
}
}
@@ -184070,7 +184267,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
- StkId base = ci->func + 1;
+ StkId base = ci->func.p + 1;
const char *name = NULL;
if (isLua(ci)) {
if (n < 0) /* access to vararg values? */
@@ -184079,7 +184276,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
}
if (name == NULL) { /* no 'standard' name? */
- StkId limit = (ci == L->ci) ? L->top : ci->next->func;
+ StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
/* generic name for any valid slot */
name = isLua(ci) ? "(temporary)" : "(C temporary)";
@@ -184097,16 +184294,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name;
lua_lock(L);
if (ar == NULL) { /* information about non-active function? */
- if (!isLfunction(s2v(L->top - 1))) /* not a Lua function? */
+ if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
name = NULL;
else /* consider live variables at function start (parameters) */
- name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0);
+ name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
}
else { /* active function; get information through 'ar' */
StkId pos = NULL; /* to avoid warnings */
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
- setobjs2s(L, L->top, pos);
+ setobjs2s(L, L->top.p, pos);
api_incr_top(L);
}
}
@@ -184121,8 +184318,8 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
lua_lock(L);
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
- setobjs2s(L, pos, L->top - 1);
- L->top--; /* pop value */
+ setobjs2s(L, pos, L->top.p - 1);
+ L->top.p--; /* pop value */
}
lua_unlock(L);
return name;
@@ -184165,7 +184362,7 @@ static int nextline (const Proto *p, int currentline, int pc) {
static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) {
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
api_incr_top(L);
}
else {
@@ -184174,7 +184371,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
const Proto *p = f->l.p;
int currentline = p->linedefined;
Table *t = luaH_new(L); /* new table to store active lines */
- sethvalue2s(L, L->top, t); /* push it on stack */
+ sethvalue2s(L, L->top.p, t); /* push it on stack */
api_incr_top(L);
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
if (!p->is_vararg) /* regular function? */
@@ -184264,20 +184461,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
lua_lock(L);
if (*what == '>') {
ci = NULL;
- func = s2v(L->top - 1);
+ func = s2v(L->top.p - 1);
api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */
- L->top--; /* pop function */
+ L->top.p--; /* pop function */
}
else {
ci = ar->i_ci;
- func = s2v(ci->func);
+ func = s2v(ci->func.p);
lua_assert(ttisfunction(func));
}
cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) {
- setobj2s(L, L->top, func);
+ setobj2s(L, L->top.p, func);
api_incr_top(L);
}
if (strchr(what, 'L'))
@@ -184532,18 +184729,19 @@ static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
/*
-** Check whether pointer 'o' points to some value in the stack
-** frame of the current function. Because 'o' may not point to a
-** value in this stack, we cannot compare it with the region
-** boundaries (undefined behaviour in ISO C).
+** Check whether pointer 'o' points to some value in the stack frame of
+** the current function and, if so, returns its index. Because 'o' may
+** not point to a value in this stack, we cannot compare it with the
+** region boundaries (undefined behavior in ISO C).
*/
-static int isinstack (CallInfo *ci, const TValue *o) {
- StkId pos;
- for (pos = ci->func + 1; pos < ci->top; pos++) {
- if (o == s2v(pos))
- return 1;
+static int instack (CallInfo *ci, const TValue *o) {
+ int pos;
+ StkId base = ci->func.p + 1;
+ for (pos = 0; base + pos < ci->top.p; pos++) {
+ if (o == s2v(base + pos))
+ return pos;
}
- return 0; /* not found */
+ return -1; /* not found */
}
@@ -184557,7 +184755,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
LClosure *c = ci_func(ci);
int i;
for (i = 0; i < c->nupvalues; i++) {
- if (c->upvals[i]->v == o) {
+ if (c->upvals[i]->v.p == o) {
*name = upvalname(c->p, i);
return "upvalue";
}
@@ -184584,9 +184782,11 @@ static const char *varinfo (lua_State *L, const TValue *o) {
const char *kind = NULL;
if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
- if (!kind && isinstack(ci, o)) /* no? try a register */
- kind = getobjname(ci_func(ci)->p, currentpc(ci),
- cast_int(cast(StkId, o) - (ci->func + 1)), &name);
+ if (!kind) { /* not an upvalue? */
+ int reg = instack(ci, o); /* try a register */
+ if (reg >= 0) /* is 'o' a register? */
+ kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
+ }
}
return formatvarinfo(L, kind, name);
}
@@ -184683,10 +184883,10 @@ l_noret luaG_errormsg (lua_State *L) {
if (L->errfunc != 0) { /* is there an error handling function? */
StkId errfunc = restorestack(L, L->errfunc);
lua_assert(ttisfunction(s2v(errfunc)));
- setobjs2s(L, L->top, L->top - 1); /* move argument */
- setobjs2s(L, L->top - 1, errfunc); /* push function */
- L->top++; /* assume EXTRA_STACK */
- luaD_callnoyield(L, L->top - 2, 1); /* call it */
+ setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
+ setobjs2s(L, L->top.p - 1, errfunc); /* push function */
+ L->top.p++; /* assume EXTRA_STACK */
+ luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
}
luaD_throw(L, LUA_ERRRUN);
}
@@ -184700,8 +184900,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
va_start(argp, fmt);
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp);
- if (isLua(ci)) /* if Lua function, add source:line information */
+ if (isLua(ci)) { /* if Lua function, add source:line information */
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
+ setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
+ L->top.p--;
+ }
luaG_errormsg(L);
}
@@ -184718,7 +184921,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
if (p->lineinfo == NULL) /* no debug information? */
return 0;
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
- int delta = 0; /* line diference */
+ int delta = 0; /* line difference */
int pc = oldpc;
for (;;) {
int lineinfo = p->lineinfo[++pc];
@@ -184745,7 +184948,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
** at most causes an extra call to a line hook.)
** This function is not "Protected" when called, so it should correct
-** 'L->top' before calling anything that can run the GC.
+** 'L->top.p' before calling anything that can run the GC.
*/
int luaG_traceexec (lua_State *L, const Instruction *pc) {
CallInfo *ci = L->ci;
@@ -184768,7 +184971,7 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
return 1; /* do not call hook again (VM yielded, so it did not move) */
}
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
- L->top = ci->top; /* correct top */
+ L->top.p = ci->top.p; /* correct top */
if (counthook)
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
if (mask & LUA_MASKLINE) {
@@ -184844,8 +185047,8 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
for (i = 0; i < cl->nupvalues; i++) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
- uv->v = &uv->u.value; /* make it closed */
- setnilvalue(uv->v);
+ uv->v.p = &uv->u.value; /* make it closed */
+ setnilvalue(uv->v.p);
cl->upvals[i] = uv;
luaC_objbarrier(L, cl, uv);
}
@@ -184856,12 +185059,11 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
** Create a new upvalue at the given level, and link it to the list of
** open upvalues of 'L' after entry 'prev'.
**/
-static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) {
+static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
UpVal *next = *prev;
- uv->v = s2v(level); /* current value lives in the stack */
- uv->tbc = tbc;
+ uv->v.p = s2v(level); /* current value lives in the stack */
uv->u.open.next = next; /* link it to list of open upvalues */
uv->u.open.previous = prev;
if (next)
@@ -184890,7 +185092,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
pp = &p->u.open.next;
}
/* not found: create a new upvalue after 'pp' */
- return newupval(L, 0, level, pp);
+ return newupval(L, level, pp);
}
@@ -184900,12 +185102,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
** (This function assumes EXTRA_STACK.)
*/
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
- StkId top = L->top;
+ StkId top = L->top.p;
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
setobj2s(L, top, tm); /* will call metamethod... */
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
- L->top = top + 3; /* add function and arguments */
+ L->top.p = top + 3; /* add function and arguments */
if (yy)
luaD_call(L, top, 0);
else
@@ -184920,7 +185122,7 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
static void checkclosemth (lua_State *L, StkId level) {
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
if (ttisnil(tm)) { /* no metamethod? */
- int idx = cast_int(level - L->ci->func); /* variable index */
+ int idx = cast_int(level - L->ci->func.p); /* variable index */
const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
if (vname == NULL) vname = "?";
luaG_runerror(L, "variable '%s' got a non-closable value", vname);
@@ -184954,23 +185156,23 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
** is used.)
*/
#define MAXDELTA \
- ((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
+ ((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1)
/*
** Insert a variable in the list of to-be-closed variables.
*/
void luaF_newtbcupval (lua_State *L, StkId level) {
- lua_assert(level > L->tbclist);
+ lua_assert(level > L->tbclist.p);
if (l_isfalse(s2v(level)))
return; /* false doesn't need to be closed */
checkclosemth(L, level); /* value must have a close method */
- while (cast_uint(level - L->tbclist) > MAXDELTA) {
- L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */
- L->tbclist->tbclist.delta = 0;
+ while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
+ L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */
+ L->tbclist.p->tbclist.delta = 0;
}
- level->tbclist.delta = cast(unsigned short, level - L->tbclist);
- L->tbclist = level;
+ level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
+ L->tbclist.p = level;
}
@@ -184990,10 +185192,10 @@ void luaF_closeupval (lua_State *L, StkId level) {
StkId upl; /* stack index pointed by 'uv' */
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
TValue *slot = &uv->u.value; /* new position for value */
- lua_assert(uplevel(uv) < L->top);
+ lua_assert(uplevel(uv) < L->top.p);
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
- setobj(L, slot, uv->v); /* move value to upvalue slot */
- uv->v = slot; /* now current value lives here */
+ setobj(L, slot, uv->v.p); /* move value to upvalue slot */
+ uv->v.p = slot; /* now current value lives here */
if (!iswhite(uv)) { /* neither white nor dead? */
nw2black(uv); /* closed upvalues cannot be gray */
luaC_barrier(L, uv, slot);
@@ -185003,31 +185205,32 @@ void luaF_closeupval (lua_State *L, StkId level) {
/*
-** Remove firt element from the tbclist plus its dummy nodes.
+** Remove first element from the tbclist plus its dummy nodes.
*/
static void poptbclist (lua_State *L) {
- StkId tbc = L->tbclist;
+ StkId tbc = L->tbclist.p;
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
tbc -= tbc->tbclist.delta;
- while (tbc > L->stack && tbc->tbclist.delta == 0)
+ while (tbc > L->stack.p && tbc->tbclist.delta == 0)
tbc -= MAXDELTA; /* remove dummy nodes */
- L->tbclist = tbc;
+ L->tbclist.p = tbc;
}
/*
** Close all upvalues and to-be-closed variables up to the given stack
-** level.
+** level. Return restored 'level'.
*/
-void luaF_close (lua_State *L, StkId level, int status, int yy) {
+StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
ptrdiff_t levelrel = savestack(L, level);
luaF_closeupval(L, level); /* first, close the upvalues */
- while (L->tbclist >= level) { /* traverse tbc's down to that level */
- StkId tbc = L->tbclist; /* get variable index */
+ while (L->tbclist.p >= level) { /* traverse tbc's down to that level */
+ StkId tbc = L->tbclist.p; /* get variable index */
poptbclist(L); /* remove it from list */
prepcallclosemth(L, tbc, status, yy); /* close variable */
level = restorestack(L, levelrel);
}
+ return level;
}
@@ -185150,7 +185353,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
case LUA_OPBOR: return intop(|, v1, v2);
case LUA_OPBXOR: return intop(^, v1, v2);
case LUA_OPSHL: return luaV_shiftl(v1, v2);
- case LUA_OPSHR: return luaV_shiftl(v1, -v2);
+ case LUA_OPSHR: return luaV_shiftr(v1, v2);
case LUA_OPUNM: return intop(-, 0, v1);
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
default: lua_assert(0); return 0;
@@ -185474,29 +185677,39 @@ void luaO_tostring (lua_State *L, TValue *obj) {
** ===================================================================
*/
-/* size for buffer space used by 'luaO_pushvfstring' */
-#define BUFVFS 200
+/*
+** Size for buffer space used by 'luaO_pushvfstring'. It should be
+** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
+** so that 'luaG_addinfo' can work directly on the buffer.
+*/
+#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95)
/* buffer used by 'luaO_pushvfstring' */
typedef struct BuffFS {
lua_State *L;
- int pushed; /* number of string pieces already on the stack */
+ int pushed; /* true if there is a part of the result on the stack */
int blen; /* length of partial string in 'space' */
char space[BUFVFS]; /* holds last part of the result */
} BuffFS;
/*
-** Push given string to the stack, as part of the buffer, and
-** join the partial strings in the stack into one.
+** Push given string to the stack, as part of the result, and
+** join it to previous partial result if there is one.
+** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
+** This call cannot invoke metamethods, as both operands must be
+** strings. It can, however, raise an error if the result is too
+** long. In that case, 'luaV_concat' frees the extra slot before
+** raising the error.
*/
-static void pushstr (BuffFS *buff, const char *str, size_t l) {
+static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
lua_State *L = buff->L;
- setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
- L->top++; /* may use one extra slot */
- buff->pushed++;
- luaV_concat(L, buff->pushed); /* join partial results into one */
- buff->pushed = 1;
+ setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr));
+ L->top.p++; /* may use one slot from EXTRA_STACK */
+ if (!buff->pushed) /* no previous string on the stack? */
+ buff->pushed = 1; /* now there is one */
+ else /* join previous string with new one */
+ luaV_concat(L, 2);
}
@@ -185542,7 +185755,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
/*
-** Add a number to the buffer.
+** Add a numeral to the buffer.
*/
static void addnum2buff (BuffFS *buff, TValue *num) {
char *numbuff = getbuff(buff, MAXNUMBER2STR);
@@ -185620,7 +185833,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
clearbuff(&buff); /* empty buffer into the stack */
lua_assert(buff.pushed == 1);
- return svalue(s2v(L->top - 1));
+ return svalue(s2v(L->top.p - 1));
}
@@ -185782,12 +185995,12 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) {
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, const TValue *p3) {
- StkId func = L->top;
+ StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
setobj2s(L, func + 3, p3); /* 3rd argument */
- L->top = func + 4;
+ L->top.p = func + 4;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 0);
@@ -185799,18 +186012,18 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, StkId res) {
ptrdiff_t result = savestack(L, res);
- StkId func = L->top;
+ StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
- L->top += 3;
+ L->top.p += 3;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 1);
else
luaD_callnoyield(L, func, 1);
res = restorestack(L, result);
- setobjs2s(L, res, --L->top); /* move result to its place */
+ setobjs2s(L, res, --L->top.p); /* move result to its place */
}
@@ -185845,7 +186058,7 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
void luaT_tryconcatTM (lua_State *L) {
- StkId top = L->top;
+ StkId top = L->top.p;
if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
TM_CONCAT)))
luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
@@ -185880,15 +186093,15 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
*/
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
TMS event) {
- if (callbinTM(L, p1, p2, L->top, event)) /* try original event */
- return !l_isfalse(s2v(L->top));
+ if (callbinTM(L, p1, p2, L->top.p, event)) /* try original event */
+ return !l_isfalse(s2v(L->top.p));
#if defined(LUA_COMPAT_LT_LE)
else if (event == TM_LE) {
/* try '!(p2 < p1)' for '(p1 <= p2)' */
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
- if (callbinTM(L, p2, p1, L->top, TM_LT)) {
+ if (callbinTM(L, p2, p1, L->top.p, TM_LT)) {
L->ci->callstatus ^= CIST_LEQ; /* clear mark */
- return l_isfalse(s2v(L->top));
+ return l_isfalse(s2v(L->top.p));
}
/* else error will remove this 'ci'; no need to clear mark */
}
@@ -185918,20 +186131,20 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
const Proto *p) {
int i;
- int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */
+ int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */
int nextra = actual - nfixparams; /* number of extra arguments */
ci->u.l.nextraargs = nextra;
luaD_checkstack(L, p->maxstacksize + 1);
/* copy function to the top of the stack */
- setobjs2s(L, L->top++, ci->func);
+ setobjs2s(L, L->top.p++, ci->func.p);
/* move fixed parameters to the top of the stack */
for (i = 1; i <= nfixparams; i++) {
- setobjs2s(L, L->top++, ci->func + i);
- setnilvalue(s2v(ci->func + i)); /* erase original parameter (for GC) */
+ setobjs2s(L, L->top.p++, ci->func.p + i);
+ setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
}
- ci->func += actual + 1;
- ci->top += actual + 1;
- lua_assert(L->top <= ci->top && ci->top <= L->stack_last);
+ ci->func.p += actual + 1;
+ ci->top.p += actual + 1;
+ lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
}
@@ -185941,10 +186154,10 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
if (wanted < 0) {
wanted = nextra; /* get all extra arguments available */
checkstackGCp(L, nextra, where); /* ensure stack space */
- L->top = where + nextra; /* next instruction will need top */
+ L->top.p = where + nextra; /* next instruction will need top */
}
for (i = 0; i < wanted && i < nextra; i++)
- setobjs2s(L, where + i, ci->func - nextra + i);
+ setobjs2s(L, where + i, ci->func.p - nextra + i);
for (; i < wanted; i++) /* complete required results with nil */
setnilvalue(s2v(where + i));
}
@@ -186331,7 +186544,7 @@ static const TValue absentkey = {ABSTKEYCONSTANT};
*/
static Node *hashint (const Table *t, lua_Integer i) {
lua_Unsigned ui = l_castS2U(i);
- if (ui <= (unsigned int)INT_MAX)
+ if (ui <= cast_uint(INT_MAX))
return hashmod(t, cast_int(ui));
else
return hashmod(t, ui);
@@ -186481,9 +186694,11 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
size |= (size >> 2);
size |= (size >> 4);
size |= (size >> 8);
+#if (UINT_MAX >> 14) > 3 /* unsigned int has more than 16 bits */
size |= (size >> 16);
#if (UINT_MAX >> 30) > 3
size |= (size >> 32); /* unsigned int has more than 32 bits */
+#endif
#endif
size++;
lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
@@ -186712,7 +186927,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
luaG_runerror(L, "table overflow");
size = twoto(lsize);
t->node = luaM_newvector(L, size, Node);
- for (i = 0; i < (int)size; i++) {
+ for (i = 0; i < cast_int(size); i++) {
Node *n = gnode(t, i);
gnext(n) = 0;
setnilkey(n);
@@ -187199,8 +187414,6 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainpositionTV(t, key);
}
-int luaH_isdummy (const Table *t) { return isdummy(t); }
-
#endif
/*
** $Id: ldo.c $
@@ -187308,11 +187521,11 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
}
default: {
lua_assert(errorstatus(errcode)); /* real error */
- setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
+ setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */
break;
}
}
- L->top = oldtop + 1;
+ L->top.p = oldtop + 1;
}
@@ -187325,7 +187538,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
global_State *g = G(L);
errcode = luaE_resetthread(L, errcode); /* close all upvalues */
if (g->mainthread->errorJmp) { /* main thread has a handler? */
- setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
+ setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */
luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
}
else { /* no handler at all; abort */
@@ -187361,16 +187574,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
** Stack reallocation
** ===================================================================
*/
-static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
+
+
+/*
+** Change all pointers to the stack into offsets.
+*/
+static void relstack (lua_State *L) {
CallInfo *ci;
UpVal *up;
- L->top = (L->top - oldstack) + newstack;
- L->tbclist = (L->tbclist - oldstack) + newstack;
+ L->top.offset = savestack(L, L->top.p);
+ L->tbclist.offset = savestack(L, L->tbclist.p);
for (up = L->openupval; up != NULL; up = up->u.open.next)
- up->v = s2v((uplevel(up) - oldstack) + newstack);
+ up->v.offset = savestack(L, uplevel(up));
for (ci = L->ci; ci != NULL; ci = ci->previous) {
- ci->top = (ci->top - oldstack) + newstack;
- ci->func = (ci->func - oldstack) + newstack;
+ ci->top.offset = savestack(L, ci->top.p);
+ ci->func.offset = savestack(L, ci->func.p);
+ }
+}
+
+
+/*
+** Change back all offsets into pointers.
+*/
+static void correctstack (lua_State *L) {
+ CallInfo *ci;
+ UpVal *up;
+ L->top.p = restorestack(L, L->top.offset);
+ L->tbclist.p = restorestack(L, L->tbclist.offset);
+ for (up = L->openupval; up != NULL; up = up->u.open.next)
+ up->v.p = s2v(restorestack(L, up->v.offset));
+ for (ci = L->ci; ci != NULL; ci = ci->previous) {
+ ci->top.p = restorestack(L, ci->top.offset);
+ ci->func.p = restorestack(L, ci->func.offset);
if (isLua(ci))
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
}
@@ -187380,44 +187615,45 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/* some space for error handling */
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
-
/*
-** Reallocate the stack to a new size, correcting all pointers into
-** it. (There are pointers to a stack from its upvalues, from its list
-** of call infos, plus a few individual pointers.) The reallocation is
-** done in two steps (allocation + free) because the correction must be
-** done while both addresses (the old stack and the new one) are valid.
-** (In ISO C, any pointer use after the pointer has been deallocated is
-** undefined behavior.)
+** Reallocate the stack to a new size, correcting all pointers into it.
+** In ISO C, any pointer use after the pointer has been deallocated is
+** undefined behavior. So, before the reallocation, all pointers are
+** changed to offsets, and after the reallocation they are changed back
+** to pointers. As during the reallocation the pointers are invalid, the
+** reallocation cannot run emergency collections.
+**
** In case of allocation error, raise an error or return false according
** to 'raiseerror'.
*/
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
int oldsize = stacksize(L);
int i;
- StkId newstack = luaM_reallocvector(L, NULL, 0,
- newsize + EXTRA_STACK, StackValue);
+ StkId newstack;
+ int oldgcstop = G(L)->gcstopem;
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
+ relstack(L); /* change pointers to offsets */
+ G(L)->gcstopem = 1; /* stop emergency collection */
+ newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
+ newsize + EXTRA_STACK, StackValue);
+ G(L)->gcstopem = oldgcstop; /* restore emergency collection */
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
+ correctstack(L); /* change offsets back to pointers */
if (raiseerror)
luaM_error(L);
else return 0; /* do not raise an error */
}
- /* number of elements to be copied to the new stack */
- i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK;
- memcpy(newstack, L->stack, i * sizeof(StackValue));
- for (; i < newsize + EXTRA_STACK; i++)
+ L->stack.p = newstack;
+ correctstack(L); /* change offsets back to pointers */
+ L->stack_last.p = L->stack.p + newsize;
+ for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
setnilvalue(s2v(newstack + i)); /* erase new segment */
- correctstack(L, L->stack, newstack);
- luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
- L->stack = newstack;
- L->stack_last = L->stack + newsize;
return 1;
}
/*
-** Try to grow the stack by at least 'n' elements. when 'raiseerror'
+** Try to grow the stack by at least 'n' elements. When 'raiseerror'
** is true, raises any error; otherwise, return 0 in case of errors.
*/
int luaD_growstack (lua_State *L, int n, int raiseerror) {
@@ -187431,35 +187667,38 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
luaD_throw(L, LUA_ERRERR); /* error inside message handler */
return 0; /* if not 'raiseerror', just signal it */
}
- else {
+ else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */
int newsize = 2 * size; /* tentative new size */
- int needed = cast_int(L->top - L->stack) + n;
+ int needed = cast_int(L->top.p - L->stack.p) + n;
if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */
newsize = LUAI_MAXSTACK;
if (newsize < needed) /* but must respect what was asked for */
newsize = needed;
if (l_likely(newsize <= LUAI_MAXSTACK))
return luaD_reallocstack(L, newsize, raiseerror);
- else { /* stack overflow */
- /* add extra size to be able to handle the error message */
- luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
- if (raiseerror)
- luaG_runerror(L, "stack overflow");
- return 0;
- }
}
+ /* else stack overflow */
+ /* add extra size to be able to handle the error message */
+ luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
+ if (raiseerror)
+ luaG_runerror(L, "stack overflow");
+ return 0;
}
+/*
+** Compute how much of the stack is being used, by computing the
+** maximum top of all call frames in the stack and the current top.
+*/
static int stackinuse (lua_State *L) {
CallInfo *ci;
int res;
- StkId lim = L->top;
+ StkId lim = L->top.p;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
- if (lim < ci->top) lim = ci->top;
+ if (lim < ci->top.p) lim = ci->top.p;
}
- lua_assert(lim <= L->stack_last);
- res = cast_int(lim - L->stack) + 1; /* part of stack in use */
+ lua_assert(lim <= L->stack_last.p + EXTRA_STACK);
+ res = cast_int(lim - L->stack.p) + 1; /* part of stack in use */
if (res < LUA_MINSTACK)
res = LUA_MINSTACK; /* ensure a minimum size */
return res;
@@ -187477,17 +187716,13 @@ static int stackinuse (lua_State *L) {
*/
void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
- int nsize = inuse * 2; /* proposed new size */
- int max = inuse * 3; /* maximum "reasonable" size */
- if (max > LUAI_MAXSTACK) {
- max = LUAI_MAXSTACK; /* respect stack limit */
- if (nsize > LUAI_MAXSTACK)
- nsize = LUAI_MAXSTACK;
- }
+ int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3;
/* if thread is currently not handling a stack overflow and its
size is larger than maximum "reasonable" size, shrink it */
- if (inuse <= LUAI_MAXSTACK && stacksize(L) > max)
+ if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) {
+ int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2;
luaD_reallocstack(L, nsize, 0); /* ok if that fails */
+ }
else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */
luaE_shrinkCI(L); /* shrink CI list */
@@ -187496,7 +187731,7 @@ void luaD_shrinkstack (lua_State *L) {
void luaD_inctop (lua_State *L) {
luaD_checkstack(L, 1);
- L->top++;
+ L->top.p++;
}
/* }================================================================== */
@@ -187513,8 +187748,8 @@ void luaD_hook (lua_State *L, int event, int line,
if (hook && L->allowhook) { /* make sure there is a hook */
int mask = CIST_HOOKED;
CallInfo *ci = L->ci;
- ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */
- ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */
+ ptrdiff_t top = savestack(L, L->top.p); /* preserve original 'top' */
+ ptrdiff_t ci_top = savestack(L, ci->top.p); /* idem for 'ci->top' */
lua_Debug ar;
ar.event = event;
ar.currentline = line;
@@ -187524,11 +187759,11 @@ void luaD_hook (lua_State *L, int event, int line,
ci->u2.transferinfo.ftransfer = ftransfer;
ci->u2.transferinfo.ntransfer = ntransfer;
}
- if (isLua(ci) && L->top < ci->top)
- L->top = ci->top; /* protect entire activation register */
+ if (isLua(ci) && L->top.p < ci->top.p)
+ L->top.p = ci->top.p; /* protect entire activation register */
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
- if (ci->top < L->top + LUA_MINSTACK)
- ci->top = L->top + LUA_MINSTACK;
+ if (ci->top.p < L->top.p + LUA_MINSTACK)
+ ci->top.p = L->top.p + LUA_MINSTACK;
L->allowhook = 0; /* cannot call hooks inside a hook */
ci->callstatus |= mask;
lua_unlock(L);
@@ -187536,8 +187771,8 @@ void luaD_hook (lua_State *L, int event, int line,
lua_lock(L);
lua_assert(!L->allowhook);
L->allowhook = 1;
- ci->top = restorestack(L, ci_top);
- L->top = restorestack(L, top);
+ ci->top.p = restorestack(L, ci_top);
+ L->top.p = restorestack(L, top);
ci->callstatus &= ~mask;
}
}
@@ -187568,7 +187803,7 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
*/
static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
- StkId firstres = L->top - nres; /* index of first result */
+ StkId firstres = L->top.p - nres; /* index of first result */
int delta = 0; /* correction for vararg functions */
int ftransfer;
if (isLua(ci)) {
@@ -187576,10 +187811,10 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (p->is_vararg)
delta = ci->u.l.nextraargs + p->numparams + 1;
}
- ci->func += delta; /* if vararg, back to virtual 'func' */
- ftransfer = cast(unsigned short, firstres - ci->func);
+ ci->func.p += delta; /* if vararg, back to virtual 'func' */
+ ftransfer = cast(unsigned short, firstres - ci->func.p);
luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */
- ci->func -= delta;
+ ci->func.p -= delta;
}
if (isLua(ci = ci->previous))
L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */
@@ -187598,9 +187833,9 @@ StkId luaD_tryfuncTM (lua_State *L, StkId func) {
tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */
if (l_unlikely(ttisnil(tm)))
luaG_callerror(L, s2v(func)); /* nothing to call */
- for (p = L->top; p > func; p--) /* open space for metamethod */
+ for (p = L->top.p; p > func; p--) /* open space for metamethod */
setobjs2s(L, p, p-1);
- L->top++; /* stack space pre-allocated by the caller */
+ L->top.p++; /* stack space pre-allocated by the caller */
setobj2s(L, func, tm); /* metamethod is the new function to be called */
return func;
}
@@ -187617,28 +187852,29 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
int i;
switch (wanted) { /* handle typical cases separately */
case 0: /* no values needed */
- L->top = res;
+ L->top.p = res;
return;
case 1: /* one value needed */
if (nres == 0) /* no results? */
setnilvalue(s2v(res)); /* adjust with nil */
else /* at least one result */
- setobjs2s(L, res, L->top - nres); /* move it to proper place */
- L->top = res + 1;
+ setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
+ L->top.p = res + 1;
return;
case LUA_MULTRET:
wanted = nres; /* we want all results */
break;
default: /* two/more results and/or to-be-closed variables */
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
- ptrdiff_t savedres = savestack(L, res);
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
L->ci->u2.nres = nres;
- luaF_close(L, res, CLOSEKTOP, 1);
+ res = luaF_close(L, res, CLOSEKTOP, 1);
L->ci->callstatus &= ~CIST_CLSRET;
- if (L->hookmask) /* if needed, call hook after '__close's */
+ if (L->hookmask) { /* if needed, call hook after '__close's */
+ ptrdiff_t savedres = savestack(L, res);
rethook(L, L->ci, nres);
- res = restorestack(L, savedres); /* close and hook can move stack */
+ res = restorestack(L, savedres); /* hook can move stack */
+ }
wanted = decodeNresults(wanted);
if (wanted == LUA_MULTRET)
wanted = nres; /* we want all results */
@@ -187646,14 +187882,14 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
break;
}
/* generic case */
- firstresult = L->top - nres; /* index of first result */
+ firstresult = L->top.p - nres; /* index of first result */
if (nres > wanted) /* extra results? */
nres = wanted; /* don't need them */
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstresult + i);
for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(s2v(res + i));
- L->top = res + wanted; /* top points after the last result */
+ L->top.p = res + wanted; /* top points after the last result */
}
@@ -187668,7 +187904,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
rethook(L, ci, nres);
/* move results to proper place */
- moveresults(L, ci->func, nres, wanted);
+ moveresults(L, ci->func.p, nres, wanted);
/* function cannot be in any of these cases when returning */
lua_assert(!(ci->callstatus &
(CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
@@ -187683,10 +187919,10 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
int mask, StkId top) {
CallInfo *ci = L->ci = next_ci(L); /* new frame */
- ci->func = func;
+ ci->func.p = func;
ci->nresults = nret;
ci->callstatus = mask;
- ci->top = top;
+ ci->top.p = top;
return ci;
}
@@ -187700,10 +187936,10 @@ l_sinline int precallC (lua_State *L, StkId func, int nresults,
CallInfo *ci;
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
- L->top + LUA_MINSTACK);
- lua_assert(ci->top <= L->stack_last);
+ L->top.p + LUA_MINSTACK);
+ lua_assert(ci->top.p <= L->stack_last.p);
if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
- int narg = cast_int(L->top - func) - 1;
+ int narg = cast_int(L->top.p - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
}
lua_unlock(L);
@@ -187735,17 +187971,17 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int nfixparams = p->numparams;
int i;
checkstackGCp(L, fsize - delta, func);
- ci->func -= delta; /* restore 'func' (if vararg) */
+ ci->func.p -= delta; /* restore 'func' (if vararg) */
for (i = 0; i < narg1; i++) /* move down function and arguments */
- setobjs2s(L, ci->func + i, func + i);
- func = ci->func; /* moved-down function */
+ setobjs2s(L, ci->func.p + i, func + i);
+ func = ci->func.p; /* moved-down function */
for (; narg1 <= nfixparams; narg1++)
setnilvalue(s2v(func + narg1)); /* complete missing arguments */
- ci->top = func + 1 + fsize; /* top for new function */
- lua_assert(ci->top <= L->stack_last);
+ ci->top.p = func + 1 + fsize; /* top for new function */
+ lua_assert(ci->top.p <= L->stack_last.p);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus |= CIST_TAIL;
- L->top = func + narg1; /* set top */
+ L->top.p = func + narg1; /* set top */
return -1;
}
default: { /* not a function */
@@ -187778,15 +188014,15 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
case LUA_VLCL: { /* Lua function */
CallInfo *ci;
Proto *p = clLvalue(s2v(func))->p;
- int narg = cast_int(L->top - func) - 1; /* number of real arguments */
+ int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */
int nfixparams = p->numparams;
int fsize = p->maxstacksize; /* frame size */
checkstackGCp(L, fsize, func);
L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
ci->u.l.savedpc = p->code; /* starting point */
for (; narg < nfixparams; narg++)
- setnilvalue(s2v(L->top++)); /* complete missing arguments */
- lua_assert(ci->top <= L->stack_last);
+ setnilvalue(s2v(L->top.p++)); /* complete missing arguments */
+ lua_assert(ci->top.p <= L->stack_last.p);
return ci;
}
default: { /* not a function */
@@ -187802,12 +188038,17 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
** Call a function (C or Lua) through C. 'inc' can be 1 (increment
** number of recursive invocations in the C stack) or nyci (the same
** plus increment number of non-yieldable calls).
+** This function can be called with some use of EXTRA_STACK, so it should
+** check the stack before doing anything else. 'luaD_precall' already
+** does that.
*/
-l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) {
+l_sinline void ccall (lua_State *L, StkId func, int nResults, l_uint32 inc) {
CallInfo *ci;
L->nCcalls += inc;
- if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
+ if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
+ checkstackp(L, 0, func); /* free any use of EXTRA_STACK */
luaE_checkcstack(L);
+ }
if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */
ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */
luaV_execute(L, ci); /* call it */
@@ -187855,8 +188096,7 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
else { /* error */
StkId func = restorestack(L, ci->u2.funcidx);
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
- luaF_close(L, func, status, 1); /* can yield or raise an error */
- func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
+ func = luaF_close(L, func, status, 1); /* can yield or raise an error */
luaD_seterrorobj(L, status, func);
luaD_shrinkstack(L); /* restore stack size in case of overflow */
setcistrecst(ci, LUA_OK); /* clear original status */
@@ -187944,8 +188184,8 @@ static CallInfo *findpcall (lua_State *L) {
** coroutine error handler and should not kill the coroutine.)
*/
static int resume_error (lua_State *L, const char *msg, int narg) {
- L->top -= narg; /* remove args from the stack */
- setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
+ L->top.p -= narg; /* remove args from the stack */
+ setsvalue2s(L, L->top.p, luaS_new(L, msg)); /* push error message */
api_incr_top(L);
lua_unlock(L);
return LUA_ERRRUN;
@@ -187961,7 +188201,7 @@ static int resume_error (lua_State *L, const char *msg, int narg) {
*/
static void resume (lua_State *L, void *ud) {
int n = *(cast(int*, ud)); /* number of arguments */
- StkId firstArg = L->top - n; /* first argument */
+ StkId firstArg = L->top.p - n; /* first argument */
CallInfo *ci = L->ci;
if (L->status == LUA_OK) /* starting a coroutine? */
ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */
@@ -187969,7 +188209,7 @@ static void resume (lua_State *L, void *ud) {
lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */
if (isLua(ci)) { /* yielded inside a hook? */
- L->top = firstArg; /* discard arguments */
+ L->top.p = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */
}
else { /* 'common' yield */
@@ -188012,7 +188252,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
if (L->status == LUA_OK) { /* may be starting a coroutine */
if (L->ci != &L->base_ci) /* not in base level? */
return resume_error(L, "cannot resume non-suspended coroutine", nargs);
- else if (L->top - (L->ci->func + 1) == nargs) /* no function? */
+ else if (L->top.p - (L->ci->func.p + 1) == nargs) /* no function? */
return resume_error(L, "cannot resume dead coroutine", nargs);
}
else if (L->status != LUA_YIELD) /* ended with errors? */
@@ -188030,11 +188270,11 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
lua_assert(status == L->status); /* normal end or yield */
else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as 'dead' */
- luaD_seterrorobj(L, status, L->top); /* push error message */
- L->ci->top = L->top;
+ luaD_seterrorobj(L, status, L->top.p); /* push error message */
+ L->ci->top.p = L->top.p;
}
*nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
- : cast_int(L->top - (L->ci->func + 1));
+ : cast_int(L->top.p - (L->ci->func.p + 1));
lua_unlock(L);
return status;
}
@@ -188189,7 +188429,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
p.dyd.label.arr = NULL; p.dyd.label.size = 0;
luaZ_initbuffer(L, &p.buff);
- status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
+ status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc);
luaZ_freebuffer(L, &p.buff);
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
@@ -188809,8 +189049,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
if (tm == NULL) /* no TM? */
return 0; /* objects are different */
else {
- luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */
- return !l_isfalse(s2v(L->top));
+ luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
+ return !l_isfalse(s2v(L->top.p));
}
}
@@ -188834,17 +189074,17 @@ static void copy2buff (StkId top, int n, char *buff) {
/*
** Main operation for concatenation: concat 'total' values in the stack,
-** from 'L->top - total' up to 'L->top - 1'.
+** from 'L->top.p - total' up to 'L->top.p - 1'.
*/
void luaV_concat (lua_State *L, int total) {
if (total == 1)
return; /* "all" values already concatenated */
do {
- StkId top = L->top;
+ StkId top = L->top.p;
int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) ||
!tostring(L, s2v(top - 1)))
- luaT_tryconcatTM(L);
+ luaT_tryconcatTM(L); /* may invalidate 'top' */
else if (isemptystr(s2v(top - 1))) /* second operand is empty? */
cast_void(tostring(L, s2v(top - 2))); /* result is first operand */
else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */
@@ -188857,8 +189097,10 @@ void luaV_concat (lua_State *L, int total) {
/* collect total length and number of strings */
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
size_t l = vslen(s2v(top - n - 1));
- if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl))
+ if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) {
+ L->top.p = top - total; /* pop strings to avoid wasting stack */
luaG_runerror(L, "string length overflow");
+ }
tl += l;
}
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
@@ -188872,8 +189114,8 @@ void luaV_concat (lua_State *L, int total) {
}
setsvalue2s(L, top - n, ts); /* create result */
}
- total -= n-1; /* got 'n' strings to create 1 new */
- L->top -= n-1; /* popped 'n' strings and pushed one */
+ total -= n - 1; /* got 'n' strings to create one new */
+ L->top.p -= n - 1; /* popped 'n' strings and pushed one */
} while (total > 1); /* repeat until only 1 result left */
}
@@ -188964,12 +189206,10 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
/* number of bits in an integer */
#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT)
+
/*
** Shift left operation. (Shift right just negates 'y'.)
*/
-#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
-
-
lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
if (y < 0) { /* shift right? */
if (y <= -NBITS) return 0;
@@ -189009,26 +189249,26 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
*/
void luaV_finishOp (lua_State *L) {
CallInfo *ci = L->ci;
- StkId base = ci->func + 1;
+ StkId base = ci->func.p + 1;
Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
OpCode op = GET_OPCODE(inst);
switch (op) { /* finish its execution */
case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
- setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top);
+ setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top.p);
break;
}
case OP_UNM: case OP_BNOT: case OP_LEN:
case OP_GETTABUP: case OP_GETTABLE: case OP_GETI:
case OP_GETFIELD: case OP_SELF: {
- setobjs2s(L, base + GETARG_A(inst), --L->top);
+ setobjs2s(L, base + GETARG_A(inst), --L->top.p);
break;
}
case OP_LT: case OP_LE:
case OP_LTI: case OP_LEI:
case OP_GTI: case OP_GEI:
case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */
- int res = !l_isfalse(s2v(L->top - 1));
- L->top--;
+ int res = !l_isfalse(s2v(L->top.p - 1));
+ L->top.p--;
#if defined(LUA_COMPAT_LT_LE)
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
ci->callstatus ^= CIST_LEQ; /* clear mark */
@@ -189041,11 +189281,11 @@ void luaV_finishOp (lua_State *L) {
break;
}
case OP_CONCAT: {
- StkId top = L->top - 1; /* top when 'luaT_tryconcatTM' was called */
+ StkId top = L->top.p - 1; /* top when 'luaT_tryconcatTM' was called */
int a = GETARG_A(inst); /* first element to concatenate */
int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */
setobjs2s(L, top - 2, top); /* put TM result in proper position */
- L->top = top - 1; /* top is one after last element (at top-2) */
+ L->top.p = top - 1; /* top is one after last element (at top-2) */
luaV_concat(L, total); /* concat them (may yield again) */
break;
}
@@ -189057,7 +189297,7 @@ void luaV_finishOp (lua_State *L) {
StkId ra = base + GETARG_A(inst);
/* adjust top to signal correct number of returns, in case the
return is "up to top" ('isIT') */
- L->top = ra + ci->u2.nres;
+ L->top.p = ra + ci->u2.nres;
/* repeat instruction to close other vars. and complete the return */
ci->u.l.savedpc--;
break;
@@ -189099,6 +189339,7 @@ void luaV_finishOp (lua_State *L) {
** operation, 'fop' is the float operation.
*/
#define op_arithI(L,iop,fop) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
int imm = GETARG_sC(i); \
if (ttisinteger(v1)) { \
@@ -189127,6 +189368,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over floats and others with register operands.
*/
#define op_arithf(L,fop) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
op_arithf_aux(L, v1, v2, fop); }
@@ -189136,6 +189378,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations with K operands for floats.
*/
#define op_arithfK(L,fop) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
op_arithf_aux(L, v1, v2, fop); }
@@ -189145,6 +189388,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over integers and floats.
*/
#define op_arith_aux(L,v1,v2,iop,fop) { \
+ StkId ra = RA(i); \
if (ttisinteger(v1) && ttisinteger(v2)) { \
lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \
pc++; setivalue(s2v(ra), iop(L, i1, i2)); \
@@ -189174,6 +189418,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with constant operand.
*/
#define op_bitwiseK(L,op) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); \
lua_Integer i1; \
@@ -189187,6 +189432,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with register operands.
*/
#define op_bitwise(L,op) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
lua_Integer i1; lua_Integer i2; \
@@ -189201,18 +189447,19 @@ void luaV_finishOp (lua_State *L) {
** integers.
*/
#define op_order(L,opi,opn,other) { \
- int cond; \
- TValue *rb = vRB(i); \
- if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
- lua_Integer ia = ivalue(s2v(ra)); \
- lua_Integer ib = ivalue(rb); \
- cond = opi(ia, ib); \
- } \
- else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
- cond = opn(s2v(ra), rb); \
- else \
- Protect(cond = other(L, s2v(ra), rb)); \
- docondjump(); }
+ StkId ra = RA(i); \
+ int cond; \
+ TValue *rb = vRB(i); \
+ if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
+ lua_Integer ia = ivalue(s2v(ra)); \
+ lua_Integer ib = ivalue(rb); \
+ cond = opi(ia, ib); \
+ } \
+ else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
+ cond = opn(s2v(ra), rb); \
+ else \
+ Protect(cond = other(L, s2v(ra), rb)); \
+ docondjump(); }
/*
@@ -189220,20 +189467,21 @@ void luaV_finishOp (lua_State *L) {
** always small enough to have an exact representation as a float.)
*/
#define op_orderI(L,opi,opf,inv,tm) { \
- int cond; \
- int im = GETARG_sB(i); \
- if (ttisinteger(s2v(ra))) \
- cond = opi(ivalue(s2v(ra)), im); \
- else if (ttisfloat(s2v(ra))) { \
- lua_Number fa = fltvalue(s2v(ra)); \
- lua_Number fim = cast_num(im); \
- cond = opf(fa, fim); \
- } \
- else { \
- int isf = GETARG_C(i); \
- Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
- } \
- docondjump(); }
+ StkId ra = RA(i); \
+ int cond; \
+ int im = GETARG_sB(i); \
+ if (ttisinteger(s2v(ra))) \
+ cond = opi(ivalue(s2v(ra)), im); \
+ else if (ttisfloat(s2v(ra))) { \
+ lua_Number fa = fltvalue(s2v(ra)); \
+ lua_Number fim = cast_num(im); \
+ cond = opf(fa, fim); \
+ } \
+ else { \
+ int isf = GETARG_C(i); \
+ Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
+ } \
+ docondjump(); }
/* }================================================================== */
@@ -189262,7 +189510,7 @@ void luaV_finishOp (lua_State *L) {
#define updatetrap(ci) (trap = ci->u.l.trap)
-#define updatebase(ci) (base = ci->func + 1)
+#define updatebase(ci) (base = ci->func.p + 1)
#define updatestack(ci) \
@@ -189297,7 +189545,7 @@ void luaV_finishOp (lua_State *L) {
** Whenever code can raise errors, the global 'pc' and the global
** 'top' must be correct to report occasional errors.
*/
-#define savestate(L,ci) (savepc(L), L->top = ci->top)
+#define savestate(L,ci) (savepc(L), L->top.p = ci->top.p)
/*
@@ -189317,7 +189565,7 @@ void luaV_finishOp (lua_State *L) {
/* 'c' is the limit of live values in the stack */
#define checkGC(L,c) \
- { luaC_condGC(L, (savepc(L), L->top = (c)), \
+ { luaC_condGC(L, (savepc(L), L->top.p = (c)), \
updatetrap(ci)); \
luai_threadyield(L); }
@@ -189329,7 +189577,6 @@ void luaV_finishOp (lua_State *L) {
updatebase(ci); /* correct stack */ \
} \
i = *(pc++); \
- ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
}
#define vmdispatch(o) switch(o)
@@ -189461,7 +189708,7 @@ static const void *const disptab[NUM_OPCODES] = {
startfunc:
trap = L->hookmask;
returning: /* trap already set */
- cl = clLvalue(s2v(ci->func));
+ cl = clLvalue(s2v(ci->func.p));
k = cl->p->k;
pc = ci->u.l.savedpc;
if (l_unlikely(trap)) {
@@ -189473,60 +189720,68 @@ static const void *const disptab[NUM_OPCODES] = {
}
ci->u.l.trap = 1; /* assume trap is on, for now */
}
- base = ci->func + 1;
+ base = ci->func.p + 1;
/* main loop of interpreter */
for (;;) {
Instruction i; /* instruction being executed */
- StkId ra; /* instruction's A register */
vmfetch();
#if 0
/* low-level line tracing for debugging Lua */
printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
#endif
- lua_assert(base == ci->func + 1);
- lua_assert(base <= L->top && L->top < L->stack_last);
+ lua_assert(base == ci->func.p + 1);
+ lua_assert(base <= L->top.p && L->top.p <= L->stack_last.p);
/* invalidate top for instructions not expecting it */
- lua_assert(isIT(i) || (cast_void(L->top = base), 1));
+ lua_assert(isIT(i) || (cast_void(L->top.p = base), 1));
vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) {
+ StkId ra = RA(i);
setobjs2s(L, ra, RB(i));
vmbreak;
}
vmcase(OP_LOADI) {
+ StkId ra = RA(i);
lua_Integer b = GETARG_sBx(i);
setivalue(s2v(ra), b);
vmbreak;
}
vmcase(OP_LOADF) {
+ StkId ra = RA(i);
int b = GETARG_sBx(i);
setfltvalue(s2v(ra), cast_num(b));
vmbreak;
}
vmcase(OP_LOADK) {
+ StkId ra = RA(i);
TValue *rb = k + GETARG_Bx(i);
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADKX) {
+ StkId ra = RA(i);
TValue *rb;
rb = k + GETARG_Ax(*pc); pc++;
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADFALSE) {
+ StkId ra = RA(i);
setbfvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LFALSESKIP) {
+ StkId ra = RA(i);
setbfvalue(s2v(ra));
pc++; /* skip next instruction */
vmbreak;
}
vmcase(OP_LOADTRUE) {
+ StkId ra = RA(i);
setbtvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LOADNIL) {
+ StkId ra = RA(i);
int b = GETARG_B(i);
do {
setnilvalue(s2v(ra++));
@@ -189534,19 +189789,22 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_GETUPVAL) {
+ StkId ra = RA(i);
int b = GETARG_B(i);
- setobj2s(L, ra, cl->upvals[b]->v);
+ setobj2s(L, ra, cl->upvals[b]->v.p);
vmbreak;
}
vmcase(OP_SETUPVAL) {
+ StkId ra = RA(i);
UpVal *uv = cl->upvals[GETARG_B(i)];
- setobj(L, uv->v, s2v(ra));
+ setobj(L, uv->v.p, s2v(ra));
luaC_barrier(L, uv, s2v(ra));
vmbreak;
}
vmcase(OP_GETTABUP) {
+ StkId ra = RA(i);
const TValue *slot;
- TValue *upval = cl->upvals[GETARG_B(i)]->v;
+ TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
TValue *rc = KC(i);
TString *key = tsvalue(rc); /* key must be a string */
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
@@ -189557,6 +189815,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_GETTABLE) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = vRC(i);
@@ -189571,6 +189830,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_GETI) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
int c = GETARG_C(i);
@@ -189585,6 +189845,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_GETFIELD) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = KC(i);
@@ -189598,7 +189859,7 @@ static const void *const disptab[NUM_OPCODES] = {
}
vmcase(OP_SETTABUP) {
const TValue *slot;
- TValue *upval = cl->upvals[GETARG_A(i)]->v;
+ TValue *upval = cl->upvals[GETARG_A(i)]->v.p;
TValue *rb = KB(i);
TValue *rc = RKC(i);
TString *key = tsvalue(rb); /* key must be a string */
@@ -189610,6 +189871,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SETTABLE) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i); /* key (table is in 'ra') */
TValue *rc = RKC(i); /* value */
@@ -189624,6 +189886,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SETI) {
+ StkId ra = RA(i);
const TValue *slot;
int c = GETARG_B(i);
TValue *rc = RKC(i);
@@ -189638,6 +189901,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SETFIELD) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = KB(i);
TValue *rc = RKC(i);
@@ -189650,6 +189914,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_NEWTABLE) {
+ StkId ra = RA(i);
int b = GETARG_B(i); /* log2(hash size) + 1 */
int c = GETARG_C(i); /* array size */
Table *t;
@@ -189659,7 +189924,7 @@ static const void *const disptab[NUM_OPCODES] = {
if (TESTARG_k(i)) /* non-zero extra argument? */
c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */
pc++; /* skip extra argument */
- L->top = ra + 1; /* correct top in case of emergency GC */
+ L->top.p = ra + 1; /* correct top in case of emergency GC */
t = luaH_new(L); /* memory allocation */
sethvalue2s(L, ra, t);
if (b != 0 || c != 0)
@@ -189668,6 +189933,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SELF) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = RKC(i);
@@ -189697,6 +189963,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MODK) {
+ savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_mod, luaV_modf);
vmbreak;
}
@@ -189709,6 +189976,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_IDIVK) {
+ savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_idiv, luai_numidiv);
vmbreak;
}
@@ -189725,6 +189993,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SHRI) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
@@ -189734,6 +190003,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SHLI) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
@@ -189755,6 +190025,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MOD) {
+ savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_mod, luaV_modf);
vmbreak;
}
@@ -189767,6 +190038,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_IDIV) { /* floor division */
+ savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_idiv, luai_numidiv);
vmbreak;
}
@@ -189791,6 +190063,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MMBIN) {
+ StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
TValue *rb = vRB(i);
TMS tm = (TMS)GETARG_C(i);
@@ -189800,6 +190073,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MMBINI) {
+ StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
int imm = GETARG_sB(i);
TMS tm = (TMS)GETARG_C(i);
@@ -189809,6 +190083,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MMBINK) {
+ StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
TValue *imm = KB(i);
TMS tm = (TMS)GETARG_C(i);
@@ -189818,6 +190093,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_UNM) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Number nb;
if (ttisinteger(rb)) {
@@ -189832,6 +190108,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_BNOT) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Integer ib;
if (tointegerns(rb, &ib)) {
@@ -189842,6 +190119,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_NOT) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb))
setbtvalue(s2v(ra));
@@ -189850,21 +190128,25 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_LEN) {
+ StkId ra = RA(i);
Protect(luaV_objlen(L, ra, vRB(i)));
vmbreak;
}
vmcase(OP_CONCAT) {
+ StkId ra = RA(i);
int n = GETARG_B(i); /* number of elements to concatenate */
- L->top = ra + n; /* mark the end of concat operands */
+ L->top.p = ra + n; /* mark the end of concat operands */
ProtectNT(luaV_concat(L, n));
- checkGC(L, L->top); /* 'luaV_concat' ensures correct top */
+ checkGC(L, L->top.p); /* 'luaV_concat' ensures correct top */
vmbreak;
}
vmcase(OP_CLOSE) {
+ StkId ra = RA(i);
Protect(luaF_close(L, ra, LUA_OK, 1));
vmbreak;
}
vmcase(OP_TBC) {
+ StkId ra = RA(i);
/* create new to-be-closed upvalue */
halfProtect(luaF_newtbcupval(L, ra));
vmbreak;
@@ -189874,6 +190156,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_EQ) {
+ StkId ra = RA(i);
int cond;
TValue *rb = vRB(i);
Protect(cond = luaV_equalobj(L, s2v(ra), rb));
@@ -189889,6 +190172,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_EQK) {
+ StkId ra = RA(i);
TValue *rb = KB(i);
/* basic types do not use '__eq'; we can use raw equality */
int cond = luaV_rawequalobj(s2v(ra), rb);
@@ -189896,6 +190180,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_EQI) {
+ StkId ra = RA(i);
int cond;
int im = GETARG_sB(i);
if (ttisinteger(s2v(ra)))
@@ -189924,11 +190209,13 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_TEST) {
+ StkId ra = RA(i);
int cond = !l_isfalse(s2v(ra));
docondjump();
vmbreak;
}
vmcase(OP_TESTSET) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb) == GETARG_k(i))
pc++;
@@ -189939,11 +190226,12 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_CALL) {
+ StkId ra = RA(i);
CallInfo *newci;
int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1;
if (b != 0) /* fixed number of arguments? */
- L->top = ra + b; /* top signals number of arguments */
+ L->top.p = ra + b; /* top signals number of arguments */
/* else previous instruction set top */
savepc(L); /* in case of errors */
if ((newci = luaD_precall(L, ra, nresults)) == NULL)
@@ -189955,54 +190243,57 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_TAILCALL) {
+ StkId ra = RA(i);
int b = GETARG_B(i); /* number of arguments + 1 (function) */
int n; /* number of results when calling a C function */
int nparams1 = GETARG_C(i);
/* delta is virtual 'func' - real 'func' (vararg functions) */
int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
if (b != 0)
- L->top = ra + b;
+ L->top.p = ra + b;
else /* previous instruction set top */
- b = cast_int(L->top - ra);
+ b = cast_int(L->top.p - ra);
savepc(ci); /* several calls here can raise errors */
if (TESTARG_k(i)) {
luaF_closeupval(L, base); /* close upvalues from current call */
- lua_assert(L->tbclist < base); /* no pending tbc variables */
- lua_assert(base == ci->func + 1);
+ lua_assert(L->tbclist.p < base); /* no pending tbc variables */
+ lua_assert(base == ci->func.p + 1);
}
if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */
goto startfunc; /* execute the callee */
else { /* C function? */
- ci->func -= delta; /* restore 'func' (if vararg) */
+ ci->func.p -= delta; /* restore 'func' (if vararg) */
luaD_poscall(L, ci, n); /* finish caller */
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; /* caller returns after the tail call */
}
}
vmcase(OP_RETURN) {
+ StkId ra = RA(i);
int n = GETARG_B(i) - 1; /* number of results */
int nparams1 = GETARG_C(i);
if (n < 0) /* not fixed? */
- n = cast_int(L->top - ra); /* get what is available */
+ n = cast_int(L->top.p - ra); /* get what is available */
savepc(ci);
if (TESTARG_k(i)) { /* may there be open upvalues? */
ci->u2.nres = n; /* save number of returns */
- if (L->top < ci->top)
- L->top = ci->top;
+ if (L->top.p < ci->top.p)
+ L->top.p = ci->top.p;
luaF_close(L, base, CLOSEKTOP, 1);
updatetrap(ci);
updatestack(ci);
}
if (nparams1) /* vararg function? */
- ci->func -= ci->u.l.nextraargs + nparams1;
- L->top = ra + n; /* set call for 'luaD_poscall' */
+ ci->func.p -= ci->u.l.nextraargs + nparams1;
+ L->top.p = ra + n; /* set call for 'luaD_poscall' */
luaD_poscall(L, ci, n);
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret;
}
vmcase(OP_RETURN0) {
if (l_unlikely(L->hookmask)) {
- L->top = ra;
+ StkId ra = RA(i);
+ L->top.p = ra;
savepc(ci);
luaD_poscall(L, ci, 0); /* no hurry... */
trap = 1;
@@ -190010,15 +190301,16 @@ static const void *const disptab[NUM_OPCODES] = {
else { /* do the 'poscall' here */
int nres;
L->ci = ci->previous; /* back to caller */
- L->top = base - 1;
+ L->top.p = base - 1;
for (nres = ci->nresults; l_unlikely(nres > 0); nres--)
- setnilvalue(s2v(L->top++)); /* all results are nil */
+ setnilvalue(s2v(L->top.p++)); /* all results are nil */
}
goto ret;
}
vmcase(OP_RETURN1) {
if (l_unlikely(L->hookmask)) {
- L->top = ra + 1;
+ StkId ra = RA(i);
+ L->top.p = ra + 1;
savepc(ci);
luaD_poscall(L, ci, 1); /* no hurry... */
trap = 1;
@@ -190027,12 +190319,13 @@ static const void *const disptab[NUM_OPCODES] = {
int nres = ci->nresults;
L->ci = ci->previous; /* back to caller */
if (nres == 0)
- L->top = base - 1; /* asked for no results */
+ L->top.p = base - 1; /* asked for no results */
else {
+ StkId ra = RA(i);
setobjs2s(L, base - 1, ra); /* at least this result */
- L->top = base;
+ L->top.p = base;
for (; l_unlikely(nres > 1); nres--)
- setnilvalue(s2v(L->top++)); /* complete missing results */
+ setnilvalue(s2v(L->top.p++)); /* complete missing results */
}
}
ret: /* return from a Lua function */
@@ -190044,6 +190337,7 @@ static const void *const disptab[NUM_OPCODES] = {
}
}
vmcase(OP_FORLOOP) {
+ StkId ra = RA(i);
if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));
if (count > 0) { /* still more iterations? */
@@ -190062,12 +190356,14 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_FORPREP) {
+ StkId ra = RA(i);
savestate(L, ci); /* in case of errors */
if (forprep(L, ra))
pc += GETARG_Bx(i) + 1; /* skip the loop */
vmbreak;
}
vmcase(OP_TFORPREP) {
+ StkId ra = RA(i);
/* create to-be-closed upvalue (if needed) */
halfProtect(luaF_newtbcupval(L, ra + 3));
pc += GETARG_Bx(i);
@@ -190076,7 +190372,8 @@ static const void *const disptab[NUM_OPCODES] = {
goto l_tforcall;
}
vmcase(OP_TFORCALL) {
- l_tforcall:
+ l_tforcall: {
+ StkId ra = RA(i);
/* 'ra' has the iterator function, 'ra + 1' has the state,
'ra + 2' has the control variable, and 'ra + 3' has the
to-be-closed variable. The call will use the stack after
@@ -190084,29 +190381,31 @@ static const void *const disptab[NUM_OPCODES] = {
*/
/* push function, state, and control variable */
memcpy(ra + 4, ra, 3 * sizeof(*ra));
- L->top = ra + 4 + 3;
+ L->top.p = ra + 4 + 3;
ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */
updatestack(ci); /* stack may have changed */
i = *(pc++); /* go to next instruction */
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
goto l_tforloop;
- }
+ }}
vmcase(OP_TFORLOOP) {
- l_tforloop:
+ l_tforloop: {
+ StkId ra = RA(i);
if (!ttisnil(s2v(ra + 4))) { /* continue loop? */
setobjs2s(L, ra + 2, ra + 4); /* save control variable */
pc -= GETARG_Bx(i); /* jump back */
}
vmbreak;
- }
+ }}
vmcase(OP_SETLIST) {
+ StkId ra = RA(i);
int n = GETARG_B(i);
unsigned int last = GETARG_C(i);
Table *h = hvalue(s2v(ra));
if (n == 0)
- n = cast_int(L->top - ra) - 1; /* get up to the top */
+ n = cast_int(L->top.p - ra) - 1; /* get up to the top */
else
- L->top = ci->top; /* correct top in case of emergency GC */
+ L->top.p = ci->top.p; /* correct top in case of emergency GC */
last += n;
if (TESTARG_k(i)) {
last += GETARG_Ax(*pc) * (MAXARG_C + 1);
@@ -190123,12 +190422,14 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_CLOSURE) {
+ StkId ra = RA(i);
Proto *p = cl->p->p[GETARG_Bx(i)];
halfProtect(pushclosure(L, p, cl->upvals, base, ra));
checkGC(L, ra + 1);
vmbreak;
}
vmcase(OP_VARARG) {
+ StkId ra = RA(i);
int n = GETARG_C(i) - 1; /* required results */
Protect(luaT_getvarargs(L, ci, ra, n));
vmbreak;
@@ -190213,27 +190514,28 @@ const char lua_ident[] =
static TValue *index2value (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
- StkId o = ci->func + idx;
- api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index");
- if (o >= L->top) return &G(L)->nilvalue;
+ StkId o = ci->func.p + idx;
+ api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index");
+ if (o >= L->top.p) return &G(L)->nilvalue;
else return s2v(o);
}
else if (!ispseudo(idx)) { /* negative index */
- api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
- return s2v(L->top + idx);
+ api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
+ "invalid index");
+ return s2v(L->top.p + idx);
}
else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry;
else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
- if (ttisCclosure(s2v(ci->func))) { /* C closure? */
- CClosure *func = clCvalue(s2v(ci->func));
+ if (ttisCclosure(s2v(ci->func.p))) { /* C closure? */
+ CClosure *func = clCvalue(s2v(ci->func.p));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue;
}
else { /* light C function or Lua function (through a hook)?) */
- api_check(L, ttislcf(s2v(ci->func)), "caller not a C function");
+ api_check(L, ttislcf(s2v(ci->func.p)), "caller not a C function");
return &G(L)->nilvalue; /* no upvalues */
}
}
@@ -190247,14 +190549,15 @@ static TValue *index2value (lua_State *L, int idx) {
l_sinline StkId index2stack (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
- StkId o = ci->func + idx;
- api_check(L, o < L->top, "invalid index");
+ StkId o = ci->func.p + idx;
+ api_check(L, o < L->top.p, "invalid index");
return o;
}
else { /* non-positive index */
- api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
+ api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
+ "invalid index");
api_check(L, !ispseudo(idx), "invalid index");
- return L->top + idx;
+ return L->top.p + idx;
}
}
@@ -190265,17 +190568,12 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
lua_lock(L);
ci = L->ci;
api_check(L, n >= 0, "negative 'n'");
- if (L->stack_last - L->top > n) /* stack large enough? */
+ if (L->stack_last.p - L->top.p > n) /* stack large enough? */
res = 1; /* yes; check is OK */
- else { /* no; need to grow stack */
- int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;
- if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */
- res = 0; /* no */
- else /* try to grow stack */
- res = luaD_growstack(L, n, 0);
- }
- if (res && ci->top < L->top + n)
- ci->top = L->top + n; /* adjust frame top */
+ else /* need to grow stack */
+ res = luaD_growstack(L, n, 0);
+ if (res && ci->top.p < L->top.p + n)
+ ci->top.p = L->top.p + n; /* adjust frame top */
lua_unlock(L);
return res;
}
@@ -190287,11 +190585,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
lua_lock(to);
api_checknelems(from, n);
api_check(from, G(from) == G(to), "moving among independent states");
- api_check(from, to->ci->top - to->top >= n, "stack overflow");
- from->top -= n;
+ api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow");
+ from->top.p -= n;
for (i = 0; i < n; i++) {
- setobjs2s(to, to->top, from->top + i);
- to->top++; /* stack already checked by previous 'api_check' */
+ setobjs2s(to, to->top.p, from->top.p + i);
+ to->top.p++; /* stack already checked by previous 'api_check' */
}
lua_unlock(to);
}
@@ -190325,12 +190623,12 @@ LUA_API lua_Number lua_version (lua_State *L) {
LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx))
? idx
- : cast_int(L->top - L->ci->func) + idx;
+ : cast_int(L->top.p - L->ci->func.p) + idx;
}
LUA_API int lua_gettop (lua_State *L) {
- return cast_int(L->top - (L->ci->func + 1));
+ return cast_int(L->top.p - (L->ci->func.p + 1));
}
@@ -190340,24 +190638,24 @@ LUA_API void lua_settop (lua_State *L, int idx) {
ptrdiff_t diff; /* difference for new top */
lua_lock(L);
ci = L->ci;
- func = ci->func;
+ func = ci->func.p;
if (idx >= 0) {
- api_check(L, idx <= ci->top - (func + 1), "new top too large");
- diff = ((func + 1) + idx) - L->top;
+ api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
+ diff = ((func + 1) + idx) - L->top.p;
for (; diff > 0; diff--)
- setnilvalue(s2v(L->top++)); /* clear new slots */
+ setnilvalue(s2v(L->top.p++)); /* clear new slots */
}
else {
- api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
+ api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top");
diff = idx + 1; /* will "subtract" index (as it is negative) */
}
- api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot");
- newtop = L->top + diff;
- if (diff < 0 && L->tbclist >= newtop) {
+ api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot");
+ newtop = L->top.p + diff;
+ if (diff < 0 && L->tbclist.p >= newtop) {
lua_assert(hastocloseCfunc(ci->nresults));
- luaF_close(L, newtop, CLOSEKTOP, 0);
+ newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
}
- L->top = newtop; /* correct top only after closing any upvalue */
+ L->top.p = newtop; /* correct top only after closing any upvalue */
lua_unlock(L);
}
@@ -190366,10 +190664,9 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
StkId level;
lua_lock(L);
level = index2stack(L, idx);
- api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
+ api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
"no variable to close at given level");
- luaF_close(L, level, CLOSEKTOP, 0);
- level = index2stack(L, idx); /* stack may be moved */
+ level = luaF_close(L, level, CLOSEKTOP, 0);
setnilvalue(s2v(level));
lua_unlock(L);
}
@@ -190398,7 +190695,7 @@ l_sinline void reverse (lua_State *L, StkId from, StkId to) {
LUA_API void lua_rotate (lua_State *L, int idx, int n) {
StkId p, t, m;
lua_lock(L);
- t = L->top - 1; /* end of stack segment being rotated */
+ t = L->top.p - 1; /* end of stack segment being rotated */
p = index2stack(L, idx); /* start of segment */
api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
@@ -190417,7 +190714,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
api_check(L, isvalid(L, to), "invalid index");
setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */
- luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr);
+ luaC_barrier(L, clCvalue(s2v(L->ci->func.p)), fr);
/* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */
lua_unlock(L);
@@ -190426,7 +190723,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
LUA_API void lua_pushvalue (lua_State *L, int idx) {
lua_lock(L);
- setobj2s(L, L->top, index2value(L, idx));
+ setobj2s(L, L->top.p, index2value(L, idx));
api_incr_top(L);
lua_unlock(L);
}
@@ -190495,12 +190792,12 @@ LUA_API void lua_arith (lua_State *L, int op) {
api_checknelems(L, 2); /* all other operations expect two operands */
else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1);
- setobjs2s(L, L->top, L->top - 1);
+ setobjs2s(L, L->top.p, L->top.p - 1);
api_incr_top(L);
}
/* first operand at top - 2, second at top - 1; result go to top - 2 */
- luaO_arith(L, op, s2v(L->top - 2), s2v(L->top - 1), L->top - 2);
- L->top--; /* remove second operand */
+ luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2);
+ L->top.p--; /* remove second operand */
lua_unlock(L);
}
@@ -190526,7 +190823,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
- size_t sz = luaO_str2num(s, s2v(L->top));
+ size_t sz = luaO_str2num(s, s2v(L->top.p));
if (sz != 0)
api_incr_top(L);
return sz;
@@ -190653,7 +190950,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
LUA_API void lua_pushnil (lua_State *L) {
lua_lock(L);
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
api_incr_top(L);
lua_unlock(L);
}
@@ -190661,7 +190958,7 @@ LUA_API void lua_pushnil (lua_State *L) {
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
lua_lock(L);
- setfltvalue(s2v(L->top), n);
+ setfltvalue(s2v(L->top.p), n);
api_incr_top(L);
lua_unlock(L);
}
@@ -190669,7 +190966,7 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
lua_lock(L);
- setivalue(s2v(L->top), n);
+ setivalue(s2v(L->top.p), n);
api_incr_top(L);
lua_unlock(L);
}
@@ -190684,7 +190981,7 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts;
lua_lock(L);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
- setsvalue2s(L, L->top, ts);
+ setsvalue2s(L, L->top.p, ts);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
@@ -190695,11 +190992,11 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
lua_lock(L);
if (s == NULL)
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
else {
TString *ts;
ts = luaS_new(L, s);
- setsvalue2s(L, L->top, ts);
+ setsvalue2s(L, L->top.p, ts);
s = getstr(ts); /* internal copy's address */
}
api_incr_top(L);
@@ -190736,7 +191033,7 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L);
if (n == 0) {
- setfvalue(s2v(L->top), fn);
+ setfvalue(s2v(L->top.p), fn);
api_incr_top(L);
}
else {
@@ -190745,13 +191042,13 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n);
cl->f = fn;
- L->top -= n;
+ L->top.p -= n;
while (n--) {
- setobj2n(L, &cl->upvalue[n], s2v(L->top + n));
+ setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n));
/* does not need barrier because closure is white */
lua_assert(iswhite(cl));
}
- setclCvalue(L, s2v(L->top), cl);
+ setclCvalue(L, s2v(L->top.p), cl);
api_incr_top(L);
luaC_checkGC(L);
}
@@ -190762,9 +191059,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
LUA_API void lua_pushboolean (lua_State *L, int b) {
lua_lock(L);
if (b)
- setbtvalue(s2v(L->top));
+ setbtvalue(s2v(L->top.p));
else
- setbfvalue(s2v(L->top));
+ setbfvalue(s2v(L->top.p));
api_incr_top(L);
lua_unlock(L);
}
@@ -190772,7 +191069,7 @@ LUA_API void lua_pushboolean (lua_State *L, int b) {
LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
lua_lock(L);
- setpvalue(s2v(L->top), p);
+ setpvalue(s2v(L->top.p), p);
api_incr_top(L);
lua_unlock(L);
}
@@ -190780,7 +191077,7 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
LUA_API int lua_pushthread (lua_State *L) {
lua_lock(L);
- setthvalue(L, s2v(L->top), L);
+ setthvalue(L, s2v(L->top.p), L);
api_incr_top(L);
lua_unlock(L);
return (G(L)->mainthread == L);
@@ -190797,16 +191094,16 @@ l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
- setobj2s(L, L->top, slot);
+ setobj2s(L, L->top.p, slot);
api_incr_top(L);
}
else {
- setsvalue2s(L, L->top, str);
+ setsvalue2s(L, L->top.p, str);
api_incr_top(L);
- luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
+ luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
}
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
@@ -190833,13 +191130,13 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
TValue *t;
lua_lock(L);
t = index2value(L, idx);
- if (luaV_fastget(L, t, s2v(L->top - 1), slot, luaH_get)) {
- setobj2s(L, L->top - 1, slot);
+ if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) {
+ setobj2s(L, L->top.p - 1, slot);
}
else
- luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
+ luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
@@ -190855,27 +191152,27 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) {
- setobj2s(L, L->top, slot);
+ setobj2s(L, L->top.p, slot);
}
else {
TValue aux;
setivalue(&aux, n);
- luaV_finishget(L, t, &aux, L->top, slot);
+ luaV_finishget(L, t, &aux, L->top.p, slot);
}
api_incr_top(L);
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
l_sinline int finishrawget (lua_State *L, const TValue *val) {
if (isempty(val)) /* avoid copying empty items to the stack */
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
else
- setobj2s(L, L->top, val);
+ setobj2s(L, L->top.p, val);
api_incr_top(L);
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
@@ -190892,8 +191189,8 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
- val = luaH_get(t, s2v(L->top - 1));
- L->top--; /* remove key */
+ val = luaH_get(t, s2v(L->top.p - 1));
+ L->top.p--; /* remove key */
return finishrawget(L, val);
}
@@ -190920,7 +191217,7 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t;
lua_lock(L);
t = luaH_new(L);
- sethvalue2s(L, L->top, t);
+ sethvalue2s(L, L->top.p, t);
api_incr_top(L);
if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec);
@@ -190947,7 +191244,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
break;
}
if (mt != NULL) {
- sethvalue2s(L, L->top, mt);
+ sethvalue2s(L, L->top.p, mt);
api_incr_top(L);
res = 1;
}
@@ -190963,12 +191260,12 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
o = index2value(L, idx);
api_check(L, ttisfulluserdata(o), "full userdata expected");
if (n <= 0 || n > uvalue(o)->nuvalue) {
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
t = LUA_TNONE;
}
else {
- setobj2s(L, L->top, &uvalue(o)->uv[n - 1].uv);
- t = ttype(s2v(L->top));
+ setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv);
+ t = ttype(s2v(L->top.p));
}
api_incr_top(L);
lua_unlock(L);
@@ -190988,14 +191285,14 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
TString *str = luaS_new(L, k);
api_checknelems(L, 1);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
- luaV_finishfastset(L, t, slot, s2v(L->top - 1));
- L->top--; /* pop value */
+ luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
+ L->top.p--; /* pop value */
}
else {
- setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
+ setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */
api_incr_top(L);
- luaV_finishset(L, t, s2v(L->top - 1), s2v(L->top - 2), slot);
- L->top -= 2; /* pop value and key */
+ luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot);
+ L->top.p -= 2; /* pop value and key */
}
lua_unlock(L); /* lock done by caller */
}
@@ -191015,12 +191312,12 @@ LUA_API void lua_settable (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 2);
t = index2value(L, idx);
- if (luaV_fastget(L, t, s2v(L->top - 2), slot, luaH_get)) {
- luaV_finishfastset(L, t, slot, s2v(L->top - 1));
+ if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) {
+ luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
}
else
- luaV_finishset(L, t, s2v(L->top - 2), s2v(L->top - 1), slot);
- L->top -= 2; /* pop index and value */
+ luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot);
+ L->top.p -= 2; /* pop index and value */
lua_unlock(L);
}
@@ -191038,14 +191335,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
api_checknelems(L, 1);
t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) {
- luaV_finishfastset(L, t, slot, s2v(L->top - 1));
+ luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
}
else {
TValue aux;
setivalue(&aux, n);
- luaV_finishset(L, t, &aux, s2v(L->top - 1), slot);
+ luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot);
}
- L->top--; /* pop value */
+ L->top.p--; /* pop value */
lua_unlock(L);
}
@@ -191055,16 +191352,16 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
lua_lock(L);
api_checknelems(L, n);
t = gettable(L, idx);
- luaH_set(L, t, key, s2v(L->top - 1));
+ luaH_set(L, t, key, s2v(L->top.p - 1));
invalidateTMcache(t);
- luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
- L->top -= n;
+ luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
+ L->top.p -= n;
lua_unlock(L);
}
LUA_API void lua_rawset (lua_State *L, int idx) {
- aux_rawset(L, idx, s2v(L->top - 2), 2);
+ aux_rawset(L, idx, s2v(L->top.p - 2), 2);
}
@@ -191080,9 +191377,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
- luaH_setint(L, t, n, s2v(L->top - 1));
- luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
- L->top--;
+ luaH_setint(L, t, n, s2v(L->top.p - 1));
+ luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
+ L->top.p--;
lua_unlock(L);
}
@@ -191093,11 +191390,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
lua_lock(L);
api_checknelems(L, 1);
obj = index2value(L, objindex);
- if (ttisnil(s2v(L->top - 1)))
+ if (ttisnil(s2v(L->top.p - 1)))
mt = NULL;
else {
- api_check(L, ttistable(s2v(L->top - 1)), "table expected");
- mt = hvalue(s2v(L->top - 1));
+ api_check(L, ttistable(s2v(L->top.p - 1)), "table expected");
+ mt = hvalue(s2v(L->top.p - 1));
}
switch (ttype(obj)) {
case LUA_TTABLE: {
@@ -191121,7 +191418,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
break;
}
}
- L->top--;
+ L->top.p--;
lua_unlock(L);
return 1;
}
@@ -191137,11 +191434,11 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */
else {
- setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1));
- luaC_barrierback(L, gcvalue(o), s2v(L->top - 1));
+ setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1));
+ luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1));
res = 1;
}
- L->top--;
+ L->top.p--;
lua_unlock(L);
return res;
}
@@ -191153,7 +191450,8 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
#define checkresults(L,na,nr) \
- api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
+ api_check(L, (nr) == LUA_MULTRET \
+ || (L->ci->top.p - L->top.p >= (nr) - (na)), \
"results from function overflow current stack size")
@@ -191166,7 +191464,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
api_checknelems(L, nargs+1);
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults);
- func = L->top - (nargs+1);
+ func = L->top.p - (nargs+1);
if (k != NULL && yieldable(L)) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */
@@ -191214,7 +191512,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
api_check(L, ttisfunction(s2v(o)), "error handler must be a function");
func = savestack(L, o);
}
- c.func = L->top - (nargs+1); /* function to be called */
+ c.func = L->top.p - (nargs+1); /* function to be called */
if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */
c.nresults = nresults; /* do a 'conventional' protected call */
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
@@ -191249,12 +191547,12 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname, mode);
if (status == LUA_OK) { /* no errors? */
- LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */
+ LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */
if (f->nupvalues >= 1) { /* does it have an upvalue? */
/* get global table from registry */
const TValue *gt = getGtable(L);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
- setobj(L, f->upvals[0]->v, gt);
+ setobj(L, f->upvals[0]->v.p, gt);
luaC_barrier(L, f->upvals[0], gt);
}
}
@@ -191268,7 +191566,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
TValue *o;
lua_lock(L);
api_checknelems(L, 1);
- o = s2v(L->top - 1);
+ o = s2v(L->top.p - 1);
if (isLfunction(o))
status = luaU_dump(L, getproto(o), writer, data, strip);
else
@@ -191394,7 +191692,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
LUA_API int lua_error (lua_State *L) {
TValue *errobj;
lua_lock(L);
- errobj = s2v(L->top - 1);
+ errobj = s2v(L->top.p - 1);
api_checknelems(L, 1);
/* error object is the memory error message? */
if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
@@ -191412,12 +191710,12 @@ LUA_API int lua_next (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
- more = luaH_next(L, t, L->top - 1);
+ more = luaH_next(L, t, L->top.p - 1);
if (more) {
api_incr_top(L);
}
else /* no more elements */
- L->top -= 1; /* remove key */
+ L->top.p -= 1; /* remove key */
lua_unlock(L);
return more;
}
@@ -191429,7 +191727,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
lua_lock(L);
o = index2stack(L, idx);
nresults = L->ci->nresults;
- api_check(L, L->tbclist < o, "given index below or equal a marked one");
+ api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
if (!hastocloseCfunc(nresults)) /* function not marked yet? */
L->ci->nresults = codeNresults(nresults); /* mark it */
@@ -191444,7 +191742,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
if (n > 0)
luaV_concat(L, n);
else { /* nothing to concatenate */
- setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */
+ setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */
api_incr_top(L);
}
luaC_checkGC(L);
@@ -191456,7 +191754,7 @@ LUA_API void lua_len (lua_State *L, int idx) {
TValue *t;
lua_lock(L);
t = index2value(L, idx);
- luaV_objlen(L, L->top, t);
+ luaV_objlen(L, L->top.p, t);
api_incr_top(L);
lua_unlock(L);
}
@@ -191501,7 +191799,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
lua_lock(L);
api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value");
u = luaS_newudata(L, size, nuvalue);
- setuvalue(L, s2v(L->top), u);
+ setuvalue(L, s2v(L->top.p), u);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
@@ -191527,7 +191825,7 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
Proto *p = f->p;
if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues)))
return NULL; /* 'n' not in [1, p->sizeupvalues] */
- *val = f->upvals[n-1]->v;
+ *val = f->upvals[n-1]->v.p;
if (owner) *owner = obj2gco(f->upvals[n - 1]);
name = p->upvalues[n-1].name;
return (name == NULL) ? "(no name)" : getstr(name);
@@ -191543,7 +191841,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
lua_lock(L);
name = aux_upvalue(index2value(L, funcindex), n, &val, NULL);
if (name) {
- setobj2s(L, L->top, val);
+ setobj2s(L, L->top.p, val);
api_incr_top(L);
}
lua_unlock(L);
@@ -191561,8 +191859,8 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
api_checknelems(L, 1);
name = aux_upvalue(fi, n, &val, &owner);
if (name) {
- L->top--;
- setobj(L, val, s2v(L->top));
+ L->top.p--;
+ setobj(L, val, s2v(L->top.p));
luaC_barrier(L, owner, val);
}
lua_unlock(L);
@@ -192145,13 +192443,14 @@ static void newbox (lua_State *L) {
/*
** Compute new size for buffer 'B', enough to accommodate extra 'sz'
-** bytes.
+** bytes. (The test for "not big enough" also gets the case when the
+** computation of 'newsize' overflows.)
*/
static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
- size_t newsize = B->size * 2; /* double buffer size */
+ size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */
if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
return luaL_error(B->L, "buffer too large");
- if (newsize < B->n + sz) /* double is not big enough? */
+ if (newsize < B->n + sz) /* not big enough? */
newsize = B->n + sz;
return newsize;
}
@@ -192230,7 +192529,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
** box (if existent) is not on the top of the stack. So, instead of
** calling 'luaL_addlstring', it replicates the code using -2 as the
** last argument to 'prepbuffsize', signaling that the box is (or will
-** be) bellow the string being added to the buffer. (Box creation can
+** be) below the string being added to the buffer. (Box creation can
** trigger an emergency GC, so we should not remove the string from the
** stack before we have the space guaranteed.)
*/
@@ -192358,17 +192657,18 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
}
-static int skipBOM (LoadF *lf) {
- const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
- int c;
- lf->n = 0;
- do {
- c = getc(lf->f);
- if (c == EOF || c != *(const unsigned char *)p++) return c;
- lf->buff[lf->n++] = c; /* to be read by the parser */
- } while (*p != '\0');
- lf->n = 0; /* prefix matched; discard it */
- return getc(lf->f); /* return next character */
+/*
+** Skip an optional BOM at the start of a stream. If there is an
+** incomplete BOM (the first character is correct but the rest is
+** not), returns the first character anyway to force an error
+** (as no chunk can start with 0xEF).
+*/
+static int skipBOM (FILE *f) {
+ int c = getc(f); /* read first character */
+ if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */
+ return getc(f); /* ignore BOM and return next char */
+ else /* no (valid) BOM */
+ return c; /* return first character */
}
@@ -192379,13 +192679,13 @@ static int skipBOM (LoadF *lf) {
** first "valid" character of the file (after the optional BOM and
** a first-line comment).
*/
-static int skipcomment (LoadF *lf, int *cp) {
- int c = *cp = skipBOM(lf);
+static int skipcomment (FILE *f, int *cp) {
+ int c = *cp = skipBOM(f);
if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */
- c = getc(lf->f);
+ c = getc(f);
} while (c != EOF && c != '\n');
- *cp = getc(lf->f); /* skip end-of-line, if present */
+ *cp = getc(f); /* next character after comment, if present */
return 1; /* there was a comment */
}
else return 0; /* no comment */
@@ -192407,12 +192707,16 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex);
}
- if (skipcomment(&lf, &c)) /* read initial portion */
- lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
- if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
- lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
- if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
- skipcomment(&lf, &c); /* re-read initial portion */
+ lf.n = 0;
+ if (skipcomment(lf.f, &c)) /* read initial portion */
+ lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */
+ if (c == LUA_SIGNATURE[0]) { /* binary file? */
+ lf.n = 0; /* remove possible newline */
+ if (filename) { /* "real" file? */
+ lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
+ if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
+ skipcomment(lf.f, &c); /* re-read initial portion */
+ }
}
if (c != EOF)
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
@@ -193350,7 +193654,7 @@ static int luaB_auxwrap (lua_State *L) {
if (l_unlikely(r < 0)) { /* error? */
int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
- stat = lua_resetthread(co); /* close its tbc variables */
+ stat = lua_closethread(co, L); /* close its tbc variables */
lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* move error message to the caller */
}
@@ -193446,7 +193750,7 @@ static int luaB_close (lua_State *L) {
int status = auxstatus(L, co);
switch (status) {
case COS_DEAD: case COS_YIELD: {
- status = lua_resetthread(co);
+ status = lua_closethread(co, L);
if (status == LUA_OK) {
lua_pushboolean(L, 1);
return 1;
@@ -195062,7 +195366,7 @@ static int math_type (lua_State *L) {
/* try to find an integer type with at least 64 bits */
-#if (ULONG_MAX >> 31 >> 31) >= 3
+#if ((ULONG_MAX >> 31) >> 31) >= 3
/* 'long' has at least 64 bits */
#define Rand64 unsigned long
@@ -195072,9 +195376,9 @@ static int math_type (lua_State *L) {
/* there is a 'long long' type (which must have at least 64 bits) */
#define Rand64 unsigned long long
-#elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3
+#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
-/* 'lua_Integer' has at least 64 bits */
+/* 'lua_Unsigned' has at least 64 bits */
#define Rand64 lua_Unsigned
#endif
@@ -195295,12 +195599,12 @@ static lua_Number I2d (Rand64 x) {
/* convert a 'Rand64' to a 'lua_Unsigned' */
static lua_Unsigned I2UInt (Rand64 x) {
- return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l);
+ return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
}
/* convert a 'lua_Unsigned' to a 'Rand64' */
static Rand64 Int2I (lua_Unsigned n) {
- return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n);
+ return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n);
}
#endif /* } */
@@ -196267,8 +196571,13 @@ static const luaL_Reg ll_funcs[] = {
static void createsearcherstable (lua_State *L) {
- static const lua_CFunction searchers[] =
- {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
+ static const lua_CFunction searchers[] = {
+ searcher_preload,
+ searcher_Lua,
+ searcher_C,
+ searcher_Croot,
+ NULL
+ };
int i;
/* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
@@ -196351,23 +196660,14 @@ LUAMOD_API int luaopen_package (lua_State *L) {
*/
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
-/* options for ANSI C 89 (only 1-char options) */
-#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
-
-/* options for ISO C 99 and POSIX */
-#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
- "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
-
-/* options for Windows */
-#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
- "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
-
#if defined(LUA_USE_WINDOWS)
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
-#elif defined(LUA_USE_C89)
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
+#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
+ "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
+#elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */
+#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
#else /* C99 specification */
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
+#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
+ "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
#endif
#endif /* } */
@@ -196459,12 +196759,21 @@ LUAMOD_API int luaopen_package (lua_State *L) {
/* }================================================================== */
+#if !defined(l_system)
+#if defined(LUA_USE_IOS)
+/* Despite claiming to be ISO C, iOS does not implement 'system'. */
+#define l_system(cmd) ((cmd) == NULL ? 0 : -1)
+#else
+#define l_system(cmd) system(cmd) /* default definition */
+#endif
+#endif
+
static int os_execute (lua_State *L) {
const char *cmd = luaL_optstring(L, 1, NULL);
int stat;
errno = 0;
- stat = system(cmd);
+ stat = l_system(cmd);
if (cmd != NULL)
return luaL_execresult(L, stat);
else {
@@ -196581,9 +196890,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
res = d;
}
else {
- /* unsigned avoids overflow when lua_Integer has 32 bits */
- if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta
- : (lua_Integer)INT_MIN + delta <= res))
+ if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta;
}
@@ -197321,7 +197628,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
static const char *match (MatchState *ms, const char *s, const char *p) {
if (l_unlikely(ms->matchdepth-- == 0))
luaL_error(ms->L, "pattern too complex");
- init: /* using goto's to optimize tail recursion */
+ init: /* using goto to optimize tail recursion */
if (p != ms->p_end) { /* end of pattern? */
switch (*p) {
case '(': { /* start capture */
@@ -198718,7 +199025,7 @@ static int tremove (lua_State *L) {
lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */
/* check whether 'pos' is in [1, size + 1] */
- luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1,
+ luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
"position out of bounds");
lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) {
@@ -199080,6 +199387,9 @@ LUAMOD_API int luaopen_table (lua_State *L) {
#define MAXUTF 0x7FFFFFFFu
+
+#define MSGInvalid "invalid UTF-8 code"
+
/*
** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
*/
@@ -199090,7 +199400,8 @@ typedef unsigned long utfint;
#endif
-#define iscont(p) ((*(p) & 0xC0) == 0x80)
+#define iscont(c) (((c) & 0xC0) == 0x80)
+#define iscontp(p) iscont(*(p))
/* from strlib */
@@ -199120,7 +199431,7 @@ static const char *utf8_decode (const char *s, utfint *val, int strict) {
int count = 0; /* to count number of continuation bytes */
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
unsigned int cc = (unsigned char)s[++count]; /* read next byte */
- if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
+ if (!iscont(cc)) /* not a continuation byte? */
return NULL; /* invalid byte sequence */
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
}
@@ -199195,7 +199506,7 @@ static int codepoint (lua_State *L) {
utfint code;
s = utf8_decode(s, &code, !lax);
if (s == NULL)
- return luaL_error(L, "invalid UTF-8 code");
+ return luaL_error(L, MSGInvalid);
lua_pushinteger(L, code);
n++;
}
@@ -199245,16 +199556,16 @@ static int byteoffset (lua_State *L) {
"position out of bounds");
if (n == 0) {
/* find beginning of current byte sequence */
- while (posi > 0 && iscont(s + posi)) posi--;
+ while (posi > 0 && iscontp(s + posi)) posi--;
}
else {
- if (iscont(s + posi))
+ if (iscontp(s + posi))
return luaL_error(L, "initial position is a continuation byte");
if (n < 0) {
while (n < 0 && posi > 0) { /* move back */
do { /* find beginning of previous character */
posi--;
- } while (posi > 0 && iscont(s + posi));
+ } while (posi > 0 && iscontp(s + posi));
n++;
}
}
@@ -199263,7 +199574,7 @@ static int byteoffset (lua_State *L) {
while (n > 0 && posi < (lua_Integer)len) {
do { /* find beginning of next character */
posi++;
- } while (iscont(s + posi)); /* (cannot pass final '\0') */
+ } while (iscontp(s + posi)); /* (cannot pass final '\0') */
n--;
}
}
@@ -199281,15 +199592,15 @@ static int iter_aux (lua_State *L, int strict) {
const char *s = luaL_checklstring(L, 1, &len);
lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
if (n < len) {
- while (iscont(s + n)) n++; /* skip continuation bytes */
+ while (iscontp(s + n)) n++; /* go to next character */
}
if (n >= len) /* (also handles original 'n' being negative) */
return 0; /* no more codepoints */
else {
utfint code;
const char *next = utf8_decode(s + n, &code, strict);
- if (next == NULL)
- return luaL_error(L, "invalid UTF-8 code");
+ if (next == NULL || iscontp(next))
+ return luaL_error(L, MSGInvalid);
lua_pushinteger(L, n + 1);
lua_pushinteger(L, code);
return 2;
@@ -199308,7 +199619,8 @@ static int iter_auxlax (lua_State *L) {
static int iter_codes (lua_State *L) {
int lax = lua_toboolean(L, 2);
- luaL_checkstring(L, 1);
+ const char *s = luaL_checkstring(L, 1);
+ luaL_argcheck(L, !iscontp(s), 1, MSGInvalid);
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
lua_pushvalue(L, 1);
lua_pushinteger(L, 0);
@@ -199588,10 +199900,11 @@ static void print_version (void) {
** to the script (everything after 'script') go to positive indices;
** other arguments (before the script name) go to negative indices.
** If there is no script name, assume interpreter's name as base.
+** (If there is no interpreter's name either, 'script' is -1, so
+** table sizes are zero.)
*/
static void createargtable (lua_State *L, char **argv, int argc, int script) {
int i, narg;
- if (script == argc) script = 0; /* no script name? */
narg = argc - (script + 1); /* number of positive indices */
lua_createtable(L, narg, script + 1);
for (i = 0; i < argc; i++) {
@@ -199679,14 +199992,23 @@ static int handle_script (lua_State *L, char **argv) {
/*
** Traverses all arguments from 'argv', returning a mask with those
-** needed before running any Lua code (or an error code if it finds
-** any invalid argument). 'first' returns the first not-handled argument
-** (either the script name or a bad argument in case of error).
+** needed before running any Lua code or an error code if it finds any
+** invalid argument. In case of error, 'first' is the index of the bad
+** argument. Otherwise, 'first' is -1 if there is no program name,
+** 0 if there is no script name, or the index of the script name.
*/
static int collectargs (char **argv, int *first) {
int args = 0;
int i;
- for (i = 1; argv[i] != NULL; i++) {
+ if (argv[0] != NULL) { /* is there a program name? */
+ if (argv[0][0]) /* not empty? */
+ progname = argv[0]; /* save it */
+ }
+ else { /* no program name */
+ *first = -1;
+ return 0;
+ }
+ for (i = 1; argv[i] != NULL; i++) { /* handle arguments */
*first = i;
if (argv[i][0] != '-') /* not an option? */
return args; /* stop handling options */
@@ -199727,7 +200049,7 @@ static int collectargs (char **argv, int *first) {
return has_error;
}
}
- *first = i; /* no script name */
+ *first = 0; /* no script name */
return args;
}
@@ -200020,8 +200342,8 @@ static int pmain (lua_State *L) {
char **argv = (char **)lua_touserdata(L, 2);
int script;
int args = collectargs(argv, &script);
+ int optlim = (script > 0) ? script : argc; /* first argv not an option */
luaL_checkversion(L); /* check that interpreter has correct version */
- if (argv[0] && argv[0][0]) progname = argv[0];
if (args == has_error) { /* bad arg? */
print_usage(argv[script]); /* 'script' has index of bad arg. */
return 0;
@@ -200034,19 +200356,21 @@ static int pmain (lua_State *L) {
}
luaL_openlibs(L); /* open standard libraries */
createargtable(L, argv, argc, script); /* create table 'arg' */
- lua_gc(L, LUA_GCGEN, 0, 0); /* GC in generational mode */
+ lua_gc(L, LUA_GCRESTART); /* start GC... */
+ lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */
if (!(args & has_E)) { /* no option '-E'? */
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */
}
- if (!runargs(L, argv, script)) /* execute arguments -e and -l */
+ if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */
return 0; /* something failed */
- if (script < argc && /* execute main script (if there is one) */
- handle_script(L, argv + script) != LUA_OK)
- return 0;
+ if (script > 0) { /* execute main script (if there is one) */
+ if (handle_script(L, argv + script) != LUA_OK)
+ return 0; /* interrupt in case of error */
+ }
if (args & has_i) /* -i option? */
doREPL(L); /* do read-eval-print loop */
- else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */
+ else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */
if (lua_stdin_is_tty()) { /* running in interactive mode? */
print_version();
doREPL(L); /* do read-eval-print loop */
@@ -200065,6 +200389,7 @@ int main (int argc, char **argv) {
l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE;
}
+ lua_gc(L, LUA_GCSTOP); /* stop GC while building state */
lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
lua_pushinteger(L, argc); /* 1st argument */
lua_pushlightuserdata(L, argv); /* 2nd argument */
@@ -200081,7 +200406,7 @@ int main (int argc, char **argv) {
MIT License
Copyright (c) 1994–2019 Lua.org, PUC-Rio.
- Copyright (c) 2020-2022 Eduardo Bart (https://github.com/edubart).
+ Copyright (c) 2020-2023 Eduardo Bart (https://github.com/edubart).
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -200105,7 +200430,7 @@ int main (int argc, char **argv) {
#undef cast
#undef G
//---
-#line 1 "engine/split/3rd_stb_image.h"
+#line 1 "3rd_stb_image.h"
/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk
@@ -208094,7 +208419,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/
#line 0
-#line 1 "engine/split/3rd_stb_image_write.h"
+#line 1 "3rd_stb_image_write.h"
/* stb_image_write - v1.16 - public domain - http://nothings.org/stb
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk
@@ -209826,7 +210151,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define STBTT_free(x,u) ((void)(u),FREE(x))
#define NK_ASSERT ASSERT
#define NK_DTOA(s,n) strcpy(s, va("%f", n)) // override cos built-in nk_dtoa() will freeze while parsing UINT_MAX otherwise
-#line 1 "engine/split/3rd_nuklear.h"
+#line 1 "3rd_nuklear.h"
/*
/// # Nuklear
/// ![](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)
@@ -240198,7 +240523,7 @@ nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args)
/// for his single header file packer.
*/
#line 0
-#line 1 "engine/split/3rd_nuklear_glfw_gl3.h"
+#line 1 "3rd_nuklear_glfw_gl3.h"
/*
* Nuklear - 1.32.0 - public domain
@@ -240753,7 +241078,7 @@ void nk_glfw3_shutdown(struct nk_glfw* glfw)
#endif
#line 0
static char *ui_filter = 0;
-#line 1 "engine/split/3rd_nuklear_filebrowser.h"
+#line 1 "3rd_nuklear_filebrowser.h"
// file browser for nuklear, based on https://github.com/vurtun/nuklear/blob/master/example/file_browser.c (public domain)
// - rlyeh, public domain
//
@@ -241246,7 +241571,7 @@ static struct nk_image icon_load_rect(unsigned id, unsigned w, unsigned h, unsig
//#include "3rd_assimp/postprocess.h"
//#pragma comment(lib, "3rd/3rd_assimp/x64/assimp")
#endif
-#line 1 "engine/split/3rd_json5.h"
+#line 1 "3rd_json5.h"
// JSON5 + SJSON parser module
//
// License:
@@ -241688,7 +242013,7 @@ int main() {
#endif // JSON5_C
#line 0
-#line 1 "engine/split/3rd_gjk.h"
+#line 1 "3rd_gjk.h"
// GJK distance algorithm. original code by @vurtun and @randygaul, public domain.
// [src] https://gist.github.com/vurtun/29727217c269a2fbf4c0ed9a1d11cb40
// - rlyeh, public domain.
@@ -242297,7 +242622,7 @@ gjk_result gjk_quad(float a_radius, float b_radius) {
#endif
#line 0
-#line 1 "engine/split/3rd_compress.h"
+#line 1 "3rd_compress.h"
// compress.c de/compressors into a single-file header
// - rlyeh, public domain
//
@@ -253138,7 +253463,7 @@ unsigned file_decode(FILE* in, FILE* out, FILE *logfile) { // multi decoder
#endif // COMPRESS_C
#line 0
-#line 1 "engine/split/3rd_archive.h"
+#line 1 "3rd_archive.h"
// archive.c pak/zip/tar/dir archivers
// - rlyeh, public domain
@@ -254767,7 +255092,7 @@ int main( int argc, char **argv ) {
#if is(win32)
#include // timeapi.h
#endif
-#line 1 "engine/split/3rd_thread.h"
+#line 1 "3rd_thread.h"
/*
------------------------------------------------------------------------------
Licensing information can be found at the end of the file.
@@ -256497,7 +256822,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/
#line 0
-#line 1 "engine/split/3rd_plmpeg.h"
+#line 1 "3rd_plmpeg.h"
/*
PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer
@@ -260763,7 +261088,7 @@ void plm_audio_matrix_transform(int s[32][3], int ss, float *d, int dp) {
#endif // PL_MPEG_IMPLEMENTATION
#line 0
-#line 1 "engine/split/3rd_jo_mpeg.h"
+#line 1 "3rd_jo_mpeg.h"
/* public domain Simple, Minimalistic, No Allocations MPEG writer - http://jonolick.com
*
* Latest revisions:
@@ -261030,7 +261355,7 @@ void jo_write_mpeg(FILE *fp, const unsigned char *bgrx, int width, int height, i
#endif
#line 0
//#define _RTL_RUN_ONCE _RTL_RUN_ONCE2 // __MINGW64__
-#line 1 "engine/split/3rd_https.h"
+#line 1 "3rd_https.h"
/*
------------------------------------------------------------------------------
Licensing information can be found at the end of the file.
@@ -308013,7 +308338,7 @@ int main() {
#line 0
#undef F2
#undef F3
-#line 1 "engine/split/3rd_enet.h"
+#line 1 "3rd_enet.h"
/**
* include/enet.h - a Single-Header auto-generated variant of enet.h library.
*
@@ -314154,7 +314479,7 @@ extern "C" {
#endif // ENET_INCLUDE_H
#line 0
#define tls_init tls_init2
-#line 1 "engine/split/3rd_bq_websocket.h"
+#line 1 "3rd_bq_websocket.h"
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
@@ -320517,7 +320842,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#endif // BQ_PLATFORM_IMPLEMENTATION
#line 0
-#line 1 "engine/split/3rd_simplex.h"
+#line 1 "3rd_simplex.h"
/** 1D, 2D, 3D and 4D float Perlin Simplex noise */
/** Original code, stefan gustavson (PD). */
@@ -321000,7 +321325,7 @@ float snoise4(float x, float y, float z, float w) {
#endif
#line 0
-#line 1 "engine/split/3rd_tfd.h"
+#line 1 "3rd_tfd.h"
/* If you are using a C++ compiler to compile tinyfiledialogs.c (maybe renamed with an extension ".cpp")
then comment out << extern "C" >> bellow in this header file) */
@@ -329060,7 +329385,7 @@ tinyfd_messageBox("The selected hexcolor is",
#endif // TFD_IMPLEMENTATION
#line 0
-#line 1 "engine/split/3rd_stb_sprintf.h"
+#line 1 "3rd_stb_sprintf.h"
// stb_sprintf - v1.10 - public domain snprintf() implementation
// originally by Jeff Roberts / RAD Game Tools, 2015/10/20
// http://github.com/nothings/stb
@@ -330969,7 +331294,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#line 0
#define g g2
-#line 1 "engine/split/3rd_xml.h"
+#line 1 "3rd_xml.h"
// original xml.h/xml.c files by tor andersson, public domain
#ifndef xml_h
@@ -331500,7 +331825,7 @@ struct xml *xml_parse(char *s, int preserve_white, char **errorp)
#endif
#line 0
#undef g
-#line 1 "engine/split/3rd_polychop.h"
+#line 1 "3rd_polychop.h"
/* Progressive Mesh type Polygon Reduction Algorithm
*
* 1998: Original version by Stan Melax (c) 1998
@@ -331921,7 +332246,7 @@ API void ProgressiveMesh(int vert_n, int vert_stride, const float *v, int tri_n,
else if(!strcmp(id, "held") && nargs ==1) push(ev, input_held(pop(ev))); \
else if(!strcmp(id, "up") && nargs ==1) push(ev, input_up(pop(ev))); \
else if(!strcmp(id, "idle") && nargs ==1) push(ev, input_idle(pop(ev)));
-#line 1 "engine/split/3rd_eval.h"
+#line 1 "3rd_eval.h"
/* A mathematical expression evaluator.
* It uses a recursive descent parser internally.
* Author: Werner Stoop
@@ -332431,7 +332756,7 @@ int main() {
}
#endif
#line 0
-#line 1 "engine/split/3rd_luadebugger.h"
+#line 1 "3rd_luadebugger.h"
/*
Copyright (c) 2023 Scott Lembcke and Howling Moon Software
@@ -333911,7 +334236,7 @@ int dbg_pcall(lua_State *lua, int nargs, int nresults, int msgh){
return err;
}
#line 0
-#line 1 "engine/split/3rd_base64.h"
+#line 1 "3rd_base64.h"
// base64 de/encoder. Based on code by Jon Mayo - November 13, 2003 (PUBLIC DOMAIN).
// - rlyeh, public domain
@@ -333940,7 +334265,7 @@ unsigned base64_bounds(unsigned size) {
char* base64_encode(const void *inp, unsigned inlen) { // free() after use
unsigned outlen = base64_bounds(inlen);
- char *out_ = malloc(outlen);
+ char *out_ = MALLOC(outlen);
out_[outlen] = 0;
uint_least32_t v;
@@ -333957,21 +334282,21 @@ char* base64_encode(const void *inp, unsigned inlen) { // free() after use
while (rem >= 6) {
rem -= 6;
if (io >= outlen)
- return (free(out_), 0); /* truncation is failure */
+ return (FREE(out_), NULL); /* truncation is failure */
out[io ++] = base64enc_tab[(v >> rem) & 63];
}
}
if (rem) {
v <<= (6 - rem);
if (io >= outlen)
- return (free(out_), 0); /* truncation is failure */
+ return (FREE(out_), NULL); /* truncation is failure */
out[io ++] = base64enc_tab[v & 63];
}
while(io&3) {
- if(io>=outlen) return (free(out_), 0); /* truncation is failure */
+ if(io>=outlen) return (FREE(out_), NULL); /* truncation is failure */
out[io++]='=';
}
- if(io>=outlen) return (free(out_), 0); /* no room for null terminator */
+ if(io>=outlen) return (FREE(out_), NULL); /* no room for null terminator */
out[io]=0;
return out_;
}
@@ -334053,6 +334378,4020 @@ array(char) base64_decode(const char *inp, unsigned inlen) { // array_free() aft
#endif // array_resize
#endif // BASE64_C
#line 0
+
+#if ENABLE_RPMALLOC
+#line 1 "3rd_rpmalloc.h"
+/* rpmalloc.h - Memory allocator - Public Domain - 2016 Mattias Jansson
+ *
+ * This library provides a cross-platform lock free thread caching malloc implementation in C11.
+ * The latest source code is always available at
+ *
+ * https://github.com/mjansson/rpmalloc
+ *
+ * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
+ *
+ */
+
+#pragma once
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__clang__) || defined(__GNUC__)
+# define RPMALLOC_EXPORT __attribute__((visibility("default")))
+# define RPMALLOC_ALLOCATOR
+# if (defined(__clang_major__) && (__clang_major__ < 4)) || (defined(__GNUC__) && defined(ENABLE_PRELOAD) && ENABLE_PRELOAD)
+# define RPMALLOC_ATTRIB_MALLOC
+# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
+# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size)
+# else
+# define RPMALLOC_ATTRIB_MALLOC __attribute__((__malloc__))
+# define RPMALLOC_ATTRIB_ALLOC_SIZE(size) __attribute__((alloc_size(size)))
+# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) __attribute__((alloc_size(count, size)))
+# endif
+# define RPMALLOC_CDECL
+#elif defined(_MSC_VER)
+# define RPMALLOC_EXPORT
+# define RPMALLOC_ALLOCATOR __declspec(allocator) __declspec(restrict)
+# define RPMALLOC_ATTRIB_MALLOC
+# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
+# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)
+# define RPMALLOC_CDECL __cdecl
+#else
+# define RPMALLOC_EXPORT
+# define RPMALLOC_ALLOCATOR
+# define RPMALLOC_ATTRIB_MALLOC
+# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
+# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)
+# define RPMALLOC_CDECL
+#endif
+
+//! Define RPMALLOC_CONFIGURABLE to enable configuring sizes. Will introduce
+// a very small overhead due to some size calculations not being compile time constants
+#ifndef RPMALLOC_CONFIGURABLE
+#define RPMALLOC_CONFIGURABLE 0
+#endif
+
+//! Define RPMALLOC_FIRST_CLASS_HEAPS to enable heap based API (rpmalloc_heap_* functions).
+// Will introduce a very small overhead to track fully allocated spans in heaps
+#ifndef RPMALLOC_FIRST_CLASS_HEAPS
+#define RPMALLOC_FIRST_CLASS_HEAPS 0
+#endif
+
+//! Flag to rpaligned_realloc to not preserve content in reallocation
+#define RPMALLOC_NO_PRESERVE 1
+//! Flag to rpaligned_realloc to fail and return null pointer if grow cannot be done in-place,
+// in which case the original pointer is still valid (just like a call to realloc which failes to allocate
+// a new block).
+#define RPMALLOC_GROW_OR_FAIL 2
+
+typedef struct rpmalloc_global_statistics_t {
+ //! Current amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
+ size_t mapped;
+ //! Peak amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
+ size_t mapped_peak;
+ //! Current amount of memory in global caches for small and medium sizes (<32KiB)
+ size_t cached;
+ //! Current amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
+ size_t huge_alloc;
+ //! Peak amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
+ size_t huge_alloc_peak;
+ //! Total amount of memory mapped since initialization (only if ENABLE_STATISTICS=1)
+ size_t mapped_total;
+ //! Total amount of memory unmapped since initialization (only if ENABLE_STATISTICS=1)
+ size_t unmapped_total;
+} rpmalloc_global_statistics_t;
+
+typedef struct rpmalloc_thread_statistics_t {
+ //! Current number of bytes available in thread size class caches for small and medium sizes (<32KiB)
+ size_t sizecache;
+ //! Current number of bytes available in thread span caches for small and medium sizes (<32KiB)
+ size_t spancache;
+ //! Total number of bytes transitioned from thread cache to global cache (only if ENABLE_STATISTICS=1)
+ size_t thread_to_global;
+ //! Total number of bytes transitioned from global cache to thread cache (only if ENABLE_STATISTICS=1)
+ size_t global_to_thread;
+ //! Per span count statistics (only if ENABLE_STATISTICS=1)
+ struct {
+ //! Currently used number of spans
+ size_t current;
+ //! High water mark of spans used
+ size_t peak;
+ //! Number of spans transitioned to global cache
+ size_t to_global;
+ //! Number of spans transitioned from global cache
+ size_t from_global;
+ //! Number of spans transitioned to thread cache
+ size_t to_cache;
+ //! Number of spans transitioned from thread cache
+ size_t from_cache;
+ //! Number of spans transitioned to reserved state
+ size_t to_reserved;
+ //! Number of spans transitioned from reserved state
+ size_t from_reserved;
+ //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
+ size_t map_calls;
+ } span_use[64];
+ //! Per size class statistics (only if ENABLE_STATISTICS=1)
+ struct {
+ //! Current number of allocations
+ size_t alloc_current;
+ //! Peak number of allocations
+ size_t alloc_peak;
+ //! Total number of allocations
+ size_t alloc_total;
+ //! Total number of frees
+ size_t free_total;
+ //! Number of spans transitioned to cache
+ size_t spans_to_cache;
+ //! Number of spans transitioned from cache
+ size_t spans_from_cache;
+ //! Number of spans transitioned from reserved state
+ size_t spans_from_reserved;
+ //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
+ size_t map_calls;
+ } size_use[128];
+} rpmalloc_thread_statistics_t;
+
+typedef struct rpmalloc_config_t {
+ //! Map memory pages for the given number of bytes. The returned address MUST be
+ // aligned to the rpmalloc span size, which will always be a power of two.
+ // Optionally the function can store an alignment offset in the offset variable
+ // in case it performs alignment and the returned pointer is offset from the
+ // actual start of the memory region due to this alignment. The alignment offset
+ // will be passed to the memory unmap function. The alignment offset MUST NOT be
+ // larger than 65535 (storable in an uint16_t), if it is you must use natural
+ // alignment to shift it into 16 bits. If you set a memory_map function, you
+ // must also set a memory_unmap function or else the default implementation will
+ // be used for both. This function must be thread safe, it can be called by
+ // multiple threads simultaneously.
+ void* (*memory_map)(size_t size, size_t* offset);
+ //! Unmap the memory pages starting at address and spanning the given number of bytes.
+ // If release is set to non-zero, the unmap is for an entire span range as returned by
+ // a previous call to memory_map and that the entire range should be released. The
+ // release argument holds the size of the entire span range. If release is set to 0,
+ // the unmap is a partial decommit of a subset of the mapped memory range.
+ // If you set a memory_unmap function, you must also set a memory_map function or
+ // else the default implementation will be used for both. This function must be thread
+ // safe, it can be called by multiple threads simultaneously.
+ void (*memory_unmap)(void* address, size_t size, size_t offset, size_t release);
+ //! Called when an assert fails, if asserts are enabled. Will use the standard assert()
+ // if this is not set.
+ void (*error_callback)(const char* message);
+ //! Called when a call to map memory pages fails (out of memory). If this callback is
+ // not set or returns zero the library will return a null pointer in the allocation
+ // call. If this callback returns non-zero the map call will be retried. The argument
+ // passed is the number of bytes that was requested in the map call. Only used if
+ // the default system memory map function is used (memory_map callback is not set).
+ int (*map_fail_callback)(size_t size);
+ //! Size of memory pages. The page size MUST be a power of two. All memory mapping
+ // requests to memory_map will be made with size set to a multiple of the page size.
+ // Used if RPMALLOC_CONFIGURABLE is defined to 1, otherwise system page size is used.
+ size_t page_size;
+ //! Size of a span of memory blocks. MUST be a power of two, and in [4096,262144]
+ // range (unless 0 - set to 0 to use the default span size). Used if RPMALLOC_CONFIGURABLE
+ // is defined to 1.
+ size_t span_size;
+ //! Number of spans to map at each request to map new virtual memory blocks. This can
+ // be used to minimize the system call overhead at the cost of virtual memory address
+ // space. The extra mapped pages will not be written until actually used, so physical
+ // committed memory should not be affected in the default implementation. Will be
+ // aligned to a multiple of spans that match memory page size in case of huge pages.
+ size_t span_map_count;
+ //! Enable use of large/huge pages. If this flag is set to non-zero and page size is
+ // zero, the allocator will try to enable huge pages and auto detect the configuration.
+ // If this is set to non-zero and page_size is also non-zero, the allocator will
+ // assume huge pages have been configured and enabled prior to initializing the
+ // allocator.
+ // For Windows, see https://docs.microsoft.com/en-us/windows/desktop/memory/large-page-support
+ // For Linux, see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
+ int enable_huge_pages;
+ //! Respectively allocated pages and huge allocated pages names for systems
+ // supporting it to be able to distinguish among anonymous regions.
+ const char *page_name;
+ const char *huge_page_name;
+} rpmalloc_config_t;
+
+//! Initialize allocator with default configuration
+RPMALLOC_EXPORT int
+rpmalloc_initialize(void);
+
+//! Initialize allocator with given configuration
+RPMALLOC_EXPORT int
+rpmalloc_initialize_config(const rpmalloc_config_t* config);
+
+//! Get allocator configuration
+RPMALLOC_EXPORT const rpmalloc_config_t*
+rpmalloc_config(void);
+
+//! Finalize allocator
+RPMALLOC_EXPORT void
+rpmalloc_finalize(void);
+
+//! Initialize allocator for calling thread
+RPMALLOC_EXPORT void
+rpmalloc_thread_initialize(void);
+
+//! Finalize allocator for calling thread
+RPMALLOC_EXPORT void
+rpmalloc_thread_finalize(int release_caches);
+
+//! Perform deferred deallocations pending for the calling thread heap
+RPMALLOC_EXPORT void
+rpmalloc_thread_collect(void);
+
+//! Query if allocator is initialized for calling thread
+RPMALLOC_EXPORT int
+rpmalloc_is_thread_initialized(void);
+
+//! Get per-thread statistics
+RPMALLOC_EXPORT void
+rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats);
+
+//! Get global statistics
+RPMALLOC_EXPORT void
+rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats);
+
+//! Dump all statistics in human readable format to file (should be a FILE*)
+RPMALLOC_EXPORT void
+rpmalloc_dump_statistics(void* file);
+
+//! Allocate a memory block of at least the given size
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1);
+
+//! Free the given memory block
+RPMALLOC_EXPORT void
+rpfree(void* ptr);
+
+//! Allocate a memory block of at least the given size and zero initialize it
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpcalloc(size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2);
+
+//! Reallocate the given block to at least the given size
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rprealloc(void* ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+//! Reallocate the given block to at least the given size and alignment,
+// with optional control flags (see RPMALLOC_NO_PRESERVE).
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
+
+//! Allocate a memory block of at least the given size and alignment.
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+//! Allocate a memory block of at least the given size and alignment, and zero initialize it.
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpaligned_calloc(size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
+
+//! Allocate a memory block of at least the given size and alignment.
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+//! Allocate a memory block of at least the given size and alignment.
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT int
+rpposix_memalign(void** memptr, size_t alignment, size_t size);
+
+//! Query the usable size of the given memory block (from given pointer to the end of block)
+RPMALLOC_EXPORT size_t
+rpmalloc_usable_size(void* ptr);
+
+//! Dummy empty function for forcing linker symbol inclusion
+RPMALLOC_EXPORT void
+rpmalloc_linker_reference(void);
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+
+//! Heap type
+typedef struct heap_t rpmalloc_heap_t;
+
+//! Acquire a new heap. Will reuse existing released heaps or allocate memory for a new heap
+// if none available. Heap API is implemented with the strict assumption that only one single
+// thread will call heap functions for a given heap at any given time, no functions are thread safe.
+RPMALLOC_EXPORT rpmalloc_heap_t*
+rpmalloc_heap_acquire(void);
+
+//! Release a heap (does NOT free the memory allocated by the heap, use rpmalloc_heap_free_all before destroying the heap).
+// Releasing a heap will enable it to be reused by other threads. Safe to pass a null pointer.
+RPMALLOC_EXPORT void
+rpmalloc_heap_release(rpmalloc_heap_t* heap);
+
+//! Allocate a memory block of at least the given size using the given heap.
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+//! Allocate a memory block of at least the given size using the given heap. The returned
+// block will have the requested alignment. Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB).
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
+
+//! Allocate a memory block of at least the given size using the given heap and zero initialize it.
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
+
+//! Allocate a memory block of at least the given size using the given heap and zero initialize it. The returned
+// block will have the requested alignment. Alignment must either be zero, or a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB).
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
+
+//! Reallocate the given block to at least the given size. The memory block MUST be allocated
+// by the same heap given to this function.
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
+
+//! Reallocate the given block to at least the given size. The memory block MUST be allocated
+// by the same heap given to this function. The returned block will have the requested alignment.
+// Alignment must be either zero, or a power of two and a multiple of sizeof(void*), and should ideally be
+// less than memory page size. A caveat of rpmalloc internals is that this must also be strictly less than
+// the span size (default 64KiB).
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(4);
+
+//! Free the given memory block from the given heap. The memory block MUST be allocated
+// by the same heap given to this function.
+RPMALLOC_EXPORT void
+rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr);
+
+//! Free all memory allocated by the heap
+RPMALLOC_EXPORT void
+rpmalloc_heap_free_all(rpmalloc_heap_t* heap);
+
+//! Set the given heap as the current heap for the calling thread. A heap MUST only be current heap
+// for a single thread, a heap can never be shared between multiple threads. The previous
+// current heap for the calling thread is released to be reused by other threads.
+RPMALLOC_EXPORT void
+rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap);
+
+//! Returns which heap the given pointer is allocated on
+RPMALLOC_EXPORT rpmalloc_heap_t*
+rpmalloc_get_heap_for_ptr(void* ptr);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#line 0
+#line 1 "3rd_rpmalloc.c"
+/* rpmalloc.c - Memory allocator - Public Domain - 2016-2020 Mattias Jansson
+ *
+ * This library provides a cross-platform lock free thread caching malloc implementation in C11.
+ * The latest source code is always available at
+ *
+ * https://github.com/mjansson/rpmalloc
+ *
+ * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
+ *
+ */
+
+// #include "rpmalloc.h" //< @r-lyeh
+
+////////////
+///
+/// Build time configurable limits
+///
+//////
+
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wunused-macros"
+#pragma clang diagnostic ignored "-Wunused-function"
+#if __has_warning("-Wreserved-identifier")
+#pragma clang diagnostic ignored "-Wreserved-identifier"
+#endif
+#if __has_warning("-Wstatic-in-inline")
+#pragma clang diagnostic ignored "-Wstatic-in-inline"
+#endif
+#elif defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-macros"
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+#if !defined(__has_builtin)
+#define __has_builtin(b) 0
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+
+#if __has_builtin(__builtin_memcpy_inline)
+#define _rpmalloc_memcpy_const(x, y, s) __builtin_memcpy_inline(x, y, s)
+#else
+#define _rpmalloc_memcpy_const(x, y, s) \
+ do { \
+ _Static_assert(__builtin_choose_expr(__builtin_constant_p(s), 1, 0), "len must be a constant integer"); \
+ memcpy(x, y, s); \
+ } while (0)
+#endif
+
+#if __has_builtin(__builtin_memset_inline)
+#define _rpmalloc_memset_const(x, y, s) __builtin_memset_inline(x, y, s)
+#else
+#define _rpmalloc_memset_const(x, y, s) \
+ do { \
+ _Static_assert(__builtin_choose_expr(__builtin_constant_p(s), 1, 0), "len must be a constant integer"); \
+ memset(x, y, s); \
+ } while (0)
+#endif
+#else
+#define _rpmalloc_memcpy_const(x, y, s) memcpy(x, y, s)
+#define _rpmalloc_memset_const(x, y, s) memset(x, y, s)
+#endif
+
+#if __has_builtin(__builtin_assume)
+#define rpmalloc_assume(cond) __builtin_assume(cond)
+#elif defined(__GNUC__)
+#define rpmalloc_assume(cond) \
+ do { \
+ if (!__builtin_expect(cond, 0)) \
+ __builtin_unreachable(); \
+ } while (0)
+#elif defined(_MSC_VER)
+#define rpmalloc_assume(cond) __assume(cond)
+#else
+#define rpmalloc_assume(cond) 0
+#endif
+
+#ifndef HEAP_ARRAY_SIZE
+//! Size of heap hashmap
+#define HEAP_ARRAY_SIZE 47
+#endif
+#ifndef ENABLE_THREAD_CACHE
+//! Enable per-thread cache
+#define ENABLE_THREAD_CACHE 1
+#endif
+#ifndef ENABLE_GLOBAL_CACHE
+//! Enable global cache shared between all threads, requires thread cache
+#define ENABLE_GLOBAL_CACHE 1
+#endif
+#ifndef ENABLE_VALIDATE_ARGS
+//! Enable validation of args to public entry points
+#define ENABLE_VALIDATE_ARGS 0
+#endif
+#ifndef ENABLE_STATISTICS
+//! Enable statistics collection
+#define ENABLE_STATISTICS 0
+#endif
+#ifndef ENABLE_ASSERTS
+//! Enable asserts
+#define ENABLE_ASSERTS 0
+#endif
+#ifndef ENABLE_OVERRIDE
+//! Override standard library malloc/free and new/delete entry points
+#define ENABLE_OVERRIDE 0
+#endif
+#ifndef ENABLE_PRELOAD
+//! Support preloading
+#define ENABLE_PRELOAD 0
+#endif
+#ifndef DISABLE_UNMAP
+//! Disable unmapping memory pages (also enables unlimited cache)
+#define DISABLE_UNMAP 0
+#endif
+#ifndef ENABLE_UNLIMITED_CACHE
+//! Enable unlimited global cache (no unmapping until finalization)
+#define ENABLE_UNLIMITED_CACHE 0
+#endif
+#ifndef ENABLE_ADAPTIVE_THREAD_CACHE
+//! Enable adaptive thread cache size based on use heuristics
+#define ENABLE_ADAPTIVE_THREAD_CACHE 0
+#endif
+#ifndef DEFAULT_SPAN_MAP_COUNT
+//! Default number of spans to map in call to map more virtual memory (default values yield 4MiB here)
+#define DEFAULT_SPAN_MAP_COUNT 64
+#endif
+#ifndef GLOBAL_CACHE_MULTIPLIER
+//! Multiplier for global cache
+#define GLOBAL_CACHE_MULTIPLIER 8
+#endif
+
+#if DISABLE_UNMAP && !ENABLE_GLOBAL_CACHE
+#error Must use global cache if unmap is disabled
+#endif
+
+#if DISABLE_UNMAP
+#undef ENABLE_UNLIMITED_CACHE
+#define ENABLE_UNLIMITED_CACHE 1
+#endif
+
+#if !ENABLE_GLOBAL_CACHE
+#undef ENABLE_UNLIMITED_CACHE
+#define ENABLE_UNLIMITED_CACHE 0
+#endif
+
+#if !ENABLE_THREAD_CACHE
+#undef ENABLE_ADAPTIVE_THREAD_CACHE
+#define ENABLE_ADAPTIVE_THREAD_CACHE 0
+#endif
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
+# define PLATFORM_WINDOWS 1
+# define PLATFORM_POSIX 0
+#else
+# define PLATFORM_WINDOWS 0
+# define PLATFORM_POSIX 1
+#endif
+
+/// Platform and arch specifics
+#if defined(_MSC_VER) && !defined(__clang__)
+# pragma warning (disable: 5105)
+# ifndef FORCEINLINE
+# define FORCEINLINE inline __forceinline
+# endif
+# define _Static_assert static_assert
+#else
+# ifndef FORCEINLINE
+# define FORCEINLINE inline __attribute__((__always_inline__))
+# endif
+#endif
+#if PLATFORM_WINDOWS
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include
+# if ENABLE_VALIDATE_ARGS
+# include
+# endif
+#else
+# include
+# include
+# include
+# include
+# if defined(__linux__) || defined(__ANDROID__)
+# include
+# if !defined(PR_SET_VMA)
+# define PR_SET_VMA 0x53564d41
+# define PR_SET_VMA_ANON_NAME 0
+# endif
+# endif
+# if defined(__APPLE__)
+# include
+# if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+# include
+# include
+# endif
+# include
+# endif
+# if defined(__HAIKU__) || defined(__TINYC__)
+# include
+# endif
+#endif
+
+#include
+#include
+#include
+
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+#include
+static DWORD fls_key;
+#endif
+
+#if PLATFORM_POSIX
+# include
+# include
+# ifdef __FreeBSD__
+# include
+# define MAP_HUGETLB MAP_ALIGNED_SUPER
+# ifndef PROT_MAX
+# define PROT_MAX(f) 0
+# endif
+# else
+# define PROT_MAX(f) 0
+# endif
+# ifdef __sun
+extern int madvise(caddr_t, size_t, int);
+# endif
+# ifndef MAP_UNINITIALIZED
+# define MAP_UNINITIALIZED 0
+# endif
+#endif
+#include
+
+#if ENABLE_ASSERTS
+# undef NDEBUG
+# if defined(_MSC_VER) && !defined(_DEBUG)
+# define _DEBUG
+# endif
+# include
+#define RPMALLOC_TOSTRING_M(x) #x
+#define RPMALLOC_TOSTRING(x) RPMALLOC_TOSTRING_M(x)
+#define rpmalloc_assert(truth, message) \
+ do { \
+ if (!(truth)) { \
+ if (_memory_config.error_callback) { \
+ _memory_config.error_callback( \
+ message " (" RPMALLOC_TOSTRING(truth) ") at " __FILE__ ":" RPMALLOC_TOSTRING(__LINE__)); \
+ } else { \
+ assert((truth) && message); \
+ } \
+ } \
+ } while (0)
+#else
+# define rpmalloc_assert(truth, message) do {} while(0)
+#endif
+#if ENABLE_STATISTICS
+# include
+#endif
+
+//////
+///
+/// Atomic access abstraction (since MSVC does not do C11 yet)
+///
+//////
+
+#if defined(_MSC_VER) && !defined(__clang__)
+
+typedef volatile long atomic32_t;
+typedef volatile long long atomic64_t;
+typedef volatile void* atomicptr_t;
+
+static FORCEINLINE int32_t atomic_load32(atomic32_t* src) { return *src; }
+static FORCEINLINE void atomic_store32(atomic32_t* dst, int32_t val) { *dst = val; }
+static FORCEINLINE int32_t atomic_incr32(atomic32_t* val) { return (int32_t)InterlockedIncrement(val); }
+static FORCEINLINE int32_t atomic_decr32(atomic32_t* val) { return (int32_t)InterlockedDecrement(val); }
+static FORCEINLINE int32_t atomic_add32(atomic32_t* val, int32_t add) { return (int32_t)InterlockedExchangeAdd(val, add) + add; }
+static FORCEINLINE int atomic_cas32_acquire(atomic32_t* dst, int32_t val, int32_t ref) { return (InterlockedCompareExchange(dst, val, ref) == ref) ? 1 : 0; }
+static FORCEINLINE void atomic_store32_release(atomic32_t* dst, int32_t val) { *dst = val; }
+static FORCEINLINE int64_t atomic_load64(atomic64_t* src) { return *src; }
+static FORCEINLINE int64_t atomic_add64(atomic64_t* val, int64_t add) { return (int64_t)InterlockedExchangeAdd64(val, add) + add; }
+static FORCEINLINE void* atomic_load_ptr(atomicptr_t* src) { return (void*)*src; }
+static FORCEINLINE void atomic_store_ptr(atomicptr_t* dst, void* val) { *dst = val; }
+static FORCEINLINE void atomic_store_ptr_release(atomicptr_t* dst, void* val) { *dst = val; }
+static FORCEINLINE void* atomic_exchange_ptr_acquire(atomicptr_t* dst, void* val) { return (void*)InterlockedExchangePointer((void* volatile*)dst, val); }
+static FORCEINLINE int atomic_cas_ptr(atomicptr_t* dst, void* val, void* ref) { return (InterlockedCompareExchangePointer((void* volatile*)dst, val, ref) == ref) ? 1 : 0; }
+
+#define EXPECTED(x) (x)
+#define UNEXPECTED(x) (x)
+
+#else
+
+#include
+
+typedef volatile _Atomic(int32_t) atomic32_t;
+typedef volatile _Atomic(int64_t) atomic64_t;
+typedef volatile _Atomic(void*) atomicptr_t;
+
+static FORCEINLINE int32_t atomic_load32(atomic32_t* src) { return atomic_load_explicit(src, memory_order_relaxed); }
+static FORCEINLINE void atomic_store32(atomic32_t* dst, int32_t val) { atomic_store_explicit(dst, val, memory_order_relaxed); }
+static FORCEINLINE int32_t atomic_incr32(atomic32_t* val) { return atomic_fetch_add_explicit(val, 1, memory_order_relaxed) + 1; }
+static FORCEINLINE int32_t atomic_decr32(atomic32_t* val) { return atomic_fetch_add_explicit(val, -1, memory_order_relaxed) - 1; }
+static FORCEINLINE int32_t atomic_add32(atomic32_t* val, int32_t add) { return atomic_fetch_add_explicit(val, add, memory_order_relaxed) + add; }
+static FORCEINLINE int atomic_cas32_acquire(atomic32_t* dst, int32_t val, int32_t ref) { return atomic_compare_exchange_weak_explicit(dst, &ref, val, memory_order_acquire, memory_order_relaxed); }
+static FORCEINLINE void atomic_store32_release(atomic32_t* dst, int32_t val) { atomic_store_explicit(dst, val, memory_order_release); }
+static FORCEINLINE int64_t atomic_load64(atomic64_t* val) { return atomic_load_explicit(val, memory_order_relaxed); }
+static FORCEINLINE int64_t atomic_add64(atomic64_t* val, int64_t add) { return atomic_fetch_add_explicit(val, add, memory_order_relaxed) + add; }
+static FORCEINLINE void* atomic_load_ptr(atomicptr_t* src) { return atomic_load_explicit(src, memory_order_relaxed); }
+static FORCEINLINE void atomic_store_ptr(atomicptr_t* dst, void* val) { atomic_store_explicit(dst, val, memory_order_relaxed); }
+static FORCEINLINE void atomic_store_ptr_release(atomicptr_t* dst, void* val) { atomic_store_explicit(dst, val, memory_order_release); }
+static FORCEINLINE void* atomic_exchange_ptr_acquire(atomicptr_t* dst, void* val) { return atomic_exchange_explicit(dst, val, memory_order_acquire); }
+static FORCEINLINE int atomic_cas_ptr(atomicptr_t* dst, void* val, void* ref) { return atomic_compare_exchange_weak_explicit(dst, &ref, val, memory_order_relaxed, memory_order_relaxed); }
+
+#define EXPECTED(x) __builtin_expect((x), 1)
+#define UNEXPECTED(x) __builtin_expect((x), 0)
+
+#endif
+
+////////////
+///
+/// Statistics related functions (evaluate to nothing when statistics not enabled)
+///
+//////
+
+#if ENABLE_STATISTICS
+# define _rpmalloc_stat_inc(counter) atomic_incr32(counter)
+# define _rpmalloc_stat_dec(counter) atomic_decr32(counter)
+# define _rpmalloc_stat_add(counter, value) atomic_add32(counter, (int32_t)(value))
+# define _rpmalloc_stat_add64(counter, value) atomic_add64(counter, (int64_t)(value))
+# define _rpmalloc_stat_add_peak(counter, value, peak) do { int32_t _cur_count = atomic_add32(counter, (int32_t)(value)); if (_cur_count > (peak)) peak = _cur_count; } while (0)
+# define _rpmalloc_stat_sub(counter, value) atomic_add32(counter, -(int32_t)(value))
+# define _rpmalloc_stat_inc_alloc(heap, class_idx) do { \
+ int32_t alloc_current = atomic_incr32(&heap->size_class_use[class_idx].alloc_current); \
+ if (alloc_current > heap->size_class_use[class_idx].alloc_peak) \
+ heap->size_class_use[class_idx].alloc_peak = alloc_current; \
+ atomic_incr32(&heap->size_class_use[class_idx].alloc_total); \
+} while(0)
+# define _rpmalloc_stat_inc_free(heap, class_idx) do { \
+ atomic_decr32(&heap->size_class_use[class_idx].alloc_current); \
+ atomic_incr32(&heap->size_class_use[class_idx].free_total); \
+} while(0)
+#else
+# define _rpmalloc_stat_inc(counter) do {} while(0)
+# define _rpmalloc_stat_dec(counter) do {} while(0)
+# define _rpmalloc_stat_add(counter, value) do {} while(0)
+# define _rpmalloc_stat_add64(counter, value) do {} while(0)
+# define _rpmalloc_stat_add_peak(counter, value, peak) do {} while (0)
+# define _rpmalloc_stat_sub(counter, value) do {} while(0)
+# define _rpmalloc_stat_inc_alloc(heap, class_idx) do {} while(0)
+# define _rpmalloc_stat_inc_free(heap, class_idx) do {} while(0)
+#endif
+
+
+///
+/// Preconfigured limits and sizes
+///
+
+//! Granularity of a small allocation block (must be power of two)
+#define SMALL_GRANULARITY 16
+//! Small granularity shift count
+#define SMALL_GRANULARITY_SHIFT 4
+//! Number of small block size classes
+#define SMALL_CLASS_COUNT 65
+//! Maximum size of a small block
+#define SMALL_SIZE_LIMIT (SMALL_GRANULARITY * (SMALL_CLASS_COUNT - 1))
+//! Granularity of a medium allocation block
+#define MEDIUM_GRANULARITY 512
+//! Medium granularity shift count
+#define MEDIUM_GRANULARITY_SHIFT 9
+//! Number of medium block size classes
+#define MEDIUM_CLASS_COUNT 61
+//! Total number of small + medium size classes
+#define SIZE_CLASS_COUNT (SMALL_CLASS_COUNT + MEDIUM_CLASS_COUNT)
+//! Number of large block size classes
+#define LARGE_CLASS_COUNT 63
+//! Maximum size of a medium block
+#define MEDIUM_SIZE_LIMIT (SMALL_SIZE_LIMIT + (MEDIUM_GRANULARITY * MEDIUM_CLASS_COUNT))
+//! Maximum size of a large block
+#define LARGE_SIZE_LIMIT ((LARGE_CLASS_COUNT * _memory_span_size) - SPAN_HEADER_SIZE)
+//! Size of a span header (must be a multiple of SMALL_GRANULARITY and a power of two)
+#define SPAN_HEADER_SIZE 128
+//! Number of spans in thread cache
+#define MAX_THREAD_SPAN_CACHE 400
+//! Number of spans to transfer between thread and global cache
+#define THREAD_SPAN_CACHE_TRANSFER 64
+//! Number of spans in thread cache for large spans (must be greater than LARGE_CLASS_COUNT / 2)
+#define MAX_THREAD_SPAN_LARGE_CACHE 100
+//! Number of spans to transfer between thread and global cache for large spans
+#define THREAD_SPAN_LARGE_CACHE_TRANSFER 6
+
+_Static_assert((SMALL_GRANULARITY & (SMALL_GRANULARITY - 1)) == 0, "Small granularity must be power of two");
+_Static_assert((SPAN_HEADER_SIZE & (SPAN_HEADER_SIZE - 1)) == 0, "Span header size must be power of two");
+
+#if ENABLE_VALIDATE_ARGS
+//! Maximum allocation size to avoid integer overflow
+#undef MAX_ALLOC_SIZE
+#define MAX_ALLOC_SIZE (((size_t)-1) - _memory_span_size)
+#endif
+
+#define pointer_offset(ptr, ofs) (void*)((char*)(ptr) + (ptrdiff_t)(ofs))
+#define pointer_diff(first, second) (ptrdiff_t)((const char*)(first) - (const char*)(second))
+
+#define INVALID_POINTER ((void*)((uintptr_t)-1))
+
+#define SIZE_CLASS_LARGE SIZE_CLASS_COUNT
+#define SIZE_CLASS_HUGE ((uint32_t)-1)
+
+////////////
+///
+/// Data types
+///
+//////
+
+//! A memory heap, per thread
+typedef struct heap_t heap_t;
+//! Span of memory pages
+typedef struct span_t span_t;
+//! Span list
+typedef struct span_list_t span_list_t;
+//! Span active data
+typedef struct span_active_t span_active_t;
+//! Size class definition
+typedef struct size_class_t size_class_t;
+//! Global cache
+typedef struct global_cache_t global_cache_t;
+
+//! Flag indicating span is the first (master) span of a split superspan
+#define SPAN_FLAG_MASTER 1U
+//! Flag indicating span is a secondary (sub) span of a split superspan
+#define SPAN_FLAG_SUBSPAN 2U
+//! Flag indicating span has blocks with increased alignment
+#define SPAN_FLAG_ALIGNED_BLOCKS 4U
+//! Flag indicating an unmapped master span
+#define SPAN_FLAG_UNMAPPED_MASTER 8U
+
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+struct span_use_t {
+ //! Current number of spans used (actually used, not in cache)
+ atomic32_t current;
+ //! High water mark of spans used
+ atomic32_t high;
+#if ENABLE_STATISTICS
+ //! Number of spans in deferred list
+ atomic32_t spans_deferred;
+ //! Number of spans transitioned to global cache
+ atomic32_t spans_to_global;
+ //! Number of spans transitioned from global cache
+ atomic32_t spans_from_global;
+ //! Number of spans transitioned to thread cache
+ atomic32_t spans_to_cache;
+ //! Number of spans transitioned from thread cache
+ atomic32_t spans_from_cache;
+ //! Number of spans transitioned to reserved state
+ atomic32_t spans_to_reserved;
+ //! Number of spans transitioned from reserved state
+ atomic32_t spans_from_reserved;
+ //! Number of raw memory map calls
+ atomic32_t spans_map_calls;
+#endif
+};
+typedef struct span_use_t span_use_t;
+#endif
+
+#if ENABLE_STATISTICS
+struct size_class_use_t {
+ //! Current number of allocations
+ atomic32_t alloc_current;
+ //! Peak number of allocations
+ int32_t alloc_peak;
+ //! Total number of allocations
+ atomic32_t alloc_total;
+ //! Total number of frees
+ atomic32_t free_total;
+ //! Number of spans in use
+ atomic32_t spans_current;
+ //! Number of spans transitioned to cache
+ int32_t spans_peak;
+ //! Number of spans transitioned to cache
+ atomic32_t spans_to_cache;
+ //! Number of spans transitioned from cache
+ atomic32_t spans_from_cache;
+ //! Number of spans transitioned from reserved state
+ atomic32_t spans_from_reserved;
+ //! Number of spans mapped
+ atomic32_t spans_map_calls;
+ int32_t unused;
+};
+typedef struct size_class_use_t size_class_use_t;
+#endif
+
+// A span can either represent a single span of memory pages with size declared by span_map_count configuration variable,
+// or a set of spans in a continuous region, a super span. Any reference to the term "span" usually refers to both a single
+// span or a super span. A super span can further be divided into multiple spans (or this, super spans), where the first
+// (super)span is the master and subsequent (super)spans are subspans. The master span keeps track of how many subspans
+// that are still alive and mapped in virtual memory, and once all subspans and master have been unmapped the entire
+// superspan region is released and unmapped (on Windows for example, the entire superspan range has to be released
+// in the same call to release the virtual memory range, but individual subranges can be decommitted individually
+// to reduce physical memory use).
+struct span_t {
+ //! Free list
+ void* free_list;
+ //! Total block count of size class
+ uint32_t block_count;
+ //! Size class
+ uint32_t size_class;
+ //! Index of last block initialized in free list
+ uint32_t free_list_limit;
+ //! Number of used blocks remaining when in partial state
+ uint32_t used_count;
+ //! Deferred free list
+ atomicptr_t free_list_deferred;
+ //! Size of deferred free list, or list of spans when part of a cache list
+ uint32_t list_size;
+ //! Size of a block
+ uint32_t block_size;
+ //! Flags and counters
+ uint32_t flags;
+ //! Number of spans
+ uint32_t span_count;
+ //! Total span counter for master spans
+ uint32_t total_spans;
+ //! Offset from master span for subspans
+ uint32_t offset_from_master;
+ //! Remaining span counter, for master spans
+ atomic32_t remaining_spans;
+ //! Alignment offset
+ uint32_t align_offset;
+ //! Owning heap
+ heap_t* heap;
+ //! Next span
+ span_t* next;
+ //! Previous span
+ span_t* prev;
+};
+_Static_assert(sizeof(span_t) <= SPAN_HEADER_SIZE, "span size mismatch");
+
+struct span_cache_t {
+ size_t count;
+ span_t* span[MAX_THREAD_SPAN_CACHE];
+};
+typedef struct span_cache_t span_cache_t;
+
+struct span_large_cache_t {
+ size_t count;
+ span_t* span[MAX_THREAD_SPAN_LARGE_CACHE];
+};
+typedef struct span_large_cache_t span_large_cache_t;
+
+struct heap_size_class_t {
+ //! Free list of active span
+ void* free_list;
+ //! Double linked list of partially used spans with free blocks.
+ // Previous span pointer in head points to tail span of list.
+ span_t* partial_span;
+ //! Early level cache of fully free spans
+ span_t* cache;
+};
+typedef struct heap_size_class_t heap_size_class_t;
+
+// Control structure for a heap, either a thread heap or a first class heap if enabled
+struct heap_t {
+ //! Owning thread ID
+ uintptr_t owner_thread;
+ //! Free lists for each size class
+ heap_size_class_t size_class[SIZE_CLASS_COUNT];
+#if ENABLE_THREAD_CACHE
+ //! Arrays of fully freed spans, single span
+ span_cache_t span_cache;
+#endif
+ //! List of deferred free spans (single linked list)
+ atomicptr_t span_free_deferred;
+ //! Number of full spans
+ size_t full_span_count;
+ //! Mapped but unused spans
+ span_t* span_reserve;
+ //! Master span for mapped but unused spans
+ span_t* span_reserve_master;
+ //! Number of mapped but unused spans
+ uint32_t spans_reserved;
+ //! Child count
+ atomic32_t child_count;
+ //! Next heap in id list
+ heap_t* next_heap;
+ //! Next heap in orphan list
+ heap_t* next_orphan;
+ //! Heap ID
+ int32_t id;
+ //! Finalization state flag
+ int finalize;
+ //! Master heap owning the memory pages
+ heap_t* master_heap;
+#if ENABLE_THREAD_CACHE
+ //! Arrays of fully freed spans, large spans with > 1 span count
+ span_large_cache_t span_large_cache[LARGE_CLASS_COUNT - 1];
+#endif
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ //! Double linked list of fully utilized spans with free blocks for each size class.
+ // Previous span pointer in head points to tail span of list.
+ span_t* full_span[SIZE_CLASS_COUNT];
+ //! Double linked list of large and huge spans allocated by this heap
+ span_t* large_huge_span;
+#endif
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+ //! Current and high water mark of spans used per span count
+ span_use_t span_use[LARGE_CLASS_COUNT];
+#endif
+#if ENABLE_STATISTICS
+ //! Allocation stats per size class
+ size_class_use_t size_class_use[SIZE_CLASS_COUNT + 1];
+ //! Number of bytes transitioned thread -> global
+ atomic64_t thread_to_global;
+ //! Number of bytes transitioned global -> thread
+ atomic64_t global_to_thread;
+#endif
+};
+
+// Size class for defining a block size bucket
+struct size_class_t {
+ //! Size of blocks in this class
+ uint32_t block_size;
+ //! Number of blocks in each chunk
+ uint16_t block_count;
+ //! Class index this class is merged with
+ uint16_t class_idx;
+};
+_Static_assert(sizeof(size_class_t) == 8, "Size class size mismatch");
+
+struct global_cache_t {
+ //! Cache lock
+ atomic32_t lock;
+ //! Cache count
+ uint32_t count;
+#if ENABLE_STATISTICS
+ //! Insert count
+ size_t insert_count;
+ //! Extract count
+ size_t extract_count;
+#endif
+ //! Cached spans
+ span_t* span[GLOBAL_CACHE_MULTIPLIER * MAX_THREAD_SPAN_CACHE];
+ //! Unlimited cache overflow
+ span_t* overflow;
+};
+
+////////////
+///
+/// Global data
+///
+//////
+
+//! Default span size (64KiB)
+#define _memory_default_span_size (64 * 1024)
+#define _memory_default_span_size_shift 16
+#define _memory_default_span_mask (~((uintptr_t)(_memory_span_size - 1)))
+
+//! Initialized flag
+static int _rpmalloc_initialized;
+//! Main thread ID
+static uintptr_t _rpmalloc_main_thread_id;
+//! Configuration
+static rpmalloc_config_t _memory_config;
+//! Memory page size
+static size_t _memory_page_size;
+//! Shift to divide by page size
+static size_t _memory_page_size_shift;
+//! Granularity at which memory pages are mapped by OS
+static size_t _memory_map_granularity;
+#if RPMALLOC_CONFIGURABLE
+//! Size of a span of memory pages
+static size_t _memory_span_size;
+//! Shift to divide by span size
+static size_t _memory_span_size_shift;
+//! Mask to get to start of a memory span
+static uintptr_t _memory_span_mask;
+#else
+//! Hardwired span size
+#define _memory_span_size _memory_default_span_size
+#define _memory_span_size_shift _memory_default_span_size_shift
+#define _memory_span_mask _memory_default_span_mask
+#endif
+//! Number of spans to map in each map call
+static size_t _memory_span_map_count;
+//! Number of spans to keep reserved in each heap
+static size_t _memory_heap_reserve_count;
+//! Global size classes
+static size_class_t _memory_size_class[SIZE_CLASS_COUNT];
+//! Run-time size limit of medium blocks
+static size_t _memory_medium_size_limit;
+//! Heap ID counter
+static atomic32_t _memory_heap_id;
+//! Huge page support
+static int _memory_huge_pages;
+#if ENABLE_GLOBAL_CACHE
+//! Global span cache
+static global_cache_t _memory_span_cache[LARGE_CLASS_COUNT];
+#endif
+//! Global reserved spans
+static span_t* _memory_global_reserve;
+//! Global reserved count
+static size_t _memory_global_reserve_count;
+//! Global reserved master
+static span_t* _memory_global_reserve_master;
+//! All heaps
+static heap_t* _memory_heaps[HEAP_ARRAY_SIZE];
+//! Used to restrict access to mapping memory for huge pages
+static atomic32_t _memory_global_lock;
+//! Orphaned heaps
+static heap_t* _memory_orphan_heaps;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+//! Orphaned heaps (first class heaps)
+static heap_t* _memory_first_class_orphan_heaps;
+#endif
+#if ENABLE_STATISTICS
+//! Allocations counter
+static atomic64_t _allocation_counter;
+//! Deallocations counter
+static atomic64_t _deallocation_counter;
+//! Active heap count
+static atomic32_t _memory_active_heaps;
+//! Number of currently mapped memory pages
+static atomic32_t _mapped_pages;
+//! Peak number of concurrently mapped memory pages
+static int32_t _mapped_pages_peak;
+//! Number of mapped master spans
+static atomic32_t _master_spans;
+//! Number of unmapped dangling master spans
+static atomic32_t _unmapped_master_spans;
+//! Running counter of total number of mapped memory pages since start
+static atomic32_t _mapped_total;
+//! Running counter of total number of unmapped memory pages since start
+static atomic32_t _unmapped_total;
+//! Number of currently mapped memory pages in OS calls
+static atomic32_t _mapped_pages_os;
+//! Number of currently allocated pages in huge allocations
+static atomic32_t _huge_pages_current;
+//! Peak number of currently allocated pages in huge allocations
+static int32_t _huge_pages_peak;
+#endif
+
+////////////
+///
+/// Thread local heap and ID
+///
+//////
+
+//! Current thread heap
+#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)
+static pthread_key_t _memory_thread_heap;
+#else
+# ifdef _MSC_VER
+# define _Thread_local __declspec(thread)
+# define TLS_MODEL
+# else
+# ifndef __HAIKU__
+# define TLS_MODEL __attribute__((tls_model("initial-exec")))
+# else
+# define TLS_MODEL
+# endif
+# if !defined(__clang__) && defined(__GNUC__)
+# define _Thread_local __thread
+# endif
+# endif
+static _Thread_local heap_t* _memory_thread_heap TLS_MODEL;
+#endif
+
+static inline heap_t*
+get_thread_heap_raw(void) {
+#if (defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD
+ return pthread_getspecific(_memory_thread_heap);
+#else
+ return _memory_thread_heap;
+#endif
+}
+
+//! Get the current thread heap
+static inline heap_t*
+get_thread_heap(void) {
+ heap_t* heap = get_thread_heap_raw();
+#if ENABLE_PRELOAD
+ if (EXPECTED(heap != 0))
+ return heap;
+ rpmalloc_initialize();
+ return get_thread_heap_raw();
+#else
+ return heap;
+#endif
+}
+
+//! Fast thread ID
+static inline uintptr_t
+get_thread_id(void) {
+#if defined(_WIN32)
+ return (uintptr_t)((void*)NtCurrentTeb());
+#elif (defined(__GNUC__) || defined(__clang__)) && !defined(__CYGWIN__)
+ uintptr_t tid;
+# if defined(__i386__)
+ __asm__("movl %%gs:0, %0" : "=r" (tid) : : );
+# elif defined(__x86_64__)
+# if defined(__MACH__)
+ __asm__("movq %%gs:0, %0" : "=r" (tid) : : );
+# else
+ __asm__("movq %%fs:0, %0" : "=r" (tid) : : );
+# endif
+# elif defined(__arm__)
+ __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3" : "=r" (tid));
+# elif defined(__aarch64__)
+# if defined(__MACH__)
+ // tpidr_el0 likely unused, always return 0 on iOS
+ __asm__ volatile ("mrs %0, tpidrro_el0" : "=r" (tid));
+# else
+ __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tid));
+# endif
+# else
+# error This platform needs implementation of get_thread_id()
+# endif
+ return tid;
+#else
+# error This platform needs implementation of get_thread_id()
+#endif
+}
+
+//! Set the current thread heap
+static void
+set_thread_heap(heap_t* heap) {
+#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)
+ pthread_setspecific(_memory_thread_heap, heap);
+#else
+ _memory_thread_heap = heap;
+#endif
+ if (heap)
+ heap->owner_thread = get_thread_id();
+}
+
+//! Set main thread ID
+extern void
+rpmalloc_set_main_thread(void);
+
+void
+rpmalloc_set_main_thread(void) {
+ _rpmalloc_main_thread_id = get_thread_id();
+}
+
+static void
+_rpmalloc_spin(void) {
+#if defined(_MSC_VER)
+ _mm_pause();
+#elif defined(__x86_64__) || defined(__i386__)
+ __asm__ volatile("pause" ::: "memory");
+#elif defined(__aarch64__) || (defined(__arm__) && __ARM_ARCH >= 7)
+ __asm__ volatile("yield" ::: "memory");
+#elif defined(__powerpc__) || defined(__powerpc64__)
+ // No idea if ever been compiled in such archs but ... as precaution
+ __asm__ volatile("or 27,27,27");
+#elif defined(__sparc__)
+ __asm__ volatile("rd %ccr, %g0 \n\trd %ccr, %g0 \n\trd %ccr, %g0");
+#else
+ struct timespec ts = {0};
+ nanosleep(&ts, 0);
+#endif
+}
+
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+static void NTAPI
+_rpmalloc_thread_destructor(void* value) {
+#if ENABLE_OVERRIDE
+ // If this is called on main thread it means rpmalloc_finalize
+ // has not been called and shutdown is forced (through _exit) or unclean
+ if (get_thread_id() == _rpmalloc_main_thread_id)
+ return;
+#endif
+ if (value)
+ rpmalloc_thread_finalize(1);
+}
+#endif
+
+
+////////////
+///
+/// Low level memory map/unmap
+///
+//////
+
+static void
+_rpmalloc_set_name(void* address, size_t size) {
+#if defined(__linux__) || defined(__ANDROID__)
+ const char *name = _memory_huge_pages ? _memory_config.huge_page_name : _memory_config.page_name;
+ if (address == MAP_FAILED || !name)
+ return;
+ // If the kernel does not support CONFIG_ANON_VMA_NAME or if the call fails
+ // (e.g. invalid name) it is a no-op basically.
+ (void)prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (uintptr_t)address, size, (uintptr_t)name);
+#else
+ (void)sizeof(size);
+ (void)sizeof(address);
+#endif
+}
+
+
+//! Map more virtual memory
+// size is number of bytes to map
+// offset receives the offset in bytes from start of mapped region
+// returns address to start of mapped region to use
+static void*
+_rpmalloc_mmap(size_t size, size_t* offset) {
+ rpmalloc_assert(!(size % _memory_page_size), "Invalid mmap size");
+ rpmalloc_assert(size >= _memory_page_size, "Invalid mmap size");
+ void* address = _memory_config.memory_map(size, offset);
+ if (EXPECTED(address != 0)) {
+ _rpmalloc_stat_add_peak(&_mapped_pages, (size >> _memory_page_size_shift), _mapped_pages_peak);
+ _rpmalloc_stat_add(&_mapped_total, (size >> _memory_page_size_shift));
+ }
+ return address;
+}
+
+//! Unmap virtual memory
+// address is the memory address to unmap, as returned from _memory_map
+// size is the number of bytes to unmap, which might be less than full region for a partial unmap
+// offset is the offset in bytes to the actual mapped region, as set by _memory_map
+// release is set to 0 for partial unmap, or size of entire range for a full unmap
+static void
+_rpmalloc_unmap(void* address, size_t size, size_t offset, size_t release) {
+ rpmalloc_assert(!release || (release >= size), "Invalid unmap size");
+ rpmalloc_assert(!release || (release >= _memory_page_size), "Invalid unmap size");
+ if (release) {
+ rpmalloc_assert(!(release % _memory_page_size), "Invalid unmap size");
+ _rpmalloc_stat_sub(&_mapped_pages, (release >> _memory_page_size_shift));
+ _rpmalloc_stat_add(&_unmapped_total, (release >> _memory_page_size_shift));
+ }
+ _memory_config.memory_unmap(address, size, offset, release);
+}
+
+//! Default implementation to map new pages to virtual memory
+static void*
+_rpmalloc_mmap_os(size_t size, size_t* offset) {
+ //Either size is a heap (a single page) or a (multiple) span - we only need to align spans, and only if larger than map granularity
+ size_t padding = ((size >= _memory_span_size) && (_memory_span_size > _memory_map_granularity)) ? _memory_span_size : 0;
+ rpmalloc_assert(size >= _memory_page_size, "Invalid mmap size");
+#if PLATFORM_WINDOWS
+ //Ok to MEM_COMMIT - according to MSDN, "actual physical pages are not allocated unless/until the virtual addresses are actually accessed"
+ void* ptr = VirtualAlloc(0, size + padding, (_memory_huge_pages ? MEM_LARGE_PAGES : 0) | MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ if (!ptr) {
+ if (_memory_config.map_fail_callback) {
+ if (_memory_config.map_fail_callback(size + padding))
+ return _rpmalloc_mmap_os(size, offset);
+ } else {
+ rpmalloc_assert(ptr, "Failed to map virtual memory block");
+ }
+ return 0;
+ }
+#else
+ int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_UNINITIALIZED;
+# if defined(__APPLE__) && !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+ int fd = (int)VM_MAKE_TAG(240U);
+ if (_memory_huge_pages)
+ fd |= VM_FLAGS_SUPERPAGE_SIZE_2MB;
+ void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, fd, 0);
+# elif defined(MAP_HUGETLB)
+ void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE | PROT_MAX(PROT_READ | PROT_WRITE), (_memory_huge_pages ? MAP_HUGETLB : 0) | flags, -1, 0);
+# if defined(MADV_HUGEPAGE)
+ // In some configurations, huge pages allocations might fail thus
+ // we fallback to normal allocations and promote the region as transparent huge page
+ if ((ptr == MAP_FAILED || !ptr) && _memory_huge_pages) {
+ ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, -1, 0);
+ if (ptr && ptr != MAP_FAILED) {
+ int prm = madvise(ptr, size + padding, MADV_HUGEPAGE);
+ (void)prm;
+ rpmalloc_assert((prm == 0), "Failed to promote the page to THP");
+ }
+ }
+# endif
+ _rpmalloc_set_name(ptr, size + padding);
+# elif defined(MAP_ALIGNED)
+ const size_t align = (sizeof(size_t) * 8) - (size_t)(__builtin_clzl(size - 1));
+ void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, (_memory_huge_pages ? MAP_ALIGNED(align) : 0) | flags, -1, 0);
+# elif defined(MAP_ALIGN)
+ caddr_t base = (_memory_huge_pages ? (caddr_t)(4 << 20) : 0);
+ void* ptr = mmap(base, size + padding, PROT_READ | PROT_WRITE, (_memory_huge_pages ? MAP_ALIGN : 0) | flags, -1, 0);
+# else
+ void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, -1, 0);
+# endif
+ if ((ptr == MAP_FAILED) || !ptr) {
+ if (_memory_config.map_fail_callback) {
+ if (_memory_config.map_fail_callback(size + padding))
+ return _rpmalloc_mmap_os(size, offset);
+ } else if (errno != ENOMEM) {
+ rpmalloc_assert((ptr != MAP_FAILED) && ptr, "Failed to map virtual memory block");
+ }
+ return 0;
+ }
+#endif
+ _rpmalloc_stat_add(&_mapped_pages_os, (int32_t)((size + padding) >> _memory_page_size_shift));
+ if (padding) {
+ size_t final_padding = padding - ((uintptr_t)ptr & ~_memory_span_mask);
+ rpmalloc_assert(final_padding <= _memory_span_size, "Internal failure in padding");
+ rpmalloc_assert(final_padding <= padding, "Internal failure in padding");
+ rpmalloc_assert(!(final_padding % 8), "Internal failure in padding");
+ ptr = pointer_offset(ptr, final_padding);
+ *offset = final_padding >> 3;
+ }
+ rpmalloc_assert((size < _memory_span_size) || !((uintptr_t)ptr & ~_memory_span_mask), "Internal failure in padding");
+ return ptr;
+}
+
+//! Default implementation to unmap pages from virtual memory
+static void
+_rpmalloc_unmap_os(void* address, size_t size, size_t offset, size_t release) {
+ rpmalloc_assert(release || (offset == 0), "Invalid unmap size");
+ rpmalloc_assert(!release || (release >= _memory_page_size), "Invalid unmap size");
+ rpmalloc_assert(size >= _memory_page_size, "Invalid unmap size");
+ if (release && offset) {
+ offset <<= 3;
+ address = pointer_offset(address, -(int32_t)offset);
+ if ((release >= _memory_span_size) && (_memory_span_size > _memory_map_granularity)) {
+ //Padding is always one span size
+ release += _memory_span_size;
+ }
+ }
+#if !DISABLE_UNMAP
+#if PLATFORM_WINDOWS
+ if (!VirtualFree(address, release ? 0 : size, release ? MEM_RELEASE : MEM_DECOMMIT)) {
+ rpmalloc_assert(0, "Failed to unmap virtual memory block");
+ }
+#else
+ if (release) {
+ if (munmap(address, release)) {
+ rpmalloc_assert(0, "Failed to unmap virtual memory block");
+ }
+ } else {
+#if defined(MADV_FREE_REUSABLE)
+ int ret;
+ while ((ret = madvise(address, size, MADV_FREE_REUSABLE)) == -1 && (errno == EAGAIN))
+ errno = 0;
+ if ((ret == -1) && (errno != 0)) {
+#elif defined(MADV_DONTNEED)
+ if (madvise(address, size, MADV_DONTNEED)) {
+#elif defined(MADV_PAGEOUT)
+ if (madvise(address, size, MADV_PAGEOUT)) {
+#elif defined(MADV_FREE)
+ if (madvise(address, size, MADV_FREE)) {
+#else
+ if (posix_madvise(address, size, POSIX_MADV_DONTNEED)) {
+#endif
+ rpmalloc_assert(0, "Failed to madvise virtual memory block as free");
+ }
+ }
+#endif
+#endif
+ if (release)
+ _rpmalloc_stat_sub(&_mapped_pages_os, release >> _memory_page_size_shift);
+}
+
+static void
+_rpmalloc_span_mark_as_subspan_unless_master(span_t* master, span_t* subspan, size_t span_count);
+
+//! Use global reserved spans to fulfill a memory map request (reserve size must be checked by caller)
+static span_t*
+_rpmalloc_global_get_reserved_spans(size_t span_count) {
+ span_t* span = _memory_global_reserve;
+ _rpmalloc_span_mark_as_subspan_unless_master(_memory_global_reserve_master, span, span_count);
+ _memory_global_reserve_count -= span_count;
+ if (_memory_global_reserve_count)
+ _memory_global_reserve = (span_t*)pointer_offset(span, span_count << _memory_span_size_shift);
+ else
+ _memory_global_reserve = 0;
+ return span;
+}
+
+//! Store the given spans as global reserve (must only be called from within new heap allocation, not thread safe)
+static void
+_rpmalloc_global_set_reserved_spans(span_t* master, span_t* reserve, size_t reserve_span_count) {
+ _memory_global_reserve_master = master;
+ _memory_global_reserve_count = reserve_span_count;
+ _memory_global_reserve = reserve;
+}
+
+
+////////////
+///
+/// Span linked list management
+///
+//////
+
+//! Add a span to double linked list at the head
+static void
+_rpmalloc_span_double_link_list_add(span_t** head, span_t* span) {
+ if (*head)
+ (*head)->prev = span;
+ span->next = *head;
+ *head = span;
+}
+
+//! Pop head span from double linked list
+static void
+_rpmalloc_span_double_link_list_pop_head(span_t** head, span_t* span) {
+ rpmalloc_assert(*head == span, "Linked list corrupted");
+ span = *head;
+ *head = span->next;
+}
+
+//! Remove a span from double linked list
+static void
+_rpmalloc_span_double_link_list_remove(span_t** head, span_t* span) {
+ rpmalloc_assert(*head, "Linked list corrupted");
+ if (*head == span) {
+ *head = span->next;
+ } else {
+ span_t* next_span = span->next;
+ span_t* prev_span = span->prev;
+ prev_span->next = next_span;
+ if (EXPECTED(next_span != 0))
+ next_span->prev = prev_span;
+ }
+}
+
+
+////////////
+///
+/// Span control
+///
+//////
+
+static void
+_rpmalloc_heap_cache_insert(heap_t* heap, span_t* span);
+
+static void
+_rpmalloc_heap_finalize(heap_t* heap);
+
+static void
+_rpmalloc_heap_set_reserved_spans(heap_t* heap, span_t* master, span_t* reserve, size_t reserve_span_count);
+
+//! Declare the span to be a subspan and store distance from master span and span count
+static void
+_rpmalloc_span_mark_as_subspan_unless_master(span_t* master, span_t* subspan, size_t span_count) {
+ rpmalloc_assert((subspan != master) || (subspan->flags & SPAN_FLAG_MASTER), "Span master pointer and/or flag mismatch");
+ if (subspan != master) {
+ subspan->flags = SPAN_FLAG_SUBSPAN;
+ subspan->offset_from_master = (uint32_t)((uintptr_t)pointer_diff(subspan, master) >> _memory_span_size_shift);
+ subspan->align_offset = 0;
+ }
+ subspan->span_count = (uint32_t)span_count;
+}
+
+//! Use reserved spans to fulfill a memory map request (reserve size must be checked by caller)
+static span_t*
+_rpmalloc_span_map_from_reserve(heap_t* heap, size_t span_count) {
+ //Update the heap span reserve
+ span_t* span = heap->span_reserve;
+ heap->span_reserve = (span_t*)pointer_offset(span, span_count * _memory_span_size);
+ heap->spans_reserved -= (uint32_t)span_count;
+
+ _rpmalloc_span_mark_as_subspan_unless_master(heap->span_reserve_master, span, span_count);
+ if (span_count <= LARGE_CLASS_COUNT)
+ _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_from_reserved);
+
+ return span;
+}
+
+//! Get the aligned number of spans to map in based on wanted count, configured mapping granularity and the page size
+static size_t
+_rpmalloc_span_align_count(size_t span_count) {
+ size_t request_count = (span_count > _memory_span_map_count) ? span_count : _memory_span_map_count;
+ if ((_memory_page_size > _memory_span_size) && ((request_count * _memory_span_size) % _memory_page_size))
+ request_count += _memory_span_map_count - (request_count % _memory_span_map_count);
+ return request_count;
+}
+
+//! Setup a newly mapped span
+static void
+_rpmalloc_span_initialize(span_t* span, size_t total_span_count, size_t span_count, size_t align_offset) {
+ span->total_spans = (uint32_t)total_span_count;
+ span->span_count = (uint32_t)span_count;
+ span->align_offset = (uint32_t)align_offset;
+ span->flags = SPAN_FLAG_MASTER;
+ atomic_store32(&span->remaining_spans, (int32_t)total_span_count);
+}
+
+static void
+_rpmalloc_span_unmap(span_t* span);
+
+//! Map an aligned set of spans, taking configured mapping granularity and the page size into account
+static span_t*
+_rpmalloc_span_map_aligned_count(heap_t* heap, size_t span_count) {
+ //If we already have some, but not enough, reserved spans, release those to heap cache and map a new
+ //full set of spans. Otherwise we would waste memory if page size > span size (huge pages)
+ size_t aligned_span_count = _rpmalloc_span_align_count(span_count);
+ size_t align_offset = 0;
+ span_t* span = (span_t*)_rpmalloc_mmap(aligned_span_count * _memory_span_size, &align_offset);
+ if (!span)
+ return 0;
+ _rpmalloc_span_initialize(span, aligned_span_count, span_count, align_offset);
+ _rpmalloc_stat_inc(&_master_spans);
+ if (span_count <= LARGE_CLASS_COUNT)
+ _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_map_calls);
+ if (aligned_span_count > span_count) {
+ span_t* reserved_spans = (span_t*)pointer_offset(span, span_count * _memory_span_size);
+ size_t reserved_count = aligned_span_count - span_count;
+ if (heap->spans_reserved) {
+ _rpmalloc_span_mark_as_subspan_unless_master(heap->span_reserve_master, heap->span_reserve, heap->spans_reserved);
+ _rpmalloc_heap_cache_insert(heap, heap->span_reserve);
+ }
+ if (reserved_count > _memory_heap_reserve_count) {
+ // If huge pages or eager spam map count, the global reserve spin lock is held by caller, _rpmalloc_span_map
+ rpmalloc_assert(atomic_load32(&_memory_global_lock) == 1, "Global spin lock not held as expected");
+ size_t remain_count = reserved_count - _memory_heap_reserve_count;
+ reserved_count = _memory_heap_reserve_count;
+ span_t* remain_span = (span_t*)pointer_offset(reserved_spans, reserved_count * _memory_span_size);
+ if (_memory_global_reserve) {
+ _rpmalloc_span_mark_as_subspan_unless_master(_memory_global_reserve_master, _memory_global_reserve, _memory_global_reserve_count);
+ _rpmalloc_span_unmap(_memory_global_reserve);
+ }
+ _rpmalloc_global_set_reserved_spans(span, remain_span, remain_count);
+ }
+ _rpmalloc_heap_set_reserved_spans(heap, span, reserved_spans, reserved_count);
+ }
+ return span;
+}
+
+//! Map in memory pages for the given number of spans (or use previously reserved pages)
+static span_t*
+_rpmalloc_span_map(heap_t* heap, size_t span_count) {
+ if (span_count <= heap->spans_reserved)
+ return _rpmalloc_span_map_from_reserve(heap, span_count);
+ span_t* span = 0;
+ int use_global_reserve = (_memory_page_size > _memory_span_size) || (_memory_span_map_count > _memory_heap_reserve_count);
+ if (use_global_reserve) {
+ // If huge pages, make sure only one thread maps more memory to avoid bloat
+ while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))
+ _rpmalloc_spin();
+ if (_memory_global_reserve_count >= span_count) {
+ size_t reserve_count = (!heap->spans_reserved ? _memory_heap_reserve_count : span_count);
+ if (_memory_global_reserve_count < reserve_count)
+ reserve_count = _memory_global_reserve_count;
+ span = _rpmalloc_global_get_reserved_spans(reserve_count);
+ if (span) {
+ if (reserve_count > span_count) {
+ span_t* reserved_span = (span_t*)pointer_offset(span, span_count << _memory_span_size_shift);
+ _rpmalloc_heap_set_reserved_spans(heap, _memory_global_reserve_master, reserved_span, reserve_count - span_count);
+ }
+ // Already marked as subspan in _rpmalloc_global_get_reserved_spans
+ span->span_count = (uint32_t)span_count;
+ }
+ }
+ }
+ if (!span)
+ span = _rpmalloc_span_map_aligned_count(heap, span_count);
+ if (use_global_reserve)
+ atomic_store32_release(&_memory_global_lock, 0);
+ return span;
+}
+
+//! Unmap memory pages for the given number of spans (or mark as unused if no partial unmappings)
+static void
+_rpmalloc_span_unmap(span_t* span) {
+ rpmalloc_assert((span->flags & SPAN_FLAG_MASTER) || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ rpmalloc_assert(!(span->flags & SPAN_FLAG_MASTER) || !(span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+
+ int is_master = !!(span->flags & SPAN_FLAG_MASTER);
+ span_t* master = is_master ? span : ((span_t*)pointer_offset(span, -(intptr_t)((uintptr_t)span->offset_from_master * _memory_span_size)));
+ rpmalloc_assert(is_master || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ rpmalloc_assert(master->flags & SPAN_FLAG_MASTER, "Span flag corrupted");
+
+ size_t span_count = span->span_count;
+ if (!is_master) {
+ //Directly unmap subspans (unless huge pages, in which case we defer and unmap entire page range with master)
+ rpmalloc_assert(span->align_offset == 0, "Span align offset corrupted");
+ if (_memory_span_size >= _memory_page_size)
+ _rpmalloc_unmap(span, span_count * _memory_span_size, 0, 0);
+ } else {
+ //Special double flag to denote an unmapped master
+ //It must be kept in memory since span header must be used
+ span->flags |= SPAN_FLAG_MASTER | SPAN_FLAG_SUBSPAN | SPAN_FLAG_UNMAPPED_MASTER;
+ _rpmalloc_stat_add(&_unmapped_master_spans, 1);
+ }
+
+ if (atomic_add32(&master->remaining_spans, -(int32_t)span_count) <= 0) {
+ //Everything unmapped, unmap the master span with release flag to unmap the entire range of the super span
+ rpmalloc_assert(!!(master->flags & SPAN_FLAG_MASTER) && !!(master->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ size_t unmap_count = master->span_count;
+ if (_memory_span_size < _memory_page_size)
+ unmap_count = master->total_spans;
+ _rpmalloc_stat_sub(&_master_spans, 1);
+ _rpmalloc_stat_sub(&_unmapped_master_spans, 1);
+ _rpmalloc_unmap(master, unmap_count * _memory_span_size, master->align_offset, (size_t)master->total_spans * _memory_span_size);
+ }
+}
+
+//! Move the span (used for small or medium allocations) to the heap thread cache
+static void
+_rpmalloc_span_release_to_cache(heap_t* heap, span_t* span) {
+ rpmalloc_assert(heap == span->heap, "Span heap pointer corrupted");
+ rpmalloc_assert(span->size_class < SIZE_CLASS_COUNT, "Invalid span size class");
+ rpmalloc_assert(span->span_count == 1, "Invalid span count");
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+ atomic_decr32(&heap->span_use[0].current);
+#endif
+ _rpmalloc_stat_dec(&heap->size_class_use[span->size_class].spans_current);
+ if (!heap->finalize) {
+ _rpmalloc_stat_inc(&heap->span_use[0].spans_to_cache);
+ _rpmalloc_stat_inc(&heap->size_class_use[span->size_class].spans_to_cache);
+ if (heap->size_class[span->size_class].cache)
+ _rpmalloc_heap_cache_insert(heap, heap->size_class[span->size_class].cache);
+ heap->size_class[span->size_class].cache = span;
+ } else {
+ _rpmalloc_span_unmap(span);
+ }
+}
+
+//! Initialize a (partial) free list up to next system memory page, while reserving the first block
+//! as allocated, returning number of blocks in list
+static uint32_t
+free_list_partial_init(void** list, void** first_block, void* page_start, void* block_start, uint32_t block_count, uint32_t block_size) {
+ rpmalloc_assert(block_count, "Internal failure");
+ *first_block = block_start;
+ if (block_count > 1) {
+ void* free_block = pointer_offset(block_start, block_size);
+ void* block_end = pointer_offset(block_start, (size_t)block_size * block_count);
+ //If block size is less than half a memory page, bound init to next memory page boundary
+ if (block_size < (_memory_page_size >> 1)) {
+ void* page_end = pointer_offset(page_start, _memory_page_size);
+ if (page_end < block_end)
+ block_end = page_end;
+ }
+ *list = free_block;
+ block_count = 2;
+ void* next_block = pointer_offset(free_block, block_size);
+ while (next_block < block_end) {
+ *((void**)free_block) = next_block;
+ free_block = next_block;
+ ++block_count;
+ next_block = pointer_offset(next_block, block_size);
+ }
+ *((void**)free_block) = 0;
+ } else {
+ *list = 0;
+ }
+ return block_count;
+}
+
+//! Initialize an unused span (from cache or mapped) to be new active span, putting the initial free list in heap class free list
+static void*
+_rpmalloc_span_initialize_new(heap_t* heap, heap_size_class_t* heap_size_class, span_t* span, uint32_t class_idx) {
+ rpmalloc_assert(span->span_count == 1, "Internal failure");
+ size_class_t* size_class = _memory_size_class + class_idx;
+ span->size_class = class_idx;
+ span->heap = heap;
+ span->flags &= ~SPAN_FLAG_ALIGNED_BLOCKS;
+ span->block_size = size_class->block_size;
+ span->block_count = size_class->block_count;
+ span->free_list = 0;
+ span->list_size = 0;
+ atomic_store_ptr_release(&span->free_list_deferred, 0);
+
+ //Setup free list. Only initialize one system page worth of free blocks in list
+ void* block;
+ span->free_list_limit = free_list_partial_init(&heap_size_class->free_list, &block,
+ span, pointer_offset(span, SPAN_HEADER_SIZE), size_class->block_count, size_class->block_size);
+ //Link span as partial if there remains blocks to be initialized as free list, or full if fully initialized
+ if (span->free_list_limit < span->block_count) {
+ _rpmalloc_span_double_link_list_add(&heap_size_class->partial_span, span);
+ span->used_count = span->free_list_limit;
+ } else {
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->full_span[class_idx], span);
+#endif
+ ++heap->full_span_count;
+ span->used_count = span->block_count;
+ }
+ return block;
+}
+
+static void
+_rpmalloc_span_extract_free_list_deferred(span_t* span) {
+ // We need acquire semantics on the CAS operation since we are interested in the list size
+ // Refer to _rpmalloc_deallocate_defer_small_or_medium for further comments on this dependency
+ do {
+ span->free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);
+ } while (span->free_list == INVALID_POINTER);
+ span->used_count -= span->list_size;
+ span->list_size = 0;
+ atomic_store_ptr_release(&span->free_list_deferred, 0);
+}
+
+static int
+_rpmalloc_span_is_fully_utilized(span_t* span) {
+ rpmalloc_assert(span->free_list_limit <= span->block_count, "Span free list corrupted");
+ return !span->free_list && (span->free_list_limit >= span->block_count);
+}
+
+static int
+_rpmalloc_span_finalize(heap_t* heap, size_t iclass, span_t* span, span_t** list_head) {
+ void* free_list = heap->size_class[iclass].free_list;
+ span_t* class_span = (span_t*)((uintptr_t)free_list & _memory_span_mask);
+ if (span == class_span) {
+ // Adopt the heap class free list back into the span free list
+ void* block = span->free_list;
+ void* last_block = 0;
+ while (block) {
+ last_block = block;
+ block = *((void**)block);
+ }
+ uint32_t free_count = 0;
+ block = free_list;
+ while (block) {
+ ++free_count;
+ block = *((void**)block);
+ }
+ if (last_block) {
+ *((void**)last_block) = free_list;
+ } else {
+ span->free_list = free_list;
+ }
+ heap->size_class[iclass].free_list = 0;
+ span->used_count -= free_count;
+ }
+ //If this assert triggers you have memory leaks
+ rpmalloc_assert(span->list_size == span->used_count, "Memory leak detected");
+ if (span->list_size == span->used_count) {
+ _rpmalloc_stat_dec(&heap->span_use[0].current);
+ _rpmalloc_stat_dec(&heap->size_class_use[iclass].spans_current);
+ // This function only used for spans in double linked lists
+ if (list_head)
+ _rpmalloc_span_double_link_list_remove(list_head, span);
+ _rpmalloc_span_unmap(span);
+ return 1;
+ }
+ return 0;
+}
+
+
+////////////
+///
+/// Global cache
+///
+//////
+
+#if ENABLE_GLOBAL_CACHE
+
+//! Finalize a global cache
+static void
+_rpmalloc_global_cache_finalize(global_cache_t* cache) {
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+
+ for (size_t ispan = 0; ispan < cache->count; ++ispan)
+ _rpmalloc_span_unmap(cache->span[ispan]);
+ cache->count = 0;
+
+ while (cache->overflow) {
+ span_t* span = cache->overflow;
+ cache->overflow = span->next;
+ _rpmalloc_span_unmap(span);
+ }
+
+ atomic_store32_release(&cache->lock, 0);
+}
+
+static void
+_rpmalloc_global_cache_insert_spans(span_t** span, size_t span_count, size_t count) {
+ const size_t cache_limit = (span_count == 1) ?
+ GLOBAL_CACHE_MULTIPLIER * MAX_THREAD_SPAN_CACHE :
+ GLOBAL_CACHE_MULTIPLIER * (MAX_THREAD_SPAN_LARGE_CACHE - (span_count >> 1));
+
+ global_cache_t* cache = &_memory_span_cache[span_count - 1];
+
+ size_t insert_count = count;
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+
+#if ENABLE_STATISTICS
+ cache->insert_count += count;
+#endif
+ if ((cache->count + insert_count) > cache_limit)
+ insert_count = cache_limit - cache->count;
+
+ memcpy(cache->span + cache->count, span, sizeof(span_t*) * insert_count);
+ cache->count += (uint32_t)insert_count;
+
+#if ENABLE_UNLIMITED_CACHE
+ while (insert_count < count) {
+#else
+ // Enable unlimited cache if huge pages, or we will leak since it is unlikely that an entire huge page
+ // will be unmapped, and we're unable to partially decommit a huge page
+ while ((_memory_page_size > _memory_span_size) && (insert_count < count)) {
+#endif
+ span_t* current_span = span[insert_count++];
+ current_span->next = cache->overflow;
+ cache->overflow = current_span;
+ }
+ atomic_store32_release(&cache->lock, 0);
+
+ span_t* keep = 0;
+ for (size_t ispan = insert_count; ispan < count; ++ispan) {
+ span_t* current_span = span[ispan];
+ // Keep master spans that has remaining subspans to avoid dangling them
+ if ((current_span->flags & SPAN_FLAG_MASTER) &&
+ (atomic_load32(¤t_span->remaining_spans) > (int32_t)current_span->span_count)) {
+ current_span->next = keep;
+ keep = current_span;
+ } else {
+ _rpmalloc_span_unmap(current_span);
+ }
+ }
+
+ if (keep) {
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+
+ size_t islot = 0;
+ while (keep) {
+ for (; islot < cache->count; ++islot) {
+ span_t* current_span = cache->span[islot];
+ if (!(current_span->flags & SPAN_FLAG_MASTER) || ((current_span->flags & SPAN_FLAG_MASTER) &&
+ (atomic_load32(¤t_span->remaining_spans) <= (int32_t)current_span->span_count))) {
+ _rpmalloc_span_unmap(current_span);
+ cache->span[islot] = keep;
+ break;
+ }
+ }
+ if (islot == cache->count)
+ break;
+ keep = keep->next;
+ }
+
+ if (keep) {
+ span_t* tail = keep;
+ while (tail->next)
+ tail = tail->next;
+ tail->next = cache->overflow;
+ cache->overflow = keep;
+ }
+
+ atomic_store32_release(&cache->lock, 0);
+ }
+}
+
+static size_t
+_rpmalloc_global_cache_extract_spans(span_t** span, size_t span_count, size_t count) {
+ global_cache_t* cache = &_memory_span_cache[span_count - 1];
+
+ size_t extract_count = 0;
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+
+#if ENABLE_STATISTICS
+ cache->extract_count += count;
+#endif
+ size_t want = count - extract_count;
+ if (want > cache->count)
+ want = cache->count;
+
+ memcpy(span + extract_count, cache->span + (cache->count - want), sizeof(span_t*) * want);
+ cache->count -= (uint32_t)want;
+ extract_count += want;
+
+ while ((extract_count < count) && cache->overflow) {
+ span_t* current_span = cache->overflow;
+ span[extract_count++] = current_span;
+ cache->overflow = current_span->next;
+ }
+
+#if ENABLE_ASSERTS
+ for (size_t ispan = 0; ispan < extract_count; ++ispan) {
+ rpmalloc_assert(span[ispan]->span_count == span_count, "Global cache span count mismatch");
+ }
+#endif
+
+ atomic_store32_release(&cache->lock, 0);
+
+ return extract_count;
+}
+
+#endif
+
+////////////
+///
+/// Heap control
+///
+//////
+
+static void _rpmalloc_deallocate_huge(span_t*);
+
+//! Store the given spans as reserve in the given heap
+static void
+_rpmalloc_heap_set_reserved_spans(heap_t* heap, span_t* master, span_t* reserve, size_t reserve_span_count) {
+ heap->span_reserve_master = master;
+ heap->span_reserve = reserve;
+ heap->spans_reserved = (uint32_t)reserve_span_count;
+}
+
+//! Adopt the deferred span cache list, optionally extracting the first single span for immediate re-use
+static void
+_rpmalloc_heap_cache_adopt_deferred(heap_t* heap, span_t** single_span) {
+ span_t* span = (span_t*)((void*)atomic_exchange_ptr_acquire(&heap->span_free_deferred, 0));
+ while (span) {
+ span_t* next_span = (span_t*)span->free_list;
+ rpmalloc_assert(span->heap == heap, "Span heap pointer corrupted");
+ if (EXPECTED(span->size_class < SIZE_CLASS_COUNT)) {
+ rpmalloc_assert(heap->full_span_count, "Heap span counter corrupted");
+ --heap->full_span_count;
+ _rpmalloc_stat_dec(&heap->span_use[0].spans_deferred);
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&heap->full_span[span->size_class], span);
+#endif
+ _rpmalloc_stat_dec(&heap->span_use[0].current);
+ _rpmalloc_stat_dec(&heap->size_class_use[span->size_class].spans_current);
+ if (single_span && !*single_span)
+ *single_span = span;
+ else
+ _rpmalloc_heap_cache_insert(heap, span);
+ } else {
+ if (span->size_class == SIZE_CLASS_HUGE) {
+ _rpmalloc_deallocate_huge(span);
+ } else {
+ rpmalloc_assert(span->size_class == SIZE_CLASS_LARGE, "Span size class invalid");
+ rpmalloc_assert(heap->full_span_count, "Heap span counter corrupted");
+ --heap->full_span_count;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&heap->large_huge_span, span);
+#endif
+ uint32_t idx = span->span_count - 1;
+ _rpmalloc_stat_dec(&heap->span_use[idx].spans_deferred);
+ _rpmalloc_stat_dec(&heap->span_use[idx].current);
+ if (!idx && single_span && !*single_span)
+ *single_span = span;
+ else
+ _rpmalloc_heap_cache_insert(heap, span);
+ }
+ }
+ span = next_span;
+ }
+}
+
+static void
+_rpmalloc_heap_unmap(heap_t* heap) {
+ if (!heap->master_heap) {
+ if ((heap->finalize > 1) && !atomic_load32(&heap->child_count)) {
+ span_t* span = (span_t*)((uintptr_t)heap & _memory_span_mask);
+ _rpmalloc_span_unmap(span);
+ }
+ } else {
+ if (atomic_decr32(&heap->master_heap->child_count) == 0) {
+ _rpmalloc_heap_unmap(heap->master_heap);
+ }
+ }
+}
+
+static void
+_rpmalloc_heap_global_finalize(heap_t* heap) {
+ if (heap->finalize++ > 1) {
+ --heap->finalize;
+ return;
+ }
+
+ _rpmalloc_heap_finalize(heap);
+
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+ span_cache->count = 0;
+ }
+#endif
+
+ if (heap->full_span_count) {
+ --heap->finalize;
+ return;
+ }
+
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ if (heap->size_class[iclass].free_list || heap->size_class[iclass].partial_span) {
+ --heap->finalize;
+ return;
+ }
+ }
+ //Heap is now completely free, unmap and remove from heap list
+ size_t list_idx = (size_t)heap->id % HEAP_ARRAY_SIZE;
+ heap_t* list_heap = _memory_heaps[list_idx];
+ if (list_heap == heap) {
+ _memory_heaps[list_idx] = heap->next_heap;
+ } else {
+ while (list_heap->next_heap != heap)
+ list_heap = list_heap->next_heap;
+ list_heap->next_heap = heap->next_heap;
+ }
+
+ _rpmalloc_heap_unmap(heap);
+}
+
+//! Insert a single span into thread heap cache, releasing to global cache if overflow
+static void
+_rpmalloc_heap_cache_insert(heap_t* heap, span_t* span) {
+ if (UNEXPECTED(heap->finalize != 0)) {
+ _rpmalloc_span_unmap(span);
+ _rpmalloc_heap_global_finalize(heap);
+ return;
+ }
+#if ENABLE_THREAD_CACHE
+ size_t span_count = span->span_count;
+ _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_to_cache);
+ if (span_count == 1) {
+ span_cache_t* span_cache = &heap->span_cache;
+ span_cache->span[span_cache->count++] = span;
+ if (span_cache->count == MAX_THREAD_SPAN_CACHE) {
+ const size_t remain_count = MAX_THREAD_SPAN_CACHE - THREAD_SPAN_CACHE_TRANSFER;
+#if ENABLE_GLOBAL_CACHE
+ _rpmalloc_stat_add64(&heap->thread_to_global, THREAD_SPAN_CACHE_TRANSFER * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_to_global, THREAD_SPAN_CACHE_TRANSFER);
+ _rpmalloc_global_cache_insert_spans(span_cache->span + remain_count, span_count, THREAD_SPAN_CACHE_TRANSFER);
+#else
+ for (size_t ispan = 0; ispan < THREAD_SPAN_CACHE_TRANSFER; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[remain_count + ispan]);
+#endif
+ span_cache->count = remain_count;
+ }
+ } else {
+ size_t cache_idx = span_count - 2;
+ span_large_cache_t* span_cache = heap->span_large_cache + cache_idx;
+ span_cache->span[span_cache->count++] = span;
+ const size_t cache_limit = (MAX_THREAD_SPAN_LARGE_CACHE - (span_count >> 1));
+ if (span_cache->count == cache_limit) {
+ const size_t transfer_limit = 2 + (cache_limit >> 2);
+ const size_t transfer_count = (THREAD_SPAN_LARGE_CACHE_TRANSFER <= transfer_limit ? THREAD_SPAN_LARGE_CACHE_TRANSFER : transfer_limit);
+ const size_t remain_count = cache_limit - transfer_count;
+#if ENABLE_GLOBAL_CACHE
+ _rpmalloc_stat_add64(&heap->thread_to_global, transfer_count * span_count * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_to_global, transfer_count);
+ _rpmalloc_global_cache_insert_spans(span_cache->span + remain_count, span_count, transfer_count);
+#else
+ for (size_t ispan = 0; ispan < transfer_count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[remain_count + ispan]);
+#endif
+ span_cache->count = remain_count;
+ }
+ }
+#else
+ (void)sizeof(heap);
+ _rpmalloc_span_unmap(span);
+#endif
+}
+
+//! Extract the given number of spans from the different cache levels
+static span_t*
+_rpmalloc_heap_thread_cache_extract(heap_t* heap, size_t span_count) {
+ span_t* span = 0;
+#if ENABLE_THREAD_CACHE
+ span_cache_t* span_cache;
+ if (span_count == 1)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (span_count - 2));
+ if (span_cache->count) {
+ _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_from_cache);
+ return span_cache->span[--span_cache->count];
+ }
+#endif
+ return span;
+}
+
+static span_t*
+_rpmalloc_heap_thread_cache_deferred_extract(heap_t* heap, size_t span_count) {
+ span_t* span = 0;
+ if (span_count == 1) {
+ _rpmalloc_heap_cache_adopt_deferred(heap, &span);
+ } else {
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+ span = _rpmalloc_heap_thread_cache_extract(heap, span_count);
+ }
+ return span;
+}
+
+static span_t*
+_rpmalloc_heap_reserved_extract(heap_t* heap, size_t span_count) {
+ if (heap->spans_reserved >= span_count)
+ return _rpmalloc_span_map(heap, span_count);
+ return 0;
+}
+
+//! Extract a span from the global cache
+static span_t*
+_rpmalloc_heap_global_cache_extract(heap_t* heap, size_t span_count) {
+#if ENABLE_GLOBAL_CACHE
+#if ENABLE_THREAD_CACHE
+ span_cache_t* span_cache;
+ size_t wanted_count;
+ if (span_count == 1) {
+ span_cache = &heap->span_cache;
+ wanted_count = THREAD_SPAN_CACHE_TRANSFER;
+ } else {
+ span_cache = (span_cache_t*)(heap->span_large_cache + (span_count - 2));
+ wanted_count = THREAD_SPAN_LARGE_CACHE_TRANSFER;
+ }
+ span_cache->count = _rpmalloc_global_cache_extract_spans(span_cache->span, span_count, wanted_count);
+ if (span_cache->count) {
+ _rpmalloc_stat_add64(&heap->global_to_thread, span_count * span_cache->count * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_from_global, span_cache->count);
+ return span_cache->span[--span_cache->count];
+ }
+#else
+ span_t* span = 0;
+ size_t count = _rpmalloc_global_cache_extract_spans(&span, span_count, 1);
+ if (count) {
+ _rpmalloc_stat_add64(&heap->global_to_thread, span_count * count * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_from_global, count);
+ return span;
+ }
+#endif
+#endif
+ (void)sizeof(heap);
+ (void)sizeof(span_count);
+ return 0;
+}
+
+static void
+_rpmalloc_inc_span_statistics(heap_t* heap, size_t span_count, uint32_t class_idx) {
+ (void)sizeof(heap);
+ (void)sizeof(span_count);
+ (void)sizeof(class_idx);
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+ uint32_t idx = (uint32_t)span_count - 1;
+ uint32_t current_count = (uint32_t)atomic_incr32(&heap->span_use[idx].current);
+ if (current_count > (uint32_t)atomic_load32(&heap->span_use[idx].high))
+ atomic_store32(&heap->span_use[idx].high, (int32_t)current_count);
+ _rpmalloc_stat_add_peak(&heap->size_class_use[class_idx].spans_current, 1, heap->size_class_use[class_idx].spans_peak);
+#endif
+}
+
+//! Get a span from one of the cache levels (thread cache, reserved, global cache) or fallback to mapping more memory
+static span_t*
+_rpmalloc_heap_extract_new_span(heap_t* heap, heap_size_class_t* heap_size_class, size_t span_count, uint32_t class_idx) {
+ span_t* span;
+#if ENABLE_THREAD_CACHE
+ if (heap_size_class && heap_size_class->cache) {
+ span = heap_size_class->cache;
+ heap_size_class->cache = (heap->span_cache.count ? heap->span_cache.span[--heap->span_cache.count] : 0);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+#endif
+ (void)sizeof(class_idx);
+ // Allow 50% overhead to increase cache hits
+ size_t base_span_count = span_count;
+ size_t limit_span_count = (span_count > 2) ? (span_count + (span_count >> 1)) : span_count;
+ if (limit_span_count > LARGE_CLASS_COUNT)
+ limit_span_count = LARGE_CLASS_COUNT;
+ do {
+ span = _rpmalloc_heap_thread_cache_extract(heap, span_count);
+ if (EXPECTED(span != 0)) {
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+ span = _rpmalloc_heap_thread_cache_deferred_extract(heap, span_count);
+ if (EXPECTED(span != 0)) {
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+ span = _rpmalloc_heap_reserved_extract(heap, span_count);
+ if (EXPECTED(span != 0)) {
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_reserved);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+ span = _rpmalloc_heap_global_cache_extract(heap, span_count);
+ if (EXPECTED(span != 0)) {
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+ ++span_count;
+ } while (span_count <= limit_span_count);
+ //Final fallback, map in more virtual memory
+ span = _rpmalloc_span_map(heap, base_span_count);
+ _rpmalloc_inc_span_statistics(heap, base_span_count, class_idx);
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_map_calls);
+ return span;
+}
+
+static void
+_rpmalloc_heap_initialize(heap_t* heap) {
+ _rpmalloc_memset_const(heap, 0, sizeof(heap_t));
+ //Get a new heap ID
+ heap->id = 1 + atomic_incr32(&_memory_heap_id);
+
+ //Link in heap in heap ID map
+ size_t list_idx = (size_t)heap->id % HEAP_ARRAY_SIZE;
+ heap->next_heap = _memory_heaps[list_idx];
+ _memory_heaps[list_idx] = heap;
+}
+
+static void
+_rpmalloc_heap_orphan(heap_t* heap, int first_class) {
+ heap->owner_thread = (uintptr_t)-1;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ heap_t** heap_list = (first_class ? &_memory_first_class_orphan_heaps : &_memory_orphan_heaps);
+#else
+ (void)sizeof(first_class);
+ heap_t** heap_list = &_memory_orphan_heaps;
+#endif
+ heap->next_orphan = *heap_list;
+ *heap_list = heap;
+}
+
+//! Allocate a new heap from newly mapped memory pages
+static heap_t*
+_rpmalloc_heap_allocate_new(void) {
+ // Map in pages for a 16 heaps. If page size is greater than required size for this, map a page and
+ // use first part for heaps and remaining part for spans for allocations. Adds a lot of complexity,
+ // but saves a lot of memory on systems where page size > 64 spans (4MiB)
+ size_t heap_size = sizeof(heap_t);
+ size_t aligned_heap_size = 16 * ((heap_size + 15) / 16);
+ size_t request_heap_count = 16;
+ size_t heap_span_count = ((aligned_heap_size * request_heap_count) + sizeof(span_t) + _memory_span_size - 1) / _memory_span_size;
+ size_t block_size = _memory_span_size * heap_span_count;
+ size_t span_count = heap_span_count;
+ span_t* span = 0;
+ // If there are global reserved spans, use these first
+ if (_memory_global_reserve_count >= heap_span_count) {
+ span = _rpmalloc_global_get_reserved_spans(heap_span_count);
+ }
+ if (!span) {
+ if (_memory_page_size > block_size) {
+ span_count = _memory_page_size / _memory_span_size;
+ block_size = _memory_page_size;
+ // If using huge pages, make sure to grab enough heaps to avoid reallocating a huge page just to serve new heaps
+ size_t possible_heap_count = (block_size - sizeof(span_t)) / aligned_heap_size;
+ if (possible_heap_count >= (request_heap_count * 16))
+ request_heap_count *= 16;
+ else if (possible_heap_count < request_heap_count)
+ request_heap_count = possible_heap_count;
+ heap_span_count = ((aligned_heap_size * request_heap_count) + sizeof(span_t) + _memory_span_size - 1) / _memory_span_size;
+ }
+
+ size_t align_offset = 0;
+ span = (span_t*)_rpmalloc_mmap(block_size, &align_offset);
+ if (!span)
+ return 0;
+
+ // Master span will contain the heaps
+ _rpmalloc_stat_inc(&_master_spans);
+ _rpmalloc_span_initialize(span, span_count, heap_span_count, align_offset);
+ }
+
+ size_t remain_size = _memory_span_size - sizeof(span_t);
+ heap_t* heap = (heap_t*)pointer_offset(span, sizeof(span_t));
+ _rpmalloc_heap_initialize(heap);
+
+ // Put extra heaps as orphans
+ size_t num_heaps = remain_size / aligned_heap_size;
+ if (num_heaps < request_heap_count)
+ num_heaps = request_heap_count;
+ atomic_store32(&heap->child_count, (int32_t)num_heaps - 1);
+ heap_t* extra_heap = (heap_t*)pointer_offset(heap, aligned_heap_size);
+ while (num_heaps > 1) {
+ _rpmalloc_heap_initialize(extra_heap);
+ extra_heap->master_heap = heap;
+ _rpmalloc_heap_orphan(extra_heap, 1);
+ extra_heap = (heap_t*)pointer_offset(extra_heap, aligned_heap_size);
+ --num_heaps;
+ }
+
+ if (span_count > heap_span_count) {
+ // Cap reserved spans
+ size_t remain_count = span_count - heap_span_count;
+ size_t reserve_count = (remain_count > _memory_heap_reserve_count ? _memory_heap_reserve_count : remain_count);
+ span_t* remain_span = (span_t*)pointer_offset(span, heap_span_count * _memory_span_size);
+ _rpmalloc_heap_set_reserved_spans(heap, span, remain_span, reserve_count);
+
+ if (remain_count > reserve_count) {
+ // Set to global reserved spans
+ remain_span = (span_t*)pointer_offset(remain_span, reserve_count * _memory_span_size);
+ reserve_count = remain_count - reserve_count;
+ _rpmalloc_global_set_reserved_spans(span, remain_span, reserve_count);
+ }
+ }
+
+ return heap;
+}
+
+static heap_t*
+_rpmalloc_heap_extract_orphan(heap_t** heap_list) {
+ heap_t* heap = *heap_list;
+ *heap_list = (heap ? heap->next_orphan : 0);
+ return heap;
+}
+
+//! Allocate a new heap, potentially reusing a previously orphaned heap
+static heap_t*
+_rpmalloc_heap_allocate(int first_class) {
+ heap_t* heap = 0;
+ while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))
+ _rpmalloc_spin();
+ if (first_class == 0)
+ heap = _rpmalloc_heap_extract_orphan(&_memory_orphan_heaps);
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ if (!heap)
+ heap = _rpmalloc_heap_extract_orphan(&_memory_first_class_orphan_heaps);
+#endif
+ if (!heap)
+ heap = _rpmalloc_heap_allocate_new();
+ atomic_store32_release(&_memory_global_lock, 0);
+ if (heap)
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+ return heap;
+}
+
+static void
+_rpmalloc_heap_release(void* heapptr, int first_class, int release_cache) {
+ heap_t* heap = (heap_t*)heapptr;
+ if (!heap)
+ return;
+ //Release thread cache spans back to global cache
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+ if (release_cache || heap->finalize) {
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ if (!span_cache->count)
+ continue;
+#if ENABLE_GLOBAL_CACHE
+ if (heap->finalize) {
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+ } else {
+ _rpmalloc_stat_add64(&heap->thread_to_global, span_cache->count * (iclass + 1) * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[iclass].spans_to_global, span_cache->count);
+ _rpmalloc_global_cache_insert_spans(span_cache->span, iclass + 1, span_cache->count);
+ }
+#else
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+#endif
+ span_cache->count = 0;
+ }
+#endif
+ }
+
+ if (get_thread_heap_raw() == heap)
+ set_thread_heap(0);
+
+#if ENABLE_STATISTICS
+ atomic_decr32(&_memory_active_heaps);
+ rpmalloc_assert(atomic_load32(&_memory_active_heaps) >= 0, "Still active heaps during finalization");
+#endif
+
+ // If we are forcibly terminating with _exit the state of the
+ // lock atomic is unknown and it's best to just go ahead and exit
+ if (get_thread_id() != _rpmalloc_main_thread_id) {
+ while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))
+ _rpmalloc_spin();
+ }
+ _rpmalloc_heap_orphan(heap, first_class);
+ atomic_store32_release(&_memory_global_lock, 0);
+}
+
+static void
+_rpmalloc_heap_release_raw(void* heapptr, int release_cache) {
+ _rpmalloc_heap_release(heapptr, 0, release_cache);
+}
+
+static void
+_rpmalloc_heap_release_raw_fc(void* heapptr) {
+ _rpmalloc_heap_release_raw(heapptr, 1);
+}
+
+static void
+_rpmalloc_heap_finalize(heap_t* heap) {
+ if (heap->spans_reserved) {
+ span_t* span = _rpmalloc_span_map(heap, heap->spans_reserved);
+ _rpmalloc_span_unmap(span);
+ heap->spans_reserved = 0;
+ }
+
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ if (heap->size_class[iclass].cache)
+ _rpmalloc_span_unmap(heap->size_class[iclass].cache);
+ heap->size_class[iclass].cache = 0;
+ span_t* span = heap->size_class[iclass].partial_span;
+ while (span) {
+ span_t* next = span->next;
+ _rpmalloc_span_finalize(heap, iclass, span, &heap->size_class[iclass].partial_span);
+ span = next;
+ }
+ // If class still has a free list it must be a full span
+ if (heap->size_class[iclass].free_list) {
+ span_t* class_span = (span_t*)((uintptr_t)heap->size_class[iclass].free_list & _memory_span_mask);
+ span_t** list = 0;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ list = &heap->full_span[iclass];
+#endif
+ --heap->full_span_count;
+ if (!_rpmalloc_span_finalize(heap, iclass, class_span, list)) {
+ if (list)
+ _rpmalloc_span_double_link_list_remove(list, class_span);
+ _rpmalloc_span_double_link_list_add(&heap->size_class[iclass].partial_span, class_span);
+ }
+ }
+ }
+
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+ span_cache->count = 0;
+ }
+#endif
+ rpmalloc_assert(!atomic_load_ptr(&heap->span_free_deferred), "Heaps still active during finalization");
+}
+
+
+////////////
+///
+/// Allocation entry points
+///
+//////
+
+//! Pop first block from a free list
+static void*
+free_list_pop(void** list) {
+ void* block = *list;
+ *list = *((void**)block);
+ return block;
+}
+
+//! Allocate a small/medium sized memory block from the given heap
+static void*
+_rpmalloc_allocate_from_heap_fallback(heap_t* heap, heap_size_class_t* heap_size_class, uint32_t class_idx) {
+ span_t* span = heap_size_class->partial_span;
+ rpmalloc_assume(heap != 0);
+ if (EXPECTED(span != 0)) {
+ rpmalloc_assert(span->block_count == _memory_size_class[span->size_class].block_count, "Span block count corrupted");
+ rpmalloc_assert(!_rpmalloc_span_is_fully_utilized(span), "Internal failure");
+ void* block;
+ if (span->free_list) {
+ //Span local free list is not empty, swap to size class free list
+ block = free_list_pop(&span->free_list);
+ heap_size_class->free_list = span->free_list;
+ span->free_list = 0;
+ } else {
+ //If the span did not fully initialize free list, link up another page worth of blocks
+ void* block_start = pointer_offset(span, SPAN_HEADER_SIZE + ((size_t)span->free_list_limit * span->block_size));
+ span->free_list_limit += free_list_partial_init(&heap_size_class->free_list, &block,
+ (void*)((uintptr_t)block_start & ~(_memory_page_size - 1)), block_start,
+ span->block_count - span->free_list_limit, span->block_size);
+ }
+ rpmalloc_assert(span->free_list_limit <= span->block_count, "Span block count corrupted");
+ span->used_count = span->free_list_limit;
+
+ //Swap in deferred free list if present
+ if (atomic_load_ptr(&span->free_list_deferred))
+ _rpmalloc_span_extract_free_list_deferred(span);
+
+ //If span is still not fully utilized keep it in partial list and early return block
+ if (!_rpmalloc_span_is_fully_utilized(span))
+ return block;
+
+ //The span is fully utilized, unlink from partial list and add to fully utilized list
+ _rpmalloc_span_double_link_list_pop_head(&heap_size_class->partial_span, span);
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->full_span[class_idx], span);
+#endif
+ ++heap->full_span_count;
+ return block;
+ }
+
+ //Find a span in one of the cache levels
+ span = _rpmalloc_heap_extract_new_span(heap, heap_size_class, 1, class_idx);
+ if (EXPECTED(span != 0)) {
+ //Mark span as owned by this heap and set base data, return first block
+ return _rpmalloc_span_initialize_new(heap, heap_size_class, span, class_idx);
+ }
+
+ return 0;
+}
+
+//! Allocate a small sized memory block from the given heap
+static void*
+_rpmalloc_allocate_small(heap_t* heap, size_t size) {
+ rpmalloc_assert(heap, "No thread heap");
+ //Small sizes have unique size classes
+ const uint32_t class_idx = (uint32_t)((size + (SMALL_GRANULARITY - 1)) >> SMALL_GRANULARITY_SHIFT);
+ heap_size_class_t* heap_size_class = heap->size_class + class_idx;
+ _rpmalloc_stat_inc_alloc(heap, class_idx);
+ if (EXPECTED(heap_size_class->free_list != 0))
+ return free_list_pop(&heap_size_class->free_list);
+ return _rpmalloc_allocate_from_heap_fallback(heap, heap_size_class, class_idx);
+}
+
+//! Allocate a medium sized memory block from the given heap
+static void*
+_rpmalloc_allocate_medium(heap_t* heap, size_t size) {
+ rpmalloc_assert(heap, "No thread heap");
+ //Calculate the size class index and do a dependent lookup of the final class index (in case of merged classes)
+ const uint32_t base_idx = (uint32_t)(SMALL_CLASS_COUNT + ((size - (SMALL_SIZE_LIMIT + 1)) >> MEDIUM_GRANULARITY_SHIFT));
+ const uint32_t class_idx = _memory_size_class[base_idx].class_idx;
+ heap_size_class_t* heap_size_class = heap->size_class + class_idx;
+ _rpmalloc_stat_inc_alloc(heap, class_idx);
+ if (EXPECTED(heap_size_class->free_list != 0))
+ return free_list_pop(&heap_size_class->free_list);
+ return _rpmalloc_allocate_from_heap_fallback(heap, heap_size_class, class_idx);
+}
+
+//! Allocate a large sized memory block from the given heap
+static void*
+_rpmalloc_allocate_large(heap_t* heap, size_t size) {
+ rpmalloc_assert(heap, "No thread heap");
+ //Calculate number of needed max sized spans (including header)
+ //Since this function is never called if size > LARGE_SIZE_LIMIT
+ //the span_count is guaranteed to be <= LARGE_CLASS_COUNT
+ size += SPAN_HEADER_SIZE;
+ size_t span_count = size >> _memory_span_size_shift;
+ if (size & (_memory_span_size - 1))
+ ++span_count;
+
+ //Find a span in one of the cache levels
+ span_t* span = _rpmalloc_heap_extract_new_span(heap, 0, span_count, SIZE_CLASS_LARGE);
+ if (!span)
+ return span;
+
+ //Mark span as owned by this heap and set base data
+ rpmalloc_assert(span->span_count >= span_count, "Internal failure");
+ span->size_class = SIZE_CLASS_LARGE;
+ span->heap = heap;
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);
+#endif
+ ++heap->full_span_count;
+
+ return pointer_offset(span, SPAN_HEADER_SIZE);
+}
+
+//! Allocate a huge block by mapping memory pages directly
+static void*
+_rpmalloc_allocate_huge(heap_t* heap, size_t size) {
+ rpmalloc_assert(heap, "No thread heap");
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+ size += SPAN_HEADER_SIZE;
+ size_t num_pages = size >> _memory_page_size_shift;
+ if (size & (_memory_page_size - 1))
+ ++num_pages;
+ size_t align_offset = 0;
+ span_t* span = (span_t*)_rpmalloc_mmap(num_pages * _memory_page_size, &align_offset);
+ if (!span)
+ return span;
+
+ //Store page count in span_count
+ span->size_class = SIZE_CLASS_HUGE;
+ span->span_count = (uint32_t)num_pages;
+ span->align_offset = (uint32_t)align_offset;
+ span->heap = heap;
+ _rpmalloc_stat_add_peak(&_huge_pages_current, num_pages, _huge_pages_peak);
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);
+#endif
+ ++heap->full_span_count;
+
+ return pointer_offset(span, SPAN_HEADER_SIZE);
+}
+
+//! Allocate a block of the given size
+static void*
+_rpmalloc_allocate(heap_t* heap, size_t size) {
+ _rpmalloc_stat_add64(&_allocation_counter, 1);
+ if (EXPECTED(size <= SMALL_SIZE_LIMIT))
+ return _rpmalloc_allocate_small(heap, size);
+ else if (size <= _memory_medium_size_limit)
+ return _rpmalloc_allocate_medium(heap, size);
+ else if (size <= LARGE_SIZE_LIMIT)
+ return _rpmalloc_allocate_large(heap, size);
+ return _rpmalloc_allocate_huge(heap, size);
+}
+
+static void*
+_rpmalloc_aligned_allocate(heap_t* heap, size_t alignment, size_t size) {
+ if (alignment <= SMALL_GRANULARITY)
+ return _rpmalloc_allocate(heap, size);
+
+#if ENABLE_VALIDATE_ARGS
+ if ((size + alignment) < size) {
+ errno = EINVAL;
+ return 0;
+ }
+ if (alignment & (alignment - 1)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+
+ if ((alignment <= SPAN_HEADER_SIZE) && ((size + SPAN_HEADER_SIZE) < _memory_medium_size_limit)) {
+ // If alignment is less or equal to span header size (which is power of two),
+ // and size aligned to span header size multiples is less than size + alignment,
+ // then use natural alignment of blocks to provide alignment
+ size_t multiple_size = size ? (size + (SPAN_HEADER_SIZE - 1)) & ~(uintptr_t)(SPAN_HEADER_SIZE - 1) : SPAN_HEADER_SIZE;
+ rpmalloc_assert(!(multiple_size % SPAN_HEADER_SIZE), "Failed alignment calculation");
+ if (multiple_size <= (size + alignment))
+ return _rpmalloc_allocate(heap, multiple_size);
+ }
+
+ void* ptr = 0;
+ size_t align_mask = alignment - 1;
+ if (alignment <= _memory_page_size) {
+ ptr = _rpmalloc_allocate(heap, size + alignment);
+ if ((uintptr_t)ptr & align_mask) {
+ ptr = (void*)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment);
+ //Mark as having aligned blocks
+ span_t* span = (span_t*)((uintptr_t)ptr & _memory_span_mask);
+ span->flags |= SPAN_FLAG_ALIGNED_BLOCKS;
+ }
+ return ptr;
+ }
+
+ // Fallback to mapping new pages for this request. Since pointers passed
+ // to rpfree must be able to reach the start of the span by bitmasking of
+ // the address with the span size, the returned aligned pointer from this
+ // function must be with a span size of the start of the mapped area.
+ // In worst case this requires us to loop and map pages until we get a
+ // suitable memory address. It also means we can never align to span size
+ // or greater, since the span header will push alignment more than one
+ // span size away from span start (thus causing pointer mask to give us
+ // an invalid span start on free)
+ if (alignment & align_mask) {
+ errno = EINVAL;
+ return 0;
+ }
+ if (alignment >= _memory_span_size) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ size_t extra_pages = alignment / _memory_page_size;
+
+ // Since each span has a header, we will at least need one extra memory page
+ size_t num_pages = 1 + (size / _memory_page_size);
+ if (size & (_memory_page_size - 1))
+ ++num_pages;
+
+ if (extra_pages > num_pages)
+ num_pages = 1 + extra_pages;
+
+ size_t original_pages = num_pages;
+ size_t limit_pages = (_memory_span_size / _memory_page_size) * 2;
+ if (limit_pages < (original_pages * 2))
+ limit_pages = original_pages * 2;
+
+ size_t mapped_size, align_offset;
+ span_t* span;
+
+retry:
+ align_offset = 0;
+ mapped_size = num_pages * _memory_page_size;
+
+ span = (span_t*)_rpmalloc_mmap(mapped_size, &align_offset);
+ if (!span) {
+ errno = ENOMEM;
+ return 0;
+ }
+ ptr = pointer_offset(span, SPAN_HEADER_SIZE);
+
+ if ((uintptr_t)ptr & align_mask)
+ ptr = (void*)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment);
+
+ if (((size_t)pointer_diff(ptr, span) >= _memory_span_size) ||
+ (pointer_offset(ptr, size) > pointer_offset(span, mapped_size)) ||
+ (((uintptr_t)ptr & _memory_span_mask) != (uintptr_t)span)) {
+ _rpmalloc_unmap(span, mapped_size, align_offset, mapped_size);
+ ++num_pages;
+ if (num_pages > limit_pages) {
+ errno = EINVAL;
+ return 0;
+ }
+ goto retry;
+ }
+
+ //Store page count in span_count
+ span->size_class = SIZE_CLASS_HUGE;
+ span->span_count = (uint32_t)num_pages;
+ span->align_offset = (uint32_t)align_offset;
+ span->heap = heap;
+ _rpmalloc_stat_add_peak(&_huge_pages_current, num_pages, _huge_pages_peak);
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);
+#endif
+ ++heap->full_span_count;
+
+ _rpmalloc_stat_add64(&_allocation_counter, 1);
+
+ return ptr;
+}
+
+
+////////////
+///
+/// Deallocation entry points
+///
+//////
+
+//! Deallocate the given small/medium memory block in the current thread local heap
+static void
+_rpmalloc_deallocate_direct_small_or_medium(span_t* span, void* block) {
+ heap_t* heap = span->heap;
+ rpmalloc_assert(heap->owner_thread == get_thread_id() || !heap->owner_thread || heap->finalize, "Internal failure");
+ //Add block to free list
+ if (UNEXPECTED(_rpmalloc_span_is_fully_utilized(span))) {
+ span->used_count = span->block_count;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&heap->full_span[span->size_class], span);
+#endif
+ _rpmalloc_span_double_link_list_add(&heap->size_class[span->size_class].partial_span, span);
+ --heap->full_span_count;
+ }
+ *((void**)block) = span->free_list;
+ --span->used_count;
+ span->free_list = block;
+ if (UNEXPECTED(span->used_count == span->list_size)) {
+ // If there are no used blocks it is guaranteed that no other external thread is accessing the span
+ if (span->used_count) {
+ // Make sure we have synchronized the deferred list and list size by using acquire semantics
+ // and guarantee that no external thread is accessing span concurrently
+ void* free_list;
+ do {
+ free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);
+ } while (free_list == INVALID_POINTER);
+ atomic_store_ptr_release(&span->free_list_deferred, free_list);
+ }
+ _rpmalloc_span_double_link_list_remove(&heap->size_class[span->size_class].partial_span, span);
+ _rpmalloc_span_release_to_cache(heap, span);
+ }
+}
+
+static void
+_rpmalloc_deallocate_defer_free_span(heap_t* heap, span_t* span) {
+ if (span->size_class != SIZE_CLASS_HUGE)
+ _rpmalloc_stat_inc(&heap->span_use[span->span_count - 1].spans_deferred);
+ //This list does not need ABA protection, no mutable side state
+ do {
+ span->free_list = (void*)atomic_load_ptr(&heap->span_free_deferred);
+ } while (!atomic_cas_ptr(&heap->span_free_deferred, span, span->free_list));
+}
+
+//! Put the block in the deferred free list of the owning span
+static void
+_rpmalloc_deallocate_defer_small_or_medium(span_t* span, void* block) {
+ // The memory ordering here is a bit tricky, to avoid having to ABA protect
+ // the deferred free list to avoid desynchronization of list and list size
+ // we need to have acquire semantics on successful CAS of the pointer to
+ // guarantee the list_size variable validity + release semantics on pointer store
+ void* free_list;
+ do {
+ free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);
+ } while (free_list == INVALID_POINTER);
+ *((void**)block) = free_list;
+ uint32_t free_count = ++span->list_size;
+ int all_deferred_free = (free_count == span->block_count);
+ atomic_store_ptr_release(&span->free_list_deferred, block);
+ if (all_deferred_free) {
+ // Span was completely freed by this block. Due to the INVALID_POINTER spin lock
+ // no other thread can reach this state simultaneously on this span.
+ // Safe to move to owner heap deferred cache
+ _rpmalloc_deallocate_defer_free_span(span->heap, span);
+ }
+}
+
+static void
+_rpmalloc_deallocate_small_or_medium(span_t* span, void* p) {
+ _rpmalloc_stat_inc_free(span->heap, span->size_class);
+ if (span->flags & SPAN_FLAG_ALIGNED_BLOCKS) {
+ //Realign pointer to block start
+ void* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);
+ uint32_t block_offset = (uint32_t)pointer_diff(p, blocks_start);
+ p = pointer_offset(p, -(int32_t)(block_offset % span->block_size));
+ }
+ //Check if block belongs to this heap or if deallocation should be deferred
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#else
+ int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#endif
+ if (!defer)
+ _rpmalloc_deallocate_direct_small_or_medium(span, p);
+ else
+ _rpmalloc_deallocate_defer_small_or_medium(span, p);
+}
+
+//! Deallocate the given large memory block to the current heap
+static void
+_rpmalloc_deallocate_large(span_t* span) {
+ rpmalloc_assert(span->size_class == SIZE_CLASS_LARGE, "Bad span size class");
+ rpmalloc_assert(!(span->flags & SPAN_FLAG_MASTER) || !(span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ rpmalloc_assert((span->flags & SPAN_FLAG_MASTER) || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ //We must always defer (unless finalizing) if from another heap since we cannot touch the list or counters of another heap
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#else
+ int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#endif
+ if (defer) {
+ _rpmalloc_deallocate_defer_free_span(span->heap, span);
+ return;
+ }
+ rpmalloc_assert(span->heap->full_span_count, "Heap span counter corrupted");
+ --span->heap->full_span_count;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&span->heap->large_huge_span, span);
+#endif
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+ //Decrease counter
+ size_t idx = span->span_count - 1;
+ atomic_decr32(&span->heap->span_use[idx].current);
+#endif
+ heap_t* heap = span->heap;
+ rpmalloc_assert(heap, "No thread heap");
+#if ENABLE_THREAD_CACHE
+ const int set_as_reserved = ((span->span_count > 1) && (heap->span_cache.count == 0) && !heap->finalize && !heap->spans_reserved);
+#else
+ const int set_as_reserved = ((span->span_count > 1) && !heap->finalize && !heap->spans_reserved);
+#endif
+ if (set_as_reserved) {
+ heap->span_reserve = span;
+ heap->spans_reserved = span->span_count;
+ if (span->flags & SPAN_FLAG_MASTER) {
+ heap->span_reserve_master = span;
+ } else { //SPAN_FLAG_SUBSPAN
+ span_t* master = (span_t*)pointer_offset(span, -(intptr_t)((size_t)span->offset_from_master * _memory_span_size));
+ heap->span_reserve_master = master;
+ rpmalloc_assert(master->flags & SPAN_FLAG_MASTER, "Span flag corrupted");
+ rpmalloc_assert(atomic_load32(&master->remaining_spans) >= (int32_t)span->span_count, "Master span count corrupted");
+ }
+ _rpmalloc_stat_inc(&heap->span_use[idx].spans_to_reserved);
+ } else {
+ //Insert into cache list
+ _rpmalloc_heap_cache_insert(heap, span);
+ }
+}
+
+//! Deallocate the given huge span
+static void
+_rpmalloc_deallocate_huge(span_t* span) {
+ rpmalloc_assert(span->heap, "No span heap");
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#else
+ int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#endif
+ if (defer) {
+ _rpmalloc_deallocate_defer_free_span(span->heap, span);
+ return;
+ }
+ rpmalloc_assert(span->heap->full_span_count, "Heap span counter corrupted");
+ --span->heap->full_span_count;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&span->heap->large_huge_span, span);
+#endif
+
+ //Oversized allocation, page count is stored in span_count
+ size_t num_pages = span->span_count;
+ _rpmalloc_unmap(span, num_pages * _memory_page_size, span->align_offset, num_pages * _memory_page_size);
+ _rpmalloc_stat_sub(&_huge_pages_current, num_pages);
+}
+
+//! Deallocate the given block
+static void
+_rpmalloc_deallocate(void* p) {
+ _rpmalloc_stat_add64(&_deallocation_counter, 1);
+ //Grab the span (always at start of span, using span alignment)
+ span_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);
+ if (UNEXPECTED(!span))
+ return;
+ if (EXPECTED(span->size_class < SIZE_CLASS_COUNT))
+ _rpmalloc_deallocate_small_or_medium(span, p);
+ else if (span->size_class == SIZE_CLASS_LARGE)
+ _rpmalloc_deallocate_large(span);
+ else
+ _rpmalloc_deallocate_huge(span);
+}
+
+////////////
+///
+/// Reallocation entry points
+///
+//////
+
+static size_t
+_rpmalloc_usable_size(void* p);
+
+//! Reallocate the given block to the given size
+static void*
+_rpmalloc_reallocate(heap_t* heap, void* p, size_t size, size_t oldsize, unsigned int flags) {
+ if (p) {
+ //Grab the span using guaranteed span alignment
+ span_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);
+ if (EXPECTED(span->size_class < SIZE_CLASS_COUNT)) {
+ //Small/medium sized block
+ rpmalloc_assert(span->span_count == 1, "Span counter corrupted");
+ void* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);
+ uint32_t block_offset = (uint32_t)pointer_diff(p, blocks_start);
+ uint32_t block_idx = block_offset / span->block_size;
+ void* block = pointer_offset(blocks_start, (size_t)block_idx * span->block_size);
+ if (!oldsize)
+ oldsize = (size_t)((ptrdiff_t)span->block_size - pointer_diff(p, block));
+ if ((size_t)span->block_size >= size) {
+ //Still fits in block, never mind trying to save memory, but preserve data if alignment changed
+ if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))
+ memmove(block, p, oldsize);
+ return block;
+ }
+ } else if (span->size_class == SIZE_CLASS_LARGE) {
+ //Large block
+ size_t total_size = size + SPAN_HEADER_SIZE;
+ size_t num_spans = total_size >> _memory_span_size_shift;
+ if (total_size & (_memory_span_mask - 1))
+ ++num_spans;
+ size_t current_spans = span->span_count;
+ void* block = pointer_offset(span, SPAN_HEADER_SIZE);
+ if (!oldsize)
+ oldsize = (current_spans * _memory_span_size) - (size_t)pointer_diff(p, block) - SPAN_HEADER_SIZE;
+ if ((current_spans >= num_spans) && (total_size >= (oldsize / 2))) {
+ //Still fits in block, never mind trying to save memory, but preserve data if alignment changed
+ if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))
+ memmove(block, p, oldsize);
+ return block;
+ }
+ } else {
+ //Oversized block
+ size_t total_size = size + SPAN_HEADER_SIZE;
+ size_t num_pages = total_size >> _memory_page_size_shift;
+ if (total_size & (_memory_page_size - 1))
+ ++num_pages;
+ //Page count is stored in span_count
+ size_t current_pages = span->span_count;
+ void* block = pointer_offset(span, SPAN_HEADER_SIZE);
+ if (!oldsize)
+ oldsize = (current_pages * _memory_page_size) - (size_t)pointer_diff(p, block) - SPAN_HEADER_SIZE;
+ if ((current_pages >= num_pages) && (num_pages >= (current_pages / 2))) {
+ //Still fits in block, never mind trying to save memory, but preserve data if alignment changed
+ if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))
+ memmove(block, p, oldsize);
+ return block;
+ }
+ }
+ } else {
+ oldsize = 0;
+ }
+
+ if (!!(flags & RPMALLOC_GROW_OR_FAIL))
+ return 0;
+
+ //Size is greater than block size, need to allocate a new block and deallocate the old
+ //Avoid hysteresis by overallocating if increase is small (below 37%)
+ size_t lower_bound = oldsize + (oldsize >> 2) + (oldsize >> 3);
+ size_t new_size = (size > lower_bound) ? size : ((size > oldsize) ? lower_bound : size);
+ void* block = _rpmalloc_allocate(heap, new_size);
+ if (p && block) {
+ if (!(flags & RPMALLOC_NO_PRESERVE))
+ memcpy(block, p, oldsize < new_size ? oldsize : new_size);
+ _rpmalloc_deallocate(p);
+ }
+
+ return block;
+}
+
+static void*
+_rpmalloc_aligned_reallocate(heap_t* heap, void* ptr, size_t alignment, size_t size, size_t oldsize,
+ unsigned int flags) {
+ if (alignment <= SMALL_GRANULARITY)
+ return _rpmalloc_reallocate(heap, ptr, size, oldsize, flags);
+
+ int no_alloc = !!(flags & RPMALLOC_GROW_OR_FAIL);
+ size_t usablesize = (ptr ? _rpmalloc_usable_size(ptr) : 0);
+ if ((usablesize >= size) && !((uintptr_t)ptr & (alignment - 1))) {
+ if (no_alloc || (size >= (usablesize / 2)))
+ return ptr;
+ }
+ // Aligned alloc marks span as having aligned blocks
+ void* block = (!no_alloc ? _rpmalloc_aligned_allocate(heap, alignment, size) : 0);
+ if (EXPECTED(block != 0)) {
+ if (!(flags & RPMALLOC_NO_PRESERVE) && ptr) {
+ if (!oldsize)
+ oldsize = usablesize;
+ memcpy(block, ptr, oldsize < size ? oldsize : size);
+ }
+ _rpmalloc_deallocate(ptr);
+ }
+ return block;
+}
+
+
+////////////
+///
+/// Initialization, finalization and utility
+///
+//////
+
+//! Get the usable size of the given block
+static size_t
+_rpmalloc_usable_size(void* p) {
+ //Grab the span using guaranteed span alignment
+ span_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);
+ if (span->size_class < SIZE_CLASS_COUNT) {
+ //Small/medium block
+ void* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);
+ return span->block_size - ((size_t)pointer_diff(p, blocks_start) % span->block_size);
+ }
+ if (span->size_class == SIZE_CLASS_LARGE) {
+ //Large block
+ size_t current_spans = span->span_count;
+ return (current_spans * _memory_span_size) - (size_t)pointer_diff(p, span);
+ }
+ //Oversized block, page count is stored in span_count
+ size_t current_pages = span->span_count;
+ return (current_pages * _memory_page_size) - (size_t)pointer_diff(p, span);
+}
+
+//! Adjust and optimize the size class properties for the given class
+static void
+_rpmalloc_adjust_size_class(size_t iclass) {
+ size_t block_size = _memory_size_class[iclass].block_size;
+ size_t block_count = (_memory_span_size - SPAN_HEADER_SIZE) / block_size;
+
+ _memory_size_class[iclass].block_count = (uint16_t)block_count;
+ _memory_size_class[iclass].class_idx = (uint16_t)iclass;
+
+ //Check if previous size classes can be merged
+ if (iclass >= SMALL_CLASS_COUNT) {
+ size_t prevclass = iclass;
+ while (prevclass > 0) {
+ --prevclass;
+ //A class can be merged if number of pages and number of blocks are equal
+ if (_memory_size_class[prevclass].block_count == _memory_size_class[iclass].block_count)
+ _rpmalloc_memcpy_const(_memory_size_class + prevclass, _memory_size_class + iclass, sizeof(_memory_size_class[iclass]));
+ else
+ break;
+ }
+ }
+}
+
+//! Initialize the allocator and setup global data
+extern inline int
+rpmalloc_initialize(void) {
+ if (_rpmalloc_initialized) {
+ rpmalloc_thread_initialize();
+ return 0;
+ }
+ return rpmalloc_initialize_config(0);
+}
+
+int
+rpmalloc_initialize_config(const rpmalloc_config_t* config) {
+ if (_rpmalloc_initialized) {
+ rpmalloc_thread_initialize();
+ return 0;
+ }
+ _rpmalloc_initialized = 1;
+
+ if (config)
+ memcpy(&_memory_config, config, sizeof(rpmalloc_config_t));
+ else
+ _rpmalloc_memset_const(&_memory_config, 0, sizeof(rpmalloc_config_t));
+
+ if (!_memory_config.memory_map || !_memory_config.memory_unmap) {
+ _memory_config.memory_map = _rpmalloc_mmap_os;
+ _memory_config.memory_unmap = _rpmalloc_unmap_os;
+ }
+
+#if PLATFORM_WINDOWS
+ SYSTEM_INFO system_info;
+ memset(&system_info, 0, sizeof(system_info));
+ GetSystemInfo(&system_info);
+ _memory_map_granularity = system_info.dwAllocationGranularity;
+#else
+ _memory_map_granularity = (size_t)sysconf(_SC_PAGESIZE);
+#endif
+
+#if RPMALLOC_CONFIGURABLE
+ _memory_page_size = _memory_config.page_size;
+#else
+ _memory_page_size = 0;
+#endif
+ _memory_huge_pages = 0;
+ if (!_memory_page_size) {
+#if PLATFORM_WINDOWS
+ _memory_page_size = system_info.dwPageSize;
+#else
+ _memory_page_size = _memory_map_granularity;
+ if (_memory_config.enable_huge_pages) {
+#if defined(__linux__)
+ size_t huge_page_size = 0;
+ FILE* meminfo = fopen("/proc/meminfo", "r");
+ if (meminfo) {
+ char line[128];
+ while (!huge_page_size && fgets(line, sizeof(line) - 1, meminfo)) {
+ line[sizeof(line) - 1] = 0;
+ if (strstr(line, "Hugepagesize:"))
+ huge_page_size = (size_t)strtol(line + 13, 0, 10) * 1024;
+ }
+ fclose(meminfo);
+ }
+ if (huge_page_size) {
+ _memory_huge_pages = 1;
+ _memory_page_size = huge_page_size;
+ _memory_map_granularity = huge_page_size;
+ }
+#elif defined(__FreeBSD__)
+ int rc;
+ size_t sz = sizeof(rc);
+
+ if (sysctlbyname("vm.pmap.pg_ps_enabled", &rc, &sz, NULL, 0) == 0 && rc == 1) {
+ static size_t defsize = 2 * 1024 * 1024;
+ int nsize = 0;
+ size_t sizes[4] = {0};
+ _memory_huge_pages = 1;
+ _memory_page_size = defsize;
+ if ((nsize = getpagesizes(sizes, 4)) >= 2) {
+ nsize --;
+ for (size_t csize = sizes[nsize]; nsize >= 0 && csize; --nsize, csize = sizes[nsize]) {
+ //! Unlikely, but as a precaution..
+ rpmalloc_assert(!(csize & (csize -1)) && !(csize % 1024), "Invalid page size");
+ if (defsize < csize) {
+ _memory_page_size = csize;
+ break;
+ }
+ }
+ }
+ _memory_map_granularity = _memory_page_size;
+ }
+#elif defined(__APPLE__) || defined(__NetBSD__)
+ _memory_huge_pages = 1;
+ _memory_page_size = 2 * 1024 * 1024;
+ _memory_map_granularity = _memory_page_size;
+#endif
+ }
+#endif
+ } else {
+ if (_memory_config.enable_huge_pages)
+ _memory_huge_pages = 1;
+ }
+
+#if PLATFORM_WINDOWS
+ if (_memory_config.enable_huge_pages) {
+ HANDLE token = 0;
+ size_t large_page_minimum = GetLargePageMinimum();
+ if (large_page_minimum)
+ OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token);
+ if (token) {
+ LUID luid;
+ if (LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid)) {
+ TOKEN_PRIVILEGES token_privileges;
+ memset(&token_privileges, 0, sizeof(token_privileges));
+ token_privileges.PrivilegeCount = 1;
+ token_privileges.Privileges[0].Luid = luid;
+ token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ if (AdjustTokenPrivileges(token, FALSE, &token_privileges, 0, 0, 0)) {
+ if (GetLastError() == ERROR_SUCCESS)
+ _memory_huge_pages = 1;
+ }
+ }
+ CloseHandle(token);
+ }
+ if (_memory_huge_pages) {
+ if (large_page_minimum > _memory_page_size)
+ _memory_page_size = large_page_minimum;
+ if (large_page_minimum > _memory_map_granularity)
+ _memory_map_granularity = large_page_minimum;
+ }
+ }
+#endif
+
+ size_t min_span_size = 256;
+ size_t max_page_size;
+#if UINTPTR_MAX > 0xFFFFFFFF
+ max_page_size = 4096ULL * 1024ULL * 1024ULL;
+#else
+ max_page_size = 4 * 1024 * 1024;
+#endif
+ if (_memory_page_size < min_span_size)
+ _memory_page_size = min_span_size;
+ if (_memory_page_size > max_page_size)
+ _memory_page_size = max_page_size;
+ _memory_page_size_shift = 0;
+ size_t page_size_bit = _memory_page_size;
+ while (page_size_bit != 1) {
+ ++_memory_page_size_shift;
+ page_size_bit >>= 1;
+ }
+ _memory_page_size = ((size_t)1 << _memory_page_size_shift);
+
+#if RPMALLOC_CONFIGURABLE
+ if (!_memory_config.span_size) {
+ _memory_span_size = _memory_default_span_size;
+ _memory_span_size_shift = _memory_default_span_size_shift;
+ _memory_span_mask = _memory_default_span_mask;
+ } else {
+ size_t span_size = _memory_config.span_size;
+ if (span_size > (256 * 1024))
+ span_size = (256 * 1024);
+ _memory_span_size = 4096;
+ _memory_span_size_shift = 12;
+ while (_memory_span_size < span_size) {
+ _memory_span_size <<= 1;
+ ++_memory_span_size_shift;
+ }
+ _memory_span_mask = ~(uintptr_t)(_memory_span_size - 1);
+ }
+#endif
+
+ _memory_span_map_count = ( _memory_config.span_map_count ? _memory_config.span_map_count : DEFAULT_SPAN_MAP_COUNT);
+ if ((_memory_span_size * _memory_span_map_count) < _memory_page_size)
+ _memory_span_map_count = (_memory_page_size / _memory_span_size);
+ if ((_memory_page_size >= _memory_span_size) && ((_memory_span_map_count * _memory_span_size) % _memory_page_size))
+ _memory_span_map_count = (_memory_page_size / _memory_span_size);
+ _memory_heap_reserve_count = (_memory_span_map_count > DEFAULT_SPAN_MAP_COUNT) ? DEFAULT_SPAN_MAP_COUNT : _memory_span_map_count;
+
+ _memory_config.page_size = _memory_page_size;
+ _memory_config.span_size = _memory_span_size;
+ _memory_config.span_map_count = _memory_span_map_count;
+ _memory_config.enable_huge_pages = _memory_huge_pages;
+
+#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)
+ if (pthread_key_create(&_memory_thread_heap, _rpmalloc_heap_release_raw_fc))
+ return -1;
+#endif
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+ fls_key = FlsAlloc(&_rpmalloc_thread_destructor);
+#endif
+
+ //Setup all small and medium size classes
+ size_t iclass = 0;
+ _memory_size_class[iclass].block_size = SMALL_GRANULARITY;
+ _rpmalloc_adjust_size_class(iclass);
+ for (iclass = 1; iclass < SMALL_CLASS_COUNT; ++iclass) {
+ size_t size = iclass * SMALL_GRANULARITY;
+ _memory_size_class[iclass].block_size = (uint32_t)size;
+ _rpmalloc_adjust_size_class(iclass);
+ }
+ //At least two blocks per span, then fall back to large allocations
+ _memory_medium_size_limit = (_memory_span_size - SPAN_HEADER_SIZE) >> 1;
+ if (_memory_medium_size_limit > MEDIUM_SIZE_LIMIT)
+ _memory_medium_size_limit = MEDIUM_SIZE_LIMIT;
+ for (iclass = 0; iclass < MEDIUM_CLASS_COUNT; ++iclass) {
+ size_t size = SMALL_SIZE_LIMIT + ((iclass + 1) * MEDIUM_GRANULARITY);
+ if (size > _memory_medium_size_limit) {
+ _memory_medium_size_limit = SMALL_SIZE_LIMIT + (iclass * MEDIUM_GRANULARITY);
+ break;
+ }
+ _memory_size_class[SMALL_CLASS_COUNT + iclass].block_size = (uint32_t)size;
+ _rpmalloc_adjust_size_class(SMALL_CLASS_COUNT + iclass);
+ }
+
+ _memory_orphan_heaps = 0;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _memory_first_class_orphan_heaps = 0;
+#endif
+#if ENABLE_STATISTICS
+ atomic_store32(&_memory_active_heaps, 0);
+ atomic_store32(&_mapped_pages, 0);
+ _mapped_pages_peak = 0;
+ atomic_store32(&_master_spans, 0);
+ atomic_store32(&_mapped_total, 0);
+ atomic_store32(&_unmapped_total, 0);
+ atomic_store32(&_mapped_pages_os, 0);
+ atomic_store32(&_huge_pages_current, 0);
+ _huge_pages_peak = 0;
+#endif
+ memset(_memory_heaps, 0, sizeof(_memory_heaps));
+ atomic_store32_release(&_memory_global_lock, 0);
+
+ rpmalloc_linker_reference();
+
+ //Initialize this thread
+ rpmalloc_thread_initialize();
+ return 0;
+}
+
+//! Finalize the allocator
+void
+rpmalloc_finalize(void) {
+ rpmalloc_thread_finalize(1);
+ //rpmalloc_dump_statistics(stdout);
+
+ if (_memory_global_reserve) {
+ atomic_add32(&_memory_global_reserve_master->remaining_spans, -(int32_t)_memory_global_reserve_count);
+ _memory_global_reserve_master = 0;
+ _memory_global_reserve_count = 0;
+ _memory_global_reserve = 0;
+ }
+ atomic_store32_release(&_memory_global_lock, 0);
+
+ //Free all thread caches and fully free spans
+ for (size_t list_idx = 0; list_idx < HEAP_ARRAY_SIZE; ++list_idx) {
+ heap_t* heap = _memory_heaps[list_idx];
+ while (heap) {
+ heap_t* next_heap = heap->next_heap;
+ heap->finalize = 1;
+ _rpmalloc_heap_global_finalize(heap);
+ heap = next_heap;
+ }
+ }
+
+#if ENABLE_GLOBAL_CACHE
+ //Free global caches
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass)
+ _rpmalloc_global_cache_finalize(&_memory_span_cache[iclass]);
+#endif
+
+#if (defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD
+ pthread_key_delete(_memory_thread_heap);
+#endif
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+ FlsFree(fls_key);
+ fls_key = 0;
+#endif
+#if ENABLE_STATISTICS
+ //If you hit these asserts you probably have memory leaks (perhaps global scope data doing dynamic allocations) or double frees in your code
+ rpmalloc_assert(atomic_load32(&_mapped_pages) == 0, "Memory leak detected");
+ rpmalloc_assert(atomic_load32(&_mapped_pages_os) == 0, "Memory leak detected");
+#endif
+
+ _rpmalloc_initialized = 0;
+}
+
+//! Initialize thread, assign heap
+extern inline void
+rpmalloc_thread_initialize(void) {
+ if (!get_thread_heap_raw()) {
+ heap_t* heap = _rpmalloc_heap_allocate(0);
+ if (heap) {
+ _rpmalloc_stat_inc(&_memory_active_heaps);
+ set_thread_heap(heap);
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+ FlsSetValue(fls_key, heap);
+#endif
+ }
+ }
+}
+
+//! Finalize thread, orphan heap
+void
+rpmalloc_thread_finalize(int release_caches) {
+ heap_t* heap = get_thread_heap_raw();
+ if (heap)
+ _rpmalloc_heap_release_raw(heap, release_caches);
+ set_thread_heap(0);
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+ FlsSetValue(fls_key, 0);
+#endif
+}
+
+int
+rpmalloc_is_thread_initialized(void) {
+ return (get_thread_heap_raw() != 0) ? 1 : 0;
+}
+
+const rpmalloc_config_t*
+rpmalloc_config(void) {
+ return &_memory_config;
+}
+
+// Extern interface
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc(size_t size) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ heap_t* heap = get_thread_heap();
+ return _rpmalloc_allocate(heap, size);
+}
+
+extern inline void
+rpfree(void* ptr) {
+ _rpmalloc_deallocate(ptr);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpcalloc(size_t num, size_t size) {
+ size_t total;
+#if ENABLE_VALIDATE_ARGS
+#if PLATFORM_WINDOWS
+ int err = SizeTMult(num, size, &total);
+ if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#else
+ int err = __builtin_umull_overflow(num, size, &total);
+ if (err || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+#else
+ total = num * size;
+#endif
+ heap_t* heap = get_thread_heap();
+ void* block = _rpmalloc_allocate(heap, total);
+ if (block)
+ memset(block, 0, total);
+ return block;
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rprealloc(void* ptr, size_t size) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return ptr;
+ }
+#endif
+ heap_t* heap = get_thread_heap();
+ return _rpmalloc_reallocate(heap, ptr, size, 0, 0);
+}
+
+extern RPMALLOC_ALLOCATOR void*
+rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize,
+ unsigned int flags) {
+#if ENABLE_VALIDATE_ARGS
+ if ((size + alignment < size) || (alignment > _memory_page_size)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ heap_t* heap = get_thread_heap();
+ return _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, oldsize, flags);
+}
+
+extern RPMALLOC_ALLOCATOR void*
+rpaligned_alloc(size_t alignment, size_t size) {
+ heap_t* heap = get_thread_heap();
+ return _rpmalloc_aligned_allocate(heap, alignment, size);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpaligned_calloc(size_t alignment, size_t num, size_t size) {
+ size_t total;
+#if ENABLE_VALIDATE_ARGS
+#if PLATFORM_WINDOWS
+ int err = SizeTMult(num, size, &total);
+ if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#else
+ int err = __builtin_umull_overflow(num, size, &total);
+ if (err || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+#else
+ total = num * size;
+#endif
+ void* block = rpaligned_alloc(alignment, total);
+ if (block)
+ memset(block, 0, total);
+ return block;
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmemalign(size_t alignment, size_t size) {
+ return rpaligned_alloc(alignment, size);
+}
+
+extern inline int
+rpposix_memalign(void **memptr, size_t alignment, size_t size) {
+ if (memptr)
+ *memptr = rpaligned_alloc(alignment, size);
+ else
+ return EINVAL;
+ return *memptr ? 0 : ENOMEM;
+}
+
+extern inline size_t
+rpmalloc_usable_size(void* ptr) {
+ return (ptr ? _rpmalloc_usable_size(ptr) : 0);
+}
+
+extern inline void
+rpmalloc_thread_collect(void) {
+}
+
+void
+rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats) {
+ memset(stats, 0, sizeof(rpmalloc_thread_statistics_t));
+ heap_t* heap = get_thread_heap_raw();
+ if (!heap)
+ return;
+
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ size_class_t* size_class = _memory_size_class + iclass;
+ span_t* span = heap->size_class[iclass].partial_span;
+ while (span) {
+ size_t free_count = span->list_size;
+ size_t block_count = size_class->block_count;
+ if (span->free_list_limit < block_count)
+ block_count = span->free_list_limit;
+ free_count += (block_count - span->used_count);
+ stats->sizecache += free_count * size_class->block_size;
+ span = span->next;
+ }
+ }
+
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ stats->spancache += span_cache->count * (iclass + 1) * _memory_span_size;
+ }
+#endif
+
+ span_t* deferred = (span_t*)atomic_load_ptr(&heap->span_free_deferred);
+ while (deferred) {
+ if (deferred->size_class != SIZE_CLASS_HUGE)
+ stats->spancache += (size_t)deferred->span_count * _memory_span_size;
+ deferred = (span_t*)deferred->free_list;
+ }
+
+#if ENABLE_STATISTICS
+ stats->thread_to_global = (size_t)atomic_load64(&heap->thread_to_global);
+ stats->global_to_thread = (size_t)atomic_load64(&heap->global_to_thread);
+
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ stats->span_use[iclass].current = (size_t)atomic_load32(&heap->span_use[iclass].current);
+ stats->span_use[iclass].peak = (size_t)atomic_load32(&heap->span_use[iclass].high);
+ stats->span_use[iclass].to_global = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_global);
+ stats->span_use[iclass].from_global = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_global);
+ stats->span_use[iclass].to_cache = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_cache);
+ stats->span_use[iclass].from_cache = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_cache);
+ stats->span_use[iclass].to_reserved = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_reserved);
+ stats->span_use[iclass].from_reserved = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_reserved);
+ stats->span_use[iclass].map_calls = (size_t)atomic_load32(&heap->span_use[iclass].spans_map_calls);
+ }
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ stats->size_use[iclass].alloc_current = (size_t)atomic_load32(&heap->size_class_use[iclass].alloc_current);
+ stats->size_use[iclass].alloc_peak = (size_t)heap->size_class_use[iclass].alloc_peak;
+ stats->size_use[iclass].alloc_total = (size_t)atomic_load32(&heap->size_class_use[iclass].alloc_total);
+ stats->size_use[iclass].free_total = (size_t)atomic_load32(&heap->size_class_use[iclass].free_total);
+ stats->size_use[iclass].spans_to_cache = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_to_cache);
+ stats->size_use[iclass].spans_from_cache = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_cache);
+ stats->size_use[iclass].spans_from_reserved = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_reserved);
+ stats->size_use[iclass].map_calls = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_map_calls);
+ }
+#endif
+}
+
+void
+rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats) {
+ memset(stats, 0, sizeof(rpmalloc_global_statistics_t));
+#if ENABLE_STATISTICS
+ stats->mapped = (size_t)atomic_load32(&_mapped_pages) * _memory_page_size;
+ stats->mapped_peak = (size_t)_mapped_pages_peak * _memory_page_size;
+ stats->mapped_total = (size_t)atomic_load32(&_mapped_total) * _memory_page_size;
+ stats->unmapped_total = (size_t)atomic_load32(&_unmapped_total) * _memory_page_size;
+ stats->huge_alloc = (size_t)atomic_load32(&_huge_pages_current) * _memory_page_size;
+ stats->huge_alloc_peak = (size_t)_huge_pages_peak * _memory_page_size;
+#endif
+#if ENABLE_GLOBAL_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ global_cache_t* cache = &_memory_span_cache[iclass];
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+ uint32_t count = cache->count;
+#if ENABLE_UNLIMITED_CACHE
+ span_t* current_span = cache->overflow;
+ while (current_span) {
+ ++count;
+ current_span = current_span->next;
+ }
+#endif
+ atomic_store32_release(&cache->lock, 0);
+ stats->cached += count * (iclass + 1) * _memory_span_size;
+ }
+#endif
+}
+
+#if ENABLE_STATISTICS
+
+static void
+_memory_heap_dump_statistics(heap_t* heap, void* file) {
+ fprintf(file, "Heap %d stats:\n", heap->id);
+ fprintf(file, "Class CurAlloc PeakAlloc TotAlloc TotFree BlkSize BlkCount SpansCur SpansPeak PeakAllocMiB ToCacheMiB FromCacheMiB FromReserveMiB MmapCalls\n");
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ if (!atomic_load32(&heap->size_class_use[iclass].alloc_total))
+ continue;
+ fprintf(file, "%3u: %10u %10u %10u %10u %8u %8u %8d %9d %13zu %11zu %12zu %14zu %9u\n", (uint32_t)iclass,
+ atomic_load32(&heap->size_class_use[iclass].alloc_current),
+ heap->size_class_use[iclass].alloc_peak,
+ atomic_load32(&heap->size_class_use[iclass].alloc_total),
+ atomic_load32(&heap->size_class_use[iclass].free_total),
+ _memory_size_class[iclass].block_size,
+ _memory_size_class[iclass].block_count,
+ atomic_load32(&heap->size_class_use[iclass].spans_current),
+ heap->size_class_use[iclass].spans_peak,
+ ((size_t)heap->size_class_use[iclass].alloc_peak * (size_t)_memory_size_class[iclass].block_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_to_cache) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_cache) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_reserved) * _memory_span_size) / (size_t)(1024 * 1024),
+ atomic_load32(&heap->size_class_use[iclass].spans_map_calls));
+ }
+ fprintf(file, "Spans Current Peak Deferred PeakMiB Cached ToCacheMiB FromCacheMiB ToReserveMiB FromReserveMiB ToGlobalMiB FromGlobalMiB MmapCalls\n");
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ if (!atomic_load32(&heap->span_use[iclass].high) && !atomic_load32(&heap->span_use[iclass].spans_map_calls))
+ continue;
+ fprintf(file, "%4u: %8d %8u %8u %8zu %7u %11zu %12zu %12zu %14zu %11zu %13zu %10u\n", (uint32_t)(iclass + 1),
+ atomic_load32(&heap->span_use[iclass].current),
+ atomic_load32(&heap->span_use[iclass].high),
+ atomic_load32(&heap->span_use[iclass].spans_deferred),
+ ((size_t)atomic_load32(&heap->span_use[iclass].high) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),
+#if ENABLE_THREAD_CACHE
+ (unsigned int)(!iclass ? heap->span_cache.count : heap->span_large_cache[iclass - 1].count),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_cache) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_cache) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
+#else
+ 0, (size_t)0, (size_t)0,
+#endif
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_reserved) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_reserved) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_global) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_global) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),
+ atomic_load32(&heap->span_use[iclass].spans_map_calls));
+ }
+ fprintf(file, "Full spans: %zu\n", heap->full_span_count);
+ fprintf(file, "ThreadToGlobalMiB GlobalToThreadMiB\n");
+ fprintf(file, "%17zu %17zu\n", (size_t)atomic_load64(&heap->thread_to_global) / (size_t)(1024 * 1024), (size_t)atomic_load64(&heap->global_to_thread) / (size_t)(1024 * 1024));
+}
+
+#endif
+
+void
+rpmalloc_dump_statistics(void* file) {
+#if ENABLE_STATISTICS
+ for (size_t list_idx = 0; list_idx < HEAP_ARRAY_SIZE; ++list_idx) {
+ heap_t* heap = _memory_heaps[list_idx];
+ while (heap) {
+ int need_dump = 0;
+ for (size_t iclass = 0; !need_dump && (iclass < SIZE_CLASS_COUNT); ++iclass) {
+ if (!atomic_load32(&heap->size_class_use[iclass].alloc_total)) {
+ rpmalloc_assert(!atomic_load32(&heap->size_class_use[iclass].free_total), "Heap statistics counter mismatch");
+ rpmalloc_assert(!atomic_load32(&heap->size_class_use[iclass].spans_map_calls), "Heap statistics counter mismatch");
+ continue;
+ }
+ need_dump = 1;
+ }
+ for (size_t iclass = 0; !need_dump && (iclass < LARGE_CLASS_COUNT); ++iclass) {
+ if (!atomic_load32(&heap->span_use[iclass].high) && !atomic_load32(&heap->span_use[iclass].spans_map_calls))
+ continue;
+ need_dump = 1;
+ }
+ if (need_dump)
+ _memory_heap_dump_statistics(heap, file);
+ heap = heap->next_heap;
+ }
+ }
+ fprintf(file, "Global stats:\n");
+ size_t huge_current = (size_t)atomic_load32(&_huge_pages_current) * _memory_page_size;
+ size_t huge_peak = (size_t)_huge_pages_peak * _memory_page_size;
+ fprintf(file, "HugeCurrentMiB HugePeakMiB\n");
+ fprintf(file, "%14zu %11zu\n", huge_current / (size_t)(1024 * 1024), huge_peak / (size_t)(1024 * 1024));
+
+#if ENABLE_GLOBAL_CACHE
+ fprintf(file, "GlobalCacheMiB\n");
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ global_cache_t* cache = _memory_span_cache + iclass;
+ size_t global_cache = (size_t)cache->count * iclass * _memory_span_size;
+
+ size_t global_overflow_cache = 0;
+ span_t* span = cache->overflow;
+ while (span) {
+ global_overflow_cache += iclass * _memory_span_size;
+ span = span->next;
+ }
+ if (global_cache || global_overflow_cache || cache->insert_count || cache->extract_count)
+ fprintf(file, "%4zu: %8zuMiB (%8zuMiB overflow) %14zu insert %14zu extract\n", iclass + 1, global_cache / (size_t)(1024 * 1024), global_overflow_cache / (size_t)(1024 * 1024), cache->insert_count, cache->extract_count);
+ }
+#endif
+
+ size_t mapped = (size_t)atomic_load32(&_mapped_pages) * _memory_page_size;
+ size_t mapped_os = (size_t)atomic_load32(&_mapped_pages_os) * _memory_page_size;
+ size_t mapped_peak = (size_t)_mapped_pages_peak * _memory_page_size;
+ size_t mapped_total = (size_t)atomic_load32(&_mapped_total) * _memory_page_size;
+ size_t unmapped_total = (size_t)atomic_load32(&_unmapped_total) * _memory_page_size;
+ fprintf(file, "MappedMiB MappedOSMiB MappedPeakMiB MappedTotalMiB UnmappedTotalMiB\n");
+ fprintf(file, "%9zu %11zu %13zu %14zu %16zu\n",
+ mapped / (size_t)(1024 * 1024),
+ mapped_os / (size_t)(1024 * 1024),
+ mapped_peak / (size_t)(1024 * 1024),
+ mapped_total / (size_t)(1024 * 1024),
+ unmapped_total / (size_t)(1024 * 1024));
+
+ fprintf(file, "\n");
+#if 0
+ int64_t allocated = atomic_load64(&_allocation_counter);
+ int64_t deallocated = atomic_load64(&_deallocation_counter);
+ fprintf(file, "Allocation count: %lli\n", allocated);
+ fprintf(file, "Deallocation count: %lli\n", deallocated);
+ fprintf(file, "Current allocations: %lli\n", (allocated - deallocated));
+ fprintf(file, "Master spans: %d\n", atomic_load32(&_master_spans));
+ fprintf(file, "Dangling master spans: %d\n", atomic_load32(&_unmapped_master_spans));
+#endif
+#endif
+ (void)sizeof(file);
+}
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+
+extern inline rpmalloc_heap_t*
+rpmalloc_heap_acquire(void) {
+ // Must be a pristine heap from newly mapped memory pages, or else memory blocks
+ // could already be allocated from the heap which would (wrongly) be released when
+ // heap is cleared with rpmalloc_heap_free_all(). Also heaps guaranteed to be
+ // pristine from the dedicated orphan list can be used.
+ heap_t* heap = _rpmalloc_heap_allocate(1);
+ rpmalloc_assume(heap != NULL);
+ heap->owner_thread = 0;
+ _rpmalloc_stat_inc(&_memory_active_heaps);
+ return heap;
+}
+
+extern inline void
+rpmalloc_heap_release(rpmalloc_heap_t* heap) {
+ if (heap)
+ _rpmalloc_heap_release(heap, 1, 1);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ return _rpmalloc_allocate(heap, size);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ return _rpmalloc_aligned_allocate(heap, alignment, size);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) {
+ return rpmalloc_heap_aligned_calloc(heap, 0, num, size);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) {
+ size_t total;
+#if ENABLE_VALIDATE_ARGS
+#if PLATFORM_WINDOWS
+ int err = SizeTMult(num, size, &total);
+ if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#else
+ int err = __builtin_umull_overflow(num, size, &total);
+ if (err || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+#else
+ total = num * size;
+#endif
+ void* block = _rpmalloc_aligned_allocate(heap, alignment, total);
+ if (block)
+ memset(block, 0, total);
+ return block;
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return ptr;
+ }
+#endif
+ return _rpmalloc_reallocate(heap, ptr, size, 0, flags);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) {
+#if ENABLE_VALIDATE_ARGS
+ if ((size + alignment < size) || (alignment > _memory_page_size)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ return _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, 0, flags);
+}
+
+extern inline void
+rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr) {
+ (void)sizeof(heap);
+ _rpmalloc_deallocate(ptr);
+}
+
+extern inline void
+rpmalloc_heap_free_all(rpmalloc_heap_t* heap) {
+ span_t* span;
+ span_t* next_span;
+
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ span = heap->size_class[iclass].partial_span;
+ while (span) {
+ next_span = span->next;
+ _rpmalloc_heap_cache_insert(heap, span);
+ span = next_span;
+ }
+ heap->size_class[iclass].partial_span = 0;
+ span = heap->full_span[iclass];
+ while (span) {
+ next_span = span->next;
+ _rpmalloc_heap_cache_insert(heap, span);
+ span = next_span;
+ }
+ }
+ memset(heap->size_class, 0, sizeof(heap->size_class));
+ memset(heap->full_span, 0, sizeof(heap->full_span));
+
+ span = heap->large_huge_span;
+ while (span) {
+ next_span = span->next;
+ if (UNEXPECTED(span->size_class == SIZE_CLASS_HUGE))
+ _rpmalloc_deallocate_huge(span);
+ else
+ _rpmalloc_heap_cache_insert(heap, span);
+ span = next_span;
+ }
+ heap->large_huge_span = 0;
+ heap->full_span_count = 0;
+
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ if (!span_cache->count)
+ continue;
+#if ENABLE_GLOBAL_CACHE
+ _rpmalloc_stat_add64(&heap->thread_to_global, span_cache->count * (iclass + 1) * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[iclass].spans_to_global, span_cache->count);
+ _rpmalloc_global_cache_insert_spans(span_cache->span, iclass + 1, span_cache->count);
+#else
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+#endif
+ span_cache->count = 0;
+ }
+#endif
+
+#if ENABLE_STATISTICS
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ atomic_store32(&heap->size_class_use[iclass].alloc_current, 0);
+ atomic_store32(&heap->size_class_use[iclass].spans_current, 0);
+ }
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ atomic_store32(&heap->span_use[iclass].current, 0);
+ }
+#endif
+}
+
+extern inline void
+rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap) {
+ heap_t* prev_heap = get_thread_heap_raw();
+ if (prev_heap != heap) {
+ set_thread_heap(heap);
+ if (prev_heap)
+ rpmalloc_heap_release(prev_heap);
+ }
+}
+
+extern inline rpmalloc_heap_t*
+rpmalloc_get_heap_for_ptr(void* ptr)
+{
+ //Grab the span, and then the heap from the span
+ span_t* span = (span_t*)((uintptr_t)ptr & _memory_span_mask);
+ if (span)
+ {
+ return span->heap;
+ }
+ return 0;
+}
+
+#endif
+
+#if ENABLE_PRELOAD || ENABLE_OVERRIDE
+
+#include "malloc.c"
+
+#endif
+
+void
+rpmalloc_linker_reference(void) {
+ (void)sizeof(_rpmalloc_initialized);
+}
+#line 0
+//{{FILE: 3rd_rpmalloci.c}}
+#define SYS_MEM_INIT() rpmalloc_initialize()
+#define SYS_MEM_REALLOC rprealloc
+#define SYS_MEM_SIZE rpmalloc_usable_size
+#endif
+
//#define SQLITE_OMIT_LOAD_EXTENSION
//#define SQLITE_CORE 1
//#define SQLITE_DEBUG 1
@@ -334066,6 +338405,9244 @@ array(char) base64_decode(const char *inp, unsigned inlen) { // array_free() aft
//#undef rehash
//#undef NB
//#undef threadid
+
+// editor
+#line 1 "3rd_icon_mdi.h"
+// Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py for languages C and C++
+// from https://raw.githubusercontent.com/Templarian/MaterialDesign-Webfont/master/css/materialdesignicons.css
+// for use with https://github.com/Templarian/MaterialDesign-Webfont/raw/master/fonts/materialdesignicons-webfont.ttf
+#pragma once
+
+#define FONT_ICON_FILE_NAME_MDI "materialdesignicons-webfont.ttf"
+
+#define ICON_MIN_MDI 0xF68C
+#define ICON_MAX_16_MDI 0xF68C
+#define ICON_MAX_MDI 0xF1CC7
+#define ICON_MDI_AB_TESTING "\xf3\xb0\x87\x89" // U+F01C9
+#define ICON_MDI_ABACUS "\xf3\xb1\x9b\xa0" // U+F16E0
+#define ICON_MDI_ABJAD_ARABIC "\xf3\xb1\x8c\xa8" // U+F1328
+#define ICON_MDI_ABJAD_HEBREW "\xf3\xb1\x8c\xa9" // U+F1329
+#define ICON_MDI_ABUGIDA_DEVANAGARI "\xf3\xb1\x8c\xaa" // U+F132A
+#define ICON_MDI_ABUGIDA_THAI "\xf3\xb1\x8c\xab" // U+F132B
+#define ICON_MDI_ACCESS_POINT "\xf3\xb0\x80\x83" // U+F0003
+#define ICON_MDI_ACCESS_POINT_CHECK "\xf3\xb1\x94\xb8" // U+F1538
+#define ICON_MDI_ACCESS_POINT_MINUS "\xf3\xb1\x94\xb9" // U+F1539
+#define ICON_MDI_ACCESS_POINT_NETWORK "\xf3\xb0\x80\x82" // U+F0002
+#define ICON_MDI_ACCESS_POINT_NETWORK_OFF "\xf3\xb0\xaf\xa1" // U+F0BE1
+#define ICON_MDI_ACCESS_POINT_OFF "\xf3\xb1\x94\x91" // U+F1511
+#define ICON_MDI_ACCESS_POINT_PLUS "\xf3\xb1\x94\xba" // U+F153A
+#define ICON_MDI_ACCESS_POINT_REMOVE "\xf3\xb1\x94\xbb" // U+F153B
+#define ICON_MDI_ACCOUNT "\xf3\xb0\x80\x84" // U+F0004
+#define ICON_MDI_ACCOUNT_ALERT "\xf3\xb0\x80\x85" // U+F0005
+#define ICON_MDI_ACCOUNT_ALERT_OUTLINE "\xf3\xb0\xad\x90" // U+F0B50
+#define ICON_MDI_ACCOUNT_ARROW_DOWN "\xf3\xb1\xa1\xa8" // U+F1868
+#define ICON_MDI_ACCOUNT_ARROW_DOWN_OUTLINE "\xf3\xb1\xa1\xa9" // U+F1869
+#define ICON_MDI_ACCOUNT_ARROW_LEFT "\xf3\xb0\xad\x91" // U+F0B51
+#define ICON_MDI_ACCOUNT_ARROW_LEFT_OUTLINE "\xf3\xb0\xad\x92" // U+F0B52
+#define ICON_MDI_ACCOUNT_ARROW_RIGHT "\xf3\xb0\xad\x93" // U+F0B53
+#define ICON_MDI_ACCOUNT_ARROW_RIGHT_OUTLINE "\xf3\xb0\xad\x94" // U+F0B54
+#define ICON_MDI_ACCOUNT_ARROW_UP "\xf3\xb1\xa1\xa7" // U+F1867
+#define ICON_MDI_ACCOUNT_ARROW_UP_OUTLINE "\xf3\xb1\xa1\xaa" // U+F186A
+#define ICON_MDI_ACCOUNT_BADGE "\xf3\xb1\xac\x8a" // U+F1B0A
+#define ICON_MDI_ACCOUNT_BADGE_OUTLINE "\xf3\xb1\xac\x8b" // U+F1B0B
+#define ICON_MDI_ACCOUNT_BOX "\xf3\xb0\x80\x86" // U+F0006
+#define ICON_MDI_ACCOUNT_BOX_MULTIPLE "\xf3\xb0\xa4\xb4" // U+F0934
+#define ICON_MDI_ACCOUNT_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x80\x8a" // U+F100A
+#define ICON_MDI_ACCOUNT_BOX_OUTLINE "\xf3\xb0\x80\x87" // U+F0007
+#define ICON_MDI_ACCOUNT_CANCEL "\xf3\xb1\x8b\x9f" // U+F12DF
+#define ICON_MDI_ACCOUNT_CANCEL_OUTLINE "\xf3\xb1\x8b\xa0" // U+F12E0
+#define ICON_MDI_ACCOUNT_CARD "\xf3\xb1\xae\xa4" // U+F1BA4
+#define ICON_MDI_ACCOUNT_CARD_OUTLINE "\xf3\xb1\xae\xa5" // U+F1BA5
+#define ICON_MDI_ACCOUNT_CASH "\xf3\xb1\x82\x97" // U+F1097
+#define ICON_MDI_ACCOUNT_CASH_OUTLINE "\xf3\xb1\x82\x98" // U+F1098
+#define ICON_MDI_ACCOUNT_CHECK "\xf3\xb0\x80\x88" // U+F0008
+#define ICON_MDI_ACCOUNT_CHECK_OUTLINE "\xf3\xb0\xaf\xa2" // U+F0BE2
+#define ICON_MDI_ACCOUNT_CHILD "\xf3\xb0\xaa\x89" // U+F0A89
+#define ICON_MDI_ACCOUNT_CHILD_CIRCLE "\xf3\xb0\xaa\x8a" // U+F0A8A
+#define ICON_MDI_ACCOUNT_CHILD_OUTLINE "\xf3\xb1\x83\x88" // U+F10C8
+#define ICON_MDI_ACCOUNT_CIRCLE "\xf3\xb0\x80\x89" // U+F0009
+#define ICON_MDI_ACCOUNT_CIRCLE_OUTLINE "\xf3\xb0\xad\x95" // U+F0B55
+#define ICON_MDI_ACCOUNT_CLOCK "\xf3\xb0\xad\x96" // U+F0B56
+#define ICON_MDI_ACCOUNT_CLOCK_OUTLINE "\xf3\xb0\xad\x97" // U+F0B57
+#define ICON_MDI_ACCOUNT_COG "\xf3\xb1\x8d\xb0" // U+F1370
+#define ICON_MDI_ACCOUNT_COG_OUTLINE "\xf3\xb1\x8d\xb1" // U+F1371
+#define ICON_MDI_ACCOUNT_CONVERT "\xf3\xb0\x80\x8a" // U+F000A
+#define ICON_MDI_ACCOUNT_CONVERT_OUTLINE "\xf3\xb1\x8c\x81" // U+F1301
+#define ICON_MDI_ACCOUNT_COWBOY_HAT "\xf3\xb0\xba\x9b" // U+F0E9B
+#define ICON_MDI_ACCOUNT_COWBOY_HAT_OUTLINE "\xf3\xb1\x9f\xb3" // U+F17F3
+#define ICON_MDI_ACCOUNT_CREDIT_CARD "\xf3\xb1\xae\xa6" // U+F1BA6
+#define ICON_MDI_ACCOUNT_CREDIT_CARD_OUTLINE "\xf3\xb1\xae\xa7" // U+F1BA7
+#define ICON_MDI_ACCOUNT_DETAILS "\xf3\xb0\x98\xb1" // U+F0631
+#define ICON_MDI_ACCOUNT_DETAILS_OUTLINE "\xf3\xb1\x8d\xb2" // U+F1372
+#define ICON_MDI_ACCOUNT_EDIT "\xf3\xb0\x9a\xbc" // U+F06BC
+#define ICON_MDI_ACCOUNT_EDIT_OUTLINE "\xf3\xb0\xbf\xbb" // U+F0FFB
+#define ICON_MDI_ACCOUNT_EYE "\xf3\xb0\x90\xa0" // U+F0420
+#define ICON_MDI_ACCOUNT_EYE_OUTLINE "\xf3\xb1\x89\xbb" // U+F127B
+#define ICON_MDI_ACCOUNT_FILE "\xf3\xb1\xb2\xa7" // U+F1CA7
+#define ICON_MDI_ACCOUNT_FILE_OUTLINE "\xf3\xb1\xb2\xa8" // U+F1CA8
+#define ICON_MDI_ACCOUNT_FILE_TEXT "\xf3\xb1\xb2\xa9" // U+F1CA9
+#define ICON_MDI_ACCOUNT_FILE_TEXT_OUTLINE "\xf3\xb1\xb2\xaa" // U+F1CAA
+#define ICON_MDI_ACCOUNT_FILTER "\xf3\xb0\xa4\xb6" // U+F0936
+#define ICON_MDI_ACCOUNT_FILTER_OUTLINE "\xf3\xb0\xbe\x9d" // U+F0F9D
+#define ICON_MDI_ACCOUNT_GROUP "\xf3\xb0\xa1\x89" // U+F0849
+#define ICON_MDI_ACCOUNT_GROUP_OUTLINE "\xf3\xb0\xad\x98" // U+F0B58
+#define ICON_MDI_ACCOUNT_HARD_HAT "\xf3\xb0\x96\xb5" // U+F05B5
+#define ICON_MDI_ACCOUNT_HARD_HAT_OUTLINE "\xf3\xb1\xa8\x9f" // U+F1A1F
+#define ICON_MDI_ACCOUNT_HEART "\xf3\xb0\xa2\x99" // U+F0899
+#define ICON_MDI_ACCOUNT_HEART_OUTLINE "\xf3\xb0\xaf\xa3" // U+F0BE3
+#define ICON_MDI_ACCOUNT_INJURY "\xf3\xb1\xa0\x95" // U+F1815
+#define ICON_MDI_ACCOUNT_INJURY_OUTLINE "\xf3\xb1\xa0\x96" // U+F1816
+#define ICON_MDI_ACCOUNT_KEY "\xf3\xb0\x80\x8b" // U+F000B
+#define ICON_MDI_ACCOUNT_KEY_OUTLINE "\xf3\xb0\xaf\xa4" // U+F0BE4
+#define ICON_MDI_ACCOUNT_LOCK "\xf3\xb1\x85\x9e" // U+F115E
+#define ICON_MDI_ACCOUNT_LOCK_OPEN "\xf3\xb1\xa5\xa0" // U+F1960
+#define ICON_MDI_ACCOUNT_LOCK_OPEN_OUTLINE "\xf3\xb1\xa5\xa1" // U+F1961
+#define ICON_MDI_ACCOUNT_LOCK_OUTLINE "\xf3\xb1\x85\x9f" // U+F115F
+#define ICON_MDI_ACCOUNT_MINUS "\xf3\xb0\x80\x8d" // U+F000D
+#define ICON_MDI_ACCOUNT_MINUS_OUTLINE "\xf3\xb0\xab\xac" // U+F0AEC
+#define ICON_MDI_ACCOUNT_MULTIPLE "\xf3\xb0\x80\x8e" // U+F000E
+#define ICON_MDI_ACCOUNT_MULTIPLE_CHECK "\xf3\xb0\xa3\x85" // U+F08C5
+#define ICON_MDI_ACCOUNT_MULTIPLE_CHECK_OUTLINE "\xf3\xb1\x87\xbe" // U+F11FE
+#define ICON_MDI_ACCOUNT_MULTIPLE_MINUS "\xf3\xb0\x97\x93" // U+F05D3
+#define ICON_MDI_ACCOUNT_MULTIPLE_MINUS_OUTLINE "\xf3\xb0\xaf\xa5" // U+F0BE5
+#define ICON_MDI_ACCOUNT_MULTIPLE_OUTLINE "\xf3\xb0\x80\x8f" // U+F000F
+#define ICON_MDI_ACCOUNT_MULTIPLE_PLUS "\xf3\xb0\x80\x90" // U+F0010
+#define ICON_MDI_ACCOUNT_MULTIPLE_PLUS_OUTLINE "\xf3\xb0\xa0\x80" // U+F0800
+#define ICON_MDI_ACCOUNT_MULTIPLE_REMOVE "\xf3\xb1\x88\x8a" // U+F120A
+#define ICON_MDI_ACCOUNT_MULTIPLE_REMOVE_OUTLINE "\xf3\xb1\x88\x8b" // U+F120B
+#define ICON_MDI_ACCOUNT_MUSIC "\xf3\xb0\xa0\x83" // U+F0803
+#define ICON_MDI_ACCOUNT_MUSIC_OUTLINE "\xf3\xb0\xb3\xa9" // U+F0CE9
+#define ICON_MDI_ACCOUNT_NETWORK "\xf3\xb0\x80\x91" // U+F0011
+#define ICON_MDI_ACCOUNT_NETWORK_OFF "\xf3\xb1\xab\xb1" // U+F1AF1
+#define ICON_MDI_ACCOUNT_NETWORK_OFF_OUTLINE "\xf3\xb1\xab\xb2" // U+F1AF2
+#define ICON_MDI_ACCOUNT_NETWORK_OUTLINE "\xf3\xb0\xaf\xa6" // U+F0BE6
+#define ICON_MDI_ACCOUNT_OFF "\xf3\xb0\x80\x92" // U+F0012
+#define ICON_MDI_ACCOUNT_OFF_OUTLINE "\xf3\xb0\xaf\xa7" // U+F0BE7
+#define ICON_MDI_ACCOUNT_OUTLINE "\xf3\xb0\x80\x93" // U+F0013
+#define ICON_MDI_ACCOUNT_PLUS "\xf3\xb0\x80\x94" // U+F0014
+#define ICON_MDI_ACCOUNT_PLUS_OUTLINE "\xf3\xb0\xa0\x81" // U+F0801
+#define ICON_MDI_ACCOUNT_QUESTION "\xf3\xb0\xad\x99" // U+F0B59
+#define ICON_MDI_ACCOUNT_QUESTION_OUTLINE "\xf3\xb0\xad\x9a" // U+F0B5A
+#define ICON_MDI_ACCOUNT_REACTIVATE "\xf3\xb1\x94\xab" // U+F152B
+#define ICON_MDI_ACCOUNT_REACTIVATE_OUTLINE "\xf3\xb1\x94\xac" // U+F152C
+#define ICON_MDI_ACCOUNT_REMOVE "\xf3\xb0\x80\x95" // U+F0015
+#define ICON_MDI_ACCOUNT_REMOVE_OUTLINE "\xf3\xb0\xab\xad" // U+F0AED
+#define ICON_MDI_ACCOUNT_SCHOOL "\xf3\xb1\xa8\xa0" // U+F1A20
+#define ICON_MDI_ACCOUNT_SCHOOL_OUTLINE "\xf3\xb1\xa8\xa1" // U+F1A21
+#define ICON_MDI_ACCOUNT_SEARCH "\xf3\xb0\x80\x96" // U+F0016
+#define ICON_MDI_ACCOUNT_SEARCH_OUTLINE "\xf3\xb0\xa4\xb5" // U+F0935
+#define ICON_MDI_ACCOUNT_SETTINGS "\xf3\xb0\x98\xb0" // U+F0630
+#define ICON_MDI_ACCOUNT_SETTINGS_OUTLINE "\xf3\xb1\x83\x89" // U+F10C9
+#define ICON_MDI_ACCOUNT_STAR "\xf3\xb0\x80\x97" // U+F0017
+#define ICON_MDI_ACCOUNT_STAR_OUTLINE "\xf3\xb0\xaf\xa8" // U+F0BE8
+#define ICON_MDI_ACCOUNT_SUPERVISOR "\xf3\xb0\xaa\x8b" // U+F0A8B
+#define ICON_MDI_ACCOUNT_SUPERVISOR_CIRCLE "\xf3\xb0\xaa\x8c" // U+F0A8C
+#define ICON_MDI_ACCOUNT_SUPERVISOR_CIRCLE_OUTLINE "\xf3\xb1\x93\xac" // U+F14EC
+#define ICON_MDI_ACCOUNT_SUPERVISOR_OUTLINE "\xf3\xb1\x84\xad" // U+F112D
+#define ICON_MDI_ACCOUNT_SWITCH "\xf3\xb0\x80\x99" // U+F0019
+#define ICON_MDI_ACCOUNT_SWITCH_OUTLINE "\xf3\xb0\x93\x8b" // U+F04CB
+#define ICON_MDI_ACCOUNT_SYNC "\xf3\xb1\xa4\x9b" // U+F191B
+#define ICON_MDI_ACCOUNT_SYNC_OUTLINE "\xf3\xb1\xa4\x9c" // U+F191C
+#define ICON_MDI_ACCOUNT_TAG "\xf3\xb1\xb0\x9b" // U+F1C1B
+#define ICON_MDI_ACCOUNT_TAG_OUTLINE "\xf3\xb1\xb0\x9c" // U+F1C1C
+#define ICON_MDI_ACCOUNT_TIE "\xf3\xb0\xb3\xa3" // U+F0CE3
+#define ICON_MDI_ACCOUNT_TIE_HAT "\xf3\xb1\xa2\x98" // U+F1898
+#define ICON_MDI_ACCOUNT_TIE_HAT_OUTLINE "\xf3\xb1\xa2\x99" // U+F1899
+#define ICON_MDI_ACCOUNT_TIE_OUTLINE "\xf3\xb1\x83\x8a" // U+F10CA
+#define ICON_MDI_ACCOUNT_TIE_VOICE "\xf3\xb1\x8c\x88" // U+F1308
+#define ICON_MDI_ACCOUNT_TIE_VOICE_OFF "\xf3\xb1\x8c\x8a" // U+F130A
+#define ICON_MDI_ACCOUNT_TIE_VOICE_OFF_OUTLINE "\xf3\xb1\x8c\x8b" // U+F130B
+#define ICON_MDI_ACCOUNT_TIE_VOICE_OUTLINE "\xf3\xb1\x8c\x89" // U+F1309
+#define ICON_MDI_ACCOUNT_TIE_WOMAN "\xf3\xb1\xaa\x8c" // U+F1A8C
+#define ICON_MDI_ACCOUNT_VOICE "\xf3\xb0\x97\x8b" // U+F05CB
+#define ICON_MDI_ACCOUNT_VOICE_OFF "\xf3\xb0\xbb\x94" // U+F0ED4
+#define ICON_MDI_ACCOUNT_WRENCH "\xf3\xb1\xa2\x9a" // U+F189A
+#define ICON_MDI_ACCOUNT_WRENCH_OUTLINE "\xf3\xb1\xa2\x9b" // U+F189B
+#define ICON_MDI_ADJUST "\xf3\xb0\x80\x9a" // U+F001A
+#define ICON_MDI_ADVERTISEMENTS "\xf3\xb1\xa4\xaa" // U+F192A
+#define ICON_MDI_ADVERTISEMENTS_OFF "\xf3\xb1\xa4\xab" // U+F192B
+#define ICON_MDI_AIR_CONDITIONER "\xf3\xb0\x80\x9b" // U+F001B
+#define ICON_MDI_AIR_FILTER "\xf3\xb0\xb5\x83" // U+F0D43
+#define ICON_MDI_AIR_HORN "\xf3\xb0\xb6\xac" // U+F0DAC
+#define ICON_MDI_AIR_HUMIDIFIER "\xf3\xb1\x82\x99" // U+F1099
+#define ICON_MDI_AIR_HUMIDIFIER_OFF "\xf3\xb1\x91\xa6" // U+F1466
+#define ICON_MDI_AIR_PURIFIER "\xf3\xb0\xb5\x84" // U+F0D44
+#define ICON_MDI_AIR_PURIFIER_OFF "\xf3\xb1\xad\x97" // U+F1B57
+#define ICON_MDI_AIRBAG "\xf3\xb0\xaf\xa9" // U+F0BE9
+#define ICON_MDI_AIRBALLOON "\xf3\xb0\x80\x9c" // U+F001C
+#define ICON_MDI_AIRBALLOON_OUTLINE "\xf3\xb1\x80\x8b" // U+F100B
+#define ICON_MDI_AIRPLANE "\xf3\xb0\x80\x9d" // U+F001D
+#define ICON_MDI_AIRPLANE_ALERT "\xf3\xb1\xa1\xba" // U+F187A
+#define ICON_MDI_AIRPLANE_CHECK "\xf3\xb1\xa1\xbb" // U+F187B
+#define ICON_MDI_AIRPLANE_CLOCK "\xf3\xb1\xa1\xbc" // U+F187C
+#define ICON_MDI_AIRPLANE_COG "\xf3\xb1\xa1\xbd" // U+F187D
+#define ICON_MDI_AIRPLANE_EDIT "\xf3\xb1\xa1\xbe" // U+F187E
+#define ICON_MDI_AIRPLANE_LANDING "\xf3\xb0\x97\x94" // U+F05D4
+#define ICON_MDI_AIRPLANE_MARKER "\xf3\xb1\xa1\xbf" // U+F187F
+#define ICON_MDI_AIRPLANE_MINUS "\xf3\xb1\xa2\x80" // U+F1880
+#define ICON_MDI_AIRPLANE_OFF "\xf3\xb0\x80\x9e" // U+F001E
+#define ICON_MDI_AIRPLANE_PLUS "\xf3\xb1\xa2\x81" // U+F1881
+#define ICON_MDI_AIRPLANE_REMOVE "\xf3\xb1\xa2\x82" // U+F1882
+#define ICON_MDI_AIRPLANE_SEARCH "\xf3\xb1\xa2\x83" // U+F1883
+#define ICON_MDI_AIRPLANE_SETTINGS "\xf3\xb1\xa2\x84" // U+F1884
+#define ICON_MDI_AIRPLANE_TAKEOFF "\xf3\xb0\x97\x95" // U+F05D5
+#define ICON_MDI_AIRPORT "\xf3\xb0\xa1\x8b" // U+F084B
+#define ICON_MDI_ALARM "\xf3\xb0\x80\xa0" // U+F0020
+#define ICON_MDI_ALARM_BELL "\xf3\xb0\x9e\x8e" // U+F078E
+#define ICON_MDI_ALARM_CHECK "\xf3\xb0\x80\xa1" // U+F0021
+#define ICON_MDI_ALARM_LIGHT "\xf3\xb0\x9e\x8f" // U+F078F
+#define ICON_MDI_ALARM_LIGHT_OFF "\xf3\xb1\x9c\x9e" // U+F171E
+#define ICON_MDI_ALARM_LIGHT_OFF_OUTLINE "\xf3\xb1\x9c\x9f" // U+F171F
+#define ICON_MDI_ALARM_LIGHT_OUTLINE "\xf3\xb0\xaf\xaa" // U+F0BEA
+#define ICON_MDI_ALARM_MULTIPLE "\xf3\xb0\x80\xa2" // U+F0022
+#define ICON_MDI_ALARM_NOTE "\xf3\xb0\xb9\xb1" // U+F0E71
+#define ICON_MDI_ALARM_NOTE_OFF "\xf3\xb0\xb9\xb2" // U+F0E72
+#define ICON_MDI_ALARM_OFF "\xf3\xb0\x80\xa3" // U+F0023
+#define ICON_MDI_ALARM_PANEL "\xf3\xb1\x97\x84" // U+F15C4
+#define ICON_MDI_ALARM_PANEL_OUTLINE "\xf3\xb1\x97\x85" // U+F15C5
+#define ICON_MDI_ALARM_PLUS "\xf3\xb0\x80\xa4" // U+F0024
+#define ICON_MDI_ALARM_SNOOZE "\xf3\xb0\x9a\x8e" // U+F068E
+#define ICON_MDI_ALBUM "\xf3\xb0\x80\xa5" // U+F0025
+#define ICON_MDI_ALERT "\xf3\xb0\x80\xa6" // U+F0026
+#define ICON_MDI_ALERT_BOX "\xf3\xb0\x80\xa7" // U+F0027
+#define ICON_MDI_ALERT_BOX_OUTLINE "\xf3\xb0\xb3\xa4" // U+F0CE4
+#define ICON_MDI_ALERT_CIRCLE "\xf3\xb0\x80\xa8" // U+F0028
+#define ICON_MDI_ALERT_CIRCLE_CHECK "\xf3\xb1\x87\xad" // U+F11ED
+#define ICON_MDI_ALERT_CIRCLE_CHECK_OUTLINE "\xf3\xb1\x87\xae" // U+F11EE
+#define ICON_MDI_ALERT_CIRCLE_OUTLINE "\xf3\xb0\x97\x96" // U+F05D6
+#define ICON_MDI_ALERT_DECAGRAM "\xf3\xb0\x9a\xbd" // U+F06BD
+#define ICON_MDI_ALERT_DECAGRAM_OUTLINE "\xf3\xb0\xb3\xa5" // U+F0CE5
+#define ICON_MDI_ALERT_MINUS "\xf3\xb1\x92\xbb" // U+F14BB
+#define ICON_MDI_ALERT_MINUS_OUTLINE "\xf3\xb1\x92\xbe" // U+F14BE
+#define ICON_MDI_ALERT_OCTAGON "\xf3\xb0\x80\xa9" // U+F0029
+#define ICON_MDI_ALERT_OCTAGON_OUTLINE "\xf3\xb0\xb3\xa6" // U+F0CE6
+#define ICON_MDI_ALERT_OCTAGRAM "\xf3\xb0\x9d\xa7" // U+F0767
+#define ICON_MDI_ALERT_OCTAGRAM_OUTLINE "\xf3\xb0\xb3\xa7" // U+F0CE7
+#define ICON_MDI_ALERT_OUTLINE "\xf3\xb0\x80\xaa" // U+F002A
+#define ICON_MDI_ALERT_PLUS "\xf3\xb1\x92\xba" // U+F14BA
+#define ICON_MDI_ALERT_PLUS_OUTLINE "\xf3\xb1\x92\xbd" // U+F14BD
+#define ICON_MDI_ALERT_REMOVE "\xf3\xb1\x92\xbc" // U+F14BC
+#define ICON_MDI_ALERT_REMOVE_OUTLINE "\xf3\xb1\x92\xbf" // U+F14BF
+#define ICON_MDI_ALERT_RHOMBUS "\xf3\xb1\x87\x8e" // U+F11CE
+#define ICON_MDI_ALERT_RHOMBUS_OUTLINE "\xf3\xb1\x87\x8f" // U+F11CF
+#define ICON_MDI_ALIEN "\xf3\xb0\xa2\x9a" // U+F089A
+#define ICON_MDI_ALIEN_OUTLINE "\xf3\xb1\x83\x8b" // U+F10CB
+#define ICON_MDI_ALIGN_HORIZONTAL_CENTER "\xf3\xb1\x87\x83" // U+F11C3
+#define ICON_MDI_ALIGN_HORIZONTAL_DISTRIBUTE "\xf3\xb1\xa5\xa2" // U+F1962
+#define ICON_MDI_ALIGN_HORIZONTAL_LEFT "\xf3\xb1\x87\x82" // U+F11C2
+#define ICON_MDI_ALIGN_HORIZONTAL_RIGHT "\xf3\xb1\x87\x84" // U+F11C4
+#define ICON_MDI_ALIGN_VERTICAL_BOTTOM "\xf3\xb1\x87\x85" // U+F11C5
+#define ICON_MDI_ALIGN_VERTICAL_CENTER "\xf3\xb1\x87\x86" // U+F11C6
+#define ICON_MDI_ALIGN_VERTICAL_DISTRIBUTE "\xf3\xb1\xa5\xa3" // U+F1963
+#define ICON_MDI_ALIGN_VERTICAL_TOP "\xf3\xb1\x87\x87" // U+F11C7
+#define ICON_MDI_ALL_INCLUSIVE "\xf3\xb0\x9a\xbe" // U+F06BE
+#define ICON_MDI_ALL_INCLUSIVE_BOX "\xf3\xb1\xa2\x8d" // U+F188D
+#define ICON_MDI_ALL_INCLUSIVE_BOX_OUTLINE "\xf3\xb1\xa2\x8e" // U+F188E
+#define ICON_MDI_ALLERGY "\xf3\xb1\x89\x98" // U+F1258
+#define ICON_MDI_ALPHA "\xf3\xb0\x80\xab" // U+F002B
+#define ICON_MDI_ALPHA_A "\xf3\xb0\xab\xae" // U+F0AEE
+#define ICON_MDI_ALPHA_A_BOX "\xf3\xb0\xac\x88" // U+F0B08
+#define ICON_MDI_ALPHA_A_BOX_OUTLINE "\xf3\xb0\xaf\xab" // U+F0BEB
+#define ICON_MDI_ALPHA_A_CIRCLE "\xf3\xb0\xaf\xac" // U+F0BEC
+#define ICON_MDI_ALPHA_A_CIRCLE_OUTLINE "\xf3\xb0\xaf\xad" // U+F0BED
+#define ICON_MDI_ALPHA_B "\xf3\xb0\xab\xaf" // U+F0AEF
+#define ICON_MDI_ALPHA_B_BOX "\xf3\xb0\xac\x89" // U+F0B09
+#define ICON_MDI_ALPHA_B_BOX_OUTLINE "\xf3\xb0\xaf\xae" // U+F0BEE
+#define ICON_MDI_ALPHA_B_CIRCLE "\xf3\xb0\xaf\xaf" // U+F0BEF
+#define ICON_MDI_ALPHA_B_CIRCLE_OUTLINE "\xf3\xb0\xaf\xb0" // U+F0BF0
+#define ICON_MDI_ALPHA_C "\xf3\xb0\xab\xb0" // U+F0AF0
+#define ICON_MDI_ALPHA_C_BOX "\xf3\xb0\xac\x8a" // U+F0B0A
+#define ICON_MDI_ALPHA_C_BOX_OUTLINE "\xf3\xb0\xaf\xb1" // U+F0BF1
+#define ICON_MDI_ALPHA_C_CIRCLE "\xf3\xb0\xaf\xb2" // U+F0BF2
+#define ICON_MDI_ALPHA_C_CIRCLE_OUTLINE "\xf3\xb0\xaf\xb3" // U+F0BF3
+#define ICON_MDI_ALPHA_D "\xf3\xb0\xab\xb1" // U+F0AF1
+#define ICON_MDI_ALPHA_D_BOX "\xf3\xb0\xac\x8b" // U+F0B0B
+#define ICON_MDI_ALPHA_D_BOX_OUTLINE "\xf3\xb0\xaf\xb4" // U+F0BF4
+#define ICON_MDI_ALPHA_D_CIRCLE "\xf3\xb0\xaf\xb5" // U+F0BF5
+#define ICON_MDI_ALPHA_D_CIRCLE_OUTLINE "\xf3\xb0\xaf\xb6" // U+F0BF6
+#define ICON_MDI_ALPHA_E "\xf3\xb0\xab\xb2" // U+F0AF2
+#define ICON_MDI_ALPHA_E_BOX "\xf3\xb0\xac\x8c" // U+F0B0C
+#define ICON_MDI_ALPHA_E_BOX_OUTLINE "\xf3\xb0\xaf\xb7" // U+F0BF7
+#define ICON_MDI_ALPHA_E_CIRCLE "\xf3\xb0\xaf\xb8" // U+F0BF8
+#define ICON_MDI_ALPHA_E_CIRCLE_OUTLINE "\xf3\xb0\xaf\xb9" // U+F0BF9
+#define ICON_MDI_ALPHA_F "\xf3\xb0\xab\xb3" // U+F0AF3
+#define ICON_MDI_ALPHA_F_BOX "\xf3\xb0\xac\x8d" // U+F0B0D
+#define ICON_MDI_ALPHA_F_BOX_OUTLINE "\xf3\xb0\xaf\xba" // U+F0BFA
+#define ICON_MDI_ALPHA_F_CIRCLE "\xf3\xb0\xaf\xbb" // U+F0BFB
+#define ICON_MDI_ALPHA_F_CIRCLE_OUTLINE "\xf3\xb0\xaf\xbc" // U+F0BFC
+#define ICON_MDI_ALPHA_G "\xf3\xb0\xab\xb4" // U+F0AF4
+#define ICON_MDI_ALPHA_G_BOX "\xf3\xb0\xac\x8e" // U+F0B0E
+#define ICON_MDI_ALPHA_G_BOX_OUTLINE "\xf3\xb0\xaf\xbd" // U+F0BFD
+#define ICON_MDI_ALPHA_G_CIRCLE "\xf3\xb0\xaf\xbe" // U+F0BFE
+#define ICON_MDI_ALPHA_G_CIRCLE_OUTLINE "\xf3\xb0\xaf\xbf" // U+F0BFF
+#define ICON_MDI_ALPHA_H "\xf3\xb0\xab\xb5" // U+F0AF5
+#define ICON_MDI_ALPHA_H_BOX "\xf3\xb0\xac\x8f" // U+F0B0F
+#define ICON_MDI_ALPHA_H_BOX_OUTLINE "\xf3\xb0\xb0\x80" // U+F0C00
+#define ICON_MDI_ALPHA_H_CIRCLE "\xf3\xb0\xb0\x81" // U+F0C01
+#define ICON_MDI_ALPHA_H_CIRCLE_OUTLINE "\xf3\xb0\xb0\x82" // U+F0C02
+#define ICON_MDI_ALPHA_I "\xf3\xb0\xab\xb6" // U+F0AF6
+#define ICON_MDI_ALPHA_I_BOX "\xf3\xb0\xac\x90" // U+F0B10
+#define ICON_MDI_ALPHA_I_BOX_OUTLINE "\xf3\xb0\xb0\x83" // U+F0C03
+#define ICON_MDI_ALPHA_I_CIRCLE "\xf3\xb0\xb0\x84" // U+F0C04
+#define ICON_MDI_ALPHA_I_CIRCLE_OUTLINE "\xf3\xb0\xb0\x85" // U+F0C05
+#define ICON_MDI_ALPHA_J "\xf3\xb0\xab\xb7" // U+F0AF7
+#define ICON_MDI_ALPHA_J_BOX "\xf3\xb0\xac\x91" // U+F0B11
+#define ICON_MDI_ALPHA_J_BOX_OUTLINE "\xf3\xb0\xb0\x86" // U+F0C06
+#define ICON_MDI_ALPHA_J_CIRCLE "\xf3\xb0\xb0\x87" // U+F0C07
+#define ICON_MDI_ALPHA_J_CIRCLE_OUTLINE "\xf3\xb0\xb0\x88" // U+F0C08
+#define ICON_MDI_ALPHA_K "\xf3\xb0\xab\xb8" // U+F0AF8
+#define ICON_MDI_ALPHA_K_BOX "\xf3\xb0\xac\x92" // U+F0B12
+#define ICON_MDI_ALPHA_K_BOX_OUTLINE "\xf3\xb0\xb0\x89" // U+F0C09
+#define ICON_MDI_ALPHA_K_CIRCLE "\xf3\xb0\xb0\x8a" // U+F0C0A
+#define ICON_MDI_ALPHA_K_CIRCLE_OUTLINE "\xf3\xb0\xb0\x8b" // U+F0C0B
+#define ICON_MDI_ALPHA_L "\xf3\xb0\xab\xb9" // U+F0AF9
+#define ICON_MDI_ALPHA_L_BOX "\xf3\xb0\xac\x93" // U+F0B13
+#define ICON_MDI_ALPHA_L_BOX_OUTLINE "\xf3\xb0\xb0\x8c" // U+F0C0C
+#define ICON_MDI_ALPHA_L_CIRCLE "\xf3\xb0\xb0\x8d" // U+F0C0D
+#define ICON_MDI_ALPHA_L_CIRCLE_OUTLINE "\xf3\xb0\xb0\x8e" // U+F0C0E
+#define ICON_MDI_ALPHA_M "\xf3\xb0\xab\xba" // U+F0AFA
+#define ICON_MDI_ALPHA_M_BOX "\xf3\xb0\xac\x94" // U+F0B14
+#define ICON_MDI_ALPHA_M_BOX_OUTLINE "\xf3\xb0\xb0\x8f" // U+F0C0F
+#define ICON_MDI_ALPHA_M_CIRCLE "\xf3\xb0\xb0\x90" // U+F0C10
+#define ICON_MDI_ALPHA_M_CIRCLE_OUTLINE "\xf3\xb0\xb0\x91" // U+F0C11
+#define ICON_MDI_ALPHA_N "\xf3\xb0\xab\xbb" // U+F0AFB
+#define ICON_MDI_ALPHA_N_BOX "\xf3\xb0\xac\x95" // U+F0B15
+#define ICON_MDI_ALPHA_N_BOX_OUTLINE "\xf3\xb0\xb0\x92" // U+F0C12
+#define ICON_MDI_ALPHA_N_CIRCLE "\xf3\xb0\xb0\x93" // U+F0C13
+#define ICON_MDI_ALPHA_N_CIRCLE_OUTLINE "\xf3\xb0\xb0\x94" // U+F0C14
+#define ICON_MDI_ALPHA_O "\xf3\xb0\xab\xbc" // U+F0AFC
+#define ICON_MDI_ALPHA_O_BOX "\xf3\xb0\xac\x96" // U+F0B16
+#define ICON_MDI_ALPHA_O_BOX_OUTLINE "\xf3\xb0\xb0\x95" // U+F0C15
+#define ICON_MDI_ALPHA_O_CIRCLE "\xf3\xb0\xb0\x96" // U+F0C16
+#define ICON_MDI_ALPHA_O_CIRCLE_OUTLINE "\xf3\xb0\xb0\x97" // U+F0C17
+#define ICON_MDI_ALPHA_P "\xf3\xb0\xab\xbd" // U+F0AFD
+#define ICON_MDI_ALPHA_P_BOX "\xf3\xb0\xac\x97" // U+F0B17
+#define ICON_MDI_ALPHA_P_BOX_OUTLINE "\xf3\xb0\xb0\x98" // U+F0C18
+#define ICON_MDI_ALPHA_P_CIRCLE "\xf3\xb0\xb0\x99" // U+F0C19
+#define ICON_MDI_ALPHA_P_CIRCLE_OUTLINE "\xf3\xb0\xb0\x9a" // U+F0C1A
+#define ICON_MDI_ALPHA_Q "\xf3\xb0\xab\xbe" // U+F0AFE
+#define ICON_MDI_ALPHA_Q_BOX "\xf3\xb0\xac\x98" // U+F0B18
+#define ICON_MDI_ALPHA_Q_BOX_OUTLINE "\xf3\xb0\xb0\x9b" // U+F0C1B
+#define ICON_MDI_ALPHA_Q_CIRCLE "\xf3\xb0\xb0\x9c" // U+F0C1C
+#define ICON_MDI_ALPHA_Q_CIRCLE_OUTLINE "\xf3\xb0\xb0\x9d" // U+F0C1D
+#define ICON_MDI_ALPHA_R "\xf3\xb0\xab\xbf" // U+F0AFF
+#define ICON_MDI_ALPHA_R_BOX "\xf3\xb0\xac\x99" // U+F0B19
+#define ICON_MDI_ALPHA_R_BOX_OUTLINE "\xf3\xb0\xb0\x9e" // U+F0C1E
+#define ICON_MDI_ALPHA_R_CIRCLE "\xf3\xb0\xb0\x9f" // U+F0C1F
+#define ICON_MDI_ALPHA_R_CIRCLE_OUTLINE "\xf3\xb0\xb0\xa0" // U+F0C20
+#define ICON_MDI_ALPHA_S "\xf3\xb0\xac\x80" // U+F0B00
+#define ICON_MDI_ALPHA_S_BOX "\xf3\xb0\xac\x9a" // U+F0B1A
+#define ICON_MDI_ALPHA_S_BOX_OUTLINE "\xf3\xb0\xb0\xa1" // U+F0C21
+#define ICON_MDI_ALPHA_S_CIRCLE "\xf3\xb0\xb0\xa2" // U+F0C22
+#define ICON_MDI_ALPHA_S_CIRCLE_OUTLINE "\xf3\xb0\xb0\xa3" // U+F0C23
+#define ICON_MDI_ALPHA_T "\xf3\xb0\xac\x81" // U+F0B01
+#define ICON_MDI_ALPHA_T_BOX "\xf3\xb0\xac\x9b" // U+F0B1B
+#define ICON_MDI_ALPHA_T_BOX_OUTLINE "\xf3\xb0\xb0\xa4" // U+F0C24
+#define ICON_MDI_ALPHA_T_CIRCLE "\xf3\xb0\xb0\xa5" // U+F0C25
+#define ICON_MDI_ALPHA_T_CIRCLE_OUTLINE "\xf3\xb0\xb0\xa6" // U+F0C26
+#define ICON_MDI_ALPHA_U "\xf3\xb0\xac\x82" // U+F0B02
+#define ICON_MDI_ALPHA_U_BOX "\xf3\xb0\xac\x9c" // U+F0B1C
+#define ICON_MDI_ALPHA_U_BOX_OUTLINE "\xf3\xb0\xb0\xa7" // U+F0C27
+#define ICON_MDI_ALPHA_U_CIRCLE "\xf3\xb0\xb0\xa8" // U+F0C28
+#define ICON_MDI_ALPHA_U_CIRCLE_OUTLINE "\xf3\xb0\xb0\xa9" // U+F0C29
+#define ICON_MDI_ALPHA_V "\xf3\xb0\xac\x83" // U+F0B03
+#define ICON_MDI_ALPHA_V_BOX "\xf3\xb0\xac\x9d" // U+F0B1D
+#define ICON_MDI_ALPHA_V_BOX_OUTLINE "\xf3\xb0\xb0\xaa" // U+F0C2A
+#define ICON_MDI_ALPHA_V_CIRCLE "\xf3\xb0\xb0\xab" // U+F0C2B
+#define ICON_MDI_ALPHA_V_CIRCLE_OUTLINE "\xf3\xb0\xb0\xac" // U+F0C2C
+#define ICON_MDI_ALPHA_W "\xf3\xb0\xac\x84" // U+F0B04
+#define ICON_MDI_ALPHA_W_BOX "\xf3\xb0\xac\x9e" // U+F0B1E
+#define ICON_MDI_ALPHA_W_BOX_OUTLINE "\xf3\xb0\xb0\xad" // U+F0C2D
+#define ICON_MDI_ALPHA_W_CIRCLE "\xf3\xb0\xb0\xae" // U+F0C2E
+#define ICON_MDI_ALPHA_W_CIRCLE_OUTLINE "\xf3\xb0\xb0\xaf" // U+F0C2F
+#define ICON_MDI_ALPHA_X "\xf3\xb0\xac\x85" // U+F0B05
+#define ICON_MDI_ALPHA_X_BOX "\xf3\xb0\xac\x9f" // U+F0B1F
+#define ICON_MDI_ALPHA_X_BOX_OUTLINE "\xf3\xb0\xb0\xb0" // U+F0C30
+#define ICON_MDI_ALPHA_X_CIRCLE "\xf3\xb0\xb0\xb1" // U+F0C31
+#define ICON_MDI_ALPHA_X_CIRCLE_OUTLINE "\xf3\xb0\xb0\xb2" // U+F0C32
+#define ICON_MDI_ALPHA_Y "\xf3\xb0\xac\x86" // U+F0B06
+#define ICON_MDI_ALPHA_Y_BOX "\xf3\xb0\xac\xa0" // U+F0B20
+#define ICON_MDI_ALPHA_Y_BOX_OUTLINE "\xf3\xb0\xb0\xb3" // U+F0C33
+#define ICON_MDI_ALPHA_Y_CIRCLE "\xf3\xb0\xb0\xb4" // U+F0C34
+#define ICON_MDI_ALPHA_Y_CIRCLE_OUTLINE "\xf3\xb0\xb0\xb5" // U+F0C35
+#define ICON_MDI_ALPHA_Z "\xf3\xb0\xac\x87" // U+F0B07
+#define ICON_MDI_ALPHA_Z_BOX "\xf3\xb0\xac\xa1" // U+F0B21
+#define ICON_MDI_ALPHA_Z_BOX_OUTLINE "\xf3\xb0\xb0\xb6" // U+F0C36
+#define ICON_MDI_ALPHA_Z_CIRCLE "\xf3\xb0\xb0\xb7" // U+F0C37
+#define ICON_MDI_ALPHA_Z_CIRCLE_OUTLINE "\xf3\xb0\xb0\xb8" // U+F0C38
+#define ICON_MDI_ALPHABET_AUREBESH "\xf3\xb1\x8c\xac" // U+F132C
+#define ICON_MDI_ALPHABET_CYRILLIC "\xf3\xb1\x8c\xad" // U+F132D
+#define ICON_MDI_ALPHABET_GREEK "\xf3\xb1\x8c\xae" // U+F132E
+#define ICON_MDI_ALPHABET_LATIN "\xf3\xb1\x8c\xaf" // U+F132F
+#define ICON_MDI_ALPHABET_PIQAD "\xf3\xb1\x8c\xb0" // U+F1330
+#define ICON_MDI_ALPHABET_TENGWAR "\xf3\xb1\x8c\xb7" // U+F1337
+#define ICON_MDI_ALPHABETICAL "\xf3\xb0\x80\xac" // U+F002C
+#define ICON_MDI_ALPHABETICAL_OFF "\xf3\xb1\x80\x8c" // U+F100C
+#define ICON_MDI_ALPHABETICAL_VARIANT "\xf3\xb1\x80\x8d" // U+F100D
+#define ICON_MDI_ALPHABETICAL_VARIANT_OFF "\xf3\xb1\x80\x8e" // U+F100E
+#define ICON_MDI_ALTIMETER "\xf3\xb0\x97\x97" // U+F05D7
+#define ICON_MDI_AMBULANCE "\xf3\xb0\x80\xaf" // U+F002F
+#define ICON_MDI_AMMUNITION "\xf3\xb0\xb3\xa8" // U+F0CE8
+#define ICON_MDI_AMPERSAND "\xf3\xb0\xaa\x8d" // U+F0A8D
+#define ICON_MDI_AMPLIFIER "\xf3\xb0\x80\xb0" // U+F0030
+#define ICON_MDI_AMPLIFIER_OFF "\xf3\xb1\x86\xb5" // U+F11B5
+#define ICON_MDI_ANCHOR "\xf3\xb0\x80\xb1" // U+F0031
+#define ICON_MDI_ANDROID "\xf3\xb0\x80\xb2" // U+F0032
+#define ICON_MDI_ANDROID_STUDIO "\xf3\xb0\x80\xb4" // U+F0034
+#define ICON_MDI_ANGLE_ACUTE "\xf3\xb0\xa4\xb7" // U+F0937
+#define ICON_MDI_ANGLE_OBTUSE "\xf3\xb0\xa4\xb8" // U+F0938
+#define ICON_MDI_ANGLE_RIGHT "\xf3\xb0\xa4\xb9" // U+F0939
+#define ICON_MDI_ANGULAR "\xf3\xb0\x9a\xb2" // U+F06B2
+#define ICON_MDI_ANGULARJS "\xf3\xb0\x9a\xbf" // U+F06BF
+#define ICON_MDI_ANIMATION "\xf3\xb0\x97\x98" // U+F05D8
+#define ICON_MDI_ANIMATION_OUTLINE "\xf3\xb0\xaa\x8f" // U+F0A8F
+#define ICON_MDI_ANIMATION_PLAY "\xf3\xb0\xa4\xba" // U+F093A
+#define ICON_MDI_ANIMATION_PLAY_OUTLINE "\xf3\xb0\xaa\x90" // U+F0A90
+#define ICON_MDI_ANSIBLE "\xf3\xb1\x82\x9a" // U+F109A
+#define ICON_MDI_ANTENNA "\xf3\xb1\x84\x99" // U+F1119
+#define ICON_MDI_ANVIL "\xf3\xb0\xa2\x9b" // U+F089B
+#define ICON_MDI_APACHE_KAFKA "\xf3\xb1\x80\x8f" // U+F100F
+#define ICON_MDI_API "\xf3\xb1\x82\x9b" // U+F109B
+#define ICON_MDI_API_OFF "\xf3\xb1\x89\x97" // U+F1257
+#define ICON_MDI_APPLE "\xf3\xb0\x80\xb5" // U+F0035
+#define ICON_MDI_APPLE_FINDER "\xf3\xb0\x80\xb6" // U+F0036
+#define ICON_MDI_APPLE_ICLOUD "\xf3\xb0\x80\xb8" // U+F0038
+#define ICON_MDI_APPLE_IOS "\xf3\xb0\x80\xb7" // U+F0037
+#define ICON_MDI_APPLE_KEYBOARD_CAPS "\xf3\xb0\x98\xb2" // U+F0632
+#define ICON_MDI_APPLE_KEYBOARD_COMMAND "\xf3\xb0\x98\xb3" // U+F0633
+#define ICON_MDI_APPLE_KEYBOARD_CONTROL "\xf3\xb0\x98\xb4" // U+F0634
+#define ICON_MDI_APPLE_KEYBOARD_OPTION "\xf3\xb0\x98\xb5" // U+F0635
+#define ICON_MDI_APPLE_KEYBOARD_SHIFT "\xf3\xb0\x98\xb6" // U+F0636
+#define ICON_MDI_APPLE_SAFARI "\xf3\xb0\x80\xb9" // U+F0039
+#define ICON_MDI_APPLICATION "\xf3\xb0\xa3\x86" // U+F08C6
+#define ICON_MDI_APPLICATION_ARRAY "\xf3\xb1\x83\xb5" // U+F10F5
+#define ICON_MDI_APPLICATION_ARRAY_OUTLINE "\xf3\xb1\x83\xb6" // U+F10F6
+#define ICON_MDI_APPLICATION_BRACES "\xf3\xb1\x83\xb7" // U+F10F7
+#define ICON_MDI_APPLICATION_BRACES_OUTLINE "\xf3\xb1\x83\xb8" // U+F10F8
+#define ICON_MDI_APPLICATION_BRACKETS "\xf3\xb0\xb2\x8b" // U+F0C8B
+#define ICON_MDI_APPLICATION_BRACKETS_OUTLINE "\xf3\xb0\xb2\x8c" // U+F0C8C
+#define ICON_MDI_APPLICATION_COG "\xf3\xb0\x99\xb5" // U+F0675
+#define ICON_MDI_APPLICATION_COG_OUTLINE "\xf3\xb1\x95\xb7" // U+F1577
+#define ICON_MDI_APPLICATION_EDIT "\xf3\xb0\x82\xae" // U+F00AE
+#define ICON_MDI_APPLICATION_EDIT_OUTLINE "\xf3\xb0\x98\x99" // U+F0619
+#define ICON_MDI_APPLICATION_EXPORT "\xf3\xb0\xb6\xad" // U+F0DAD
+#define ICON_MDI_APPLICATION_IMPORT "\xf3\xb0\xb6\xae" // U+F0DAE
+#define ICON_MDI_APPLICATION_OUTLINE "\xf3\xb0\x98\x94" // U+F0614
+#define ICON_MDI_APPLICATION_PARENTHESES "\xf3\xb1\x83\xb9" // U+F10F9
+#define ICON_MDI_APPLICATION_PARENTHESES_OUTLINE "\xf3\xb1\x83\xba" // U+F10FA
+#define ICON_MDI_APPLICATION_SETTINGS "\xf3\xb0\xad\xa0" // U+F0B60
+#define ICON_MDI_APPLICATION_SETTINGS_OUTLINE "\xf3\xb1\x95\x95" // U+F1555
+#define ICON_MDI_APPLICATION_VARIABLE "\xf3\xb1\x83\xbb" // U+F10FB
+#define ICON_MDI_APPLICATION_VARIABLE_OUTLINE "\xf3\xb1\x83\xbc" // U+F10FC
+#define ICON_MDI_APPROXIMATELY_EQUAL "\xf3\xb0\xbe\x9e" // U+F0F9E
+#define ICON_MDI_APPROXIMATELY_EQUAL_BOX "\xf3\xb0\xbe\x9f" // U+F0F9F
+#define ICON_MDI_APPS "\xf3\xb0\x80\xbb" // U+F003B
+#define ICON_MDI_APPS_BOX "\xf3\xb0\xb5\x86" // U+F0D46
+#define ICON_MDI_ARCH "\xf3\xb0\xa3\x87" // U+F08C7
+#define ICON_MDI_ARCHIVE "\xf3\xb0\x80\xbc" // U+F003C
+#define ICON_MDI_ARCHIVE_ALERT "\xf3\xb1\x93\xbd" // U+F14FD
+#define ICON_MDI_ARCHIVE_ALERT_OUTLINE "\xf3\xb1\x93\xbe" // U+F14FE
+#define ICON_MDI_ARCHIVE_ARROW_DOWN "\xf3\xb1\x89\x99" // U+F1259
+#define ICON_MDI_ARCHIVE_ARROW_DOWN_OUTLINE "\xf3\xb1\x89\x9a" // U+F125A
+#define ICON_MDI_ARCHIVE_ARROW_UP "\xf3\xb1\x89\x9b" // U+F125B
+#define ICON_MDI_ARCHIVE_ARROW_UP_OUTLINE "\xf3\xb1\x89\x9c" // U+F125C
+#define ICON_MDI_ARCHIVE_CANCEL "\xf3\xb1\x9d\x8b" // U+F174B
+#define ICON_MDI_ARCHIVE_CANCEL_OUTLINE "\xf3\xb1\x9d\x8c" // U+F174C
+#define ICON_MDI_ARCHIVE_CHECK "\xf3\xb1\x9d\x8d" // U+F174D
+#define ICON_MDI_ARCHIVE_CHECK_OUTLINE "\xf3\xb1\x9d\x8e" // U+F174E
+#define ICON_MDI_ARCHIVE_CLOCK "\xf3\xb1\x9d\x8f" // U+F174F
+#define ICON_MDI_ARCHIVE_CLOCK_OUTLINE "\xf3\xb1\x9d\x90" // U+F1750
+#define ICON_MDI_ARCHIVE_COG "\xf3\xb1\x9d\x91" // U+F1751
+#define ICON_MDI_ARCHIVE_COG_OUTLINE "\xf3\xb1\x9d\x92" // U+F1752
+#define ICON_MDI_ARCHIVE_EDIT "\xf3\xb1\x9d\x93" // U+F1753
+#define ICON_MDI_ARCHIVE_EDIT_OUTLINE "\xf3\xb1\x9d\x94" // U+F1754
+#define ICON_MDI_ARCHIVE_EYE "\xf3\xb1\x9d\x95" // U+F1755
+#define ICON_MDI_ARCHIVE_EYE_OUTLINE "\xf3\xb1\x9d\x96" // U+F1756
+#define ICON_MDI_ARCHIVE_LOCK "\xf3\xb1\x9d\x97" // U+F1757
+#define ICON_MDI_ARCHIVE_LOCK_OPEN "\xf3\xb1\x9d\x98" // U+F1758
+#define ICON_MDI_ARCHIVE_LOCK_OPEN_OUTLINE "\xf3\xb1\x9d\x99" // U+F1759
+#define ICON_MDI_ARCHIVE_LOCK_OUTLINE "\xf3\xb1\x9d\x9a" // U+F175A
+#define ICON_MDI_ARCHIVE_MARKER "\xf3\xb1\x9d\x9b" // U+F175B
+#define ICON_MDI_ARCHIVE_MARKER_OUTLINE "\xf3\xb1\x9d\x9c" // U+F175C
+#define ICON_MDI_ARCHIVE_MINUS "\xf3\xb1\x9d\x9d" // U+F175D
+#define ICON_MDI_ARCHIVE_MINUS_OUTLINE "\xf3\xb1\x9d\x9e" // U+F175E
+#define ICON_MDI_ARCHIVE_MUSIC "\xf3\xb1\x9d\x9f" // U+F175F
+#define ICON_MDI_ARCHIVE_MUSIC_OUTLINE "\xf3\xb1\x9d\xa0" // U+F1760
+#define ICON_MDI_ARCHIVE_OFF "\xf3\xb1\x9d\xa1" // U+F1761
+#define ICON_MDI_ARCHIVE_OFF_OUTLINE "\xf3\xb1\x9d\xa2" // U+F1762
+#define ICON_MDI_ARCHIVE_OUTLINE "\xf3\xb1\x88\x8e" // U+F120E
+#define ICON_MDI_ARCHIVE_PLUS "\xf3\xb1\x9d\xa3" // U+F1763
+#define ICON_MDI_ARCHIVE_PLUS_OUTLINE "\xf3\xb1\x9d\xa4" // U+F1764
+#define ICON_MDI_ARCHIVE_REFRESH "\xf3\xb1\x9d\xa5" // U+F1765
+#define ICON_MDI_ARCHIVE_REFRESH_OUTLINE "\xf3\xb1\x9d\xa6" // U+F1766
+#define ICON_MDI_ARCHIVE_REMOVE "\xf3\xb1\x9d\xa7" // U+F1767
+#define ICON_MDI_ARCHIVE_REMOVE_OUTLINE "\xf3\xb1\x9d\xa8" // U+F1768
+#define ICON_MDI_ARCHIVE_SEARCH "\xf3\xb1\x9d\xa9" // U+F1769
+#define ICON_MDI_ARCHIVE_SEARCH_OUTLINE "\xf3\xb1\x9d\xaa" // U+F176A
+#define ICON_MDI_ARCHIVE_SETTINGS "\xf3\xb1\x9d\xab" // U+F176B
+#define ICON_MDI_ARCHIVE_SETTINGS_OUTLINE "\xf3\xb1\x9d\xac" // U+F176C
+#define ICON_MDI_ARCHIVE_STAR "\xf3\xb1\x9d\xad" // U+F176D
+#define ICON_MDI_ARCHIVE_STAR_OUTLINE "\xf3\xb1\x9d\xae" // U+F176E
+#define ICON_MDI_ARCHIVE_SYNC "\xf3\xb1\x9d\xaf" // U+F176F
+#define ICON_MDI_ARCHIVE_SYNC_OUTLINE "\xf3\xb1\x9d\xb0" // U+F1770
+#define ICON_MDI_ARM_FLEX "\xf3\xb0\xbf\x97" // U+F0FD7
+#define ICON_MDI_ARM_FLEX_OUTLINE "\xf3\xb0\xbf\x96" // U+F0FD6
+#define ICON_MDI_ARRANGE_BRING_FORWARD "\xf3\xb0\x80\xbd" // U+F003D
+#define ICON_MDI_ARRANGE_BRING_TO_FRONT "\xf3\xb0\x80\xbe" // U+F003E
+#define ICON_MDI_ARRANGE_SEND_BACKWARD "\xf3\xb0\x80\xbf" // U+F003F
+#define ICON_MDI_ARRANGE_SEND_TO_BACK "\xf3\xb0\x81\x80" // U+F0040
+#define ICON_MDI_ARROW_ALL "\xf3\xb0\x81\x81" // U+F0041
+#define ICON_MDI_ARROW_BOTTOM_LEFT "\xf3\xb0\x81\x82" // U+F0042
+#define ICON_MDI_ARROW_BOTTOM_LEFT_BOLD_BOX "\xf3\xb1\xa5\xa4" // U+F1964
+#define ICON_MDI_ARROW_BOTTOM_LEFT_BOLD_BOX_OUTLINE "\xf3\xb1\xa5\xa5" // U+F1965
+#define ICON_MDI_ARROW_BOTTOM_LEFT_BOLD_OUTLINE "\xf3\xb0\xa6\xb7" // U+F09B7
+#define ICON_MDI_ARROW_BOTTOM_LEFT_THICK "\xf3\xb0\xa6\xb8" // U+F09B8
+#define ICON_MDI_ARROW_BOTTOM_LEFT_THIN "\xf3\xb1\xa6\xb6" // U+F19B6
+#define ICON_MDI_ARROW_BOTTOM_LEFT_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x96" // U+F1596
+#define ICON_MDI_ARROW_BOTTOM_RIGHT "\xf3\xb0\x81\x83" // U+F0043
+#define ICON_MDI_ARROW_BOTTOM_RIGHT_BOLD_BOX "\xf3\xb1\xa5\xa6" // U+F1966
+#define ICON_MDI_ARROW_BOTTOM_RIGHT_BOLD_BOX_OUTLINE "\xf3\xb1\xa5\xa7" // U+F1967
+#define ICON_MDI_ARROW_BOTTOM_RIGHT_BOLD_OUTLINE "\xf3\xb0\xa6\xb9" // U+F09B9
+#define ICON_MDI_ARROW_BOTTOM_RIGHT_THICK "\xf3\xb0\xa6\xba" // U+F09BA
+#define ICON_MDI_ARROW_BOTTOM_RIGHT_THIN "\xf3\xb1\xa6\xb7" // U+F19B7
+#define ICON_MDI_ARROW_BOTTOM_RIGHT_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x95" // U+F1595
+#define ICON_MDI_ARROW_COLLAPSE "\xf3\xb0\x98\x95" // U+F0615
+#define ICON_MDI_ARROW_COLLAPSE_ALL "\xf3\xb0\x81\x84" // U+F0044
+#define ICON_MDI_ARROW_COLLAPSE_DOWN "\xf3\xb0\x9e\x92" // U+F0792
+#define ICON_MDI_ARROW_COLLAPSE_HORIZONTAL "\xf3\xb0\xa1\x8c" // U+F084C
+#define ICON_MDI_ARROW_COLLAPSE_LEFT "\xf3\xb0\x9e\x93" // U+F0793
+#define ICON_MDI_ARROW_COLLAPSE_RIGHT "\xf3\xb0\x9e\x94" // U+F0794
+#define ICON_MDI_ARROW_COLLAPSE_UP "\xf3\xb0\x9e\x95" // U+F0795
+#define ICON_MDI_ARROW_COLLAPSE_VERTICAL "\xf3\xb0\xa1\x8d" // U+F084D
+#define ICON_MDI_ARROW_DECISION "\xf3\xb0\xa6\xbb" // U+F09BB
+#define ICON_MDI_ARROW_DECISION_AUTO "\xf3\xb0\xa6\xbc" // U+F09BC
+#define ICON_MDI_ARROW_DECISION_AUTO_OUTLINE "\xf3\xb0\xa6\xbd" // U+F09BD
+#define ICON_MDI_ARROW_DECISION_OUTLINE "\xf3\xb0\xa6\xbe" // U+F09BE
+#define ICON_MDI_ARROW_DOWN "\xf3\xb0\x81\x85" // U+F0045
+#define ICON_MDI_ARROW_DOWN_BOLD "\xf3\xb0\x9c\xae" // U+F072E
+#define ICON_MDI_ARROW_DOWN_BOLD_BOX "\xf3\xb0\x9c\xaf" // U+F072F
+#define ICON_MDI_ARROW_DOWN_BOLD_BOX_OUTLINE "\xf3\xb0\x9c\xb0" // U+F0730
+#define ICON_MDI_ARROW_DOWN_BOLD_CIRCLE "\xf3\xb0\x81\x87" // U+F0047
+#define ICON_MDI_ARROW_DOWN_BOLD_CIRCLE_OUTLINE "\xf3\xb0\x81\x88" // U+F0048
+#define ICON_MDI_ARROW_DOWN_BOLD_HEXAGON_OUTLINE "\xf3\xb0\x81\x89" // U+F0049
+#define ICON_MDI_ARROW_DOWN_BOLD_OUTLINE "\xf3\xb0\xa6\xbf" // U+F09BF
+#define ICON_MDI_ARROW_DOWN_BOX "\xf3\xb0\x9b\x80" // U+F06C0
+#define ICON_MDI_ARROW_DOWN_CIRCLE "\xf3\xb0\xb3\x9b" // U+F0CDB
+#define ICON_MDI_ARROW_DOWN_CIRCLE_OUTLINE "\xf3\xb0\xb3\x9c" // U+F0CDC
+#define ICON_MDI_ARROW_DOWN_DROP_CIRCLE "\xf3\xb0\x81\x8a" // U+F004A
+#define ICON_MDI_ARROW_DOWN_DROP_CIRCLE_OUTLINE "\xf3\xb0\x81\x8b" // U+F004B
+#define ICON_MDI_ARROW_DOWN_LEFT "\xf3\xb1\x9e\xa1" // U+F17A1
+#define ICON_MDI_ARROW_DOWN_LEFT_BOLD "\xf3\xb1\x9e\xa2" // U+F17A2
+#define ICON_MDI_ARROW_DOWN_RIGHT "\xf3\xb1\x9e\xa3" // U+F17A3
+#define ICON_MDI_ARROW_DOWN_RIGHT_BOLD "\xf3\xb1\x9e\xa4" // U+F17A4
+#define ICON_MDI_ARROW_DOWN_THICK "\xf3\xb0\x81\x86" // U+F0046
+#define ICON_MDI_ARROW_DOWN_THIN "\xf3\xb1\xa6\xb3" // U+F19B3
+#define ICON_MDI_ARROW_DOWN_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x99" // U+F1599
+#define ICON_MDI_ARROW_EXPAND "\xf3\xb0\x98\x96" // U+F0616
+#define ICON_MDI_ARROW_EXPAND_ALL "\xf3\xb0\x81\x8c" // U+F004C
+#define ICON_MDI_ARROW_EXPAND_DOWN "\xf3\xb0\x9e\x96" // U+F0796
+#define ICON_MDI_ARROW_EXPAND_HORIZONTAL "\xf3\xb0\xa1\x8e" // U+F084E
+#define ICON_MDI_ARROW_EXPAND_LEFT "\xf3\xb0\x9e\x97" // U+F0797
+#define ICON_MDI_ARROW_EXPAND_RIGHT "\xf3\xb0\x9e\x98" // U+F0798
+#define ICON_MDI_ARROW_EXPAND_UP "\xf3\xb0\x9e\x99" // U+F0799
+#define ICON_MDI_ARROW_EXPAND_VERTICAL "\xf3\xb0\xa1\x8f" // U+F084F
+#define ICON_MDI_ARROW_HORIZONTAL_LOCK "\xf3\xb1\x85\x9b" // U+F115B
+#define ICON_MDI_ARROW_LEFT "\xf3\xb0\x81\x8d" // U+F004D
+#define ICON_MDI_ARROW_LEFT_BOLD "\xf3\xb0\x9c\xb1" // U+F0731
+#define ICON_MDI_ARROW_LEFT_BOLD_BOX "\xf3\xb0\x9c\xb2" // U+F0732
+#define ICON_MDI_ARROW_LEFT_BOLD_BOX_OUTLINE "\xf3\xb0\x9c\xb3" // U+F0733
+#define ICON_MDI_ARROW_LEFT_BOLD_CIRCLE "\xf3\xb0\x81\x8f" // U+F004F
+#define ICON_MDI_ARROW_LEFT_BOLD_CIRCLE_OUTLINE "\xf3\xb0\x81\x90" // U+F0050
+#define ICON_MDI_ARROW_LEFT_BOLD_HEXAGON_OUTLINE "\xf3\xb0\x81\x91" // U+F0051
+#define ICON_MDI_ARROW_LEFT_BOLD_OUTLINE "\xf3\xb0\xa7\x80" // U+F09C0
+#define ICON_MDI_ARROW_LEFT_BOTTOM "\xf3\xb1\x9e\xa5" // U+F17A5
+#define ICON_MDI_ARROW_LEFT_BOTTOM_BOLD "\xf3\xb1\x9e\xa6" // U+F17A6
+#define ICON_MDI_ARROW_LEFT_BOX "\xf3\xb0\x9b\x81" // U+F06C1
+#define ICON_MDI_ARROW_LEFT_CIRCLE "\xf3\xb0\xb3\x9d" // U+F0CDD
+#define ICON_MDI_ARROW_LEFT_CIRCLE_OUTLINE "\xf3\xb0\xb3\x9e" // U+F0CDE
+#define ICON_MDI_ARROW_LEFT_DROP_CIRCLE "\xf3\xb0\x81\x92" // U+F0052
+#define ICON_MDI_ARROW_LEFT_DROP_CIRCLE_OUTLINE "\xf3\xb0\x81\x93" // U+F0053
+#define ICON_MDI_ARROW_LEFT_RIGHT "\xf3\xb0\xb9\xb3" // U+F0E73
+#define ICON_MDI_ARROW_LEFT_RIGHT_BOLD "\xf3\xb0\xb9\xb4" // U+F0E74
+#define ICON_MDI_ARROW_LEFT_RIGHT_BOLD_OUTLINE "\xf3\xb0\xa7\x81" // U+F09C1
+#define ICON_MDI_ARROW_LEFT_THICK "\xf3\xb0\x81\x8e" // U+F004E
+#define ICON_MDI_ARROW_LEFT_THIN "\xf3\xb1\xa6\xb1" // U+F19B1
+#define ICON_MDI_ARROW_LEFT_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x9a" // U+F159A
+#define ICON_MDI_ARROW_LEFT_TOP "\xf3\xb1\x9e\xa7" // U+F17A7
+#define ICON_MDI_ARROW_LEFT_TOP_BOLD "\xf3\xb1\x9e\xa8" // U+F17A8
+#define ICON_MDI_ARROW_OSCILLATING "\xf3\xb1\xb2\x91" // U+F1C91
+#define ICON_MDI_ARROW_OSCILLATING_OFF "\xf3\xb1\xb2\x92" // U+F1C92
+#define ICON_MDI_ARROW_PROJECTILE "\xf3\xb1\xa1\x80" // U+F1840
+#define ICON_MDI_ARROW_PROJECTILE_MULTIPLE "\xf3\xb1\xa0\xbf" // U+F183F
+#define ICON_MDI_ARROW_RIGHT "\xf3\xb0\x81\x94" // U+F0054
+#define ICON_MDI_ARROW_RIGHT_BOLD "\xf3\xb0\x9c\xb4" // U+F0734
+#define ICON_MDI_ARROW_RIGHT_BOLD_BOX "\xf3\xb0\x9c\xb5" // U+F0735
+#define ICON_MDI_ARROW_RIGHT_BOLD_BOX_OUTLINE "\xf3\xb0\x9c\xb6" // U+F0736
+#define ICON_MDI_ARROW_RIGHT_BOLD_CIRCLE "\xf3\xb0\x81\x96" // U+F0056
+#define ICON_MDI_ARROW_RIGHT_BOLD_CIRCLE_OUTLINE "\xf3\xb0\x81\x97" // U+F0057
+#define ICON_MDI_ARROW_RIGHT_BOLD_HEXAGON_OUTLINE "\xf3\xb0\x81\x98" // U+F0058
+#define ICON_MDI_ARROW_RIGHT_BOLD_OUTLINE "\xf3\xb0\xa7\x82" // U+F09C2
+#define ICON_MDI_ARROW_RIGHT_BOTTOM "\xf3\xb1\x9e\xa9" // U+F17A9
+#define ICON_MDI_ARROW_RIGHT_BOTTOM_BOLD "\xf3\xb1\x9e\xaa" // U+F17AA
+#define ICON_MDI_ARROW_RIGHT_BOX "\xf3\xb0\x9b\x82" // U+F06C2
+#define ICON_MDI_ARROW_RIGHT_CIRCLE "\xf3\xb0\xb3\x9f" // U+F0CDF
+#define ICON_MDI_ARROW_RIGHT_CIRCLE_OUTLINE "\xf3\xb0\xb3\xa0" // U+F0CE0
+#define ICON_MDI_ARROW_RIGHT_DROP_CIRCLE "\xf3\xb0\x81\x99" // U+F0059
+#define ICON_MDI_ARROW_RIGHT_DROP_CIRCLE_OUTLINE "\xf3\xb0\x81\x9a" // U+F005A
+#define ICON_MDI_ARROW_RIGHT_THICK "\xf3\xb0\x81\x95" // U+F0055
+#define ICON_MDI_ARROW_RIGHT_THIN "\xf3\xb1\xa6\xb0" // U+F19B0
+#define ICON_MDI_ARROW_RIGHT_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x98" // U+F1598
+#define ICON_MDI_ARROW_RIGHT_TOP "\xf3\xb1\x9e\xab" // U+F17AB
+#define ICON_MDI_ARROW_RIGHT_TOP_BOLD "\xf3\xb1\x9e\xac" // U+F17AC
+#define ICON_MDI_ARROW_SPLIT_HORIZONTAL "\xf3\xb0\xa4\xbb" // U+F093B
+#define ICON_MDI_ARROW_SPLIT_VERTICAL "\xf3\xb0\xa4\xbc" // U+F093C
+#define ICON_MDI_ARROW_TOP_LEFT "\xf3\xb0\x81\x9b" // U+F005B
+#define ICON_MDI_ARROW_TOP_LEFT_BOLD_BOX "\xf3\xb1\xa5\xa8" // U+F1968
+#define ICON_MDI_ARROW_TOP_LEFT_BOLD_BOX_OUTLINE "\xf3\xb1\xa5\xa9" // U+F1969
+#define ICON_MDI_ARROW_TOP_LEFT_BOLD_OUTLINE "\xf3\xb0\xa7\x83" // U+F09C3
+#define ICON_MDI_ARROW_TOP_LEFT_BOTTOM_RIGHT "\xf3\xb0\xb9\xb5" // U+F0E75
+#define ICON_MDI_ARROW_TOP_LEFT_BOTTOM_RIGHT_BOLD "\xf3\xb0\xb9\xb6" // U+F0E76
+#define ICON_MDI_ARROW_TOP_LEFT_THICK "\xf3\xb0\xa7\x84" // U+F09C4
+#define ICON_MDI_ARROW_TOP_LEFT_THIN "\xf3\xb1\xa6\xb5" // U+F19B5
+#define ICON_MDI_ARROW_TOP_LEFT_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x93" // U+F1593
+#define ICON_MDI_ARROW_TOP_RIGHT "\xf3\xb0\x81\x9c" // U+F005C
+#define ICON_MDI_ARROW_TOP_RIGHT_BOLD_BOX "\xf3\xb1\xa5\xaa" // U+F196A
+#define ICON_MDI_ARROW_TOP_RIGHT_BOLD_BOX_OUTLINE "\xf3\xb1\xa5\xab" // U+F196B
+#define ICON_MDI_ARROW_TOP_RIGHT_BOLD_OUTLINE "\xf3\xb0\xa7\x85" // U+F09C5
+#define ICON_MDI_ARROW_TOP_RIGHT_BOTTOM_LEFT "\xf3\xb0\xb9\xb7" // U+F0E77
+#define ICON_MDI_ARROW_TOP_RIGHT_BOTTOM_LEFT_BOLD "\xf3\xb0\xb9\xb8" // U+F0E78
+#define ICON_MDI_ARROW_TOP_RIGHT_THICK "\xf3\xb0\xa7\x86" // U+F09C6
+#define ICON_MDI_ARROW_TOP_RIGHT_THIN "\xf3\xb1\xa6\xb4" // U+F19B4
+#define ICON_MDI_ARROW_TOP_RIGHT_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x94" // U+F1594
+#define ICON_MDI_ARROW_U_DOWN_LEFT "\xf3\xb1\x9e\xad" // U+F17AD
+#define ICON_MDI_ARROW_U_DOWN_LEFT_BOLD "\xf3\xb1\x9e\xae" // U+F17AE
+#define ICON_MDI_ARROW_U_DOWN_RIGHT "\xf3\xb1\x9e\xaf" // U+F17AF
+#define ICON_MDI_ARROW_U_DOWN_RIGHT_BOLD "\xf3\xb1\x9e\xb0" // U+F17B0
+#define ICON_MDI_ARROW_U_LEFT_BOTTOM "\xf3\xb1\x9e\xb1" // U+F17B1
+#define ICON_MDI_ARROW_U_LEFT_BOTTOM_BOLD "\xf3\xb1\x9e\xb2" // U+F17B2
+#define ICON_MDI_ARROW_U_LEFT_TOP "\xf3\xb1\x9e\xb3" // U+F17B3
+#define ICON_MDI_ARROW_U_LEFT_TOP_BOLD "\xf3\xb1\x9e\xb4" // U+F17B4
+#define ICON_MDI_ARROW_U_RIGHT_BOTTOM "\xf3\xb1\x9e\xb5" // U+F17B5
+#define ICON_MDI_ARROW_U_RIGHT_BOTTOM_BOLD "\xf3\xb1\x9e\xb6" // U+F17B6
+#define ICON_MDI_ARROW_U_RIGHT_TOP "\xf3\xb1\x9e\xb7" // U+F17B7
+#define ICON_MDI_ARROW_U_RIGHT_TOP_BOLD "\xf3\xb1\x9e\xb8" // U+F17B8
+#define ICON_MDI_ARROW_U_UP_LEFT "\xf3\xb1\x9e\xb9" // U+F17B9
+#define ICON_MDI_ARROW_U_UP_LEFT_BOLD "\xf3\xb1\x9e\xba" // U+F17BA
+#define ICON_MDI_ARROW_U_UP_RIGHT "\xf3\xb1\x9e\xbb" // U+F17BB
+#define ICON_MDI_ARROW_U_UP_RIGHT_BOLD "\xf3\xb1\x9e\xbc" // U+F17BC
+#define ICON_MDI_ARROW_UP "\xf3\xb0\x81\x9d" // U+F005D
+#define ICON_MDI_ARROW_UP_BOLD "\xf3\xb0\x9c\xb7" // U+F0737
+#define ICON_MDI_ARROW_UP_BOLD_BOX "\xf3\xb0\x9c\xb8" // U+F0738
+#define ICON_MDI_ARROW_UP_BOLD_BOX_OUTLINE "\xf3\xb0\x9c\xb9" // U+F0739
+#define ICON_MDI_ARROW_UP_BOLD_CIRCLE "\xf3\xb0\x81\x9f" // U+F005F
+#define ICON_MDI_ARROW_UP_BOLD_CIRCLE_OUTLINE "\xf3\xb0\x81\xa0" // U+F0060
+#define ICON_MDI_ARROW_UP_BOLD_HEXAGON_OUTLINE "\xf3\xb0\x81\xa1" // U+F0061
+#define ICON_MDI_ARROW_UP_BOLD_OUTLINE "\xf3\xb0\xa7\x87" // U+F09C7
+#define ICON_MDI_ARROW_UP_BOX "\xf3\xb0\x9b\x83" // U+F06C3
+#define ICON_MDI_ARROW_UP_CIRCLE "\xf3\xb0\xb3\xa1" // U+F0CE1
+#define ICON_MDI_ARROW_UP_CIRCLE_OUTLINE "\xf3\xb0\xb3\xa2" // U+F0CE2
+#define ICON_MDI_ARROW_UP_DOWN "\xf3\xb0\xb9\xb9" // U+F0E79
+#define ICON_MDI_ARROW_UP_DOWN_BOLD "\xf3\xb0\xb9\xba" // U+F0E7A
+#define ICON_MDI_ARROW_UP_DOWN_BOLD_OUTLINE "\xf3\xb0\xa7\x88" // U+F09C8
+#define ICON_MDI_ARROW_UP_DROP_CIRCLE "\xf3\xb0\x81\xa2" // U+F0062
+#define ICON_MDI_ARROW_UP_DROP_CIRCLE_OUTLINE "\xf3\xb0\x81\xa3" // U+F0063
+#define ICON_MDI_ARROW_UP_LEFT "\xf3\xb1\x9e\xbd" // U+F17BD
+#define ICON_MDI_ARROW_UP_LEFT_BOLD "\xf3\xb1\x9e\xbe" // U+F17BE
+#define ICON_MDI_ARROW_UP_RIGHT "\xf3\xb1\x9e\xbf" // U+F17BF
+#define ICON_MDI_ARROW_UP_RIGHT_BOLD "\xf3\xb1\x9f\x80" // U+F17C0
+#define ICON_MDI_ARROW_UP_THICK "\xf3\xb0\x81\x9e" // U+F005E
+#define ICON_MDI_ARROW_UP_THIN "\xf3\xb1\xa6\xb2" // U+F19B2
+#define ICON_MDI_ARROW_UP_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x97" // U+F1597
+#define ICON_MDI_ARROW_VERTICAL_LOCK "\xf3\xb1\x85\x9c" // U+F115C
+#define ICON_MDI_ARTBOARD "\xf3\xb1\xae\x9a" // U+F1B9A
+#define ICON_MDI_ARTSTATION "\xf3\xb0\xad\x9b" // U+F0B5B
+#define ICON_MDI_ASPECT_RATIO "\xf3\xb0\xa8\xa4" // U+F0A24
+#define ICON_MDI_ASSISTANT "\xf3\xb0\x81\xa4" // U+F0064
+#define ICON_MDI_ASTERISK "\xf3\xb0\x9b\x84" // U+F06C4
+#define ICON_MDI_ASTERISK_CIRCLE_OUTLINE "\xf3\xb1\xa8\xa7" // U+F1A27
+#define ICON_MDI_AT "\xf3\xb0\x81\xa5" // U+F0065
+#define ICON_MDI_ATLASSIAN "\xf3\xb0\xa0\x84" // U+F0804
+#define ICON_MDI_ATM "\xf3\xb0\xb5\x87" // U+F0D47
+#define ICON_MDI_ATOM "\xf3\xb0\x9d\xa8" // U+F0768
+#define ICON_MDI_ATOM_VARIANT "\xf3\xb0\xb9\xbb" // U+F0E7B
+#define ICON_MDI_ATTACHMENT "\xf3\xb0\x81\xa6" // U+F0066
+#define ICON_MDI_ATTACHMENT_CHECK "\xf3\xb1\xab\x81" // U+F1AC1
+#define ICON_MDI_ATTACHMENT_LOCK "\xf3\xb1\xa7\x84" // U+F19C4
+#define ICON_MDI_ATTACHMENT_MINUS "\xf3\xb1\xab\x82" // U+F1AC2
+#define ICON_MDI_ATTACHMENT_OFF "\xf3\xb1\xab\x83" // U+F1AC3
+#define ICON_MDI_ATTACHMENT_PLUS "\xf3\xb1\xab\x84" // U+F1AC4
+#define ICON_MDI_ATTACHMENT_REMOVE "\xf3\xb1\xab\x85" // U+F1AC5
+#define ICON_MDI_ATV "\xf3\xb1\xad\xb0" // U+F1B70
+#define ICON_MDI_AUDIO_INPUT_RCA "\xf3\xb1\xa1\xab" // U+F186B
+#define ICON_MDI_AUDIO_INPUT_STEREO_MINIJACK "\xf3\xb1\xa1\xac" // U+F186C
+#define ICON_MDI_AUDIO_INPUT_XLR "\xf3\xb1\xa1\xad" // U+F186D
+#define ICON_MDI_AUDIO_VIDEO "\xf3\xb0\xa4\xbd" // U+F093D
+#define ICON_MDI_AUDIO_VIDEO_OFF "\xf3\xb1\x86\xb6" // U+F11B6
+#define ICON_MDI_AUGMENTED_REALITY "\xf3\xb0\xa1\x90" // U+F0850
+#define ICON_MDI_AURORA "\xf3\xb1\xae\xb9" // U+F1BB9
+#define ICON_MDI_AUTO_DOWNLOAD "\xf3\xb1\x8d\xbe" // U+F137E
+#define ICON_MDI_AUTO_FIX "\xf3\xb0\x81\xa8" // U+F0068
+#define ICON_MDI_AUTO_MODE "\xf3\xb1\xb0\xa0" // U+F1C20
+#define ICON_MDI_AUTO_UPLOAD "\xf3\xb0\x81\xa9" // U+F0069
+#define ICON_MDI_AUTORENEW "\xf3\xb0\x81\xaa" // U+F006A
+#define ICON_MDI_AUTORENEW_OFF "\xf3\xb1\xa7\xa7" // U+F19E7
+#define ICON_MDI_AV_TIMER "\xf3\xb0\x81\xab" // U+F006B
+#define ICON_MDI_AWNING "\xf3\xb1\xae\x87" // U+F1B87
+#define ICON_MDI_AWNING_OUTLINE "\xf3\xb1\xae\x88" // U+F1B88
+#define ICON_MDI_AWS "\xf3\xb0\xb8\x8f" // U+F0E0F
+#define ICON_MDI_AXE "\xf3\xb0\xa3\x88" // U+F08C8
+#define ICON_MDI_AXE_BATTLE "\xf3\xb1\xa1\x82" // U+F1842
+#define ICON_MDI_AXIS "\xf3\xb0\xb5\x88" // U+F0D48
+#define ICON_MDI_AXIS_ARROW "\xf3\xb0\xb5\x89" // U+F0D49
+#define ICON_MDI_AXIS_ARROW_INFO "\xf3\xb1\x90\x8e" // U+F140E
+#define ICON_MDI_AXIS_ARROW_LOCK "\xf3\xb0\xb5\x8a" // U+F0D4A
+#define ICON_MDI_AXIS_LOCK "\xf3\xb0\xb5\x8b" // U+F0D4B
+#define ICON_MDI_AXIS_X_ARROW "\xf3\xb0\xb5\x8c" // U+F0D4C
+#define ICON_MDI_AXIS_X_ARROW_LOCK "\xf3\xb0\xb5\x8d" // U+F0D4D
+#define ICON_MDI_AXIS_X_ROTATE_CLOCKWISE "\xf3\xb0\xb5\x8e" // U+F0D4E
+#define ICON_MDI_AXIS_X_ROTATE_COUNTERCLOCKWISE "\xf3\xb0\xb5\x8f" // U+F0D4F
+#define ICON_MDI_AXIS_X_Y_ARROW_LOCK "\xf3\xb0\xb5\x90" // U+F0D50
+#define ICON_MDI_AXIS_Y_ARROW "\xf3\xb0\xb5\x91" // U+F0D51
+#define ICON_MDI_AXIS_Y_ARROW_LOCK "\xf3\xb0\xb5\x92" // U+F0D52
+#define ICON_MDI_AXIS_Y_ROTATE_CLOCKWISE "\xf3\xb0\xb5\x93" // U+F0D53
+#define ICON_MDI_AXIS_Y_ROTATE_COUNTERCLOCKWISE "\xf3\xb0\xb5\x94" // U+F0D54
+#define ICON_MDI_AXIS_Z_ARROW "\xf3\xb0\xb5\x95" // U+F0D55
+#define ICON_MDI_AXIS_Z_ARROW_LOCK "\xf3\xb0\xb5\x96" // U+F0D56
+#define ICON_MDI_AXIS_Z_ROTATE_CLOCKWISE "\xf3\xb0\xb5\x97" // U+F0D57
+#define ICON_MDI_AXIS_Z_ROTATE_COUNTERCLOCKWISE "\xf3\xb0\xb5\x98" // U+F0D58
+#define ICON_MDI_BABEL "\xf3\xb0\xa8\xa5" // U+F0A25
+#define ICON_MDI_BABY "\xf3\xb0\x81\xac" // U+F006C
+#define ICON_MDI_BABY_BOTTLE "\xf3\xb0\xbc\xb9" // U+F0F39
+#define ICON_MDI_BABY_BOTTLE_OUTLINE "\xf3\xb0\xbc\xba" // U+F0F3A
+#define ICON_MDI_BABY_BUGGY "\xf3\xb1\x8f\xa0" // U+F13E0
+#define ICON_MDI_BABY_BUGGY_OFF "\xf3\xb1\xab\xb3" // U+F1AF3
+#define ICON_MDI_BABY_CARRIAGE "\xf3\xb0\x9a\x8f" // U+F068F
+#define ICON_MDI_BABY_CARRIAGE_OFF "\xf3\xb0\xbe\xa0" // U+F0FA0
+#define ICON_MDI_BABY_FACE "\xf3\xb0\xb9\xbc" // U+F0E7C
+#define ICON_MDI_BABY_FACE_OUTLINE "\xf3\xb0\xb9\xbd" // U+F0E7D
+#define ICON_MDI_BACKBURGER "\xf3\xb0\x81\xad" // U+F006D
+#define ICON_MDI_BACKSPACE "\xf3\xb0\x81\xae" // U+F006E
+#define ICON_MDI_BACKSPACE_OUTLINE "\xf3\xb0\xad\x9c" // U+F0B5C
+#define ICON_MDI_BACKSPACE_REVERSE "\xf3\xb0\xb9\xbe" // U+F0E7E
+#define ICON_MDI_BACKSPACE_REVERSE_OUTLINE "\xf3\xb0\xb9\xbf" // U+F0E7F
+#define ICON_MDI_BACKUP_RESTORE "\xf3\xb0\x81\xaf" // U+F006F
+#define ICON_MDI_BACTERIA "\xf3\xb0\xbb\x95" // U+F0ED5
+#define ICON_MDI_BACTERIA_OUTLINE "\xf3\xb0\xbb\x96" // U+F0ED6
+#define ICON_MDI_BADGE_ACCOUNT "\xf3\xb0\xb6\xa7" // U+F0DA7
+#define ICON_MDI_BADGE_ACCOUNT_ALERT "\xf3\xb0\xb6\xa8" // U+F0DA8
+#define ICON_MDI_BADGE_ACCOUNT_ALERT_OUTLINE "\xf3\xb0\xb6\xa9" // U+F0DA9
+#define ICON_MDI_BADGE_ACCOUNT_HORIZONTAL "\xf3\xb0\xb8\x8d" // U+F0E0D
+#define ICON_MDI_BADGE_ACCOUNT_HORIZONTAL_OUTLINE "\xf3\xb0\xb8\x8e" // U+F0E0E
+#define ICON_MDI_BADGE_ACCOUNT_OUTLINE "\xf3\xb0\xb6\xaa" // U+F0DAA
+#define ICON_MDI_BADMINTON "\xf3\xb0\xa1\x91" // U+F0851
+#define ICON_MDI_BAG_CARRY_ON "\xf3\xb0\xbc\xbb" // U+F0F3B
+#define ICON_MDI_BAG_CARRY_ON_CHECK "\xf3\xb0\xb5\xa5" // U+F0D65
+#define ICON_MDI_BAG_CARRY_ON_OFF "\xf3\xb0\xbc\xbc" // U+F0F3C
+#define ICON_MDI_BAG_CHECKED "\xf3\xb0\xbc\xbd" // U+F0F3D
+#define ICON_MDI_BAG_PERSONAL "\xf3\xb0\xb8\x90" // U+F0E10
+#define ICON_MDI_BAG_PERSONAL_OFF "\xf3\xb0\xb8\x91" // U+F0E11
+#define ICON_MDI_BAG_PERSONAL_OFF_OUTLINE "\xf3\xb0\xb8\x92" // U+F0E12
+#define ICON_MDI_BAG_PERSONAL_OUTLINE "\xf3\xb0\xb8\x93" // U+F0E13
+#define ICON_MDI_BAG_PERSONAL_PLUS "\xf3\xb1\xb2\xa4" // U+F1CA4
+#define ICON_MDI_BAG_PERSONAL_PLUS_OUTLINE "\xf3\xb1\xb2\xa5" // U+F1CA5
+#define ICON_MDI_BAG_PERSONAL_TAG "\xf3\xb1\xac\x8c" // U+F1B0C
+#define ICON_MDI_BAG_PERSONAL_TAG_OUTLINE "\xf3\xb1\xac\x8d" // U+F1B0D
+#define ICON_MDI_BAG_SUITCASE "\xf3\xb1\x96\x8b" // U+F158B
+#define ICON_MDI_BAG_SUITCASE_OFF "\xf3\xb1\x96\x8d" // U+F158D
+#define ICON_MDI_BAG_SUITCASE_OFF_OUTLINE "\xf3\xb1\x96\x8e" // U+F158E
+#define ICON_MDI_BAG_SUITCASE_OUTLINE "\xf3\xb1\x96\x8c" // U+F158C
+#define ICON_MDI_BAGUETTE "\xf3\xb0\xbc\xbe" // U+F0F3E
+#define ICON_MDI_BALCONY "\xf3\xb1\xa0\x97" // U+F1817
+#define ICON_MDI_BALLOON "\xf3\xb0\xa8\xa6" // U+F0A26
+#define ICON_MDI_BALLOT "\xf3\xb0\xa7\x89" // U+F09C9
+#define ICON_MDI_BALLOT_OUTLINE "\xf3\xb0\xa7\x8a" // U+F09CA
+#define ICON_MDI_BALLOT_RECOUNT "\xf3\xb0\xb0\xb9" // U+F0C39
+#define ICON_MDI_BALLOT_RECOUNT_OUTLINE "\xf3\xb0\xb0\xba" // U+F0C3A
+#define ICON_MDI_BANDAGE "\xf3\xb0\xb6\xaf" // U+F0DAF
+#define ICON_MDI_BANK "\xf3\xb0\x81\xb0" // U+F0070
+#define ICON_MDI_BANK_CHECK "\xf3\xb1\x99\x95" // U+F1655
+#define ICON_MDI_BANK_CIRCLE "\xf3\xb1\xb0\x83" // U+F1C03
+#define ICON_MDI_BANK_CIRCLE_OUTLINE "\xf3\xb1\xb0\x84" // U+F1C04
+#define ICON_MDI_BANK_MINUS "\xf3\xb0\xb6\xb0" // U+F0DB0
+#define ICON_MDI_BANK_OFF "\xf3\xb1\x99\x96" // U+F1656
+#define ICON_MDI_BANK_OFF_OUTLINE "\xf3\xb1\x99\x97" // U+F1657
+#define ICON_MDI_BANK_OUTLINE "\xf3\xb0\xba\x80" // U+F0E80
+#define ICON_MDI_BANK_PLUS "\xf3\xb0\xb6\xb1" // U+F0DB1
+#define ICON_MDI_BANK_REMOVE "\xf3\xb0\xb6\xb2" // U+F0DB2
+#define ICON_MDI_BANK_TRANSFER "\xf3\xb0\xa8\xa7" // U+F0A27
+#define ICON_MDI_BANK_TRANSFER_IN "\xf3\xb0\xa8\xa8" // U+F0A28
+#define ICON_MDI_BANK_TRANSFER_OUT "\xf3\xb0\xa8\xa9" // U+F0A29
+#define ICON_MDI_BARCODE "\xf3\xb0\x81\xb1" // U+F0071
+#define ICON_MDI_BARCODE_OFF "\xf3\xb1\x88\xb6" // U+F1236
+#define ICON_MDI_BARCODE_SCAN "\xf3\xb0\x81\xb2" // U+F0072
+#define ICON_MDI_BARLEY "\xf3\xb0\x81\xb3" // U+F0073
+#define ICON_MDI_BARLEY_OFF "\xf3\xb0\xad\x9d" // U+F0B5D
+#define ICON_MDI_BARN "\xf3\xb0\xad\x9e" // U+F0B5E
+#define ICON_MDI_BARREL "\xf3\xb0\x81\xb4" // U+F0074
+#define ICON_MDI_BARREL_OUTLINE "\xf3\xb1\xa8\xa8" // U+F1A28
+#define ICON_MDI_BASEBALL "\xf3\xb0\xa1\x92" // U+F0852
+#define ICON_MDI_BASEBALL_BAT "\xf3\xb0\xa1\x93" // U+F0853
+#define ICON_MDI_BASEBALL_DIAMOND "\xf3\xb1\x97\xac" // U+F15EC
+#define ICON_MDI_BASEBALL_DIAMOND_OUTLINE "\xf3\xb1\x97\xad" // U+F15ED
+#define ICON_MDI_BASEBALL_OUTLINE "\xf3\xb1\xb1\x9a" // U+F1C5A
+#define ICON_MDI_BASH "\xf3\xb1\x86\x83" // U+F1183
+#define ICON_MDI_BASKET "\xf3\xb0\x81\xb6" // U+F0076
+#define ICON_MDI_BASKET_CHECK "\xf3\xb1\xa3\xa5" // U+F18E5
+#define ICON_MDI_BASKET_CHECK_OUTLINE "\xf3\xb1\xa3\xa6" // U+F18E6
+#define ICON_MDI_BASKET_FILL "\xf3\xb0\x81\xb7" // U+F0077
+#define ICON_MDI_BASKET_MINUS "\xf3\xb1\x94\xa3" // U+F1523
+#define ICON_MDI_BASKET_MINUS_OUTLINE "\xf3\xb1\x94\xa4" // U+F1524
+#define ICON_MDI_BASKET_OFF "\xf3\xb1\x94\xa5" // U+F1525
+#define ICON_MDI_BASKET_OFF_OUTLINE "\xf3\xb1\x94\xa6" // U+F1526
+#define ICON_MDI_BASKET_OUTLINE "\xf3\xb1\x86\x81" // U+F1181
+#define ICON_MDI_BASKET_PLUS "\xf3\xb1\x94\xa7" // U+F1527
+#define ICON_MDI_BASKET_PLUS_OUTLINE "\xf3\xb1\x94\xa8" // U+F1528
+#define ICON_MDI_BASKET_REMOVE "\xf3\xb1\x94\xa9" // U+F1529
+#define ICON_MDI_BASKET_REMOVE_OUTLINE "\xf3\xb1\x94\xaa" // U+F152A
+#define ICON_MDI_BASKET_UNFILL "\xf3\xb0\x81\xb8" // U+F0078
+#define ICON_MDI_BASKETBALL "\xf3\xb0\xa0\x86" // U+F0806
+#define ICON_MDI_BASKETBALL_HOOP "\xf3\xb0\xb0\xbb" // U+F0C3B
+#define ICON_MDI_BASKETBALL_HOOP_OUTLINE "\xf3\xb0\xb0\xbc" // U+F0C3C
+#define ICON_MDI_BAT "\xf3\xb0\xad\x9f" // U+F0B5F
+#define ICON_MDI_BATHTUB "\xf3\xb1\xa0\x98" // U+F1818
+#define ICON_MDI_BATHTUB_OUTLINE "\xf3\xb1\xa0\x99" // U+F1819
+#define ICON_MDI_BATTERY "\xf3\xb0\x81\xb9" // U+F0079
+#define ICON_MDI_BATTERY_10 "\xf3\xb0\x81\xba" // U+F007A
+#define ICON_MDI_BATTERY_10_BLUETOOTH "\xf3\xb0\xa4\xbe" // U+F093E
+#define ICON_MDI_BATTERY_20 "\xf3\xb0\x81\xbb" // U+F007B
+#define ICON_MDI_BATTERY_20_BLUETOOTH "\xf3\xb0\xa4\xbf" // U+F093F
+#define ICON_MDI_BATTERY_30 "\xf3\xb0\x81\xbc" // U+F007C
+#define ICON_MDI_BATTERY_30_BLUETOOTH "\xf3\xb0\xa5\x80" // U+F0940
+#define ICON_MDI_BATTERY_40 "\xf3\xb0\x81\xbd" // U+F007D
+#define ICON_MDI_BATTERY_40_BLUETOOTH "\xf3\xb0\xa5\x81" // U+F0941
+#define ICON_MDI_BATTERY_50 "\xf3\xb0\x81\xbe" // U+F007E
+#define ICON_MDI_BATTERY_50_BLUETOOTH "\xf3\xb0\xa5\x82" // U+F0942
+#define ICON_MDI_BATTERY_60 "\xf3\xb0\x81\xbf" // U+F007F
+#define ICON_MDI_BATTERY_60_BLUETOOTH "\xf3\xb0\xa5\x83" // U+F0943
+#define ICON_MDI_BATTERY_70 "\xf3\xb0\x82\x80" // U+F0080
+#define ICON_MDI_BATTERY_70_BLUETOOTH "\xf3\xb0\xa5\x84" // U+F0944
+#define ICON_MDI_BATTERY_80 "\xf3\xb0\x82\x81" // U+F0081
+#define ICON_MDI_BATTERY_80_BLUETOOTH "\xf3\xb0\xa5\x85" // U+F0945
+#define ICON_MDI_BATTERY_90 "\xf3\xb0\x82\x82" // U+F0082
+#define ICON_MDI_BATTERY_90_BLUETOOTH "\xf3\xb0\xa5\x86" // U+F0946
+#define ICON_MDI_BATTERY_ALERT "\xf3\xb0\x82\x83" // U+F0083
+#define ICON_MDI_BATTERY_ALERT_BLUETOOTH "\xf3\xb0\xa5\x87" // U+F0947
+#define ICON_MDI_BATTERY_ALERT_VARIANT "\xf3\xb1\x83\x8c" // U+F10CC
+#define ICON_MDI_BATTERY_ALERT_VARIANT_OUTLINE "\xf3\xb1\x83\x8d" // U+F10CD
+#define ICON_MDI_BATTERY_ARROW_DOWN "\xf3\xb1\x9f\x9e" // U+F17DE
+#define ICON_MDI_BATTERY_ARROW_DOWN_OUTLINE "\xf3\xb1\x9f\x9f" // U+F17DF
+#define ICON_MDI_BATTERY_ARROW_UP "\xf3\xb1\x9f\xa0" // U+F17E0
+#define ICON_MDI_BATTERY_ARROW_UP_OUTLINE "\xf3\xb1\x9f\xa1" // U+F17E1
+#define ICON_MDI_BATTERY_BLUETOOTH "\xf3\xb0\xa5\x88" // U+F0948
+#define ICON_MDI_BATTERY_BLUETOOTH_VARIANT "\xf3\xb0\xa5\x89" // U+F0949
+#define ICON_MDI_BATTERY_CHARGING "\xf3\xb0\x82\x84" // U+F0084
+#define ICON_MDI_BATTERY_CHARGING_10 "\xf3\xb0\xa2\x9c" // U+F089C
+#define ICON_MDI_BATTERY_CHARGING_100 "\xf3\xb0\x82\x85" // U+F0085
+#define ICON_MDI_BATTERY_CHARGING_20 "\xf3\xb0\x82\x86" // U+F0086
+#define ICON_MDI_BATTERY_CHARGING_30 "\xf3\xb0\x82\x87" // U+F0087
+#define ICON_MDI_BATTERY_CHARGING_40 "\xf3\xb0\x82\x88" // U+F0088
+#define ICON_MDI_BATTERY_CHARGING_50 "\xf3\xb0\xa2\x9d" // U+F089D
+#define ICON_MDI_BATTERY_CHARGING_60 "\xf3\xb0\x82\x89" // U+F0089
+#define ICON_MDI_BATTERY_CHARGING_70 "\xf3\xb0\xa2\x9e" // U+F089E
+#define ICON_MDI_BATTERY_CHARGING_80 "\xf3\xb0\x82\x8a" // U+F008A
+#define ICON_MDI_BATTERY_CHARGING_90 "\xf3\xb0\x82\x8b" // U+F008B
+#define ICON_MDI_BATTERY_CHARGING_HIGH "\xf3\xb1\x8a\xa6" // U+F12A6
+#define ICON_MDI_BATTERY_CHARGING_LOW "\xf3\xb1\x8a\xa4" // U+F12A4
+#define ICON_MDI_BATTERY_CHARGING_MEDIUM "\xf3\xb1\x8a\xa5" // U+F12A5
+#define ICON_MDI_BATTERY_CHARGING_OUTLINE "\xf3\xb0\xa2\x9f" // U+F089F
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS "\xf3\xb0\xa0\x87" // U+F0807
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_10 "\xf3\xb0\xa0\x88" // U+F0808
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_20 "\xf3\xb0\xa0\x89" // U+F0809
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_30 "\xf3\xb0\xa0\x8a" // U+F080A
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_40 "\xf3\xb0\xa0\x8b" // U+F080B
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_50 "\xf3\xb0\xa0\x8c" // U+F080C
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_60 "\xf3\xb0\xa0\x8d" // U+F080D
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_70 "\xf3\xb0\xa0\x8e" // U+F080E
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_80 "\xf3\xb0\xa0\x8f" // U+F080F
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_90 "\xf3\xb0\xa0\x90" // U+F0810
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_ALERT "\xf3\xb0\xa0\x91" // U+F0811
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_OUTLINE "\xf3\xb0\xa0\x92" // U+F0812
+#define ICON_MDI_BATTERY_CHECK "\xf3\xb1\x9f\xa2" // U+F17E2
+#define ICON_MDI_BATTERY_CHECK_OUTLINE "\xf3\xb1\x9f\xa3" // U+F17E3
+#define ICON_MDI_BATTERY_CLOCK "\xf3\xb1\xa7\xa5" // U+F19E5
+#define ICON_MDI_BATTERY_CLOCK_OUTLINE "\xf3\xb1\xa7\xa6" // U+F19E6
+#define ICON_MDI_BATTERY_HEART "\xf3\xb1\x88\x8f" // U+F120F
+#define ICON_MDI_BATTERY_HEART_OUTLINE "\xf3\xb1\x88\x90" // U+F1210
+#define ICON_MDI_BATTERY_HEART_VARIANT "\xf3\xb1\x88\x91" // U+F1211
+#define ICON_MDI_BATTERY_HIGH "\xf3\xb1\x8a\xa3" // U+F12A3
+#define ICON_MDI_BATTERY_LOCK "\xf3\xb1\x9e\x9c" // U+F179C
+#define ICON_MDI_BATTERY_LOCK_OPEN "\xf3\xb1\x9e\x9d" // U+F179D
+#define ICON_MDI_BATTERY_LOW "\xf3\xb1\x8a\xa1" // U+F12A1
+#define ICON_MDI_BATTERY_MEDIUM "\xf3\xb1\x8a\xa2" // U+F12A2
+#define ICON_MDI_BATTERY_MINUS "\xf3\xb1\x9f\xa4" // U+F17E4
+#define ICON_MDI_BATTERY_MINUS_OUTLINE "\xf3\xb1\x9f\xa5" // U+F17E5
+#define ICON_MDI_BATTERY_MINUS_VARIANT "\xf3\xb0\x82\x8c" // U+F008C
+#define ICON_MDI_BATTERY_NEGATIVE "\xf3\xb0\x82\x8d" // U+F008D
+#define ICON_MDI_BATTERY_OFF "\xf3\xb1\x89\x9d" // U+F125D
+#define ICON_MDI_BATTERY_OFF_OUTLINE "\xf3\xb1\x89\x9e" // U+F125E
+#define ICON_MDI_BATTERY_OUTLINE "\xf3\xb0\x82\x8e" // U+F008E
+#define ICON_MDI_BATTERY_PLUS "\xf3\xb1\x9f\xa6" // U+F17E6
+#define ICON_MDI_BATTERY_PLUS_OUTLINE "\xf3\xb1\x9f\xa7" // U+F17E7
+#define ICON_MDI_BATTERY_PLUS_VARIANT "\xf3\xb0\x82\x8f" // U+F008F
+#define ICON_MDI_BATTERY_POSITIVE "\xf3\xb0\x82\x90" // U+F0090
+#define ICON_MDI_BATTERY_REMOVE "\xf3\xb1\x9f\xa8" // U+F17E8
+#define ICON_MDI_BATTERY_REMOVE_OUTLINE "\xf3\xb1\x9f\xa9" // U+F17E9
+#define ICON_MDI_BATTERY_SYNC "\xf3\xb1\xa0\xb4" // U+F1834
+#define ICON_MDI_BATTERY_SYNC_OUTLINE "\xf3\xb1\xa0\xb5" // U+F1835
+#define ICON_MDI_BATTERY_UNKNOWN "\xf3\xb0\x82\x91" // U+F0091
+#define ICON_MDI_BATTERY_UNKNOWN_BLUETOOTH "\xf3\xb0\xa5\x8a" // U+F094A
+#define ICON_MDI_BEACH "\xf3\xb0\x82\x92" // U+F0092
+#define ICON_MDI_BEAKER "\xf3\xb0\xb3\xaa" // U+F0CEA
+#define ICON_MDI_BEAKER_ALERT "\xf3\xb1\x88\xa9" // U+F1229
+#define ICON_MDI_BEAKER_ALERT_OUTLINE "\xf3\xb1\x88\xaa" // U+F122A
+#define ICON_MDI_BEAKER_CHECK "\xf3\xb1\x88\xab" // U+F122B
+#define ICON_MDI_BEAKER_CHECK_OUTLINE "\xf3\xb1\x88\xac" // U+F122C
+#define ICON_MDI_BEAKER_MINUS "\xf3\xb1\x88\xad" // U+F122D
+#define ICON_MDI_BEAKER_MINUS_OUTLINE "\xf3\xb1\x88\xae" // U+F122E
+#define ICON_MDI_BEAKER_OUTLINE "\xf3\xb0\x9a\x90" // U+F0690
+#define ICON_MDI_BEAKER_PLUS "\xf3\xb1\x88\xaf" // U+F122F
+#define ICON_MDI_BEAKER_PLUS_OUTLINE "\xf3\xb1\x88\xb0" // U+F1230
+#define ICON_MDI_BEAKER_QUESTION "\xf3\xb1\x88\xb1" // U+F1231
+#define ICON_MDI_BEAKER_QUESTION_OUTLINE "\xf3\xb1\x88\xb2" // U+F1232
+#define ICON_MDI_BEAKER_REMOVE "\xf3\xb1\x88\xb3" // U+F1233
+#define ICON_MDI_BEAKER_REMOVE_OUTLINE "\xf3\xb1\x88\xb4" // U+F1234
+#define ICON_MDI_BED "\xf3\xb0\x8b\xa3" // U+F02E3
+#define ICON_MDI_BED_CLOCK "\xf3\xb1\xae\x94" // U+F1B94
+#define ICON_MDI_BED_DOUBLE "\xf3\xb0\xbf\x94" // U+F0FD4
+#define ICON_MDI_BED_DOUBLE_OUTLINE "\xf3\xb0\xbf\x93" // U+F0FD3
+#define ICON_MDI_BED_EMPTY "\xf3\xb0\xa2\xa0" // U+F08A0
+#define ICON_MDI_BED_KING "\xf3\xb0\xbf\x92" // U+F0FD2
+#define ICON_MDI_BED_KING_OUTLINE "\xf3\xb0\xbf\x91" // U+F0FD1
+#define ICON_MDI_BED_OUTLINE "\xf3\xb0\x82\x99" // U+F0099
+#define ICON_MDI_BED_QUEEN "\xf3\xb0\xbf\x90" // U+F0FD0
+#define ICON_MDI_BED_QUEEN_OUTLINE "\xf3\xb0\xbf\x9b" // U+F0FDB
+#define ICON_MDI_BED_SINGLE "\xf3\xb1\x81\xad" // U+F106D
+#define ICON_MDI_BED_SINGLE_OUTLINE "\xf3\xb1\x81\xae" // U+F106E
+#define ICON_MDI_BEE "\xf3\xb0\xbe\xa1" // U+F0FA1
+#define ICON_MDI_BEE_FLOWER "\xf3\xb0\xbe\xa2" // U+F0FA2
+#define ICON_MDI_BEEHIVE_OFF_OUTLINE "\xf3\xb1\x8f\xad" // U+F13ED
+#define ICON_MDI_BEEHIVE_OUTLINE "\xf3\xb1\x83\x8e" // U+F10CE
+#define ICON_MDI_BEEKEEPER "\xf3\xb1\x93\xa2" // U+F14E2
+#define ICON_MDI_BEER "\xf3\xb0\x82\x98" // U+F0098
+#define ICON_MDI_BEER_OUTLINE "\xf3\xb1\x8c\x8c" // U+F130C
+#define ICON_MDI_BELL "\xf3\xb0\x82\x9a" // U+F009A
+#define ICON_MDI_BELL_ALERT "\xf3\xb0\xb5\x99" // U+F0D59
+#define ICON_MDI_BELL_ALERT_OUTLINE "\xf3\xb0\xba\x81" // U+F0E81
+#define ICON_MDI_BELL_BADGE "\xf3\xb1\x85\xab" // U+F116B
+#define ICON_MDI_BELL_BADGE_OUTLINE "\xf3\xb0\x85\xb8" // U+F0178
+#define ICON_MDI_BELL_CANCEL "\xf3\xb1\x8f\xa7" // U+F13E7
+#define ICON_MDI_BELL_CANCEL_OUTLINE "\xf3\xb1\x8f\xa8" // U+F13E8
+#define ICON_MDI_BELL_CHECK "\xf3\xb1\x87\xa5" // U+F11E5
+#define ICON_MDI_BELL_CHECK_OUTLINE "\xf3\xb1\x87\xa6" // U+F11E6
+#define ICON_MDI_BELL_CIRCLE "\xf3\xb0\xb5\x9a" // U+F0D5A
+#define ICON_MDI_BELL_CIRCLE_OUTLINE "\xf3\xb0\xb5\x9b" // U+F0D5B
+#define ICON_MDI_BELL_COG "\xf3\xb1\xa8\xa9" // U+F1A29
+#define ICON_MDI_BELL_COG_OUTLINE "\xf3\xb1\xa8\xaa" // U+F1A2A
+#define ICON_MDI_BELL_MINUS "\xf3\xb1\x8f\xa9" // U+F13E9
+#define ICON_MDI_BELL_MINUS_OUTLINE "\xf3\xb1\x8f\xaa" // U+F13EA
+#define ICON_MDI_BELL_OFF "\xf3\xb0\x82\x9b" // U+F009B
+#define ICON_MDI_BELL_OFF_OUTLINE "\xf3\xb0\xaa\x91" // U+F0A91
+#define ICON_MDI_BELL_OUTLINE "\xf3\xb0\x82\x9c" // U+F009C
+#define ICON_MDI_BELL_PLUS "\xf3\xb0\x82\x9d" // U+F009D
+#define ICON_MDI_BELL_PLUS_OUTLINE "\xf3\xb0\xaa\x92" // U+F0A92
+#define ICON_MDI_BELL_REMOVE "\xf3\xb1\x8f\xab" // U+F13EB
+#define ICON_MDI_BELL_REMOVE_OUTLINE "\xf3\xb1\x8f\xac" // U+F13EC
+#define ICON_MDI_BELL_RING "\xf3\xb0\x82\x9e" // U+F009E
+#define ICON_MDI_BELL_RING_OUTLINE "\xf3\xb0\x82\x9f" // U+F009F
+#define ICON_MDI_BELL_SLEEP "\xf3\xb0\x82\xa0" // U+F00A0
+#define ICON_MDI_BELL_SLEEP_OUTLINE "\xf3\xb0\xaa\x93" // U+F0A93
+#define ICON_MDI_BENCH "\xf3\xb1\xb0\xa1" // U+F1C21
+#define ICON_MDI_BENCH_BACK "\xf3\xb1\xb0\xa2" // U+F1C22
+#define ICON_MDI_BETA "\xf3\xb0\x82\xa1" // U+F00A1
+#define ICON_MDI_BETAMAX "\xf3\xb0\xa7\x8b" // U+F09CB
+#define ICON_MDI_BIATHLON "\xf3\xb0\xb8\x94" // U+F0E14
+#define ICON_MDI_BICYCLE "\xf3\xb1\x82\x9c" // U+F109C
+#define ICON_MDI_BICYCLE_BASKET "\xf3\xb1\x88\xb5" // U+F1235
+#define ICON_MDI_BICYCLE_CARGO "\xf3\xb1\xa2\x9c" // U+F189C
+#define ICON_MDI_BICYCLE_ELECTRIC "\xf3\xb1\x96\xb4" // U+F15B4
+#define ICON_MDI_BICYCLE_PENNY_FARTHING "\xf3\xb1\x97\xa9" // U+F15E9
+#define ICON_MDI_BIKE "\xf3\xb0\x82\xa3" // U+F00A3
+#define ICON_MDI_BIKE_FAST "\xf3\xb1\x84\x9f" // U+F111F
+#define ICON_MDI_BIKE_PEDAL "\xf3\xb1\xb0\xa3" // U+F1C23
+#define ICON_MDI_BIKE_PEDAL_CLIPLESS "\xf3\xb1\xb0\xa4" // U+F1C24
+#define ICON_MDI_BIKE_PEDAL_MOUNTAIN "\xf3\xb1\xb0\xa5" // U+F1C25
+#define ICON_MDI_BILLBOARD "\xf3\xb1\x80\x90" // U+F1010
+#define ICON_MDI_BILLIARDS "\xf3\xb0\xad\xa1" // U+F0B61
+#define ICON_MDI_BILLIARDS_RACK "\xf3\xb0\xad\xa2" // U+F0B62
+#define ICON_MDI_BINOCULARS "\xf3\xb0\x82\xa5" // U+F00A5
+#define ICON_MDI_BIO "\xf3\xb0\x82\xa6" // U+F00A6
+#define ICON_MDI_BIOHAZARD "\xf3\xb0\x82\xa7" // U+F00A7
+#define ICON_MDI_BIRD "\xf3\xb1\x97\x86" // U+F15C6
+#define ICON_MDI_BITBUCKET "\xf3\xb0\x82\xa8" // U+F00A8
+#define ICON_MDI_BITCOIN "\xf3\xb0\xa0\x93" // U+F0813
+#define ICON_MDI_BLACK_MESA "\xf3\xb0\x82\xa9" // U+F00A9
+#define ICON_MDI_BLENDER "\xf3\xb0\xb3\xab" // U+F0CEB
+#define ICON_MDI_BLENDER_OUTLINE "\xf3\xb1\xa0\x9a" // U+F181A
+#define ICON_MDI_BLENDER_SOFTWARE "\xf3\xb0\x82\xab" // U+F00AB
+#define ICON_MDI_BLINDS "\xf3\xb0\x82\xac" // U+F00AC
+#define ICON_MDI_BLINDS_HORIZONTAL "\xf3\xb1\xa8\xab" // U+F1A2B
+#define ICON_MDI_BLINDS_HORIZONTAL_CLOSED "\xf3\xb1\xa8\xac" // U+F1A2C
+#define ICON_MDI_BLINDS_OPEN "\xf3\xb1\x80\x91" // U+F1011
+#define ICON_MDI_BLINDS_VERTICAL "\xf3\xb1\xa8\xad" // U+F1A2D
+#define ICON_MDI_BLINDS_VERTICAL_CLOSED "\xf3\xb1\xa8\xae" // U+F1A2E
+#define ICON_MDI_BLOCK_HELPER "\xf3\xb0\x82\xad" // U+F00AD
+#define ICON_MDI_BLOOD_BAG "\xf3\xb0\xb3\xac" // U+F0CEC
+#define ICON_MDI_BLUETOOTH "\xf3\xb0\x82\xaf" // U+F00AF
+#define ICON_MDI_BLUETOOTH_AUDIO "\xf3\xb0\x82\xb0" // U+F00B0
+#define ICON_MDI_BLUETOOTH_CONNECT "\xf3\xb0\x82\xb1" // U+F00B1
+#define ICON_MDI_BLUETOOTH_OFF "\xf3\xb0\x82\xb2" // U+F00B2
+#define ICON_MDI_BLUETOOTH_SETTINGS "\xf3\xb0\x82\xb3" // U+F00B3
+#define ICON_MDI_BLUETOOTH_TRANSFER "\xf3\xb0\x82\xb4" // U+F00B4
+#define ICON_MDI_BLUR "\xf3\xb0\x82\xb5" // U+F00B5
+#define ICON_MDI_BLUR_LINEAR "\xf3\xb0\x82\xb6" // U+F00B6
+#define ICON_MDI_BLUR_OFF "\xf3\xb0\x82\xb7" // U+F00B7
+#define ICON_MDI_BLUR_RADIAL "\xf3\xb0\x82\xb8" // U+F00B8
+#define ICON_MDI_BOLT "\xf3\xb0\xb6\xb3" // U+F0DB3
+#define ICON_MDI_BOMB "\xf3\xb0\x9a\x91" // U+F0691
+#define ICON_MDI_BOMB_OFF "\xf3\xb0\x9b\x85" // U+F06C5
+#define ICON_MDI_BONE "\xf3\xb0\x82\xb9" // U+F00B9
+#define ICON_MDI_BONE_OFF "\xf3\xb1\xa7\xa0" // U+F19E0
+#define ICON_MDI_BOOK "\xf3\xb0\x82\xba" // U+F00BA
+#define ICON_MDI_BOOK_ACCOUNT "\xf3\xb1\x8e\xad" // U+F13AD
+#define ICON_MDI_BOOK_ACCOUNT_OUTLINE "\xf3\xb1\x8e\xae" // U+F13AE
+#define ICON_MDI_BOOK_ALERT "\xf3\xb1\x99\xbc" // U+F167C
+#define ICON_MDI_BOOK_ALERT_OUTLINE "\xf3\xb1\x99\xbd" // U+F167D
+#define ICON_MDI_BOOK_ALPHABET "\xf3\xb0\x98\x9d" // U+F061D
+#define ICON_MDI_BOOK_ARROW_DOWN "\xf3\xb1\x99\xbe" // U+F167E
+#define ICON_MDI_BOOK_ARROW_DOWN_OUTLINE "\xf3\xb1\x99\xbf" // U+F167F
+#define ICON_MDI_BOOK_ARROW_LEFT "\xf3\xb1\x9a\x80" // U+F1680
+#define ICON_MDI_BOOK_ARROW_LEFT_OUTLINE "\xf3\xb1\x9a\x81" // U+F1681
+#define ICON_MDI_BOOK_ARROW_RIGHT "\xf3\xb1\x9a\x82" // U+F1682
+#define ICON_MDI_BOOK_ARROW_RIGHT_OUTLINE "\xf3\xb1\x9a\x83" // U+F1683
+#define ICON_MDI_BOOK_ARROW_UP "\xf3\xb1\x9a\x84" // U+F1684
+#define ICON_MDI_BOOK_ARROW_UP_OUTLINE "\xf3\xb1\x9a\x85" // U+F1685
+#define ICON_MDI_BOOK_CANCEL "\xf3\xb1\x9a\x86" // U+F1686
+#define ICON_MDI_BOOK_CANCEL_OUTLINE "\xf3\xb1\x9a\x87" // U+F1687
+#define ICON_MDI_BOOK_CHECK "\xf3\xb1\x93\xb3" // U+F14F3
+#define ICON_MDI_BOOK_CHECK_OUTLINE "\xf3\xb1\x93\xb4" // U+F14F4
+#define ICON_MDI_BOOK_CLOCK "\xf3\xb1\x9a\x88" // U+F1688
+#define ICON_MDI_BOOK_CLOCK_OUTLINE "\xf3\xb1\x9a\x89" // U+F1689
+#define ICON_MDI_BOOK_COG "\xf3\xb1\x9a\x8a" // U+F168A
+#define ICON_MDI_BOOK_COG_OUTLINE "\xf3\xb1\x9a\x8b" // U+F168B
+#define ICON_MDI_BOOK_CROSS "\xf3\xb0\x82\xa2" // U+F00A2
+#define ICON_MDI_BOOK_EDIT "\xf3\xb1\x9a\x8c" // U+F168C
+#define ICON_MDI_BOOK_EDIT_OUTLINE "\xf3\xb1\x9a\x8d" // U+F168D
+#define ICON_MDI_BOOK_EDUCATION "\xf3\xb1\x9b\x89" // U+F16C9
+#define ICON_MDI_BOOK_EDUCATION_OUTLINE "\xf3\xb1\x9b\x8a" // U+F16CA
+#define ICON_MDI_BOOK_HEART "\xf3\xb1\xa8\x9d" // U+F1A1D
+#define ICON_MDI_BOOK_HEART_OUTLINE "\xf3\xb1\xa8\x9e" // U+F1A1E
+#define ICON_MDI_BOOK_INFORMATION_VARIANT "\xf3\xb1\x81\xaf" // U+F106F
+#define ICON_MDI_BOOK_LOCK "\xf3\xb0\x9e\x9a" // U+F079A
+#define ICON_MDI_BOOK_LOCK_OPEN "\xf3\xb0\x9e\x9b" // U+F079B
+#define ICON_MDI_BOOK_LOCK_OPEN_OUTLINE "\xf3\xb1\x9a\x8e" // U+F168E
+#define ICON_MDI_BOOK_LOCK_OUTLINE "\xf3\xb1\x9a\x8f" // U+F168F
+#define ICON_MDI_BOOK_MARKER "\xf3\xb1\x9a\x90" // U+F1690
+#define ICON_MDI_BOOK_MARKER_OUTLINE "\xf3\xb1\x9a\x91" // U+F1691
+#define ICON_MDI_BOOK_MINUS "\xf3\xb0\x97\x99" // U+F05D9
+#define ICON_MDI_BOOK_MINUS_MULTIPLE "\xf3\xb0\xaa\x94" // U+F0A94
+#define ICON_MDI_BOOK_MINUS_MULTIPLE_OUTLINE "\xf3\xb0\xa4\x8b" // U+F090B
+#define ICON_MDI_BOOK_MINUS_OUTLINE "\xf3\xb1\x9a\x92" // U+F1692
+#define ICON_MDI_BOOK_MULTIPLE "\xf3\xb0\x82\xbb" // U+F00BB
+#define ICON_MDI_BOOK_MULTIPLE_OUTLINE "\xf3\xb0\x90\xb6" // U+F0436
+#define ICON_MDI_BOOK_MUSIC "\xf3\xb0\x81\xa7" // U+F0067
+#define ICON_MDI_BOOK_MUSIC_OUTLINE "\xf3\xb1\x9a\x93" // U+F1693
+#define ICON_MDI_BOOK_OFF "\xf3\xb1\x9a\x94" // U+F1694
+#define ICON_MDI_BOOK_OFF_OUTLINE "\xf3\xb1\x9a\x95" // U+F1695
+#define ICON_MDI_BOOK_OPEN "\xf3\xb0\x82\xbd" // U+F00BD
+#define ICON_MDI_BOOK_OPEN_BLANK_VARIANT "\xf3\xb0\x82\xbe" // U+F00BE
+#define ICON_MDI_BOOK_OPEN_OUTLINE "\xf3\xb0\xad\xa3" // U+F0B63
+#define ICON_MDI_BOOK_OPEN_PAGE_VARIANT "\xf3\xb0\x97\x9a" // U+F05DA
+#define ICON_MDI_BOOK_OPEN_PAGE_VARIANT_OUTLINE "\xf3\xb1\x97\x96" // U+F15D6
+#define ICON_MDI_BOOK_OPEN_VARIANT "\xf3\xb1\x93\xb7" // U+F14F7
+#define ICON_MDI_BOOK_OUTLINE "\xf3\xb0\xad\xa4" // U+F0B64
+#define ICON_MDI_BOOK_PLAY "\xf3\xb0\xba\x82" // U+F0E82
+#define ICON_MDI_BOOK_PLAY_OUTLINE "\xf3\xb0\xba\x83" // U+F0E83
+#define ICON_MDI_BOOK_PLUS "\xf3\xb0\x97\x9b" // U+F05DB
+#define ICON_MDI_BOOK_PLUS_MULTIPLE "\xf3\xb0\xaa\x95" // U+F0A95
+#define ICON_MDI_BOOK_PLUS_MULTIPLE_OUTLINE "\xf3\xb0\xab\x9e" // U+F0ADE
+#define ICON_MDI_BOOK_PLUS_OUTLINE "\xf3\xb1\x9a\x96" // U+F1696
+#define ICON_MDI_BOOK_REFRESH "\xf3\xb1\x9a\x97" // U+F1697
+#define ICON_MDI_BOOK_REFRESH_OUTLINE "\xf3\xb1\x9a\x98" // U+F1698
+#define ICON_MDI_BOOK_REMOVE "\xf3\xb0\xaa\x97" // U+F0A97
+#define ICON_MDI_BOOK_REMOVE_MULTIPLE "\xf3\xb0\xaa\x96" // U+F0A96
+#define ICON_MDI_BOOK_REMOVE_MULTIPLE_OUTLINE "\xf3\xb0\x93\x8a" // U+F04CA
+#define ICON_MDI_BOOK_REMOVE_OUTLINE "\xf3\xb1\x9a\x99" // U+F1699
+#define ICON_MDI_BOOK_SEARCH "\xf3\xb0\xba\x84" // U+F0E84
+#define ICON_MDI_BOOK_SEARCH_OUTLINE "\xf3\xb0\xba\x85" // U+F0E85
+#define ICON_MDI_BOOK_SETTINGS "\xf3\xb1\x9a\x9a" // U+F169A
+#define ICON_MDI_BOOK_SETTINGS_OUTLINE "\xf3\xb1\x9a\x9b" // U+F169B
+#define ICON_MDI_BOOK_SYNC "\xf3\xb1\x9a\x9c" // U+F169C
+#define ICON_MDI_BOOK_SYNC_OUTLINE "\xf3\xb1\x9b\x88" // U+F16C8
+#define ICON_MDI_BOOK_VARIANT "\xf3\xb0\x82\xbf" // U+F00BF
+#define ICON_MDI_BOOKMARK "\xf3\xb0\x83\x80" // U+F00C0
+#define ICON_MDI_BOOKMARK_BOX "\xf3\xb1\xad\xb5" // U+F1B75
+#define ICON_MDI_BOOKMARK_BOX_MULTIPLE "\xf3\xb1\xa5\xac" // U+F196C
+#define ICON_MDI_BOOKMARK_BOX_MULTIPLE_OUTLINE "\xf3\xb1\xa5\xad" // U+F196D
+#define ICON_MDI_BOOKMARK_BOX_OUTLINE "\xf3\xb1\xad\xb6" // U+F1B76
+#define ICON_MDI_BOOKMARK_CHECK "\xf3\xb0\x83\x81" // U+F00C1
+#define ICON_MDI_BOOKMARK_CHECK_OUTLINE "\xf3\xb1\x8d\xbb" // U+F137B
+#define ICON_MDI_BOOKMARK_MINUS "\xf3\xb0\xa7\x8c" // U+F09CC
+#define ICON_MDI_BOOKMARK_MINUS_OUTLINE "\xf3\xb0\xa7\x8d" // U+F09CD
+#define ICON_MDI_BOOKMARK_MULTIPLE "\xf3\xb0\xb8\x95" // U+F0E15
+#define ICON_MDI_BOOKMARK_MULTIPLE_OUTLINE "\xf3\xb0\xb8\x96" // U+F0E16
+#define ICON_MDI_BOOKMARK_MUSIC "\xf3\xb0\x83\x82" // U+F00C2
+#define ICON_MDI_BOOKMARK_MUSIC_OUTLINE "\xf3\xb1\x8d\xb9" // U+F1379
+#define ICON_MDI_BOOKMARK_OFF "\xf3\xb0\xa7\x8e" // U+F09CE
+#define ICON_MDI_BOOKMARK_OFF_OUTLINE "\xf3\xb0\xa7\x8f" // U+F09CF
+#define ICON_MDI_BOOKMARK_OUTLINE "\xf3\xb0\x83\x83" // U+F00C3
+#define ICON_MDI_BOOKMARK_PLUS "\xf3\xb0\x83\x85" // U+F00C5
+#define ICON_MDI_BOOKMARK_PLUS_OUTLINE "\xf3\xb0\x83\x84" // U+F00C4
+#define ICON_MDI_BOOKMARK_REMOVE "\xf3\xb0\x83\x86" // U+F00C6
+#define ICON_MDI_BOOKMARK_REMOVE_OUTLINE "\xf3\xb1\x8d\xba" // U+F137A
+#define ICON_MDI_BOOKSHELF "\xf3\xb1\x89\x9f" // U+F125F
+#define ICON_MDI_BOOM_GATE "\xf3\xb0\xba\x86" // U+F0E86
+#define ICON_MDI_BOOM_GATE_ALERT "\xf3\xb0\xba\x87" // U+F0E87
+#define ICON_MDI_BOOM_GATE_ALERT_OUTLINE "\xf3\xb0\xba\x88" // U+F0E88
+#define ICON_MDI_BOOM_GATE_ARROW_DOWN "\xf3\xb0\xba\x89" // U+F0E89
+#define ICON_MDI_BOOM_GATE_ARROW_DOWN_OUTLINE "\xf3\xb0\xba\x8a" // U+F0E8A
+#define ICON_MDI_BOOM_GATE_ARROW_UP "\xf3\xb0\xba\x8c" // U+F0E8C
+#define ICON_MDI_BOOM_GATE_ARROW_UP_OUTLINE "\xf3\xb0\xba\x8d" // U+F0E8D
+#define ICON_MDI_BOOM_GATE_OUTLINE "\xf3\xb0\xba\x8b" // U+F0E8B
+#define ICON_MDI_BOOM_GATE_UP "\xf3\xb1\x9f\xb9" // U+F17F9
+#define ICON_MDI_BOOM_GATE_UP_OUTLINE "\xf3\xb1\x9f\xba" // U+F17FA
+#define ICON_MDI_BOOMBOX "\xf3\xb0\x97\x9c" // U+F05DC
+#define ICON_MDI_BOOMERANG "\xf3\xb1\x83\x8f" // U+F10CF
+#define ICON_MDI_BOOTSTRAP "\xf3\xb0\x9b\x86" // U+F06C6
+#define ICON_MDI_BORDER_ALL "\xf3\xb0\x83\x87" // U+F00C7
+#define ICON_MDI_BORDER_ALL_VARIANT "\xf3\xb0\xa2\xa1" // U+F08A1
+#define ICON_MDI_BORDER_BOTTOM "\xf3\xb0\x83\x88" // U+F00C8
+#define ICON_MDI_BORDER_BOTTOM_VARIANT "\xf3\xb0\xa2\xa2" // U+F08A2
+#define ICON_MDI_BORDER_COLOR "\xf3\xb0\x83\x89" // U+F00C9
+#define ICON_MDI_BORDER_HORIZONTAL "\xf3\xb0\x83\x8a" // U+F00CA
+#define ICON_MDI_BORDER_INSIDE "\xf3\xb0\x83\x8b" // U+F00CB
+#define ICON_MDI_BORDER_LEFT "\xf3\xb0\x83\x8c" // U+F00CC
+#define ICON_MDI_BORDER_LEFT_VARIANT "\xf3\xb0\xa2\xa3" // U+F08A3
+#define ICON_MDI_BORDER_NONE "\xf3\xb0\x83\x8d" // U+F00CD
+#define ICON_MDI_BORDER_NONE_VARIANT "\xf3\xb0\xa2\xa4" // U+F08A4
+#define ICON_MDI_BORDER_OUTSIDE "\xf3\xb0\x83\x8e" // U+F00CE
+#define ICON_MDI_BORDER_RADIUS "\xf3\xb1\xab\xb4" // U+F1AF4
+#define ICON_MDI_BORDER_RIGHT "\xf3\xb0\x83\x8f" // U+F00CF
+#define ICON_MDI_BORDER_RIGHT_VARIANT "\xf3\xb0\xa2\xa5" // U+F08A5
+#define ICON_MDI_BORDER_STYLE "\xf3\xb0\x83\x90" // U+F00D0
+#define ICON_MDI_BORDER_TOP "\xf3\xb0\x83\x91" // U+F00D1
+#define ICON_MDI_BORDER_TOP_VARIANT "\xf3\xb0\xa2\xa6" // U+F08A6
+#define ICON_MDI_BORDER_VERTICAL "\xf3\xb0\x83\x92" // U+F00D2
+#define ICON_MDI_BOTTLE_SODA "\xf3\xb1\x81\xb0" // U+F1070
+#define ICON_MDI_BOTTLE_SODA_CLASSIC "\xf3\xb1\x81\xb1" // U+F1071
+#define ICON_MDI_BOTTLE_SODA_CLASSIC_OUTLINE "\xf3\xb1\x8d\xa3" // U+F1363
+#define ICON_MDI_BOTTLE_SODA_OUTLINE "\xf3\xb1\x81\xb2" // U+F1072
+#define ICON_MDI_BOTTLE_TONIC "\xf3\xb1\x84\xae" // U+F112E
+#define ICON_MDI_BOTTLE_TONIC_OUTLINE "\xf3\xb1\x84\xaf" // U+F112F
+#define ICON_MDI_BOTTLE_TONIC_PLUS "\xf3\xb1\x84\xb0" // U+F1130
+#define ICON_MDI_BOTTLE_TONIC_PLUS_OUTLINE "\xf3\xb1\x84\xb1" // U+F1131
+#define ICON_MDI_BOTTLE_TONIC_SKULL "\xf3\xb1\x84\xb2" // U+F1132
+#define ICON_MDI_BOTTLE_TONIC_SKULL_OUTLINE "\xf3\xb1\x84\xb3" // U+F1133
+#define ICON_MDI_BOTTLE_WINE "\xf3\xb0\xa1\x94" // U+F0854
+#define ICON_MDI_BOTTLE_WINE_OUTLINE "\xf3\xb1\x8c\x90" // U+F1310
+#define ICON_MDI_BOW_ARROW "\xf3\xb1\xa1\x81" // U+F1841
+#define ICON_MDI_BOW_TIE "\xf3\xb0\x99\xb8" // U+F0678
+#define ICON_MDI_BOWL "\xf3\xb0\x8a\x8e" // U+F028E
+#define ICON_MDI_BOWL_MIX "\xf3\xb0\x98\x97" // U+F0617
+#define ICON_MDI_BOWL_MIX_OUTLINE "\xf3\xb0\x8b\xa4" // U+F02E4
+#define ICON_MDI_BOWL_OUTLINE "\xf3\xb0\x8a\xa9" // U+F02A9
+#define ICON_MDI_BOWLING "\xf3\xb0\x83\x93" // U+F00D3
+#define ICON_MDI_BOX "\xf3\xb0\x83\x94" // U+F00D4
+#define ICON_MDI_BOX_CUTTER "\xf3\xb0\x83\x95" // U+F00D5
+#define ICON_MDI_BOX_CUTTER_OFF "\xf3\xb0\xad\x8a" // U+F0B4A
+#define ICON_MDI_BOX_SHADOW "\xf3\xb0\x98\xb7" // U+F0637
+#define ICON_MDI_BOXING_GLOVE "\xf3\xb0\xad\xa5" // U+F0B65
+#define ICON_MDI_BRAILLE "\xf3\xb0\xa7\x90" // U+F09D0
+#define ICON_MDI_BRAIN "\xf3\xb0\xa7\x91" // U+F09D1
+#define ICON_MDI_BREAD_SLICE "\xf3\xb0\xb3\xae" // U+F0CEE
+#define ICON_MDI_BREAD_SLICE_OUTLINE "\xf3\xb0\xb3\xaf" // U+F0CEF
+#define ICON_MDI_BRIDGE "\xf3\xb0\x98\x98" // U+F0618
+#define ICON_MDI_BRIEFCASE "\xf3\xb0\x83\x96" // U+F00D6
+#define ICON_MDI_BRIEFCASE_ACCOUNT "\xf3\xb0\xb3\xb0" // U+F0CF0
+#define ICON_MDI_BRIEFCASE_ACCOUNT_OUTLINE "\xf3\xb0\xb3\xb1" // U+F0CF1
+#define ICON_MDI_BRIEFCASE_ARROW_LEFT_RIGHT "\xf3\xb1\xaa\x8d" // U+F1A8D
+#define ICON_MDI_BRIEFCASE_ARROW_LEFT_RIGHT_OUTLINE "\xf3\xb1\xaa\x8e" // U+F1A8E
+#define ICON_MDI_BRIEFCASE_ARROW_UP_DOWN "\xf3\xb1\xaa\x8f" // U+F1A8F
+#define ICON_MDI_BRIEFCASE_ARROW_UP_DOWN_OUTLINE "\xf3\xb1\xaa\x90" // U+F1A90
+#define ICON_MDI_BRIEFCASE_CHECK "\xf3\xb0\x83\x97" // U+F00D7
+#define ICON_MDI_BRIEFCASE_CHECK_OUTLINE "\xf3\xb1\x8c\x9e" // U+F131E
+#define ICON_MDI_BRIEFCASE_CLOCK "\xf3\xb1\x83\x90" // U+F10D0
+#define ICON_MDI_BRIEFCASE_CLOCK_OUTLINE "\xf3\xb1\x83\x91" // U+F10D1
+#define ICON_MDI_BRIEFCASE_DOWNLOAD "\xf3\xb0\x83\x98" // U+F00D8
+#define ICON_MDI_BRIEFCASE_DOWNLOAD_OUTLINE "\xf3\xb0\xb0\xbd" // U+F0C3D
+#define ICON_MDI_BRIEFCASE_EDIT "\xf3\xb0\xaa\x98" // U+F0A98
+#define ICON_MDI_BRIEFCASE_EDIT_OUTLINE "\xf3\xb0\xb0\xbe" // U+F0C3E
+#define ICON_MDI_BRIEFCASE_EYE "\xf3\xb1\x9f\x99" // U+F17D9
+#define ICON_MDI_BRIEFCASE_EYE_OUTLINE "\xf3\xb1\x9f\x9a" // U+F17DA
+#define ICON_MDI_BRIEFCASE_MINUS "\xf3\xb0\xa8\xaa" // U+F0A2A
+#define ICON_MDI_BRIEFCASE_MINUS_OUTLINE "\xf3\xb0\xb0\xbf" // U+F0C3F
+#define ICON_MDI_BRIEFCASE_OFF "\xf3\xb1\x99\x98" // U+F1658
+#define ICON_MDI_BRIEFCASE_OFF_OUTLINE "\xf3\xb1\x99\x99" // U+F1659
+#define ICON_MDI_BRIEFCASE_OUTLINE "\xf3\xb0\xa0\x94" // U+F0814
+#define ICON_MDI_BRIEFCASE_PLUS "\xf3\xb0\xa8\xab" // U+F0A2B
+#define ICON_MDI_BRIEFCASE_PLUS_OUTLINE "\xf3\xb0\xb1\x80" // U+F0C40
+#define ICON_MDI_BRIEFCASE_REMOVE "\xf3\xb0\xa8\xac" // U+F0A2C
+#define ICON_MDI_BRIEFCASE_REMOVE_OUTLINE "\xf3\xb0\xb1\x81" // U+F0C41
+#define ICON_MDI_BRIEFCASE_SEARCH "\xf3\xb0\xa8\xad" // U+F0A2D
+#define ICON_MDI_BRIEFCASE_SEARCH_OUTLINE "\xf3\xb0\xb1\x82" // U+F0C42
+#define ICON_MDI_BRIEFCASE_UPLOAD "\xf3\xb0\x83\x99" // U+F00D9
+#define ICON_MDI_BRIEFCASE_UPLOAD_OUTLINE "\xf3\xb0\xb1\x83" // U+F0C43
+#define ICON_MDI_BRIEFCASE_VARIANT "\xf3\xb1\x92\x94" // U+F1494
+#define ICON_MDI_BRIEFCASE_VARIANT_OFF "\xf3\xb1\x99\x9a" // U+F165A
+#define ICON_MDI_BRIEFCASE_VARIANT_OFF_OUTLINE "\xf3\xb1\x99\x9b" // U+F165B
+#define ICON_MDI_BRIEFCASE_VARIANT_OUTLINE "\xf3\xb1\x92\x95" // U+F1495
+#define ICON_MDI_BRIGHTNESS_1 "\xf3\xb0\x83\x9a" // U+F00DA
+#define ICON_MDI_BRIGHTNESS_2 "\xf3\xb0\x83\x9b" // U+F00DB
+#define ICON_MDI_BRIGHTNESS_3 "\xf3\xb0\x83\x9c" // U+F00DC
+#define ICON_MDI_BRIGHTNESS_4 "\xf3\xb0\x83\x9d" // U+F00DD
+#define ICON_MDI_BRIGHTNESS_5 "\xf3\xb0\x83\x9e" // U+F00DE
+#define ICON_MDI_BRIGHTNESS_6 "\xf3\xb0\x83\x9f" // U+F00DF
+#define ICON_MDI_BRIGHTNESS_7 "\xf3\xb0\x83\xa0" // U+F00E0
+#define ICON_MDI_BRIGHTNESS_AUTO "\xf3\xb0\x83\xa1" // U+F00E1
+#define ICON_MDI_BRIGHTNESS_PERCENT "\xf3\xb0\xb3\xb2" // U+F0CF2
+#define ICON_MDI_BROADCAST "\xf3\xb1\x9c\xa0" // U+F1720
+#define ICON_MDI_BROADCAST_OFF "\xf3\xb1\x9c\xa1" // U+F1721
+#define ICON_MDI_BROOM "\xf3\xb0\x83\xa2" // U+F00E2
+#define ICON_MDI_BRUSH "\xf3\xb0\x83\xa3" // U+F00E3
+#define ICON_MDI_BRUSH_OFF "\xf3\xb1\x9d\xb1" // U+F1771
+#define ICON_MDI_BRUSH_OUTLINE "\xf3\xb1\xa8\x8d" // U+F1A0D
+#define ICON_MDI_BRUSH_VARIANT "\xf3\xb1\xa0\x93" // U+F1813
+#define ICON_MDI_BUCKET "\xf3\xb1\x90\x95" // U+F1415
+#define ICON_MDI_BUCKET_OUTLINE "\xf3\xb1\x90\x96" // U+F1416
+#define ICON_MDI_BUFFET "\xf3\xb0\x95\xb8" // U+F0578
+#define ICON_MDI_BUG "\xf3\xb0\x83\xa4" // U+F00E4
+#define ICON_MDI_BUG_CHECK "\xf3\xb0\xa8\xae" // U+F0A2E
+#define ICON_MDI_BUG_CHECK_OUTLINE "\xf3\xb0\xa8\xaf" // U+F0A2F
+#define ICON_MDI_BUG_OUTLINE "\xf3\xb0\xa8\xb0" // U+F0A30
+#define ICON_MDI_BUG_PAUSE "\xf3\xb1\xab\xb5" // U+F1AF5
+#define ICON_MDI_BUG_PAUSE_OUTLINE "\xf3\xb1\xab\xb6" // U+F1AF6
+#define ICON_MDI_BUG_PLAY "\xf3\xb1\xab\xb7" // U+F1AF7
+#define ICON_MDI_BUG_PLAY_OUTLINE "\xf3\xb1\xab\xb8" // U+F1AF8
+#define ICON_MDI_BUG_STOP "\xf3\xb1\xab\xb9" // U+F1AF9
+#define ICON_MDI_BUG_STOP_OUTLINE "\xf3\xb1\xab\xba" // U+F1AFA
+#define ICON_MDI_BUGLE "\xf3\xb0\xb6\xb4" // U+F0DB4
+#define ICON_MDI_BULKHEAD_LIGHT "\xf3\xb1\xa8\xaf" // U+F1A2F
+#define ICON_MDI_BULLDOZER "\xf3\xb0\xac\xa2" // U+F0B22
+#define ICON_MDI_BULLET "\xf3\xb0\xb3\xb3" // U+F0CF3
+#define ICON_MDI_BULLETIN_BOARD "\xf3\xb0\x83\xa5" // U+F00E5
+#define ICON_MDI_BULLHORN "\xf3\xb0\x83\xa6" // U+F00E6
+#define ICON_MDI_BULLHORN_OUTLINE "\xf3\xb0\xac\xa3" // U+F0B23
+#define ICON_MDI_BULLHORN_VARIANT "\xf3\xb1\xa5\xae" // U+F196E
+#define ICON_MDI_BULLHORN_VARIANT_OUTLINE "\xf3\xb1\xa5\xaf" // U+F196F
+#define ICON_MDI_BULLSEYE "\xf3\xb0\x97\x9d" // U+F05DD
+#define ICON_MDI_BULLSEYE_ARROW "\xf3\xb0\xa3\x89" // U+F08C9
+#define ICON_MDI_BULMA "\xf3\xb1\x8b\xa7" // U+F12E7
+#define ICON_MDI_BUNK_BED "\xf3\xb1\x8c\x82" // U+F1302
+#define ICON_MDI_BUNK_BED_OUTLINE "\xf3\xb0\x82\x97" // U+F0097
+#define ICON_MDI_BUS "\xf3\xb0\x83\xa7" // U+F00E7
+#define ICON_MDI_BUS_ALERT "\xf3\xb0\xaa\x99" // U+F0A99
+#define ICON_MDI_BUS_ARTICULATED_END "\xf3\xb0\x9e\x9c" // U+F079C
+#define ICON_MDI_BUS_ARTICULATED_FRONT "\xf3\xb0\x9e\x9d" // U+F079D
+#define ICON_MDI_BUS_CLOCK "\xf3\xb0\xa3\x8a" // U+F08CA
+#define ICON_MDI_BUS_DOUBLE_DECKER "\xf3\xb0\x9e\x9e" // U+F079E
+#define ICON_MDI_BUS_ELECTRIC "\xf3\xb1\xa4\x9d" // U+F191D
+#define ICON_MDI_BUS_MARKER "\xf3\xb1\x88\x92" // U+F1212
+#define ICON_MDI_BUS_MULTIPLE "\xf3\xb0\xbc\xbf" // U+F0F3F
+#define ICON_MDI_BUS_SCHOOL "\xf3\xb0\x9e\x9f" // U+F079F
+#define ICON_MDI_BUS_SIDE "\xf3\xb0\x9e\xa0" // U+F07A0
+#define ICON_MDI_BUS_SIGN "\xf3\xb1\xb3\x81" // U+F1CC1
+#define ICON_MDI_BUS_STOP "\xf3\xb1\x80\x92" // U+F1012
+#define ICON_MDI_BUS_STOP_COVERED "\xf3\xb1\x80\x93" // U+F1013
+#define ICON_MDI_BUS_STOP_UNCOVERED "\xf3\xb1\x80\x94" // U+F1014
+#define ICON_MDI_BUS_WRENCH "\xf3\xb1\xb3\x82" // U+F1CC2
+#define ICON_MDI_BUTTERFLY "\xf3\xb1\x96\x89" // U+F1589
+#define ICON_MDI_BUTTERFLY_OUTLINE "\xf3\xb1\x96\x8a" // U+F158A
+#define ICON_MDI_BUTTON_CURSOR "\xf3\xb1\xad\x8f" // U+F1B4F
+#define ICON_MDI_BUTTON_POINTER "\xf3\xb1\xad\x90" // U+F1B50
+#define ICON_MDI_CABIN_A_FRAME "\xf3\xb1\xa2\x8c" // U+F188C
+#define ICON_MDI_CABLE_DATA "\xf3\xb1\x8e\x94" // U+F1394
+#define ICON_MDI_CACHED "\xf3\xb0\x83\xa8" // U+F00E8
+#define ICON_MDI_CACTUS "\xf3\xb0\xb6\xb5" // U+F0DB5
+#define ICON_MDI_CAKE "\xf3\xb0\x83\xa9" // U+F00E9
+#define ICON_MDI_CAKE_LAYERED "\xf3\xb0\x83\xaa" // U+F00EA
+#define ICON_MDI_CAKE_VARIANT "\xf3\xb0\x83\xab" // U+F00EB
+#define ICON_MDI_CAKE_VARIANT_OUTLINE "\xf3\xb1\x9f\xb0" // U+F17F0
+#define ICON_MDI_CALCULATOR "\xf3\xb0\x83\xac" // U+F00EC
+#define ICON_MDI_CALCULATOR_VARIANT "\xf3\xb0\xaa\x9a" // U+F0A9A
+#define ICON_MDI_CALCULATOR_VARIANT_OUTLINE "\xf3\xb1\x96\xa6" // U+F15A6
+#define ICON_MDI_CALENDAR "\xf3\xb0\x83\xad" // U+F00ED
+#define ICON_MDI_CALENDAR_ACCOUNT "\xf3\xb0\xbb\x97" // U+F0ED7
+#define ICON_MDI_CALENDAR_ACCOUNT_OUTLINE "\xf3\xb0\xbb\x98" // U+F0ED8
+#define ICON_MDI_CALENDAR_ALERT "\xf3\xb0\xa8\xb1" // U+F0A31
+#define ICON_MDI_CALENDAR_ALERT_OUTLINE "\xf3\xb1\xad\xa2" // U+F1B62
+#define ICON_MDI_CALENDAR_ARROW_LEFT "\xf3\xb1\x84\xb4" // U+F1134
+#define ICON_MDI_CALENDAR_ARROW_RIGHT "\xf3\xb1\x84\xb5" // U+F1135
+#define ICON_MDI_CALENDAR_BADGE "\xf3\xb1\xae\x9d" // U+F1B9D
+#define ICON_MDI_CALENDAR_BADGE_OUTLINE "\xf3\xb1\xae\x9e" // U+F1B9E
+#define ICON_MDI_CALENDAR_BLANK "\xf3\xb0\x83\xae" // U+F00EE
+#define ICON_MDI_CALENDAR_BLANK_MULTIPLE "\xf3\xb1\x81\xb3" // U+F1073
+#define ICON_MDI_CALENDAR_BLANK_OUTLINE "\xf3\xb0\xad\xa6" // U+F0B66
+#define ICON_MDI_CALENDAR_CHECK "\xf3\xb0\x83\xaf" // U+F00EF
+#define ICON_MDI_CALENDAR_CHECK_OUTLINE "\xf3\xb0\xb1\x84" // U+F0C44
+#define ICON_MDI_CALENDAR_CLOCK "\xf3\xb0\x83\xb0" // U+F00F0
+#define ICON_MDI_CALENDAR_CLOCK_OUTLINE "\xf3\xb1\x9b\xa1" // U+F16E1
+#define ICON_MDI_CALENDAR_COLLAPSE_HORIZONTAL "\xf3\xb1\xa2\x9d" // U+F189D
+#define ICON_MDI_CALENDAR_COLLAPSE_HORIZONTAL_OUTLINE "\xf3\xb1\xad\xa3" // U+F1B63
+#define ICON_MDI_CALENDAR_CURSOR "\xf3\xb1\x95\xbb" // U+F157B
+#define ICON_MDI_CALENDAR_CURSOR_OUTLINE "\xf3\xb1\xad\xa4" // U+F1B64
+#define ICON_MDI_CALENDAR_EDIT "\xf3\xb0\xa2\xa7" // U+F08A7
+#define ICON_MDI_CALENDAR_EDIT_OUTLINE "\xf3\xb1\xad\xa5" // U+F1B65
+#define ICON_MDI_CALENDAR_END "\xf3\xb1\x99\xac" // U+F166C
+#define ICON_MDI_CALENDAR_END_OUTLINE "\xf3\xb1\xad\xa6" // U+F1B66
+#define ICON_MDI_CALENDAR_EXPAND_HORIZONTAL "\xf3\xb1\xa2\x9e" // U+F189E
+#define ICON_MDI_CALENDAR_EXPAND_HORIZONTAL_OUTLINE "\xf3\xb1\xad\xa7" // U+F1B67
+#define ICON_MDI_CALENDAR_EXPORT "\xf3\xb0\xac\xa4" // U+F0B24
+#define ICON_MDI_CALENDAR_EXPORT_OUTLINE "\xf3\xb1\xad\xa8" // U+F1B68
+#define ICON_MDI_CALENDAR_FILTER "\xf3\xb1\xa8\xb2" // U+F1A32
+#define ICON_MDI_CALENDAR_FILTER_OUTLINE "\xf3\xb1\xa8\xb3" // U+F1A33
+#define ICON_MDI_CALENDAR_HEART "\xf3\xb0\xa7\x92" // U+F09D2
+#define ICON_MDI_CALENDAR_HEART_OUTLINE "\xf3\xb1\xad\xa9" // U+F1B69
+#define ICON_MDI_CALENDAR_IMPORT "\xf3\xb0\xac\xa5" // U+F0B25
+#define ICON_MDI_CALENDAR_IMPORT_OUTLINE "\xf3\xb1\xad\xaa" // U+F1B6A
+#define ICON_MDI_CALENDAR_LOCK "\xf3\xb1\x99\x81" // U+F1641
+#define ICON_MDI_CALENDAR_LOCK_OPEN "\xf3\xb1\xad\x9b" // U+F1B5B
+#define ICON_MDI_CALENDAR_LOCK_OPEN_OUTLINE "\xf3\xb1\xad\x9c" // U+F1B5C
+#define ICON_MDI_CALENDAR_LOCK_OUTLINE "\xf3\xb1\x99\x82" // U+F1642
+#define ICON_MDI_CALENDAR_MINUS "\xf3\xb0\xb5\x9c" // U+F0D5C
+#define ICON_MDI_CALENDAR_MINUS_OUTLINE "\xf3\xb1\xad\xab" // U+F1B6B
+#define ICON_MDI_CALENDAR_MONTH "\xf3\xb0\xb8\x97" // U+F0E17
+#define ICON_MDI_CALENDAR_MONTH_OUTLINE "\xf3\xb0\xb8\x98" // U+F0E18
+#define ICON_MDI_CALENDAR_MULTIPLE "\xf3\xb0\x83\xb1" // U+F00F1
+#define ICON_MDI_CALENDAR_MULTIPLE_CHECK "\xf3\xb0\x83\xb2" // U+F00F2
+#define ICON_MDI_CALENDAR_MULTISELECT "\xf3\xb0\xa8\xb2" // U+F0A32
+#define ICON_MDI_CALENDAR_MULTISELECT_OUTLINE "\xf3\xb1\xad\x95" // U+F1B55
+#define ICON_MDI_CALENDAR_OUTLINE "\xf3\xb0\xad\xa7" // U+F0B67
+#define ICON_MDI_CALENDAR_PLUS "\xf3\xb0\x83\xb3" // U+F00F3
+#define ICON_MDI_CALENDAR_PLUS_OUTLINE "\xf3\xb1\xad\xac" // U+F1B6C
+#define ICON_MDI_CALENDAR_QUESTION "\xf3\xb0\x9a\x92" // U+F0692
+#define ICON_MDI_CALENDAR_QUESTION_OUTLINE "\xf3\xb1\xad\xad" // U+F1B6D
+#define ICON_MDI_CALENDAR_RANGE "\xf3\xb0\x99\xb9" // U+F0679
+#define ICON_MDI_CALENDAR_RANGE_OUTLINE "\xf3\xb0\xad\xa8" // U+F0B68
+#define ICON_MDI_CALENDAR_REFRESH "\xf3\xb0\x87\xa1" // U+F01E1
+#define ICON_MDI_CALENDAR_REFRESH_OUTLINE "\xf3\xb0\x88\x83" // U+F0203
+#define ICON_MDI_CALENDAR_REMOVE "\xf3\xb0\x83\xb4" // U+F00F4
+#define ICON_MDI_CALENDAR_REMOVE_OUTLINE "\xf3\xb0\xb1\x85" // U+F0C45
+#define ICON_MDI_CALENDAR_SEARCH "\xf3\xb0\xa5\x8c" // U+F094C
+#define ICON_MDI_CALENDAR_SEARCH_OUTLINE "\xf3\xb1\xad\xae" // U+F1B6E
+#define ICON_MDI_CALENDAR_STAR "\xf3\xb0\xa7\x93" // U+F09D3
+#define ICON_MDI_CALENDAR_STAR_FOUR_POINTS "\xf3\xb1\xb0\x9f" // U+F1C1F
+#define ICON_MDI_CALENDAR_STAR_OUTLINE "\xf3\xb1\xad\x93" // U+F1B53
+#define ICON_MDI_CALENDAR_START "\xf3\xb1\x99\xad" // U+F166D
+#define ICON_MDI_CALENDAR_START_OUTLINE "\xf3\xb1\xad\xaf" // U+F1B6F
+#define ICON_MDI_CALENDAR_SYNC "\xf3\xb0\xba\x8e" // U+F0E8E
+#define ICON_MDI_CALENDAR_SYNC_OUTLINE "\xf3\xb0\xba\x8f" // U+F0E8F
+#define ICON_MDI_CALENDAR_TEXT "\xf3\xb0\x83\xb5" // U+F00F5
+#define ICON_MDI_CALENDAR_TEXT_OUTLINE "\xf3\xb0\xb1\x86" // U+F0C46
+#define ICON_MDI_CALENDAR_TODAY "\xf3\xb0\x83\xb6" // U+F00F6
+#define ICON_MDI_CALENDAR_TODAY_OUTLINE "\xf3\xb1\xa8\xb0" // U+F1A30
+#define ICON_MDI_CALENDAR_WEEK "\xf3\xb0\xa8\xb3" // U+F0A33
+#define ICON_MDI_CALENDAR_WEEK_BEGIN "\xf3\xb0\xa8\xb4" // U+F0A34
+#define ICON_MDI_CALENDAR_WEEK_BEGIN_OUTLINE "\xf3\xb1\xa8\xb1" // U+F1A31
+#define ICON_MDI_CALENDAR_WEEK_OUTLINE "\xf3\xb1\xa8\xb4" // U+F1A34
+#define ICON_MDI_CALENDAR_WEEKEND "\xf3\xb0\xbb\x99" // U+F0ED9
+#define ICON_MDI_CALENDAR_WEEKEND_OUTLINE "\xf3\xb0\xbb\x9a" // U+F0EDA
+#define ICON_MDI_CALL_MADE "\xf3\xb0\x83\xb7" // U+F00F7
+#define ICON_MDI_CALL_MERGE "\xf3\xb0\x83\xb8" // U+F00F8
+#define ICON_MDI_CALL_MISSED "\xf3\xb0\x83\xb9" // U+F00F9
+#define ICON_MDI_CALL_RECEIVED "\xf3\xb0\x83\xba" // U+F00FA
+#define ICON_MDI_CALL_SPLIT "\xf3\xb0\x83\xbb" // U+F00FB
+#define ICON_MDI_CAMCORDER "\xf3\xb0\x83\xbc" // U+F00FC
+#define ICON_MDI_CAMCORDER_OFF "\xf3\xb0\x83\xbf" // U+F00FF
+#define ICON_MDI_CAMERA "\xf3\xb0\x84\x80" // U+F0100
+#define ICON_MDI_CAMERA_ACCOUNT "\xf3\xb0\xa3\x8b" // U+F08CB
+#define ICON_MDI_CAMERA_BURST "\xf3\xb0\x9a\x93" // U+F0693
+#define ICON_MDI_CAMERA_CONTROL "\xf3\xb0\xad\xa9" // U+F0B69
+#define ICON_MDI_CAMERA_DOCUMENT "\xf3\xb1\xa1\xb1" // U+F1871
+#define ICON_MDI_CAMERA_DOCUMENT_OFF "\xf3\xb1\xa1\xb2" // U+F1872
+#define ICON_MDI_CAMERA_ENHANCE "\xf3\xb0\x84\x81" // U+F0101
+#define ICON_MDI_CAMERA_ENHANCE_OUTLINE "\xf3\xb0\xad\xaa" // U+F0B6A
+#define ICON_MDI_CAMERA_FLIP "\xf3\xb1\x97\x99" // U+F15D9
+#define ICON_MDI_CAMERA_FLIP_OUTLINE "\xf3\xb1\x97\x9a" // U+F15DA
+#define ICON_MDI_CAMERA_FRONT "\xf3\xb0\x84\x82" // U+F0102
+#define ICON_MDI_CAMERA_FRONT_VARIANT "\xf3\xb0\x84\x83" // U+F0103
+#define ICON_MDI_CAMERA_GOPRO "\xf3\xb0\x9e\xa1" // U+F07A1
+#define ICON_MDI_CAMERA_IMAGE "\xf3\xb0\xa3\x8c" // U+F08CC
+#define ICON_MDI_CAMERA_IRIS "\xf3\xb0\x84\x84" // U+F0104
+#define ICON_MDI_CAMERA_LOCK "\xf3\xb1\xa8\x94" // U+F1A14
+#define ICON_MDI_CAMERA_LOCK_OPEN "\xf3\xb1\xb0\x8d" // U+F1C0D
+#define ICON_MDI_CAMERA_LOCK_OPEN_OUTLINE "\xf3\xb1\xb0\x8e" // U+F1C0E
+#define ICON_MDI_CAMERA_LOCK_OUTLINE "\xf3\xb1\xa8\x95" // U+F1A15
+#define ICON_MDI_CAMERA_MARKER "\xf3\xb1\xa6\xa7" // U+F19A7
+#define ICON_MDI_CAMERA_MARKER_OUTLINE "\xf3\xb1\xa6\xa8" // U+F19A8
+#define ICON_MDI_CAMERA_METERING_CENTER "\xf3\xb0\x9e\xa2" // U+F07A2
+#define ICON_MDI_CAMERA_METERING_MATRIX "\xf3\xb0\x9e\xa3" // U+F07A3
+#define ICON_MDI_CAMERA_METERING_PARTIAL "\xf3\xb0\x9e\xa4" // U+F07A4
+#define ICON_MDI_CAMERA_METERING_SPOT "\xf3\xb0\x9e\xa5" // U+F07A5
+#define ICON_MDI_CAMERA_OFF "\xf3\xb0\x97\x9f" // U+F05DF
+#define ICON_MDI_CAMERA_OFF_OUTLINE "\xf3\xb1\xa6\xbf" // U+F19BF
+#define ICON_MDI_CAMERA_OUTLINE "\xf3\xb0\xb5\x9d" // U+F0D5D
+#define ICON_MDI_CAMERA_PARTY_MODE "\xf3\xb0\x84\x85" // U+F0105
+#define ICON_MDI_CAMERA_PLUS "\xf3\xb0\xbb\x9b" // U+F0EDB
+#define ICON_MDI_CAMERA_PLUS_OUTLINE "\xf3\xb0\xbb\x9c" // U+F0EDC
+#define ICON_MDI_CAMERA_REAR "\xf3\xb0\x84\x86" // U+F0106
+#define ICON_MDI_CAMERA_REAR_VARIANT "\xf3\xb0\x84\x87" // U+F0107
+#define ICON_MDI_CAMERA_RETAKE "\xf3\xb0\xb8\x99" // U+F0E19
+#define ICON_MDI_CAMERA_RETAKE_OUTLINE "\xf3\xb0\xb8\x9a" // U+F0E1A
+#define ICON_MDI_CAMERA_SWITCH "\xf3\xb0\x84\x88" // U+F0108
+#define ICON_MDI_CAMERA_SWITCH_OUTLINE "\xf3\xb0\xa1\x8a" // U+F084A
+#define ICON_MDI_CAMERA_TIMER "\xf3\xb0\x84\x89" // U+F0109
+#define ICON_MDI_CAMERA_WIRELESS "\xf3\xb0\xb6\xb6" // U+F0DB6
+#define ICON_MDI_CAMERA_WIRELESS_OUTLINE "\xf3\xb0\xb6\xb7" // U+F0DB7
+#define ICON_MDI_CAMPFIRE "\xf3\xb0\xbb\x9d" // U+F0EDD
+#define ICON_MDI_CANCEL "\xf3\xb0\x9c\xba" // U+F073A
+#define ICON_MDI_CANDELABRA "\xf3\xb1\x9f\x92" // U+F17D2
+#define ICON_MDI_CANDELABRA_FIRE "\xf3\xb1\x9f\x93" // U+F17D3
+#define ICON_MDI_CANDLE "\xf3\xb0\x97\xa2" // U+F05E2
+#define ICON_MDI_CANDY "\xf3\xb1\xa5\xb0" // U+F1970
+#define ICON_MDI_CANDY_OFF "\xf3\xb1\xa5\xb1" // U+F1971
+#define ICON_MDI_CANDY_OFF_OUTLINE "\xf3\xb1\xa5\xb2" // U+F1972
+#define ICON_MDI_CANDY_OUTLINE "\xf3\xb1\xa5\xb3" // U+F1973
+#define ICON_MDI_CANDYCANE "\xf3\xb0\x84\x8a" // U+F010A
+#define ICON_MDI_CANNABIS "\xf3\xb0\x9e\xa6" // U+F07A6
+#define ICON_MDI_CANNABIS_OFF "\xf3\xb1\x99\xae" // U+F166E
+#define ICON_MDI_CAPS_LOCK "\xf3\xb0\xaa\x9b" // U+F0A9B
+#define ICON_MDI_CAR "\xf3\xb0\x84\x8b" // U+F010B
+#define ICON_MDI_CAR_2_PLUS "\xf3\xb1\x80\x95" // U+F1015
+#define ICON_MDI_CAR_3_PLUS "\xf3\xb1\x80\x96" // U+F1016
+#define ICON_MDI_CAR_ARROW_LEFT "\xf3\xb1\x8e\xb2" // U+F13B2
+#define ICON_MDI_CAR_ARROW_RIGHT "\xf3\xb1\x8e\xb3" // U+F13B3
+#define ICON_MDI_CAR_BACK "\xf3\xb0\xb8\x9b" // U+F0E1B
+#define ICON_MDI_CAR_BATTERY "\xf3\xb0\x84\x8c" // U+F010C
+#define ICON_MDI_CAR_BRAKE_ABS "\xf3\xb0\xb1\x87" // U+F0C47
+#define ICON_MDI_CAR_BRAKE_ALERT "\xf3\xb0\xb1\x88" // U+F0C48
+#define ICON_MDI_CAR_BRAKE_FLUID_LEVEL "\xf3\xb1\xa4\x89" // U+F1909
+#define ICON_MDI_CAR_BRAKE_HOLD "\xf3\xb0\xb5\x9e" // U+F0D5E
+#define ICON_MDI_CAR_BRAKE_LOW_PRESSURE "\xf3\xb1\xa4\x8a" // U+F190A
+#define ICON_MDI_CAR_BRAKE_PARKING "\xf3\xb0\xb5\x9f" // U+F0D5F
+#define ICON_MDI_CAR_BRAKE_RETARDER "\xf3\xb1\x80\x97" // U+F1017
+#define ICON_MDI_CAR_BRAKE_TEMPERATURE "\xf3\xb1\xa4\x8b" // U+F190B
+#define ICON_MDI_CAR_BRAKE_WORN_LININGS "\xf3\xb1\xa4\x8c" // U+F190C
+#define ICON_MDI_CAR_CHILD_SEAT "\xf3\xb0\xbe\xa3" // U+F0FA3
+#define ICON_MDI_CAR_CLOCK "\xf3\xb1\xa5\xb4" // U+F1974
+#define ICON_MDI_CAR_CLUTCH "\xf3\xb1\x80\x98" // U+F1018
+#define ICON_MDI_CAR_COG "\xf3\xb1\x8f\x8c" // U+F13CC
+#define ICON_MDI_CAR_CONNECTED "\xf3\xb0\x84\x8d" // U+F010D
+#define ICON_MDI_CAR_CONVERTIBLE "\xf3\xb0\x9e\xa7" // U+F07A7
+#define ICON_MDI_CAR_COOLANT_LEVEL "\xf3\xb1\x80\x99" // U+F1019
+#define ICON_MDI_CAR_CRUISE_CONTROL "\xf3\xb0\xb5\xa0" // U+F0D60
+#define ICON_MDI_CAR_DEFROST_FRONT "\xf3\xb0\xb5\xa1" // U+F0D61
+#define ICON_MDI_CAR_DEFROST_REAR "\xf3\xb0\xb5\xa2" // U+F0D62
+#define ICON_MDI_CAR_DOOR "\xf3\xb0\xad\xab" // U+F0B6B
+#define ICON_MDI_CAR_DOOR_LOCK "\xf3\xb1\x82\x9d" // U+F109D
+#define ICON_MDI_CAR_DOOR_LOCK_OPEN "\xf3\xb1\xb2\x81" // U+F1C81
+#define ICON_MDI_CAR_ELECTRIC "\xf3\xb0\xad\xac" // U+F0B6C
+#define ICON_MDI_CAR_ELECTRIC_OUTLINE "\xf3\xb1\x96\xb5" // U+F15B5
+#define ICON_MDI_CAR_EMERGENCY "\xf3\xb1\x98\x8f" // U+F160F
+#define ICON_MDI_CAR_ESP "\xf3\xb0\xb1\x89" // U+F0C49
+#define ICON_MDI_CAR_ESTATE "\xf3\xb0\x9e\xa8" // U+F07A8
+#define ICON_MDI_CAR_HATCHBACK "\xf3\xb0\x9e\xa9" // U+F07A9
+#define ICON_MDI_CAR_INFO "\xf3\xb1\x86\xbe" // U+F11BE
+#define ICON_MDI_CAR_KEY "\xf3\xb0\xad\xad" // U+F0B6D
+#define ICON_MDI_CAR_LIFTED_PICKUP "\xf3\xb1\x94\xad" // U+F152D
+#define ICON_MDI_CAR_LIGHT_ALERT "\xf3\xb1\xa4\x8d" // U+F190D
+#define ICON_MDI_CAR_LIGHT_DIMMED "\xf3\xb0\xb1\x8a" // U+F0C4A
+#define ICON_MDI_CAR_LIGHT_FOG "\xf3\xb0\xb1\x8b" // U+F0C4B
+#define ICON_MDI_CAR_LIGHT_HIGH "\xf3\xb0\xb1\x8c" // U+F0C4C
+#define ICON_MDI_CAR_LIMOUSINE "\xf3\xb0\xa3\x8d" // U+F08CD
+#define ICON_MDI_CAR_MULTIPLE "\xf3\xb0\xad\xae" // U+F0B6E
+#define ICON_MDI_CAR_OFF "\xf3\xb0\xb8\x9c" // U+F0E1C
+#define ICON_MDI_CAR_OUTLINE "\xf3\xb1\x93\xad" // U+F14ED
+#define ICON_MDI_CAR_PARKING_LIGHTS "\xf3\xb0\xb5\xa3" // U+F0D63
+#define ICON_MDI_CAR_PICKUP "\xf3\xb0\x9e\xaa" // U+F07AA
+#define ICON_MDI_CAR_SEARCH "\xf3\xb1\xae\x8d" // U+F1B8D
+#define ICON_MDI_CAR_SEARCH_OUTLINE "\xf3\xb1\xae\x8e" // U+F1B8E
+#define ICON_MDI_CAR_SEAT "\xf3\xb0\xbe\xa4" // U+F0FA4
+#define ICON_MDI_CAR_SEAT_COOLER "\xf3\xb0\xbe\xa5" // U+F0FA5
+#define ICON_MDI_CAR_SEAT_HEATER "\xf3\xb0\xbe\xa6" // U+F0FA6
+#define ICON_MDI_CAR_SELECT "\xf3\xb1\xa1\xb9" // U+F1879
+#define ICON_MDI_CAR_SETTINGS "\xf3\xb1\x8f\x8d" // U+F13CD
+#define ICON_MDI_CAR_SHIFT_PATTERN "\xf3\xb0\xbd\x80" // U+F0F40
+#define ICON_MDI_CAR_SIDE "\xf3\xb0\x9e\xab" // U+F07AB
+#define ICON_MDI_CAR_SPEED_LIMITER "\xf3\xb1\xa4\x8e" // U+F190E
+#define ICON_MDI_CAR_SPORTS "\xf3\xb0\x9e\xac" // U+F07AC
+#define ICON_MDI_CAR_TIRE_ALERT "\xf3\xb0\xb1\x8d" // U+F0C4D
+#define ICON_MDI_CAR_TRACTION_CONTROL "\xf3\xb0\xb5\xa4" // U+F0D64
+#define ICON_MDI_CAR_TURBOCHARGER "\xf3\xb1\x80\x9a" // U+F101A
+#define ICON_MDI_CAR_WASH "\xf3\xb0\x84\x8e" // U+F010E
+#define ICON_MDI_CAR_WINDSHIELD "\xf3\xb1\x80\x9b" // U+F101B
+#define ICON_MDI_CAR_WINDSHIELD_OUTLINE "\xf3\xb1\x80\x9c" // U+F101C
+#define ICON_MDI_CAR_WIRELESS "\xf3\xb1\xa1\xb8" // U+F1878
+#define ICON_MDI_CAR_WRENCH "\xf3\xb1\xa0\x94" // U+F1814
+#define ICON_MDI_CARABINER "\xf3\xb1\x93\x80" // U+F14C0
+#define ICON_MDI_CARAVAN "\xf3\xb0\x9e\xad" // U+F07AD
+#define ICON_MDI_CARD "\xf3\xb0\xad\xaf" // U+F0B6F
+#define ICON_MDI_CARD_ACCOUNT_DETAILS "\xf3\xb0\x97\x92" // U+F05D2
+#define ICON_MDI_CARD_ACCOUNT_DETAILS_OUTLINE "\xf3\xb0\xb6\xab" // U+F0DAB
+#define ICON_MDI_CARD_ACCOUNT_DETAILS_STAR "\xf3\xb0\x8a\xa3" // U+F02A3
+#define ICON_MDI_CARD_ACCOUNT_DETAILS_STAR_OUTLINE "\xf3\xb0\x9b\x9b" // U+F06DB
+#define ICON_MDI_CARD_ACCOUNT_MAIL "\xf3\xb0\x86\x8e" // U+F018E
+#define ICON_MDI_CARD_ACCOUNT_MAIL_OUTLINE "\xf3\xb0\xba\x98" // U+F0E98
+#define ICON_MDI_CARD_ACCOUNT_PHONE "\xf3\xb0\xba\x99" // U+F0E99
+#define ICON_MDI_CARD_ACCOUNT_PHONE_OUTLINE "\xf3\xb0\xba\x9a" // U+F0E9A
+#define ICON_MDI_CARD_BULLETED "\xf3\xb0\xad\xb0" // U+F0B70
+#define ICON_MDI_CARD_BULLETED_OFF "\xf3\xb0\xad\xb1" // U+F0B71
+#define ICON_MDI_CARD_BULLETED_OFF_OUTLINE "\xf3\xb0\xad\xb2" // U+F0B72
+#define ICON_MDI_CARD_BULLETED_OUTLINE "\xf3\xb0\xad\xb3" // U+F0B73
+#define ICON_MDI_CARD_BULLETED_SETTINGS "\xf3\xb0\xad\xb4" // U+F0B74
+#define ICON_MDI_CARD_BULLETED_SETTINGS_OUTLINE "\xf3\xb0\xad\xb5" // U+F0B75
+#define ICON_MDI_CARD_MINUS "\xf3\xb1\x98\x80" // U+F1600
+#define ICON_MDI_CARD_MINUS_OUTLINE "\xf3\xb1\x98\x81" // U+F1601
+#define ICON_MDI_CARD_MULTIPLE "\xf3\xb1\x9f\xb1" // U+F17F1
+#define ICON_MDI_CARD_MULTIPLE_OUTLINE "\xf3\xb1\x9f\xb2" // U+F17F2
+#define ICON_MDI_CARD_OFF "\xf3\xb1\x98\x82" // U+F1602
+#define ICON_MDI_CARD_OFF_OUTLINE "\xf3\xb1\x98\x83" // U+F1603
+#define ICON_MDI_CARD_OUTLINE "\xf3\xb0\xad\xb6" // U+F0B76
+#define ICON_MDI_CARD_PLUS "\xf3\xb1\x87\xbf" // U+F11FF
+#define ICON_MDI_CARD_PLUS_OUTLINE "\xf3\xb1\x88\x80" // U+F1200
+#define ICON_MDI_CARD_REMOVE "\xf3\xb1\x98\x84" // U+F1604
+#define ICON_MDI_CARD_REMOVE_OUTLINE "\xf3\xb1\x98\x85" // U+F1605
+#define ICON_MDI_CARD_SEARCH "\xf3\xb1\x81\xb4" // U+F1074
+#define ICON_MDI_CARD_SEARCH_OUTLINE "\xf3\xb1\x81\xb5" // U+F1075
+#define ICON_MDI_CARD_TEXT "\xf3\xb0\xad\xb7" // U+F0B77
+#define ICON_MDI_CARD_TEXT_OUTLINE "\xf3\xb0\xad\xb8" // U+F0B78
+#define ICON_MDI_CARDS "\xf3\xb0\x98\xb8" // U+F0638
+#define ICON_MDI_CARDS_CLUB "\xf3\xb0\xa3\x8e" // U+F08CE
+#define ICON_MDI_CARDS_CLUB_OUTLINE "\xf3\xb1\xa2\x9f" // U+F189F
+#define ICON_MDI_CARDS_DIAMOND "\xf3\xb0\xa3\x8f" // U+F08CF
+#define ICON_MDI_CARDS_DIAMOND_OUTLINE "\xf3\xb1\x80\x9d" // U+F101D
+#define ICON_MDI_CARDS_HEART "\xf3\xb0\xa3\x90" // U+F08D0
+#define ICON_MDI_CARDS_HEART_OUTLINE "\xf3\xb1\xa2\xa0" // U+F18A0
+#define ICON_MDI_CARDS_OUTLINE "\xf3\xb0\x98\xb9" // U+F0639
+#define ICON_MDI_CARDS_PLAYING "\xf3\xb1\xa2\xa1" // U+F18A1
+#define ICON_MDI_CARDS_PLAYING_CLUB "\xf3\xb1\xa2\xa2" // U+F18A2
+#define ICON_MDI_CARDS_PLAYING_CLUB_MULTIPLE "\xf3\xb1\xa2\xa3" // U+F18A3
+#define ICON_MDI_CARDS_PLAYING_CLUB_MULTIPLE_OUTLINE "\xf3\xb1\xa2\xa4" // U+F18A4
+#define ICON_MDI_CARDS_PLAYING_CLUB_OUTLINE "\xf3\xb1\xa2\xa5" // U+F18A5
+#define ICON_MDI_CARDS_PLAYING_DIAMOND "\xf3\xb1\xa2\xa6" // U+F18A6
+#define ICON_MDI_CARDS_PLAYING_DIAMOND_MULTIPLE "\xf3\xb1\xa2\xa7" // U+F18A7
+#define ICON_MDI_CARDS_PLAYING_DIAMOND_MULTIPLE_OUTLINE "\xf3\xb1\xa2\xa8" // U+F18A8
+#define ICON_MDI_CARDS_PLAYING_DIAMOND_OUTLINE "\xf3\xb1\xa2\xa9" // U+F18A9
+#define ICON_MDI_CARDS_PLAYING_HEART "\xf3\xb1\xa2\xaa" // U+F18AA
+#define ICON_MDI_CARDS_PLAYING_HEART_MULTIPLE "\xf3\xb1\xa2\xab" // U+F18AB
+#define ICON_MDI_CARDS_PLAYING_HEART_MULTIPLE_OUTLINE "\xf3\xb1\xa2\xac" // U+F18AC
+#define ICON_MDI_CARDS_PLAYING_HEART_OUTLINE "\xf3\xb1\xa2\xad" // U+F18AD
+#define ICON_MDI_CARDS_PLAYING_OUTLINE "\xf3\xb0\x98\xba" // U+F063A
+#define ICON_MDI_CARDS_PLAYING_SPADE "\xf3\xb1\xa2\xae" // U+F18AE
+#define ICON_MDI_CARDS_PLAYING_SPADE_MULTIPLE "\xf3\xb1\xa2\xaf" // U+F18AF
+#define ICON_MDI_CARDS_PLAYING_SPADE_MULTIPLE_OUTLINE "\xf3\xb1\xa2\xb0" // U+F18B0
+#define ICON_MDI_CARDS_PLAYING_SPADE_OUTLINE "\xf3\xb1\xa2\xb1" // U+F18B1
+#define ICON_MDI_CARDS_SPADE "\xf3\xb0\xa3\x91" // U+F08D1
+#define ICON_MDI_CARDS_SPADE_OUTLINE "\xf3\xb1\xa2\xb2" // U+F18B2
+#define ICON_MDI_CARDS_VARIANT "\xf3\xb0\x9b\x87" // U+F06C7
+#define ICON_MDI_CARROT "\xf3\xb0\x84\x8f" // U+F010F
+#define ICON_MDI_CART "\xf3\xb0\x84\x90" // U+F0110
+#define ICON_MDI_CART_ARROW_DOWN "\xf3\xb0\xb5\xa6" // U+F0D66
+#define ICON_MDI_CART_ARROW_RIGHT "\xf3\xb0\xb1\x8e" // U+F0C4E
+#define ICON_MDI_CART_ARROW_UP "\xf3\xb0\xb5\xa7" // U+F0D67
+#define ICON_MDI_CART_CHECK "\xf3\xb1\x97\xaa" // U+F15EA
+#define ICON_MDI_CART_HEART "\xf3\xb1\xa3\xa0" // U+F18E0
+#define ICON_MDI_CART_MINUS "\xf3\xb0\xb5\xa8" // U+F0D68
+#define ICON_MDI_CART_OFF "\xf3\xb0\x99\xab" // U+F066B
+#define ICON_MDI_CART_OUTLINE "\xf3\xb0\x84\x91" // U+F0111
+#define ICON_MDI_CART_PERCENT "\xf3\xb1\xae\xae" // U+F1BAE
+#define ICON_MDI_CART_PLUS "\xf3\xb0\x84\x92" // U+F0112
+#define ICON_MDI_CART_REMOVE "\xf3\xb0\xb5\xa9" // U+F0D69
+#define ICON_MDI_CART_VARIANT "\xf3\xb1\x97\xab" // U+F15EB
+#define ICON_MDI_CASE_SENSITIVE_ALT "\xf3\xb0\x84\x93" // U+F0113
+#define ICON_MDI_CASH "\xf3\xb0\x84\x94" // U+F0114
+#define ICON_MDI_CASH_100 "\xf3\xb0\x84\x95" // U+F0115
+#define ICON_MDI_CASH_CHECK "\xf3\xb1\x93\xae" // U+F14EE
+#define ICON_MDI_CASH_CLOCK "\xf3\xb1\xaa\x91" // U+F1A91
+#define ICON_MDI_CASH_EDIT "\xf3\xb1\xb2\xab" // U+F1CAB
+#define ICON_MDI_CASH_FAST "\xf3\xb1\xa1\x9c" // U+F185C
+#define ICON_MDI_CASH_LOCK "\xf3\xb1\x93\xaa" // U+F14EA
+#define ICON_MDI_CASH_LOCK_OPEN "\xf3\xb1\x93\xab" // U+F14EB
+#define ICON_MDI_CASH_MARKER "\xf3\xb0\xb6\xb8" // U+F0DB8
+#define ICON_MDI_CASH_MINUS "\xf3\xb1\x89\xa0" // U+F1260
+#define ICON_MDI_CASH_MULTIPLE "\xf3\xb0\x84\x96" // U+F0116
+#define ICON_MDI_CASH_OFF "\xf3\xb1\xb1\xb9" // U+F1C79
+#define ICON_MDI_CASH_PLUS "\xf3\xb1\x89\xa1" // U+F1261
+#define ICON_MDI_CASH_REFUND "\xf3\xb0\xaa\x9c" // U+F0A9C
+#define ICON_MDI_CASH_REGISTER "\xf3\xb0\xb3\xb4" // U+F0CF4
+#define ICON_MDI_CASH_REMOVE "\xf3\xb1\x89\xa2" // U+F1262
+#define ICON_MDI_CASH_SYNC "\xf3\xb1\xaa\x92" // U+F1A92
+#define ICON_MDI_CASSETTE "\xf3\xb0\xa7\x94" // U+F09D4
+#define ICON_MDI_CAST "\xf3\xb0\x84\x98" // U+F0118
+#define ICON_MDI_CAST_AUDIO "\xf3\xb1\x80\x9e" // U+F101E
+#define ICON_MDI_CAST_AUDIO_VARIANT "\xf3\xb1\x9d\x89" // U+F1749
+#define ICON_MDI_CAST_CONNECTED "\xf3\xb0\x84\x99" // U+F0119
+#define ICON_MDI_CAST_EDUCATION "\xf3\xb0\xb8\x9d" // U+F0E1D
+#define ICON_MDI_CAST_OFF "\xf3\xb0\x9e\x8a" // U+F078A
+#define ICON_MDI_CAST_VARIANT "\xf3\xb0\x80\x9f" // U+F001F
+#define ICON_MDI_CASTLE "\xf3\xb0\x84\x9a" // U+F011A
+#define ICON_MDI_CAT "\xf3\xb0\x84\x9b" // U+F011B
+#define ICON_MDI_CCTV "\xf3\xb0\x9e\xae" // U+F07AE
+#define ICON_MDI_CCTV_OFF "\xf3\xb1\xa1\x9f" // U+F185F
+#define ICON_MDI_CEILING_FAN "\xf3\xb1\x9e\x97" // U+F1797
+#define ICON_MDI_CEILING_FAN_LIGHT "\xf3\xb1\x9e\x98" // U+F1798
+#define ICON_MDI_CEILING_LIGHT "\xf3\xb0\x9d\xa9" // U+F0769
+#define ICON_MDI_CEILING_LIGHT_MULTIPLE "\xf3\xb1\xa3\x9d" // U+F18DD
+#define ICON_MDI_CEILING_LIGHT_MULTIPLE_OUTLINE "\xf3\xb1\xa3\x9e" // U+F18DE
+#define ICON_MDI_CEILING_LIGHT_OUTLINE "\xf3\xb1\x9f\x87" // U+F17C7
+#define ICON_MDI_CELLPHONE "\xf3\xb0\x84\x9c" // U+F011C
+#define ICON_MDI_CELLPHONE_ARROW_DOWN "\xf3\xb0\xa7\x95" // U+F09D5
+#define ICON_MDI_CELLPHONE_ARROW_DOWN_VARIANT "\xf3\xb1\xa7\x85" // U+F19C5
+#define ICON_MDI_CELLPHONE_BASIC "\xf3\xb0\x84\x9e" // U+F011E
+#define ICON_MDI_CELLPHONE_CHARGING "\xf3\xb1\x8e\x97" // U+F1397
+#define ICON_MDI_CELLPHONE_CHECK "\xf3\xb1\x9f\xbd" // U+F17FD
+#define ICON_MDI_CELLPHONE_COG "\xf3\xb0\xa5\x91" // U+F0951
+#define ICON_MDI_CELLPHONE_DOCK "\xf3\xb0\x84\x9f" // U+F011F
+#define ICON_MDI_CELLPHONE_INFORMATION "\xf3\xb0\xbd\x81" // U+F0F41
+#define ICON_MDI_CELLPHONE_KEY "\xf3\xb0\xa5\x8e" // U+F094E
+#define ICON_MDI_CELLPHONE_LINK "\xf3\xb0\x84\xa1" // U+F0121
+#define ICON_MDI_CELLPHONE_LINK_OFF "\xf3\xb0\x84\xa2" // U+F0122
+#define ICON_MDI_CELLPHONE_LOCK "\xf3\xb0\xa5\x8f" // U+F094F
+#define ICON_MDI_CELLPHONE_MARKER "\xf3\xb1\xa0\xba" // U+F183A
+#define ICON_MDI_CELLPHONE_MESSAGE "\xf3\xb0\xa3\x93" // U+F08D3
+#define ICON_MDI_CELLPHONE_MESSAGE_OFF "\xf3\xb1\x83\x92" // U+F10D2
+#define ICON_MDI_CELLPHONE_NFC "\xf3\xb0\xba\x90" // U+F0E90
+#define ICON_MDI_CELLPHONE_NFC_OFF "\xf3\xb1\x8b\x98" // U+F12D8
+#define ICON_MDI_CELLPHONE_OFF "\xf3\xb0\xa5\x90" // U+F0950
+#define ICON_MDI_CELLPHONE_PLAY "\xf3\xb1\x80\x9f" // U+F101F
+#define ICON_MDI_CELLPHONE_REMOVE "\xf3\xb0\xa5\x8d" // U+F094D
+#define ICON_MDI_CELLPHONE_SCREENSHOT "\xf3\xb0\xa8\xb5" // U+F0A35
+#define ICON_MDI_CELLPHONE_SETTINGS "\xf3\xb0\x84\xa3" // U+F0123
+#define ICON_MDI_CELLPHONE_SOUND "\xf3\xb0\xa5\x92" // U+F0952
+#define ICON_MDI_CELLPHONE_TEXT "\xf3\xb0\xa3\x92" // U+F08D2
+#define ICON_MDI_CELLPHONE_WIRELESS "\xf3\xb0\xa0\x95" // U+F0815
+#define ICON_MDI_CENTOS "\xf3\xb1\x84\x9a" // U+F111A
+#define ICON_MDI_CERTIFICATE "\xf3\xb0\x84\xa4" // U+F0124
+#define ICON_MDI_CERTIFICATE_OUTLINE "\xf3\xb1\x86\x88" // U+F1188
+#define ICON_MDI_CHAIR_ROLLING "\xf3\xb0\xbd\x88" // U+F0F48
+#define ICON_MDI_CHAIR_SCHOOL "\xf3\xb0\x84\xa5" // U+F0125
+#define ICON_MDI_CHANDELIER "\xf3\xb1\x9e\x93" // U+F1793
+#define ICON_MDI_CHARITY "\xf3\xb0\xb1\x8f" // U+F0C4F
+#define ICON_MDI_CHARITY_SEARCH "\xf3\xb1\xb2\x82" // U+F1C82
+#define ICON_MDI_CHART_ARC "\xf3\xb0\x84\xa6" // U+F0126
+#define ICON_MDI_CHART_AREASPLINE "\xf3\xb0\x84\xa7" // U+F0127
+#define ICON_MDI_CHART_AREASPLINE_VARIANT "\xf3\xb0\xba\x91" // U+F0E91
+#define ICON_MDI_CHART_BAR "\xf3\xb0\x84\xa8" // U+F0128
+#define ICON_MDI_CHART_BAR_STACKED "\xf3\xb0\x9d\xaa" // U+F076A
+#define ICON_MDI_CHART_BELL_CURVE "\xf3\xb0\xb1\x90" // U+F0C50
+#define ICON_MDI_CHART_BELL_CURVE_CUMULATIVE "\xf3\xb0\xbe\xa7" // U+F0FA7
+#define ICON_MDI_CHART_BOX "\xf3\xb1\x95\x8d" // U+F154D
+#define ICON_MDI_CHART_BOX_OUTLINE "\xf3\xb1\x95\x8e" // U+F154E
+#define ICON_MDI_CHART_BOX_PLUS_OUTLINE "\xf3\xb1\x95\x8f" // U+F154F
+#define ICON_MDI_CHART_BUBBLE "\xf3\xb0\x97\xa3" // U+F05E3
+#define ICON_MDI_CHART_DONUT "\xf3\xb0\x9e\xaf" // U+F07AF
+#define ICON_MDI_CHART_DONUT_VARIANT "\xf3\xb0\x9e\xb0" // U+F07B0
+#define ICON_MDI_CHART_GANTT "\xf3\xb0\x99\xac" // U+F066C
+#define ICON_MDI_CHART_HISTOGRAM "\xf3\xb0\x84\xa9" // U+F0129
+#define ICON_MDI_CHART_LINE "\xf3\xb0\x84\xaa" // U+F012A
+#define ICON_MDI_CHART_LINE_STACKED "\xf3\xb0\x9d\xab" // U+F076B
+#define ICON_MDI_CHART_LINE_VARIANT "\xf3\xb0\x9e\xb1" // U+F07B1
+#define ICON_MDI_CHART_MULTILINE "\xf3\xb0\xa3\x94" // U+F08D4
+#define ICON_MDI_CHART_MULTIPLE "\xf3\xb1\x88\x93" // U+F1213
+#define ICON_MDI_CHART_PIE "\xf3\xb0\x84\xab" // U+F012B
+#define ICON_MDI_CHART_PIE_OUTLINE "\xf3\xb1\xaf\x9f" // U+F1BDF
+#define ICON_MDI_CHART_PPF "\xf3\xb1\x8e\x80" // U+F1380
+#define ICON_MDI_CHART_SANKEY "\xf3\xb1\x87\x9f" // U+F11DF
+#define ICON_MDI_CHART_SANKEY_VARIANT "\xf3\xb1\x87\xa0" // U+F11E0
+#define ICON_MDI_CHART_SCATTER_PLOT "\xf3\xb0\xba\x92" // U+F0E92
+#define ICON_MDI_CHART_SCATTER_PLOT_HEXBIN "\xf3\xb0\x99\xad" // U+F066D
+#define ICON_MDI_CHART_TIMELINE "\xf3\xb0\x99\xae" // U+F066E
+#define ICON_MDI_CHART_TIMELINE_VARIANT "\xf3\xb0\xba\x93" // U+F0E93
+#define ICON_MDI_CHART_TIMELINE_VARIANT_SHIMMER "\xf3\xb1\x96\xb6" // U+F15B6
+#define ICON_MDI_CHART_TREE "\xf3\xb0\xba\x94" // U+F0E94
+#define ICON_MDI_CHART_WATERFALL "\xf3\xb1\xa4\x98" // U+F1918
+#define ICON_MDI_CHAT "\xf3\xb0\xad\xb9" // U+F0B79
+#define ICON_MDI_CHAT_ALERT "\xf3\xb0\xad\xba" // U+F0B7A
+#define ICON_MDI_CHAT_ALERT_OUTLINE "\xf3\xb1\x8b\x89" // U+F12C9
+#define ICON_MDI_CHAT_MINUS "\xf3\xb1\x90\x90" // U+F1410
+#define ICON_MDI_CHAT_MINUS_OUTLINE "\xf3\xb1\x90\x93" // U+F1413
+#define ICON_MDI_CHAT_OUTLINE "\xf3\xb0\xbb\x9e" // U+F0EDE
+#define ICON_MDI_CHAT_PLUS "\xf3\xb1\x90\x8f" // U+F140F
+#define ICON_MDI_CHAT_PLUS_OUTLINE "\xf3\xb1\x90\x92" // U+F1412
+#define ICON_MDI_CHAT_PROCESSING "\xf3\xb0\xad\xbb" // U+F0B7B
+#define ICON_MDI_CHAT_PROCESSING_OUTLINE "\xf3\xb1\x8b\x8a" // U+F12CA
+#define ICON_MDI_CHAT_QUESTION "\xf3\xb1\x9c\xb8" // U+F1738
+#define ICON_MDI_CHAT_QUESTION_OUTLINE "\xf3\xb1\x9c\xb9" // U+F1739
+#define ICON_MDI_CHAT_REMOVE "\xf3\xb1\x90\x91" // U+F1411
+#define ICON_MDI_CHAT_REMOVE_OUTLINE "\xf3\xb1\x90\x94" // U+F1414
+#define ICON_MDI_CHAT_SLEEP "\xf3\xb1\x8b\x91" // U+F12D1
+#define ICON_MDI_CHAT_SLEEP_OUTLINE "\xf3\xb1\x8b\x92" // U+F12D2
+#define ICON_MDI_CHECK "\xf3\xb0\x84\xac" // U+F012C
+#define ICON_MDI_CHECK_ALL "\xf3\xb0\x84\xad" // U+F012D
+#define ICON_MDI_CHECK_BOLD "\xf3\xb0\xb8\x9e" // U+F0E1E
+#define ICON_MDI_CHECK_CIRCLE "\xf3\xb0\x97\xa0" // U+F05E0
+#define ICON_MDI_CHECK_CIRCLE_OUTLINE "\xf3\xb0\x97\xa1" // U+F05E1
+#define ICON_MDI_CHECK_DECAGRAM "\xf3\xb0\x9e\x91" // U+F0791
+#define ICON_MDI_CHECK_DECAGRAM_OUTLINE "\xf3\xb1\x9d\x80" // U+F1740
+#define ICON_MDI_CHECK_NETWORK "\xf3\xb0\xb1\x93" // U+F0C53
+#define ICON_MDI_CHECK_NETWORK_OUTLINE "\xf3\xb0\xb1\x94" // U+F0C54
+#define ICON_MDI_CHECK_OUTLINE "\xf3\xb0\xa1\x95" // U+F0855
+#define ICON_MDI_CHECK_UNDERLINE "\xf3\xb0\xb8\x9f" // U+F0E1F
+#define ICON_MDI_CHECK_UNDERLINE_CIRCLE "\xf3\xb0\xb8\xa0" // U+F0E20
+#define ICON_MDI_CHECK_UNDERLINE_CIRCLE_OUTLINE "\xf3\xb0\xb8\xa1" // U+F0E21
+#define ICON_MDI_CHECKBOOK "\xf3\xb0\xaa\x9d" // U+F0A9D
+#define ICON_MDI_CHECKBOOK_ARROW_LEFT "\xf3\xb1\xb0\x9d" // U+F1C1D
+#define ICON_MDI_CHECKBOOK_ARROW_RIGHT "\xf3\xb1\xb0\x9e" // U+F1C1E
+#define ICON_MDI_CHECKBOX_BLANK "\xf3\xb0\x84\xae" // U+F012E
+#define ICON_MDI_CHECKBOX_BLANK_BADGE "\xf3\xb1\x85\xb6" // U+F1176
+#define ICON_MDI_CHECKBOX_BLANK_BADGE_OUTLINE "\xf3\xb0\x84\x97" // U+F0117
+#define ICON_MDI_CHECKBOX_BLANK_CIRCLE "\xf3\xb0\x84\xaf" // U+F012F
+#define ICON_MDI_CHECKBOX_BLANK_CIRCLE_OUTLINE "\xf3\xb0\x84\xb0" // U+F0130
+#define ICON_MDI_CHECKBOX_BLANK_OFF "\xf3\xb1\x8b\xac" // U+F12EC
+#define ICON_MDI_CHECKBOX_BLANK_OFF_OUTLINE "\xf3\xb1\x8b\xad" // U+F12ED
+#define ICON_MDI_CHECKBOX_BLANK_OUTLINE "\xf3\xb0\x84\xb1" // U+F0131
+#define ICON_MDI_CHECKBOX_INTERMEDIATE "\xf3\xb0\xa1\x96" // U+F0856
+#define ICON_MDI_CHECKBOX_INTERMEDIATE_VARIANT "\xf3\xb1\xad\x94" // U+F1B54
+#define ICON_MDI_CHECKBOX_MARKED "\xf3\xb0\x84\xb2" // U+F0132
+#define ICON_MDI_CHECKBOX_MARKED_CIRCLE "\xf3\xb0\x84\xb3" // U+F0133
+#define ICON_MDI_CHECKBOX_MARKED_CIRCLE_AUTO_OUTLINE "\xf3\xb1\xb0\xa6" // U+F1C26
+#define ICON_MDI_CHECKBOX_MARKED_CIRCLE_MINUS_OUTLINE "\xf3\xb1\xb0\xa7" // U+F1C27
+#define ICON_MDI_CHECKBOX_MARKED_CIRCLE_OUTLINE "\xf3\xb0\x84\xb4" // U+F0134
+#define ICON_MDI_CHECKBOX_MARKED_CIRCLE_PLUS_OUTLINE "\xf3\xb1\xa4\xa7" // U+F1927
+#define ICON_MDI_CHECKBOX_MARKED_OUTLINE "\xf3\xb0\x84\xb5" // U+F0135
+#define ICON_MDI_CHECKBOX_MULTIPLE_BLANK "\xf3\xb0\x84\xb6" // U+F0136
+#define ICON_MDI_CHECKBOX_MULTIPLE_BLANK_CIRCLE "\xf3\xb0\x98\xbb" // U+F063B
+#define ICON_MDI_CHECKBOX_MULTIPLE_BLANK_CIRCLE_OUTLINE "\xf3\xb0\x98\xbc" // U+F063C
+#define ICON_MDI_CHECKBOX_MULTIPLE_BLANK_OUTLINE "\xf3\xb0\x84\xb7" // U+F0137
+#define ICON_MDI_CHECKBOX_MULTIPLE_MARKED "\xf3\xb0\x84\xb8" // U+F0138
+#define ICON_MDI_CHECKBOX_MULTIPLE_MARKED_CIRCLE "\xf3\xb0\x98\xbd" // U+F063D
+#define ICON_MDI_CHECKBOX_MULTIPLE_MARKED_CIRCLE_OUTLINE "\xf3\xb0\x98\xbe" // U+F063E
+#define ICON_MDI_CHECKBOX_MULTIPLE_MARKED_OUTLINE "\xf3\xb0\x84\xb9" // U+F0139
+#define ICON_MDI_CHECKBOX_MULTIPLE_OUTLINE "\xf3\xb0\xb1\x91" // U+F0C51
+#define ICON_MDI_CHECKBOX_OUTLINE "\xf3\xb0\xb1\x92" // U+F0C52
+#define ICON_MDI_CHECKERBOARD "\xf3\xb0\x84\xba" // U+F013A
+#define ICON_MDI_CHECKERBOARD_MINUS "\xf3\xb1\x88\x82" // U+F1202
+#define ICON_MDI_CHECKERBOARD_PLUS "\xf3\xb1\x88\x81" // U+F1201
+#define ICON_MDI_CHECKERBOARD_REMOVE "\xf3\xb1\x88\x83" // U+F1203
+#define ICON_MDI_CHEESE "\xf3\xb1\x8a\xb9" // U+F12B9
+#define ICON_MDI_CHEESE_OFF "\xf3\xb1\x8f\xae" // U+F13EE
+#define ICON_MDI_CHEF_HAT "\xf3\xb0\xad\xbc" // U+F0B7C
+#define ICON_MDI_CHEMICAL_WEAPON "\xf3\xb0\x84\xbb" // U+F013B
+#define ICON_MDI_CHESS_BISHOP "\xf3\xb0\xa1\x9c" // U+F085C
+#define ICON_MDI_CHESS_KING "\xf3\xb0\xa1\x97" // U+F0857
+#define ICON_MDI_CHESS_KNIGHT "\xf3\xb0\xa1\x98" // U+F0858
+#define ICON_MDI_CHESS_PAWN "\xf3\xb0\xa1\x99" // U+F0859
+#define ICON_MDI_CHESS_QUEEN "\xf3\xb0\xa1\x9a" // U+F085A
+#define ICON_MDI_CHESS_ROOK "\xf3\xb0\xa1\x9b" // U+F085B
+#define ICON_MDI_CHEVRON_DOUBLE_DOWN "\xf3\xb0\x84\xbc" // U+F013C
+#define ICON_MDI_CHEVRON_DOUBLE_LEFT "\xf3\xb0\x84\xbd" // U+F013D
+#define ICON_MDI_CHEVRON_DOUBLE_RIGHT "\xf3\xb0\x84\xbe" // U+F013E
+#define ICON_MDI_CHEVRON_DOUBLE_UP "\xf3\xb0\x84\xbf" // U+F013F
+#define ICON_MDI_CHEVRON_DOWN "\xf3\xb0\x85\x80" // U+F0140
+#define ICON_MDI_CHEVRON_DOWN_BOX "\xf3\xb0\xa7\x96" // U+F09D6
+#define ICON_MDI_CHEVRON_DOWN_BOX_OUTLINE "\xf3\xb0\xa7\x97" // U+F09D7
+#define ICON_MDI_CHEVRON_DOWN_CIRCLE "\xf3\xb0\xac\xa6" // U+F0B26
+#define ICON_MDI_CHEVRON_DOWN_CIRCLE_OUTLINE "\xf3\xb0\xac\xa7" // U+F0B27
+#define ICON_MDI_CHEVRON_LEFT "\xf3\xb0\x85\x81" // U+F0141
+#define ICON_MDI_CHEVRON_LEFT_BOX "\xf3\xb0\xa7\x98" // U+F09D8
+#define ICON_MDI_CHEVRON_LEFT_BOX_OUTLINE "\xf3\xb0\xa7\x99" // U+F09D9
+#define ICON_MDI_CHEVRON_LEFT_CIRCLE "\xf3\xb0\xac\xa8" // U+F0B28
+#define ICON_MDI_CHEVRON_LEFT_CIRCLE_OUTLINE "\xf3\xb0\xac\xa9" // U+F0B29
+#define ICON_MDI_CHEVRON_RIGHT "\xf3\xb0\x85\x82" // U+F0142
+#define ICON_MDI_CHEVRON_RIGHT_BOX "\xf3\xb0\xa7\x9a" // U+F09DA
+#define ICON_MDI_CHEVRON_RIGHT_BOX_OUTLINE "\xf3\xb0\xa7\x9b" // U+F09DB
+#define ICON_MDI_CHEVRON_RIGHT_CIRCLE "\xf3\xb0\xac\xaa" // U+F0B2A
+#define ICON_MDI_CHEVRON_RIGHT_CIRCLE_OUTLINE "\xf3\xb0\xac\xab" // U+F0B2B
+#define ICON_MDI_CHEVRON_TRIPLE_DOWN "\xf3\xb0\xb6\xb9" // U+F0DB9
+#define ICON_MDI_CHEVRON_TRIPLE_LEFT "\xf3\xb0\xb6\xba" // U+F0DBA
+#define ICON_MDI_CHEVRON_TRIPLE_RIGHT "\xf3\xb0\xb6\xbb" // U+F0DBB
+#define ICON_MDI_CHEVRON_TRIPLE_UP "\xf3\xb0\xb6\xbc" // U+F0DBC
+#define ICON_MDI_CHEVRON_UP "\xf3\xb0\x85\x83" // U+F0143
+#define ICON_MDI_CHEVRON_UP_BOX "\xf3\xb0\xa7\x9c" // U+F09DC
+#define ICON_MDI_CHEVRON_UP_BOX_OUTLINE "\xf3\xb0\xa7\x9d" // U+F09DD
+#define ICON_MDI_CHEVRON_UP_CIRCLE "\xf3\xb0\xac\xac" // U+F0B2C
+#define ICON_MDI_CHEVRON_UP_CIRCLE_OUTLINE "\xf3\xb0\xac\xad" // U+F0B2D
+#define ICON_MDI_CHILI_ALERT "\xf3\xb1\x9f\xaa" // U+F17EA
+#define ICON_MDI_CHILI_ALERT_OUTLINE "\xf3\xb1\x9f\xab" // U+F17EB
+#define ICON_MDI_CHILI_HOT "\xf3\xb0\x9e\xb2" // U+F07B2
+#define ICON_MDI_CHILI_HOT_OUTLINE "\xf3\xb1\x9f\xac" // U+F17EC
+#define ICON_MDI_CHILI_MEDIUM "\xf3\xb0\x9e\xb3" // U+F07B3
+#define ICON_MDI_CHILI_MEDIUM_OUTLINE "\xf3\xb1\x9f\xad" // U+F17ED
+#define ICON_MDI_CHILI_MILD "\xf3\xb0\x9e\xb4" // U+F07B4
+#define ICON_MDI_CHILI_MILD_OUTLINE "\xf3\xb1\x9f\xae" // U+F17EE
+#define ICON_MDI_CHILI_OFF "\xf3\xb1\x91\xa7" // U+F1467
+#define ICON_MDI_CHILI_OFF_OUTLINE "\xf3\xb1\x9f\xaf" // U+F17EF
+#define ICON_MDI_CHIP "\xf3\xb0\x98\x9a" // U+F061A
+#define ICON_MDI_CHURCH "\xf3\xb0\x85\x84" // U+F0144
+#define ICON_MDI_CHURCH_OUTLINE "\xf3\xb1\xac\x82" // U+F1B02
+#define ICON_MDI_CIGAR "\xf3\xb1\x86\x89" // U+F1189
+#define ICON_MDI_CIGAR_OFF "\xf3\xb1\x90\x9b" // U+F141B
+#define ICON_MDI_CIRCLE "\xf3\xb0\x9d\xa5" // U+F0765
+#define ICON_MDI_CIRCLE_BOX "\xf3\xb1\x97\x9c" // U+F15DC
+#define ICON_MDI_CIRCLE_BOX_OUTLINE "\xf3\xb1\x97\x9d" // U+F15DD
+#define ICON_MDI_CIRCLE_DOUBLE "\xf3\xb0\xba\x95" // U+F0E95
+#define ICON_MDI_CIRCLE_EDIT_OUTLINE "\xf3\xb0\xa3\x95" // U+F08D5
+#define ICON_MDI_CIRCLE_EXPAND "\xf3\xb0\xba\x96" // U+F0E96
+#define ICON_MDI_CIRCLE_HALF "\xf3\xb1\x8e\x95" // U+F1395
+#define ICON_MDI_CIRCLE_HALF_FULL "\xf3\xb1\x8e\x96" // U+F1396
+#define ICON_MDI_CIRCLE_MEDIUM "\xf3\xb0\xa7\x9e" // U+F09DE
+#define ICON_MDI_CIRCLE_MULTIPLE "\xf3\xb0\xac\xb8" // U+F0B38
+#define ICON_MDI_CIRCLE_MULTIPLE_OUTLINE "\xf3\xb0\x9a\x95" // U+F0695
+#define ICON_MDI_CIRCLE_OFF_OUTLINE "\xf3\xb1\x83\x93" // U+F10D3
+#define ICON_MDI_CIRCLE_OPACITY "\xf3\xb1\xa1\x93" // U+F1853
+#define ICON_MDI_CIRCLE_OUTLINE "\xf3\xb0\x9d\xa6" // U+F0766
+#define ICON_MDI_CIRCLE_SLICE_1 "\xf3\xb0\xaa\x9e" // U+F0A9E
+#define ICON_MDI_CIRCLE_SLICE_2 "\xf3\xb0\xaa\x9f" // U+F0A9F
+#define ICON_MDI_CIRCLE_SLICE_3 "\xf3\xb0\xaa\xa0" // U+F0AA0
+#define ICON_MDI_CIRCLE_SLICE_4 "\xf3\xb0\xaa\xa1" // U+F0AA1
+#define ICON_MDI_CIRCLE_SLICE_5 "\xf3\xb0\xaa\xa2" // U+F0AA2
+#define ICON_MDI_CIRCLE_SLICE_6 "\xf3\xb0\xaa\xa3" // U+F0AA3
+#define ICON_MDI_CIRCLE_SLICE_7 "\xf3\xb0\xaa\xa4" // U+F0AA4
+#define ICON_MDI_CIRCLE_SLICE_8 "\xf3\xb0\xaa\xa5" // U+F0AA5
+#define ICON_MDI_CIRCLE_SMALL "\xf3\xb0\xa7\x9f" // U+F09DF
+#define ICON_MDI_CIRCULAR_SAW "\xf3\xb0\xb8\xa2" // U+F0E22
+#define ICON_MDI_CITY "\xf3\xb0\x85\x86" // U+F0146
+#define ICON_MDI_CITY_SWITCH "\xf3\xb1\xb0\xa8" // U+F1C28
+#define ICON_MDI_CITY_VARIANT "\xf3\xb0\xa8\xb6" // U+F0A36
+#define ICON_MDI_CITY_VARIANT_OUTLINE "\xf3\xb0\xa8\xb7" // U+F0A37
+#define ICON_MDI_CLIPBOARD "\xf3\xb0\x85\x87" // U+F0147
+#define ICON_MDI_CLIPBOARD_ACCOUNT "\xf3\xb0\x85\x88" // U+F0148
+#define ICON_MDI_CLIPBOARD_ACCOUNT_OUTLINE "\xf3\xb0\xb1\x95" // U+F0C55
+#define ICON_MDI_CLIPBOARD_ALERT "\xf3\xb0\x85\x89" // U+F0149
+#define ICON_MDI_CLIPBOARD_ALERT_OUTLINE "\xf3\xb0\xb3\xb7" // U+F0CF7
+#define ICON_MDI_CLIPBOARD_ARROW_DOWN "\xf3\xb0\x85\x8a" // U+F014A
+#define ICON_MDI_CLIPBOARD_ARROW_DOWN_OUTLINE "\xf3\xb0\xb1\x96" // U+F0C56
+#define ICON_MDI_CLIPBOARD_ARROW_LEFT "\xf3\xb0\x85\x8b" // U+F014B
+#define ICON_MDI_CLIPBOARD_ARROW_LEFT_OUTLINE "\xf3\xb0\xb3\xb8" // U+F0CF8
+#define ICON_MDI_CLIPBOARD_ARROW_RIGHT "\xf3\xb0\xb3\xb9" // U+F0CF9
+#define ICON_MDI_CLIPBOARD_ARROW_RIGHT_OUTLINE "\xf3\xb0\xb3\xba" // U+F0CFA
+#define ICON_MDI_CLIPBOARD_ARROW_UP "\xf3\xb0\xb1\x97" // U+F0C57
+#define ICON_MDI_CLIPBOARD_ARROW_UP_OUTLINE "\xf3\xb0\xb1\x98" // U+F0C58
+#define ICON_MDI_CLIPBOARD_CHECK "\xf3\xb0\x85\x8e" // U+F014E
+#define ICON_MDI_CLIPBOARD_CHECK_MULTIPLE "\xf3\xb1\x89\xa3" // U+F1263
+#define ICON_MDI_CLIPBOARD_CHECK_MULTIPLE_OUTLINE "\xf3\xb1\x89\xa4" // U+F1264
+#define ICON_MDI_CLIPBOARD_CHECK_OUTLINE "\xf3\xb0\xa2\xa8" // U+F08A8
+#define ICON_MDI_CLIPBOARD_CLOCK "\xf3\xb1\x9b\xa2" // U+F16E2
+#define ICON_MDI_CLIPBOARD_CLOCK_OUTLINE "\xf3\xb1\x9b\xa3" // U+F16E3
+#define ICON_MDI_CLIPBOARD_EDIT "\xf3\xb1\x93\xa5" // U+F14E5
+#define ICON_MDI_CLIPBOARD_EDIT_OUTLINE "\xf3\xb1\x93\xa6" // U+F14E6
+#define ICON_MDI_CLIPBOARD_FILE "\xf3\xb1\x89\xa5" // U+F1265
+#define ICON_MDI_CLIPBOARD_FILE_OUTLINE "\xf3\xb1\x89\xa6" // U+F1266
+#define ICON_MDI_CLIPBOARD_FLOW "\xf3\xb0\x9b\x88" // U+F06C8
+#define ICON_MDI_CLIPBOARD_FLOW_OUTLINE "\xf3\xb1\x84\x97" // U+F1117
+#define ICON_MDI_CLIPBOARD_LIST "\xf3\xb1\x83\x94" // U+F10D4
+#define ICON_MDI_CLIPBOARD_LIST_OUTLINE "\xf3\xb1\x83\x95" // U+F10D5
+#define ICON_MDI_CLIPBOARD_MINUS "\xf3\xb1\x98\x98" // U+F1618
+#define ICON_MDI_CLIPBOARD_MINUS_OUTLINE "\xf3\xb1\x98\x99" // U+F1619
+#define ICON_MDI_CLIPBOARD_MULTIPLE "\xf3\xb1\x89\xa7" // U+F1267
+#define ICON_MDI_CLIPBOARD_MULTIPLE_OUTLINE "\xf3\xb1\x89\xa8" // U+F1268
+#define ICON_MDI_CLIPBOARD_OFF "\xf3\xb1\x98\x9a" // U+F161A
+#define ICON_MDI_CLIPBOARD_OFF_OUTLINE "\xf3\xb1\x98\x9b" // U+F161B
+#define ICON_MDI_CLIPBOARD_OUTLINE "\xf3\xb0\x85\x8c" // U+F014C
+#define ICON_MDI_CLIPBOARD_PLAY "\xf3\xb0\xb1\x99" // U+F0C59
+#define ICON_MDI_CLIPBOARD_PLAY_MULTIPLE "\xf3\xb1\x89\xa9" // U+F1269
+#define ICON_MDI_CLIPBOARD_PLAY_MULTIPLE_OUTLINE "\xf3\xb1\x89\xaa" // U+F126A
+#define ICON_MDI_CLIPBOARD_PLAY_OUTLINE "\xf3\xb0\xb1\x9a" // U+F0C5A
+#define ICON_MDI_CLIPBOARD_PLUS "\xf3\xb0\x9d\x91" // U+F0751
+#define ICON_MDI_CLIPBOARD_PLUS_OUTLINE "\xf3\xb1\x8c\x9f" // U+F131F
+#define ICON_MDI_CLIPBOARD_PULSE "\xf3\xb0\xa1\x9d" // U+F085D
+#define ICON_MDI_CLIPBOARD_PULSE_OUTLINE "\xf3\xb0\xa1\x9e" // U+F085E
+#define ICON_MDI_CLIPBOARD_REMOVE "\xf3\xb1\x98\x9c" // U+F161C
+#define ICON_MDI_CLIPBOARD_REMOVE_OUTLINE "\xf3\xb1\x98\x9d" // U+F161D
+#define ICON_MDI_CLIPBOARD_SEARCH "\xf3\xb1\x98\x9e" // U+F161E
+#define ICON_MDI_CLIPBOARD_SEARCH_OUTLINE "\xf3\xb1\x98\x9f" // U+F161F
+#define ICON_MDI_CLIPBOARD_TEXT "\xf3\xb0\x85\x8d" // U+F014D
+#define ICON_MDI_CLIPBOARD_TEXT_CLOCK "\xf3\xb1\xa3\xb9" // U+F18F9
+#define ICON_MDI_CLIPBOARD_TEXT_CLOCK_OUTLINE "\xf3\xb1\xa3\xba" // U+F18FA
+#define ICON_MDI_CLIPBOARD_TEXT_MULTIPLE "\xf3\xb1\x89\xab" // U+F126B
+#define ICON_MDI_CLIPBOARD_TEXT_MULTIPLE_OUTLINE "\xf3\xb1\x89\xac" // U+F126C
+#define ICON_MDI_CLIPBOARD_TEXT_OFF "\xf3\xb1\x98\xa0" // U+F1620
+#define ICON_MDI_CLIPBOARD_TEXT_OFF_OUTLINE "\xf3\xb1\x98\xa1" // U+F1621
+#define ICON_MDI_CLIPBOARD_TEXT_OUTLINE "\xf3\xb0\xa8\xb8" // U+F0A38
+#define ICON_MDI_CLIPBOARD_TEXT_PLAY "\xf3\xb0\xb1\x9b" // U+F0C5B
+#define ICON_MDI_CLIPBOARD_TEXT_PLAY_OUTLINE "\xf3\xb0\xb1\x9c" // U+F0C5C
+#define ICON_MDI_CLIPBOARD_TEXT_SEARCH "\xf3\xb1\x98\xa2" // U+F1622
+#define ICON_MDI_CLIPBOARD_TEXT_SEARCH_OUTLINE "\xf3\xb1\x98\xa3" // U+F1623
+#define ICON_MDI_CLIPPY "\xf3\xb0\x85\x8f" // U+F014F
+#define ICON_MDI_CLOCK "\xf3\xb0\xa5\x94" // U+F0954
+#define ICON_MDI_CLOCK_ALERT "\xf3\xb0\xa5\x95" // U+F0955
+#define ICON_MDI_CLOCK_ALERT_OUTLINE "\xf3\xb0\x97\x8e" // U+F05CE
+#define ICON_MDI_CLOCK_CHECK "\xf3\xb0\xbe\xa8" // U+F0FA8
+#define ICON_MDI_CLOCK_CHECK_OUTLINE "\xf3\xb0\xbe\xa9" // U+F0FA9
+#define ICON_MDI_CLOCK_DIGITAL "\xf3\xb0\xba\x97" // U+F0E97
+#define ICON_MDI_CLOCK_EDIT "\xf3\xb1\xa6\xba" // U+F19BA
+#define ICON_MDI_CLOCK_EDIT_OUTLINE "\xf3\xb1\xa6\xbb" // U+F19BB
+#define ICON_MDI_CLOCK_END "\xf3\xb0\x85\x91" // U+F0151
+#define ICON_MDI_CLOCK_FAST "\xf3\xb0\x85\x92" // U+F0152
+#define ICON_MDI_CLOCK_IN "\xf3\xb0\x85\x93" // U+F0153
+#define ICON_MDI_CLOCK_MINUS "\xf3\xb1\xa1\xa3" // U+F1863
+#define ICON_MDI_CLOCK_MINUS_OUTLINE "\xf3\xb1\xa1\xa4" // U+F1864
+#define ICON_MDI_CLOCK_OUT "\xf3\xb0\x85\x94" // U+F0154
+#define ICON_MDI_CLOCK_OUTLINE "\xf3\xb0\x85\x90" // U+F0150
+#define ICON_MDI_CLOCK_PLUS "\xf3\xb1\xa1\xa1" // U+F1861
+#define ICON_MDI_CLOCK_PLUS_OUTLINE "\xf3\xb1\xa1\xa2" // U+F1862
+#define ICON_MDI_CLOCK_REMOVE "\xf3\xb1\xa1\xa5" // U+F1865
+#define ICON_MDI_CLOCK_REMOVE_OUTLINE "\xf3\xb1\xa1\xa6" // U+F1866
+#define ICON_MDI_CLOCK_STAR_FOUR_POINTS "\xf3\xb1\xb0\xa9" // U+F1C29
+#define ICON_MDI_CLOCK_STAR_FOUR_POINTS_OUTLINE "\xf3\xb1\xb0\xaa" // U+F1C2A
+#define ICON_MDI_CLOCK_START "\xf3\xb0\x85\x95" // U+F0155
+#define ICON_MDI_CLOCK_TIME_EIGHT "\xf3\xb1\x91\x86" // U+F1446
+#define ICON_MDI_CLOCK_TIME_EIGHT_OUTLINE "\xf3\xb1\x91\x92" // U+F1452
+#define ICON_MDI_CLOCK_TIME_ELEVEN "\xf3\xb1\x91\x89" // U+F1449
+#define ICON_MDI_CLOCK_TIME_ELEVEN_OUTLINE "\xf3\xb1\x91\x95" // U+F1455
+#define ICON_MDI_CLOCK_TIME_FIVE "\xf3\xb1\x91\x83" // U+F1443
+#define ICON_MDI_CLOCK_TIME_FIVE_OUTLINE "\xf3\xb1\x91\x8f" // U+F144F
+#define ICON_MDI_CLOCK_TIME_FOUR "\xf3\xb1\x91\x82" // U+F1442
+#define ICON_MDI_CLOCK_TIME_FOUR_OUTLINE "\xf3\xb1\x91\x8e" // U+F144E
+#define ICON_MDI_CLOCK_TIME_NINE "\xf3\xb1\x91\x87" // U+F1447
+#define ICON_MDI_CLOCK_TIME_NINE_OUTLINE "\xf3\xb1\x91\x93" // U+F1453
+#define ICON_MDI_CLOCK_TIME_ONE "\xf3\xb1\x90\xbf" // U+F143F
+#define ICON_MDI_CLOCK_TIME_ONE_OUTLINE "\xf3\xb1\x91\x8b" // U+F144B
+#define ICON_MDI_CLOCK_TIME_SEVEN "\xf3\xb1\x91\x85" // U+F1445
+#define ICON_MDI_CLOCK_TIME_SEVEN_OUTLINE "\xf3\xb1\x91\x91" // U+F1451
+#define ICON_MDI_CLOCK_TIME_SIX "\xf3\xb1\x91\x84" // U+F1444
+#define ICON_MDI_CLOCK_TIME_SIX_OUTLINE "\xf3\xb1\x91\x90" // U+F1450
+#define ICON_MDI_CLOCK_TIME_TEN "\xf3\xb1\x91\x88" // U+F1448
+#define ICON_MDI_CLOCK_TIME_TEN_OUTLINE "\xf3\xb1\x91\x94" // U+F1454
+#define ICON_MDI_CLOCK_TIME_THREE "\xf3\xb1\x91\x81" // U+F1441
+#define ICON_MDI_CLOCK_TIME_THREE_OUTLINE "\xf3\xb1\x91\x8d" // U+F144D
+#define ICON_MDI_CLOCK_TIME_TWELVE "\xf3\xb1\x91\x8a" // U+F144A
+#define ICON_MDI_CLOCK_TIME_TWELVE_OUTLINE "\xf3\xb1\x91\x96" // U+F1456
+#define ICON_MDI_CLOCK_TIME_TWO "\xf3\xb1\x91\x80" // U+F1440
+#define ICON_MDI_CLOCK_TIME_TWO_OUTLINE "\xf3\xb1\x91\x8c" // U+F144C
+#define ICON_MDI_CLOSE "\xf3\xb0\x85\x96" // U+F0156
+#define ICON_MDI_CLOSE_BOX "\xf3\xb0\x85\x97" // U+F0157
+#define ICON_MDI_CLOSE_BOX_MULTIPLE "\xf3\xb0\xb1\x9d" // U+F0C5D
+#define ICON_MDI_CLOSE_BOX_MULTIPLE_OUTLINE "\xf3\xb0\xb1\x9e" // U+F0C5E
+#define ICON_MDI_CLOSE_BOX_OUTLINE "\xf3\xb0\x85\x98" // U+F0158
+#define ICON_MDI_CLOSE_CIRCLE "\xf3\xb0\x85\x99" // U+F0159
+#define ICON_MDI_CLOSE_CIRCLE_MULTIPLE "\xf3\xb0\x98\xaa" // U+F062A
+#define ICON_MDI_CLOSE_CIRCLE_MULTIPLE_OUTLINE "\xf3\xb0\xa2\x83" // U+F0883
+#define ICON_MDI_CLOSE_CIRCLE_OUTLINE "\xf3\xb0\x85\x9a" // U+F015A
+#define ICON_MDI_CLOSE_NETWORK "\xf3\xb0\x85\x9b" // U+F015B
+#define ICON_MDI_CLOSE_NETWORK_OUTLINE "\xf3\xb0\xb1\x9f" // U+F0C5F
+#define ICON_MDI_CLOSE_OCTAGON "\xf3\xb0\x85\x9c" // U+F015C
+#define ICON_MDI_CLOSE_OCTAGON_OUTLINE "\xf3\xb0\x85\x9d" // U+F015D
+#define ICON_MDI_CLOSE_OUTLINE "\xf3\xb0\x9b\x89" // U+F06C9
+#define ICON_MDI_CLOSE_THICK "\xf3\xb1\x8e\x98" // U+F1398
+#define ICON_MDI_CLOSED_CAPTION "\xf3\xb0\x85\x9e" // U+F015E
+#define ICON_MDI_CLOSED_CAPTION_OUTLINE "\xf3\xb0\xb6\xbd" // U+F0DBD
+#define ICON_MDI_CLOUD "\xf3\xb0\x85\x9f" // U+F015F
+#define ICON_MDI_CLOUD_ALERT "\xf3\xb0\xa7\xa0" // U+F09E0
+#define ICON_MDI_CLOUD_ALERT_OUTLINE "\xf3\xb1\xaf\xa0" // U+F1BE0
+#define ICON_MDI_CLOUD_ARROW_DOWN "\xf3\xb1\xaf\xa1" // U+F1BE1
+#define ICON_MDI_CLOUD_ARROW_DOWN_OUTLINE "\xf3\xb1\xaf\xa2" // U+F1BE2
+#define ICON_MDI_CLOUD_ARROW_LEFT "\xf3\xb1\xaf\xa3" // U+F1BE3
+#define ICON_MDI_CLOUD_ARROW_LEFT_OUTLINE "\xf3\xb1\xaf\xa4" // U+F1BE4
+#define ICON_MDI_CLOUD_ARROW_RIGHT "\xf3\xb1\xaf\xa5" // U+F1BE5
+#define ICON_MDI_CLOUD_ARROW_RIGHT_OUTLINE "\xf3\xb1\xaf\xa6" // U+F1BE6
+#define ICON_MDI_CLOUD_ARROW_UP "\xf3\xb1\xaf\xa7" // U+F1BE7
+#define ICON_MDI_CLOUD_ARROW_UP_OUTLINE "\xf3\xb1\xaf\xa8" // U+F1BE8
+#define ICON_MDI_CLOUD_BRACES "\xf3\xb0\x9e\xb5" // U+F07B5
+#define ICON_MDI_CLOUD_CANCEL "\xf3\xb1\xaf\xa9" // U+F1BE9
+#define ICON_MDI_CLOUD_CANCEL_OUTLINE "\xf3\xb1\xaf\xaa" // U+F1BEA
+#define ICON_MDI_CLOUD_CHECK "\xf3\xb1\xaf\xab" // U+F1BEB
+#define ICON_MDI_CLOUD_CHECK_OUTLINE "\xf3\xb1\xaf\xac" // U+F1BEC
+#define ICON_MDI_CLOUD_CHECK_VARIANT "\xf3\xb0\x85\xa0" // U+F0160
+#define ICON_MDI_CLOUD_CHECK_VARIANT_OUTLINE "\xf3\xb1\x8b\x8c" // U+F12CC
+#define ICON_MDI_CLOUD_CIRCLE "\xf3\xb0\x85\xa1" // U+F0161
+#define ICON_MDI_CLOUD_CIRCLE_OUTLINE "\xf3\xb1\xaf\xad" // U+F1BED
+#define ICON_MDI_CLOUD_CLOCK "\xf3\xb1\xaf\xae" // U+F1BEE
+#define ICON_MDI_CLOUD_CLOCK_OUTLINE "\xf3\xb1\xaf\xaf" // U+F1BEF
+#define ICON_MDI_CLOUD_COG "\xf3\xb1\xaf\xb0" // U+F1BF0
+#define ICON_MDI_CLOUD_COG_OUTLINE "\xf3\xb1\xaf\xb1" // U+F1BF1
+#define ICON_MDI_CLOUD_DOWNLOAD "\xf3\xb0\x85\xa2" // U+F0162
+#define ICON_MDI_CLOUD_DOWNLOAD_OUTLINE "\xf3\xb0\xad\xbd" // U+F0B7D
+#define ICON_MDI_CLOUD_KEY "\xf3\xb1\xb2\xa1" // U+F1CA1
+#define ICON_MDI_CLOUD_KEY_OUTLINE "\xf3\xb1\xb2\xa2" // U+F1CA2
+#define ICON_MDI_CLOUD_LOCK "\xf3\xb1\x87\xb1" // U+F11F1
+#define ICON_MDI_CLOUD_LOCK_OPEN "\xf3\xb1\xaf\xb2" // U+F1BF2
+#define ICON_MDI_CLOUD_LOCK_OPEN_OUTLINE "\xf3\xb1\xaf\xb3" // U+F1BF3
+#define ICON_MDI_CLOUD_LOCK_OUTLINE "\xf3\xb1\x87\xb2" // U+F11F2
+#define ICON_MDI_CLOUD_MINUS "\xf3\xb1\xaf\xb4" // U+F1BF4
+#define ICON_MDI_CLOUD_MINUS_OUTLINE "\xf3\xb1\xaf\xb5" // U+F1BF5
+#define ICON_MDI_CLOUD_OFF "\xf3\xb1\xaf\xb6" // U+F1BF6
+#define ICON_MDI_CLOUD_OFF_OUTLINE "\xf3\xb0\x85\xa4" // U+F0164
+#define ICON_MDI_CLOUD_OUTLINE "\xf3\xb0\x85\xa3" // U+F0163
+#define ICON_MDI_CLOUD_PERCENT "\xf3\xb1\xa8\xb5" // U+F1A35
+#define ICON_MDI_CLOUD_PERCENT_OUTLINE "\xf3\xb1\xa8\xb6" // U+F1A36
+#define ICON_MDI_CLOUD_PLUS "\xf3\xb1\xaf\xb7" // U+F1BF7
+#define ICON_MDI_CLOUD_PLUS_OUTLINE "\xf3\xb1\xaf\xb8" // U+F1BF8
+#define ICON_MDI_CLOUD_PRINT "\xf3\xb0\x85\xa5" // U+F0165
+#define ICON_MDI_CLOUD_PRINT_OUTLINE "\xf3\xb0\x85\xa6" // U+F0166
+#define ICON_MDI_CLOUD_QUESTION "\xf3\xb0\xa8\xb9" // U+F0A39
+#define ICON_MDI_CLOUD_QUESTION_OUTLINE "\xf3\xb1\xaf\xb9" // U+F1BF9
+#define ICON_MDI_CLOUD_REFRESH "\xf3\xb1\xaf\xba" // U+F1BFA
+#define ICON_MDI_CLOUD_REFRESH_OUTLINE "\xf3\xb1\xaf\xbb" // U+F1BFB
+#define ICON_MDI_CLOUD_REFRESH_VARIANT "\xf3\xb0\x94\xaa" // U+F052A
+#define ICON_MDI_CLOUD_REFRESH_VARIANT_OUTLINE "\xf3\xb1\xaf\xbc" // U+F1BFC
+#define ICON_MDI_CLOUD_REMOVE "\xf3\xb1\xaf\xbd" // U+F1BFD
+#define ICON_MDI_CLOUD_REMOVE_OUTLINE "\xf3\xb1\xaf\xbe" // U+F1BFE
+#define ICON_MDI_CLOUD_SEARCH "\xf3\xb0\xa5\x96" // U+F0956
+#define ICON_MDI_CLOUD_SEARCH_OUTLINE "\xf3\xb0\xa5\x97" // U+F0957
+#define ICON_MDI_CLOUD_SYNC "\xf3\xb0\x98\xbf" // U+F063F
+#define ICON_MDI_CLOUD_SYNC_OUTLINE "\xf3\xb1\x8b\x96" // U+F12D6
+#define ICON_MDI_CLOUD_TAGS "\xf3\xb0\x9e\xb6" // U+F07B6
+#define ICON_MDI_CLOUD_UPLOAD "\xf3\xb0\x85\xa7" // U+F0167
+#define ICON_MDI_CLOUD_UPLOAD_OUTLINE "\xf3\xb0\xad\xbe" // U+F0B7E
+#define ICON_MDI_CLOUDS "\xf3\xb1\xae\x95" // U+F1B95
+#define ICON_MDI_CLOVER "\xf3\xb0\xa0\x96" // U+F0816
+#define ICON_MDI_CLOVER_OUTLINE "\xf3\xb1\xb1\xa2" // U+F1C62
+#define ICON_MDI_COACH_LAMP "\xf3\xb1\x80\xa0" // U+F1020
+#define ICON_MDI_COACH_LAMP_VARIANT "\xf3\xb1\xa8\xb7" // U+F1A37
+#define ICON_MDI_COAT_RACK "\xf3\xb1\x82\x9e" // U+F109E
+#define ICON_MDI_CODE_ARRAY "\xf3\xb0\x85\xa8" // U+F0168
+#define ICON_MDI_CODE_BLOCK_BRACES "\xf3\xb1\xb2\x83" // U+F1C83
+#define ICON_MDI_CODE_BLOCK_BRACKETS "\xf3\xb1\xb2\x84" // U+F1C84
+#define ICON_MDI_CODE_BLOCK_PARENTHESES "\xf3\xb1\xb2\x85" // U+F1C85
+#define ICON_MDI_CODE_BLOCK_TAGS "\xf3\xb1\xb2\x86" // U+F1C86
+#define ICON_MDI_CODE_BRACES "\xf3\xb0\x85\xa9" // U+F0169
+#define ICON_MDI_CODE_BRACES_BOX "\xf3\xb1\x83\x96" // U+F10D6
+#define ICON_MDI_CODE_BRACKETS "\xf3\xb0\x85\xaa" // U+F016A
+#define ICON_MDI_CODE_EQUAL "\xf3\xb0\x85\xab" // U+F016B
+#define ICON_MDI_CODE_GREATER_THAN "\xf3\xb0\x85\xac" // U+F016C
+#define ICON_MDI_CODE_GREATER_THAN_OR_EQUAL "\xf3\xb0\x85\xad" // U+F016D
+#define ICON_MDI_CODE_JSON "\xf3\xb0\x98\xa6" // U+F0626
+#define ICON_MDI_CODE_LESS_THAN "\xf3\xb0\x85\xae" // U+F016E
+#define ICON_MDI_CODE_LESS_THAN_OR_EQUAL "\xf3\xb0\x85\xaf" // U+F016F
+#define ICON_MDI_CODE_NOT_EQUAL "\xf3\xb0\x85\xb0" // U+F0170
+#define ICON_MDI_CODE_NOT_EQUAL_VARIANT "\xf3\xb0\x85\xb1" // U+F0171
+#define ICON_MDI_CODE_PARENTHESES "\xf3\xb0\x85\xb2" // U+F0172
+#define ICON_MDI_CODE_PARENTHESES_BOX "\xf3\xb1\x83\x97" // U+F10D7
+#define ICON_MDI_CODE_STRING "\xf3\xb0\x85\xb3" // U+F0173
+#define ICON_MDI_CODE_TAGS "\xf3\xb0\x85\xb4" // U+F0174
+#define ICON_MDI_CODE_TAGS_CHECK "\xf3\xb0\x9a\x94" // U+F0694
+#define ICON_MDI_CODEPEN "\xf3\xb0\x85\xb5" // U+F0175
+#define ICON_MDI_COFFEE "\xf3\xb0\x85\xb6" // U+F0176
+#define ICON_MDI_COFFEE_MAKER "\xf3\xb1\x82\x9f" // U+F109F
+#define ICON_MDI_COFFEE_MAKER_CHECK "\xf3\xb1\xa4\xb1" // U+F1931
+#define ICON_MDI_COFFEE_MAKER_CHECK_OUTLINE "\xf3\xb1\xa4\xb2" // U+F1932
+#define ICON_MDI_COFFEE_MAKER_OUTLINE "\xf3\xb1\xa0\x9b" // U+F181B
+#define ICON_MDI_COFFEE_OFF "\xf3\xb0\xbe\xaa" // U+F0FAA
+#define ICON_MDI_COFFEE_OFF_OUTLINE "\xf3\xb0\xbe\xab" // U+F0FAB
+#define ICON_MDI_COFFEE_OUTLINE "\xf3\xb0\x9b\x8a" // U+F06CA
+#define ICON_MDI_COFFEE_TO_GO "\xf3\xb0\x85\xb7" // U+F0177
+#define ICON_MDI_COFFEE_TO_GO_OUTLINE "\xf3\xb1\x8c\x8e" // U+F130E
+#define ICON_MDI_COFFIN "\xf3\xb0\xad\xbf" // U+F0B7F
+#define ICON_MDI_COG "\xf3\xb0\x92\x93" // U+F0493
+#define ICON_MDI_COG_BOX "\xf3\xb0\x92\x94" // U+F0494
+#define ICON_MDI_COG_CLOCKWISE "\xf3\xb1\x87\x9d" // U+F11DD
+#define ICON_MDI_COG_COUNTERCLOCKWISE "\xf3\xb1\x87\x9e" // U+F11DE
+#define ICON_MDI_COG_OFF "\xf3\xb1\x8f\x8e" // U+F13CE
+#define ICON_MDI_COG_OFF_OUTLINE "\xf3\xb1\x8f\x8f" // U+F13CF
+#define ICON_MDI_COG_OUTLINE "\xf3\xb0\xa2\xbb" // U+F08BB
+#define ICON_MDI_COG_PAUSE "\xf3\xb1\xa4\xb3" // U+F1933
+#define ICON_MDI_COG_PAUSE_OUTLINE "\xf3\xb1\xa4\xb4" // U+F1934
+#define ICON_MDI_COG_PLAY "\xf3\xb1\xa4\xb5" // U+F1935
+#define ICON_MDI_COG_PLAY_OUTLINE "\xf3\xb1\xa4\xb6" // U+F1936
+#define ICON_MDI_COG_REFRESH "\xf3\xb1\x91\x9e" // U+F145E
+#define ICON_MDI_COG_REFRESH_OUTLINE "\xf3\xb1\x91\x9f" // U+F145F
+#define ICON_MDI_COG_STOP "\xf3\xb1\xa4\xb7" // U+F1937
+#define ICON_MDI_COG_STOP_OUTLINE "\xf3\xb1\xa4\xb8" // U+F1938
+#define ICON_MDI_COG_SYNC "\xf3\xb1\x91\xa0" // U+F1460
+#define ICON_MDI_COG_SYNC_OUTLINE "\xf3\xb1\x91\xa1" // U+F1461
+#define ICON_MDI_COG_TRANSFER "\xf3\xb1\x81\x9b" // U+F105B
+#define ICON_MDI_COG_TRANSFER_OUTLINE "\xf3\xb1\x81\x9c" // U+F105C
+#define ICON_MDI_COGS "\xf3\xb0\xa3\x96" // U+F08D6
+#define ICON_MDI_COLLAGE "\xf3\xb0\x99\x80" // U+F0640
+#define ICON_MDI_COLLAPSE_ALL "\xf3\xb0\xaa\xa6" // U+F0AA6
+#define ICON_MDI_COLLAPSE_ALL_OUTLINE "\xf3\xb0\xaa\xa7" // U+F0AA7
+#define ICON_MDI_COLOR_HELPER "\xf3\xb0\x85\xb9" // U+F0179
+#define ICON_MDI_COMMA "\xf3\xb0\xb8\xa3" // U+F0E23
+#define ICON_MDI_COMMA_BOX "\xf3\xb0\xb8\xab" // U+F0E2B
+#define ICON_MDI_COMMA_BOX_OUTLINE "\xf3\xb0\xb8\xa4" // U+F0E24
+#define ICON_MDI_COMMA_CIRCLE "\xf3\xb0\xb8\xa5" // U+F0E25
+#define ICON_MDI_COMMA_CIRCLE_OUTLINE "\xf3\xb0\xb8\xa6" // U+F0E26
+#define ICON_MDI_COMMENT "\xf3\xb0\x85\xba" // U+F017A
+#define ICON_MDI_COMMENT_ACCOUNT "\xf3\xb0\x85\xbb" // U+F017B
+#define ICON_MDI_COMMENT_ACCOUNT_OUTLINE "\xf3\xb0\x85\xbc" // U+F017C
+#define ICON_MDI_COMMENT_ALERT "\xf3\xb0\x85\xbd" // U+F017D
+#define ICON_MDI_COMMENT_ALERT_OUTLINE "\xf3\xb0\x85\xbe" // U+F017E
+#define ICON_MDI_COMMENT_ARROW_LEFT "\xf3\xb0\xa7\xa1" // U+F09E1
+#define ICON_MDI_COMMENT_ARROW_LEFT_OUTLINE "\xf3\xb0\xa7\xa2" // U+F09E2
+#define ICON_MDI_COMMENT_ARROW_RIGHT "\xf3\xb0\xa7\xa3" // U+F09E3
+#define ICON_MDI_COMMENT_ARROW_RIGHT_OUTLINE "\xf3\xb0\xa7\xa4" // U+F09E4
+#define ICON_MDI_COMMENT_BOOKMARK "\xf3\xb1\x96\xae" // U+F15AE
+#define ICON_MDI_COMMENT_BOOKMARK_OUTLINE "\xf3\xb1\x96\xaf" // U+F15AF
+#define ICON_MDI_COMMENT_CHECK "\xf3\xb0\x85\xbf" // U+F017F
+#define ICON_MDI_COMMENT_CHECK_OUTLINE "\xf3\xb0\x86\x80" // U+F0180
+#define ICON_MDI_COMMENT_EDIT "\xf3\xb1\x86\xbf" // U+F11BF
+#define ICON_MDI_COMMENT_EDIT_OUTLINE "\xf3\xb1\x8b\x84" // U+F12C4
+#define ICON_MDI_COMMENT_EYE "\xf3\xb0\xa8\xba" // U+F0A3A
+#define ICON_MDI_COMMENT_EYE_OUTLINE "\xf3\xb0\xa8\xbb" // U+F0A3B
+#define ICON_MDI_COMMENT_FLASH "\xf3\xb1\x96\xb0" // U+F15B0
+#define ICON_MDI_COMMENT_FLASH_OUTLINE "\xf3\xb1\x96\xb1" // U+F15B1
+#define ICON_MDI_COMMENT_MINUS "\xf3\xb1\x97\x9f" // U+F15DF
+#define ICON_MDI_COMMENT_MINUS_OUTLINE "\xf3\xb1\x97\xa0" // U+F15E0
+#define ICON_MDI_COMMENT_MULTIPLE "\xf3\xb0\xa1\x9f" // U+F085F
+#define ICON_MDI_COMMENT_MULTIPLE_OUTLINE "\xf3\xb0\x86\x81" // U+F0181
+#define ICON_MDI_COMMENT_OFF "\xf3\xb1\x97\xa1" // U+F15E1
+#define ICON_MDI_COMMENT_OFF_OUTLINE "\xf3\xb1\x97\xa2" // U+F15E2
+#define ICON_MDI_COMMENT_OUTLINE "\xf3\xb0\x86\x82" // U+F0182
+#define ICON_MDI_COMMENT_PLUS "\xf3\xb0\xa7\xa5" // U+F09E5
+#define ICON_MDI_COMMENT_PLUS_OUTLINE "\xf3\xb0\x86\x83" // U+F0183
+#define ICON_MDI_COMMENT_PROCESSING "\xf3\xb0\x86\x84" // U+F0184
+#define ICON_MDI_COMMENT_PROCESSING_OUTLINE "\xf3\xb0\x86\x85" // U+F0185
+#define ICON_MDI_COMMENT_QUESTION "\xf3\xb0\xa0\x97" // U+F0817
+#define ICON_MDI_COMMENT_QUESTION_OUTLINE "\xf3\xb0\x86\x86" // U+F0186
+#define ICON_MDI_COMMENT_QUOTE "\xf3\xb1\x80\xa1" // U+F1021
+#define ICON_MDI_COMMENT_QUOTE_OUTLINE "\xf3\xb1\x80\xa2" // U+F1022
+#define ICON_MDI_COMMENT_REMOVE "\xf3\xb0\x97\x9e" // U+F05DE
+#define ICON_MDI_COMMENT_REMOVE_OUTLINE "\xf3\xb0\x86\x87" // U+F0187
+#define ICON_MDI_COMMENT_SEARCH "\xf3\xb0\xa8\xbc" // U+F0A3C
+#define ICON_MDI_COMMENT_SEARCH_OUTLINE "\xf3\xb0\xa8\xbd" // U+F0A3D
+#define ICON_MDI_COMMENT_TEXT "\xf3\xb0\x86\x88" // U+F0188
+#define ICON_MDI_COMMENT_TEXT_MULTIPLE "\xf3\xb0\xa1\xa0" // U+F0860
+#define ICON_MDI_COMMENT_TEXT_MULTIPLE_OUTLINE "\xf3\xb0\xa1\xa1" // U+F0861
+#define ICON_MDI_COMMENT_TEXT_OUTLINE "\xf3\xb0\x86\x89" // U+F0189
+#define ICON_MDI_COMPARE "\xf3\xb0\x86\x8a" // U+F018A
+#define ICON_MDI_COMPARE_HORIZONTAL "\xf3\xb1\x92\x92" // U+F1492
+#define ICON_MDI_COMPARE_REMOVE "\xf3\xb1\xa2\xb3" // U+F18B3
+#define ICON_MDI_COMPARE_VERTICAL "\xf3\xb1\x92\x93" // U+F1493
+#define ICON_MDI_COMPASS "\xf3\xb0\x86\x8b" // U+F018B
+#define ICON_MDI_COMPASS_OFF "\xf3\xb0\xae\x80" // U+F0B80
+#define ICON_MDI_COMPASS_OFF_OUTLINE "\xf3\xb0\xae\x81" // U+F0B81
+#define ICON_MDI_COMPASS_OUTLINE "\xf3\xb0\x86\x8c" // U+F018C
+#define ICON_MDI_COMPASS_ROSE "\xf3\xb1\x8e\x82" // U+F1382
+#define ICON_MDI_COMPOST "\xf3\xb1\xa8\xb8" // U+F1A38
+#define ICON_MDI_CONE "\xf3\xb1\xa5\x8c" // U+F194C
+#define ICON_MDI_CONE_OFF "\xf3\xb1\xa5\x8d" // U+F194D
+#define ICON_MDI_CONNECTION "\xf3\xb1\x98\x96" // U+F1616
+#define ICON_MDI_CONSOLE "\xf3\xb0\x86\x8d" // U+F018D
+#define ICON_MDI_CONSOLE_LINE "\xf3\xb0\x9e\xb7" // U+F07B7
+#define ICON_MDI_CONSOLE_NETWORK "\xf3\xb0\xa2\xa9" // U+F08A9
+#define ICON_MDI_CONSOLE_NETWORK_OUTLINE "\xf3\xb0\xb1\xa0" // U+F0C60
+#define ICON_MDI_CONSOLIDATE "\xf3\xb1\x83\x98" // U+F10D8
+#define ICON_MDI_CONTACTLESS_PAYMENT "\xf3\xb0\xb5\xaa" // U+F0D6A
+#define ICON_MDI_CONTACTLESS_PAYMENT_CIRCLE "\xf3\xb0\x8c\xa1" // U+F0321
+#define ICON_MDI_CONTACTLESS_PAYMENT_CIRCLE_OUTLINE "\xf3\xb0\x90\x88" // U+F0408
+#define ICON_MDI_CONTACTS "\xf3\xb0\x9b\x8b" // U+F06CB
+#define ICON_MDI_CONTACTS_OUTLINE "\xf3\xb0\x96\xb8" // U+F05B8
+#define ICON_MDI_CONTAIN "\xf3\xb0\xa8\xbe" // U+F0A3E
+#define ICON_MDI_CONTAIN_END "\xf3\xb0\xa8\xbf" // U+F0A3F
+#define ICON_MDI_CONTAIN_START "\xf3\xb0\xa9\x80" // U+F0A40
+#define ICON_MDI_CONTENT_COPY "\xf3\xb0\x86\x8f" // U+F018F
+#define ICON_MDI_CONTENT_CUT "\xf3\xb0\x86\x90" // U+F0190
+#define ICON_MDI_CONTENT_DUPLICATE "\xf3\xb0\x86\x91" // U+F0191
+#define ICON_MDI_CONTENT_PASTE "\xf3\xb0\x86\x92" // U+F0192
+#define ICON_MDI_CONTENT_SAVE "\xf3\xb0\x86\x93" // U+F0193
+#define ICON_MDI_CONTENT_SAVE_ALERT "\xf3\xb0\xbd\x82" // U+F0F42
+#define ICON_MDI_CONTENT_SAVE_ALERT_OUTLINE "\xf3\xb0\xbd\x83" // U+F0F43
+#define ICON_MDI_CONTENT_SAVE_ALL "\xf3\xb0\x86\x94" // U+F0194
+#define ICON_MDI_CONTENT_SAVE_ALL_OUTLINE "\xf3\xb0\xbd\x84" // U+F0F44
+#define ICON_MDI_CONTENT_SAVE_CHECK "\xf3\xb1\xa3\xaa" // U+F18EA
+#define ICON_MDI_CONTENT_SAVE_CHECK_OUTLINE "\xf3\xb1\xa3\xab" // U+F18EB
+#define ICON_MDI_CONTENT_SAVE_COG "\xf3\xb1\x91\x9b" // U+F145B
+#define ICON_MDI_CONTENT_SAVE_COG_OUTLINE "\xf3\xb1\x91\x9c" // U+F145C
+#define ICON_MDI_CONTENT_SAVE_EDIT "\xf3\xb0\xb3\xbb" // U+F0CFB
+#define ICON_MDI_CONTENT_SAVE_EDIT_OUTLINE "\xf3\xb0\xb3\xbc" // U+F0CFC
+#define ICON_MDI_CONTENT_SAVE_MINUS "\xf3\xb1\xad\x83" // U+F1B43
+#define ICON_MDI_CONTENT_SAVE_MINUS_OUTLINE "\xf3\xb1\xad\x84" // U+F1B44
+#define ICON_MDI_CONTENT_SAVE_MOVE "\xf3\xb0\xb8\xa7" // U+F0E27
+#define ICON_MDI_CONTENT_SAVE_MOVE_OUTLINE "\xf3\xb0\xb8\xa8" // U+F0E28
+#define ICON_MDI_CONTENT_SAVE_OFF "\xf3\xb1\x99\x83" // U+F1643
+#define ICON_MDI_CONTENT_SAVE_OFF_OUTLINE "\xf3\xb1\x99\x84" // U+F1644
+#define ICON_MDI_CONTENT_SAVE_OUTLINE "\xf3\xb0\xa0\x98" // U+F0818
+#define ICON_MDI_CONTENT_SAVE_PLUS "\xf3\xb1\xad\x81" // U+F1B41
+#define ICON_MDI_CONTENT_SAVE_PLUS_OUTLINE "\xf3\xb1\xad\x82" // U+F1B42
+#define ICON_MDI_CONTENT_SAVE_SETTINGS "\xf3\xb0\x98\x9b" // U+F061B
+#define ICON_MDI_CONTENT_SAVE_SETTINGS_OUTLINE "\xf3\xb0\xac\xae" // U+F0B2E
+#define ICON_MDI_CONTRAST "\xf3\xb0\x86\x95" // U+F0195
+#define ICON_MDI_CONTRAST_BOX "\xf3\xb0\x86\x96" // U+F0196
+#define ICON_MDI_CONTRAST_CIRCLE "\xf3\xb0\x86\x97" // U+F0197
+#define ICON_MDI_CONTROLLER "\xf3\xb0\x8a\xb4" // U+F02B4
+#define ICON_MDI_CONTROLLER_CLASSIC "\xf3\xb0\xae\x82" // U+F0B82
+#define ICON_MDI_CONTROLLER_CLASSIC_OUTLINE "\xf3\xb0\xae\x83" // U+F0B83
+#define ICON_MDI_CONTROLLER_OFF "\xf3\xb0\x8a\xb5" // U+F02B5
+#define ICON_MDI_COOKIE "\xf3\xb0\x86\x98" // U+F0198
+#define ICON_MDI_COOKIE_ALERT "\xf3\xb1\x9b\x90" // U+F16D0
+#define ICON_MDI_COOKIE_ALERT_OUTLINE "\xf3\xb1\x9b\x91" // U+F16D1
+#define ICON_MDI_COOKIE_CHECK "\xf3\xb1\x9b\x92" // U+F16D2
+#define ICON_MDI_COOKIE_CHECK_OUTLINE "\xf3\xb1\x9b\x93" // U+F16D3
+#define ICON_MDI_COOKIE_CLOCK "\xf3\xb1\x9b\xa4" // U+F16E4
+#define ICON_MDI_COOKIE_CLOCK_OUTLINE "\xf3\xb1\x9b\xa5" // U+F16E5
+#define ICON_MDI_COOKIE_COG "\xf3\xb1\x9b\x94" // U+F16D4
+#define ICON_MDI_COOKIE_COG_OUTLINE "\xf3\xb1\x9b\x95" // U+F16D5
+#define ICON_MDI_COOKIE_EDIT "\xf3\xb1\x9b\xa6" // U+F16E6
+#define ICON_MDI_COOKIE_EDIT_OUTLINE "\xf3\xb1\x9b\xa7" // U+F16E7
+#define ICON_MDI_COOKIE_LOCK "\xf3\xb1\x9b\xa8" // U+F16E8
+#define ICON_MDI_COOKIE_LOCK_OUTLINE "\xf3\xb1\x9b\xa9" // U+F16E9
+#define ICON_MDI_COOKIE_MINUS "\xf3\xb1\x9b\x9a" // U+F16DA
+#define ICON_MDI_COOKIE_MINUS_OUTLINE "\xf3\xb1\x9b\x9b" // U+F16DB
+#define ICON_MDI_COOKIE_OFF "\xf3\xb1\x9b\xaa" // U+F16EA
+#define ICON_MDI_COOKIE_OFF_OUTLINE "\xf3\xb1\x9b\xab" // U+F16EB
+#define ICON_MDI_COOKIE_OUTLINE "\xf3\xb1\x9b\x9e" // U+F16DE
+#define ICON_MDI_COOKIE_PLUS "\xf3\xb1\x9b\x96" // U+F16D6
+#define ICON_MDI_COOKIE_PLUS_OUTLINE "\xf3\xb1\x9b\x97" // U+F16D7
+#define ICON_MDI_COOKIE_REFRESH "\xf3\xb1\x9b\xac" // U+F16EC
+#define ICON_MDI_COOKIE_REFRESH_OUTLINE "\xf3\xb1\x9b\xad" // U+F16ED
+#define ICON_MDI_COOKIE_REMOVE "\xf3\xb1\x9b\x98" // U+F16D8
+#define ICON_MDI_COOKIE_REMOVE_OUTLINE "\xf3\xb1\x9b\x99" // U+F16D9
+#define ICON_MDI_COOKIE_SETTINGS "\xf3\xb1\x9b\x9c" // U+F16DC
+#define ICON_MDI_COOKIE_SETTINGS_OUTLINE "\xf3\xb1\x9b\x9d" // U+F16DD
+#define ICON_MDI_COOLANT_TEMPERATURE "\xf3\xb0\x8f\x88" // U+F03C8
+#define ICON_MDI_COPYLEFT "\xf3\xb1\xa4\xb9" // U+F1939
+#define ICON_MDI_COPYRIGHT "\xf3\xb0\x97\xa6" // U+F05E6
+#define ICON_MDI_CORDOVA "\xf3\xb0\xa5\x98" // U+F0958
+#define ICON_MDI_CORN "\xf3\xb0\x9e\xb8" // U+F07B8
+#define ICON_MDI_CORN_OFF "\xf3\xb1\x8f\xaf" // U+F13EF
+#define ICON_MDI_COSINE_WAVE "\xf3\xb1\x91\xb9" // U+F1479
+#define ICON_MDI_COUNTER "\xf3\xb0\x86\x99" // U+F0199
+#define ICON_MDI_COUNTERTOP "\xf3\xb1\xa0\x9c" // U+F181C
+#define ICON_MDI_COUNTERTOP_OUTLINE "\xf3\xb1\xa0\x9d" // U+F181D
+#define ICON_MDI_COW "\xf3\xb0\x86\x9a" // U+F019A
+#define ICON_MDI_COW_OFF "\xf3\xb1\xa3\xbc" // U+F18FC
+#define ICON_MDI_CPU_32_BIT "\xf3\xb0\xbb\x9f" // U+F0EDF
+#define ICON_MDI_CPU_64_BIT "\xf3\xb0\xbb\xa0" // U+F0EE0
+#define ICON_MDI_CRADLE "\xf3\xb1\xa6\x8b" // U+F198B
+#define ICON_MDI_CRADLE_OUTLINE "\xf3\xb1\xa6\x91" // U+F1991
+#define ICON_MDI_CRANE "\xf3\xb0\xa1\xa2" // U+F0862
+#define ICON_MDI_CREATION "\xf3\xb0\x99\xb4" // U+F0674
+#define ICON_MDI_CREATION_OUTLINE "\xf3\xb1\xb0\xab" // U+F1C2B
+#define ICON_MDI_CREATIVE_COMMONS "\xf3\xb0\xb5\xab" // U+F0D6B
+#define ICON_MDI_CREDIT_CARD "\xf3\xb0\xbf\xaf" // U+F0FEF
+#define ICON_MDI_CREDIT_CARD_CHECK "\xf3\xb1\x8f\x90" // U+F13D0
+#define ICON_MDI_CREDIT_CARD_CHECK_OUTLINE "\xf3\xb1\x8f\x91" // U+F13D1
+#define ICON_MDI_CREDIT_CARD_CHIP "\xf3\xb1\xa4\x8f" // U+F190F
+#define ICON_MDI_CREDIT_CARD_CHIP_OUTLINE "\xf3\xb1\xa4\x90" // U+F1910
+#define ICON_MDI_CREDIT_CARD_CLOCK "\xf3\xb0\xbb\xa1" // U+F0EE1
+#define ICON_MDI_CREDIT_CARD_CLOCK_OUTLINE "\xf3\xb0\xbb\xa2" // U+F0EE2
+#define ICON_MDI_CREDIT_CARD_EDIT "\xf3\xb1\x9f\x97" // U+F17D7
+#define ICON_MDI_CREDIT_CARD_EDIT_OUTLINE "\xf3\xb1\x9f\x98" // U+F17D8
+#define ICON_MDI_CREDIT_CARD_FAST "\xf3\xb1\xa4\x91" // U+F1911
+#define ICON_MDI_CREDIT_CARD_FAST_OUTLINE "\xf3\xb1\xa4\x92" // U+F1912
+#define ICON_MDI_CREDIT_CARD_LOCK "\xf3\xb1\xa3\xa7" // U+F18E7
+#define ICON_MDI_CREDIT_CARD_LOCK_OUTLINE "\xf3\xb1\xa3\xa8" // U+F18E8
+#define ICON_MDI_CREDIT_CARD_MARKER "\xf3\xb0\x9a\xa8" // U+F06A8
+#define ICON_MDI_CREDIT_CARD_MARKER_OUTLINE "\xf3\xb0\xb6\xbe" // U+F0DBE
+#define ICON_MDI_CREDIT_CARD_MINUS "\xf3\xb0\xbe\xac" // U+F0FAC
+#define ICON_MDI_CREDIT_CARD_MINUS_OUTLINE "\xf3\xb0\xbe\xad" // U+F0FAD
+#define ICON_MDI_CREDIT_CARD_MULTIPLE "\xf3\xb0\xbf\xb0" // U+F0FF0
+#define ICON_MDI_CREDIT_CARD_MULTIPLE_OUTLINE "\xf3\xb0\x86\x9c" // U+F019C
+#define ICON_MDI_CREDIT_CARD_OFF "\xf3\xb0\xbf\xb1" // U+F0FF1
+#define ICON_MDI_CREDIT_CARD_OFF_OUTLINE "\xf3\xb0\x97\xa4" // U+F05E4
+#define ICON_MDI_CREDIT_CARD_OUTLINE "\xf3\xb0\x86\x9b" // U+F019B
+#define ICON_MDI_CREDIT_CARD_PLUS "\xf3\xb0\xbf\xb2" // U+F0FF2
+#define ICON_MDI_CREDIT_CARD_PLUS_OUTLINE "\xf3\xb0\x99\xb6" // U+F0676
+#define ICON_MDI_CREDIT_CARD_REFRESH "\xf3\xb1\x99\x85" // U+F1645
+#define ICON_MDI_CREDIT_CARD_REFRESH_OUTLINE "\xf3\xb1\x99\x86" // U+F1646
+#define ICON_MDI_CREDIT_CARD_REFUND "\xf3\xb0\xbf\xb3" // U+F0FF3
+#define ICON_MDI_CREDIT_CARD_REFUND_OUTLINE "\xf3\xb0\xaa\xa8" // U+F0AA8
+#define ICON_MDI_CREDIT_CARD_REMOVE "\xf3\xb0\xbe\xae" // U+F0FAE
+#define ICON_MDI_CREDIT_CARD_REMOVE_OUTLINE "\xf3\xb0\xbe\xaf" // U+F0FAF
+#define ICON_MDI_CREDIT_CARD_SCAN "\xf3\xb0\xbf\xb4" // U+F0FF4
+#define ICON_MDI_CREDIT_CARD_SCAN_OUTLINE "\xf3\xb0\x86\x9d" // U+F019D
+#define ICON_MDI_CREDIT_CARD_SEARCH "\xf3\xb1\x99\x87" // U+F1647
+#define ICON_MDI_CREDIT_CARD_SEARCH_OUTLINE "\xf3\xb1\x99\x88" // U+F1648
+#define ICON_MDI_CREDIT_CARD_SETTINGS "\xf3\xb0\xbf\xb5" // U+F0FF5
+#define ICON_MDI_CREDIT_CARD_SETTINGS_OUTLINE "\xf3\xb0\xa3\x97" // U+F08D7
+#define ICON_MDI_CREDIT_CARD_SYNC "\xf3\xb1\x99\x89" // U+F1649
+#define ICON_MDI_CREDIT_CARD_SYNC_OUTLINE "\xf3\xb1\x99\x8a" // U+F164A
+#define ICON_MDI_CREDIT_CARD_WIRELESS "\xf3\xb0\xa0\x82" // U+F0802
+#define ICON_MDI_CREDIT_CARD_WIRELESS_OFF "\xf3\xb0\x95\xba" // U+F057A
+#define ICON_MDI_CREDIT_CARD_WIRELESS_OFF_OUTLINE "\xf3\xb0\x95\xbb" // U+F057B
+#define ICON_MDI_CREDIT_CARD_WIRELESS_OUTLINE "\xf3\xb0\xb5\xac" // U+F0D6C
+#define ICON_MDI_CRICKET "\xf3\xb0\xb5\xad" // U+F0D6D
+#define ICON_MDI_CROP "\xf3\xb0\x86\x9e" // U+F019E
+#define ICON_MDI_CROP_FREE "\xf3\xb0\x86\x9f" // U+F019F
+#define ICON_MDI_CROP_LANDSCAPE "\xf3\xb0\x86\xa0" // U+F01A0
+#define ICON_MDI_CROP_PORTRAIT "\xf3\xb0\x86\xa1" // U+F01A1
+#define ICON_MDI_CROP_ROTATE "\xf3\xb0\x9a\x96" // U+F0696
+#define ICON_MDI_CROP_SQUARE "\xf3\xb0\x86\xa2" // U+F01A2
+#define ICON_MDI_CROSS "\xf3\xb0\xa5\x93" // U+F0953
+#define ICON_MDI_CROSS_BOLNISI "\xf3\xb0\xb3\xad" // U+F0CED
+#define ICON_MDI_CROSS_CELTIC "\xf3\xb0\xb3\xb5" // U+F0CF5
+#define ICON_MDI_CROSS_OUTLINE "\xf3\xb0\xb3\xb6" // U+F0CF6
+#define ICON_MDI_CROSSHAIRS "\xf3\xb0\x86\xa3" // U+F01A3
+#define ICON_MDI_CROSSHAIRS_GPS "\xf3\xb0\x86\xa4" // U+F01A4
+#define ICON_MDI_CROSSHAIRS_OFF "\xf3\xb0\xbd\x85" // U+F0F45
+#define ICON_MDI_CROSSHAIRS_QUESTION "\xf3\xb1\x84\xb6" // U+F1136
+#define ICON_MDI_CROWD "\xf3\xb1\xa5\xb5" // U+F1975
+#define ICON_MDI_CROWN "\xf3\xb0\x86\xa5" // U+F01A5
+#define ICON_MDI_CROWN_CIRCLE "\xf3\xb1\x9f\x9c" // U+F17DC
+#define ICON_MDI_CROWN_CIRCLE_OUTLINE "\xf3\xb1\x9f\x9d" // U+F17DD
+#define ICON_MDI_CROWN_OUTLINE "\xf3\xb1\x87\x90" // U+F11D0
+#define ICON_MDI_CRYENGINE "\xf3\xb0\xa5\x99" // U+F0959
+#define ICON_MDI_CRYSTAL_BALL "\xf3\xb0\xac\xaf" // U+F0B2F
+#define ICON_MDI_CUBE "\xf3\xb0\x86\xa6" // U+F01A6
+#define ICON_MDI_CUBE_OFF "\xf3\xb1\x90\x9c" // U+F141C
+#define ICON_MDI_CUBE_OFF_OUTLINE "\xf3\xb1\x90\x9d" // U+F141D
+#define ICON_MDI_CUBE_OUTLINE "\xf3\xb0\x86\xa7" // U+F01A7
+#define ICON_MDI_CUBE_SCAN "\xf3\xb0\xae\x84" // U+F0B84
+#define ICON_MDI_CUBE_SEND "\xf3\xb0\x86\xa8" // U+F01A8
+#define ICON_MDI_CUBE_UNFOLDED "\xf3\xb0\x86\xa9" // U+F01A9
+#define ICON_MDI_CUP "\xf3\xb0\x86\xaa" // U+F01AA
+#define ICON_MDI_CUP_OFF "\xf3\xb0\x97\xa5" // U+F05E5
+#define ICON_MDI_CUP_OFF_OUTLINE "\xf3\xb1\x8d\xbd" // U+F137D
+#define ICON_MDI_CUP_OUTLINE "\xf3\xb1\x8c\x8f" // U+F130F
+#define ICON_MDI_CUP_WATER "\xf3\xb0\x86\xab" // U+F01AB
+#define ICON_MDI_CUPBOARD "\xf3\xb0\xbd\x86" // U+F0F46
+#define ICON_MDI_CUPBOARD_OUTLINE "\xf3\xb0\xbd\x87" // U+F0F47
+#define ICON_MDI_CUPCAKE "\xf3\xb0\xa5\x9a" // U+F095A
+#define ICON_MDI_CURLING "\xf3\xb0\xa1\xa3" // U+F0863
+#define ICON_MDI_CURRENCY_BDT "\xf3\xb0\xa1\xa4" // U+F0864
+#define ICON_MDI_CURRENCY_BRL "\xf3\xb0\xae\x85" // U+F0B85
+#define ICON_MDI_CURRENCY_BTC "\xf3\xb0\x86\xac" // U+F01AC
+#define ICON_MDI_CURRENCY_CNY "\xf3\xb0\x9e\xba" // U+F07BA
+#define ICON_MDI_CURRENCY_ETH "\xf3\xb0\x9e\xbb" // U+F07BB
+#define ICON_MDI_CURRENCY_EUR "\xf3\xb0\x86\xad" // U+F01AD
+#define ICON_MDI_CURRENCY_EUR_OFF "\xf3\xb1\x8c\x95" // U+F1315
+#define ICON_MDI_CURRENCY_FRA "\xf3\xb1\xa8\xb9" // U+F1A39
+#define ICON_MDI_CURRENCY_GBP "\xf3\xb0\x86\xae" // U+F01AE
+#define ICON_MDI_CURRENCY_ILS "\xf3\xb0\xb1\xa1" // U+F0C61
+#define ICON_MDI_CURRENCY_INR "\xf3\xb0\x86\xaf" // U+F01AF
+#define ICON_MDI_CURRENCY_JPY "\xf3\xb0\x9e\xbc" // U+F07BC
+#define ICON_MDI_CURRENCY_KRW "\xf3\xb0\x9e\xbd" // U+F07BD
+#define ICON_MDI_CURRENCY_KZT "\xf3\xb0\xa1\xa5" // U+F0865
+#define ICON_MDI_CURRENCY_MNT "\xf3\xb1\x94\x92" // U+F1512
+#define ICON_MDI_CURRENCY_NGN "\xf3\xb0\x86\xb0" // U+F01B0
+#define ICON_MDI_CURRENCY_PHP "\xf3\xb0\xa7\xa6" // U+F09E6
+#define ICON_MDI_CURRENCY_RIAL "\xf3\xb0\xba\x9c" // U+F0E9C
+#define ICON_MDI_CURRENCY_RUB "\xf3\xb0\x86\xb1" // U+F01B1
+#define ICON_MDI_CURRENCY_RUPEE "\xf3\xb1\xa5\xb6" // U+F1976
+#define ICON_MDI_CURRENCY_SIGN "\xf3\xb0\x9e\xbe" // U+F07BE
+#define ICON_MDI_CURRENCY_THB "\xf3\xb1\xb0\x85" // U+F1C05
+#define ICON_MDI_CURRENCY_TRY "\xf3\xb0\x86\xb2" // U+F01B2
+#define ICON_MDI_CURRENCY_TWD "\xf3\xb0\x9e\xbf" // U+F07BF
+#define ICON_MDI_CURRENCY_UAH "\xf3\xb1\xae\x9b" // U+F1B9B
+#define ICON_MDI_CURRENCY_USD "\xf3\xb0\x87\x81" // U+F01C1
+#define ICON_MDI_CURRENCY_USD_OFF "\xf3\xb0\x99\xba" // U+F067A
+#define ICON_MDI_CURRENT_AC "\xf3\xb1\x92\x80" // U+F1480
+#define ICON_MDI_CURRENT_DC "\xf3\xb0\xa5\x9c" // U+F095C
+#define ICON_MDI_CURSOR_DEFAULT "\xf3\xb0\x87\x80" // U+F01C0
+#define ICON_MDI_CURSOR_DEFAULT_CLICK "\xf3\xb0\xb3\xbd" // U+F0CFD
+#define ICON_MDI_CURSOR_DEFAULT_CLICK_OUTLINE "\xf3\xb0\xb3\xbe" // U+F0CFE
+#define ICON_MDI_CURSOR_DEFAULT_GESTURE "\xf3\xb1\x84\xa7" // U+F1127
+#define ICON_MDI_CURSOR_DEFAULT_GESTURE_OUTLINE "\xf3\xb1\x84\xa8" // U+F1128
+#define ICON_MDI_CURSOR_DEFAULT_OUTLINE "\xf3\xb0\x86\xbf" // U+F01BF
+#define ICON_MDI_CURSOR_MOVE "\xf3\xb0\x86\xbe" // U+F01BE
+#define ICON_MDI_CURSOR_POINTER "\xf3\xb0\x86\xbd" // U+F01BD
+#define ICON_MDI_CURSOR_TEXT "\xf3\xb0\x97\xa7" // U+F05E7
+#define ICON_MDI_CURTAINS "\xf3\xb1\xa1\x86" // U+F1846
+#define ICON_MDI_CURTAINS_CLOSED "\xf3\xb1\xa1\x87" // U+F1847
+#define ICON_MDI_CYLINDER "\xf3\xb1\xa5\x8e" // U+F194E
+#define ICON_MDI_CYLINDER_OFF "\xf3\xb1\xa5\x8f" // U+F194F
+#define ICON_MDI_DANCE_BALLROOM "\xf3\xb1\x97\xbb" // U+F15FB
+#define ICON_MDI_DANCE_POLE "\xf3\xb1\x95\xb8" // U+F1578
+#define ICON_MDI_DATA_MATRIX "\xf3\xb1\x94\xbc" // U+F153C
+#define ICON_MDI_DATA_MATRIX_EDIT "\xf3\xb1\x94\xbd" // U+F153D
+#define ICON_MDI_DATA_MATRIX_MINUS "\xf3\xb1\x94\xbe" // U+F153E
+#define ICON_MDI_DATA_MATRIX_PLUS "\xf3\xb1\x94\xbf" // U+F153F
+#define ICON_MDI_DATA_MATRIX_REMOVE "\xf3\xb1\x95\x80" // U+F1540
+#define ICON_MDI_DATA_MATRIX_SCAN "\xf3\xb1\x95\x81" // U+F1541
+#define ICON_MDI_DATABASE "\xf3\xb0\x86\xbc" // U+F01BC
+#define ICON_MDI_DATABASE_ALERT "\xf3\xb1\x98\xba" // U+F163A
+#define ICON_MDI_DATABASE_ALERT_OUTLINE "\xf3\xb1\x98\xa4" // U+F1624
+#define ICON_MDI_DATABASE_ARROW_DOWN "\xf3\xb1\x98\xbb" // U+F163B
+#define ICON_MDI_DATABASE_ARROW_DOWN_OUTLINE "\xf3\xb1\x98\xa5" // U+F1625
+#define ICON_MDI_DATABASE_ARROW_LEFT "\xf3\xb1\x98\xbc" // U+F163C
+#define ICON_MDI_DATABASE_ARROW_LEFT_OUTLINE "\xf3\xb1\x98\xa6" // U+F1626
+#define ICON_MDI_DATABASE_ARROW_RIGHT "\xf3\xb1\x98\xbd" // U+F163D
+#define ICON_MDI_DATABASE_ARROW_RIGHT_OUTLINE "\xf3\xb1\x98\xa7" // U+F1627
+#define ICON_MDI_DATABASE_ARROW_UP "\xf3\xb1\x98\xbe" // U+F163E
+#define ICON_MDI_DATABASE_ARROW_UP_OUTLINE "\xf3\xb1\x98\xa8" // U+F1628
+#define ICON_MDI_DATABASE_CHECK "\xf3\xb0\xaa\xa9" // U+F0AA9
+#define ICON_MDI_DATABASE_CHECK_OUTLINE "\xf3\xb1\x98\xa9" // U+F1629
+#define ICON_MDI_DATABASE_CLOCK "\xf3\xb1\x98\xbf" // U+F163F
+#define ICON_MDI_DATABASE_CLOCK_OUTLINE "\xf3\xb1\x98\xaa" // U+F162A
+#define ICON_MDI_DATABASE_COG "\xf3\xb1\x99\x8b" // U+F164B
+#define ICON_MDI_DATABASE_COG_OUTLINE "\xf3\xb1\x99\x8c" // U+F164C
+#define ICON_MDI_DATABASE_EDIT "\xf3\xb0\xae\x86" // U+F0B86
+#define ICON_MDI_DATABASE_EDIT_OUTLINE "\xf3\xb1\x98\xab" // U+F162B
+#define ICON_MDI_DATABASE_EXPORT "\xf3\xb0\xa5\x9e" // U+F095E
+#define ICON_MDI_DATABASE_EXPORT_OUTLINE "\xf3\xb1\x98\xac" // U+F162C
+#define ICON_MDI_DATABASE_EYE "\xf3\xb1\xa4\x9f" // U+F191F
+#define ICON_MDI_DATABASE_EYE_OFF "\xf3\xb1\xa4\xa0" // U+F1920
+#define ICON_MDI_DATABASE_EYE_OFF_OUTLINE "\xf3\xb1\xa4\xa1" // U+F1921
+#define ICON_MDI_DATABASE_EYE_OUTLINE "\xf3\xb1\xa4\xa2" // U+F1922
+#define ICON_MDI_DATABASE_IMPORT "\xf3\xb0\xa5\x9d" // U+F095D
+#define ICON_MDI_DATABASE_IMPORT_OUTLINE "\xf3\xb1\x98\xad" // U+F162D
+#define ICON_MDI_DATABASE_LOCK "\xf3\xb0\xaa\xaa" // U+F0AAA
+#define ICON_MDI_DATABASE_LOCK_OUTLINE "\xf3\xb1\x98\xae" // U+F162E
+#define ICON_MDI_DATABASE_MARKER "\xf3\xb1\x8b\xb6" // U+F12F6
+#define ICON_MDI_DATABASE_MARKER_OUTLINE "\xf3\xb1\x98\xaf" // U+F162F
+#define ICON_MDI_DATABASE_MINUS "\xf3\xb0\x86\xbb" // U+F01BB
+#define ICON_MDI_DATABASE_MINUS_OUTLINE "\xf3\xb1\x98\xb0" // U+F1630
+#define ICON_MDI_DATABASE_OFF "\xf3\xb1\x99\x80" // U+F1640
+#define ICON_MDI_DATABASE_OFF_OUTLINE "\xf3\xb1\x98\xb1" // U+F1631
+#define ICON_MDI_DATABASE_OUTLINE "\xf3\xb1\x98\xb2" // U+F1632
+#define ICON_MDI_DATABASE_PLUS "\xf3\xb0\x86\xba" // U+F01BA
+#define ICON_MDI_DATABASE_PLUS_OUTLINE "\xf3\xb1\x98\xb3" // U+F1633
+#define ICON_MDI_DATABASE_REFRESH "\xf3\xb0\x97\x82" // U+F05C2
+#define ICON_MDI_DATABASE_REFRESH_OUTLINE "\xf3\xb1\x98\xb4" // U+F1634
+#define ICON_MDI_DATABASE_REMOVE "\xf3\xb0\xb4\x80" // U+F0D00
+#define ICON_MDI_DATABASE_REMOVE_OUTLINE "\xf3\xb1\x98\xb5" // U+F1635
+#define ICON_MDI_DATABASE_SEARCH "\xf3\xb0\xa1\xa6" // U+F0866
+#define ICON_MDI_DATABASE_SEARCH_OUTLINE "\xf3\xb1\x98\xb6" // U+F1636
+#define ICON_MDI_DATABASE_SETTINGS "\xf3\xb0\xb4\x81" // U+F0D01
+#define ICON_MDI_DATABASE_SETTINGS_OUTLINE "\xf3\xb1\x98\xb7" // U+F1637
+#define ICON_MDI_DATABASE_SYNC "\xf3\xb0\xb3\xbf" // U+F0CFF
+#define ICON_MDI_DATABASE_SYNC_OUTLINE "\xf3\xb1\x98\xb8" // U+F1638
+#define ICON_MDI_DEATH_STAR "\xf3\xb0\xa3\x98" // U+F08D8
+#define ICON_MDI_DEATH_STAR_VARIANT "\xf3\xb0\xa3\x99" // U+F08D9
+#define ICON_MDI_DEATHLY_HALLOWS "\xf3\xb0\xae\x87" // U+F0B87
+#define ICON_MDI_DEBIAN "\xf3\xb0\xa3\x9a" // U+F08DA
+#define ICON_MDI_DEBUG_STEP_INTO "\xf3\xb0\x86\xb9" // U+F01B9
+#define ICON_MDI_DEBUG_STEP_OUT "\xf3\xb0\x86\xb8" // U+F01B8
+#define ICON_MDI_DEBUG_STEP_OVER "\xf3\xb0\x86\xb7" // U+F01B7
+#define ICON_MDI_DECAGRAM "\xf3\xb0\x9d\xac" // U+F076C
+#define ICON_MDI_DECAGRAM_OUTLINE "\xf3\xb0\x9d\xad" // U+F076D
+#define ICON_MDI_DECIMAL "\xf3\xb1\x82\xa1" // U+F10A1
+#define ICON_MDI_DECIMAL_COMMA "\xf3\xb1\x82\xa2" // U+F10A2
+#define ICON_MDI_DECIMAL_COMMA_DECREASE "\xf3\xb1\x82\xa3" // U+F10A3
+#define ICON_MDI_DECIMAL_COMMA_INCREASE "\xf3\xb1\x82\xa4" // U+F10A4
+#define ICON_MDI_DECIMAL_DECREASE "\xf3\xb0\x86\xb6" // U+F01B6
+#define ICON_MDI_DECIMAL_INCREASE "\xf3\xb0\x86\xb5" // U+F01B5
+#define ICON_MDI_DELETE "\xf3\xb0\x86\xb4" // U+F01B4
+#define ICON_MDI_DELETE_ALERT "\xf3\xb1\x82\xa5" // U+F10A5
+#define ICON_MDI_DELETE_ALERT_OUTLINE "\xf3\xb1\x82\xa6" // U+F10A6
+#define ICON_MDI_DELETE_CIRCLE "\xf3\xb0\x9a\x83" // U+F0683
+#define ICON_MDI_DELETE_CIRCLE_OUTLINE "\xf3\xb0\xae\x88" // U+F0B88
+#define ICON_MDI_DELETE_CLOCK "\xf3\xb1\x95\x96" // U+F1556
+#define ICON_MDI_DELETE_CLOCK_OUTLINE "\xf3\xb1\x95\x97" // U+F1557
+#define ICON_MDI_DELETE_EMPTY "\xf3\xb0\x9b\x8c" // U+F06CC
+#define ICON_MDI_DELETE_EMPTY_OUTLINE "\xf3\xb0\xba\x9d" // U+F0E9D
+#define ICON_MDI_DELETE_FOREVER "\xf3\xb0\x97\xa8" // U+F05E8
+#define ICON_MDI_DELETE_FOREVER_OUTLINE "\xf3\xb0\xae\x89" // U+F0B89
+#define ICON_MDI_DELETE_OFF "\xf3\xb1\x82\xa7" // U+F10A7
+#define ICON_MDI_DELETE_OFF_OUTLINE "\xf3\xb1\x82\xa8" // U+F10A8
+#define ICON_MDI_DELETE_OUTLINE "\xf3\xb0\xa7\xa7" // U+F09E7
+#define ICON_MDI_DELETE_RESTORE "\xf3\xb0\xa0\x99" // U+F0819
+#define ICON_MDI_DELETE_SWEEP "\xf3\xb0\x97\xa9" // U+F05E9
+#define ICON_MDI_DELETE_SWEEP_OUTLINE "\xf3\xb0\xb1\xa2" // U+F0C62
+#define ICON_MDI_DELETE_VARIANT "\xf3\xb0\x86\xb3" // U+F01B3
+#define ICON_MDI_DELTA "\xf3\xb0\x87\x82" // U+F01C2
+#define ICON_MDI_DESK "\xf3\xb1\x88\xb9" // U+F1239
+#define ICON_MDI_DESK_LAMP "\xf3\xb0\xa5\x9f" // U+F095F
+#define ICON_MDI_DESK_LAMP_OFF "\xf3\xb1\xac\x9f" // U+F1B1F
+#define ICON_MDI_DESK_LAMP_ON "\xf3\xb1\xac\xa0" // U+F1B20
+#define ICON_MDI_DESKPHONE "\xf3\xb0\x87\x83" // U+F01C3
+#define ICON_MDI_DESKTOP_CLASSIC "\xf3\xb0\x9f\x80" // U+F07C0
+#define ICON_MDI_DESKTOP_TOWER "\xf3\xb0\x87\x85" // U+F01C5
+#define ICON_MDI_DESKTOP_TOWER_MONITOR "\xf3\xb0\xaa\xab" // U+F0AAB
+#define ICON_MDI_DETAILS "\xf3\xb0\x87\x86" // U+F01C6
+#define ICON_MDI_DEV_TO "\xf3\xb0\xb5\xae" // U+F0D6E
+#define ICON_MDI_DEVELOPER_BOARD "\xf3\xb0\x9a\x97" // U+F0697
+#define ICON_MDI_DEVIANTART "\xf3\xb0\x87\x87" // U+F01C7
+#define ICON_MDI_DEVICES "\xf3\xb0\xbe\xb0" // U+F0FB0
+#define ICON_MDI_DHARMACHAKRA "\xf3\xb0\xa5\x8b" // U+F094B
+#define ICON_MDI_DIABETES "\xf3\xb1\x84\xa6" // U+F1126
+#define ICON_MDI_DIALPAD "\xf3\xb0\x98\x9c" // U+F061C
+#define ICON_MDI_DIAMETER "\xf3\xb0\xb1\xa3" // U+F0C63
+#define ICON_MDI_DIAMETER_OUTLINE "\xf3\xb0\xb1\xa4" // U+F0C64
+#define ICON_MDI_DIAMETER_VARIANT "\xf3\xb0\xb1\xa5" // U+F0C65
+#define ICON_MDI_DIAMOND "\xf3\xb0\xae\x8a" // U+F0B8A
+#define ICON_MDI_DIAMOND_OUTLINE "\xf3\xb0\xae\x8b" // U+F0B8B
+#define ICON_MDI_DIAMOND_STONE "\xf3\xb0\x87\x88" // U+F01C8
+#define ICON_MDI_DICE_1 "\xf3\xb0\x87\x8a" // U+F01CA
+#define ICON_MDI_DICE_1_OUTLINE "\xf3\xb1\x85\x8a" // U+F114A
+#define ICON_MDI_DICE_2 "\xf3\xb0\x87\x8b" // U+F01CB
+#define ICON_MDI_DICE_2_OUTLINE "\xf3\xb1\x85\x8b" // U+F114B
+#define ICON_MDI_DICE_3 "\xf3\xb0\x87\x8c" // U+F01CC
+#define ICON_MDI_DICE_3_OUTLINE "\xf3\xb1\x85\x8c" // U+F114C
+#define ICON_MDI_DICE_4 "\xf3\xb0\x87\x8d" // U+F01CD
+#define ICON_MDI_DICE_4_OUTLINE "\xf3\xb1\x85\x8d" // U+F114D
+#define ICON_MDI_DICE_5 "\xf3\xb0\x87\x8e" // U+F01CE
+#define ICON_MDI_DICE_5_OUTLINE "\xf3\xb1\x85\x8e" // U+F114E
+#define ICON_MDI_DICE_6 "\xf3\xb0\x87\x8f" // U+F01CF
+#define ICON_MDI_DICE_6_OUTLINE "\xf3\xb1\x85\x8f" // U+F114F
+#define ICON_MDI_DICE_D10 "\xf3\xb1\x85\x93" // U+F1153
+#define ICON_MDI_DICE_D10_OUTLINE "\xf3\xb0\x9d\xaf" // U+F076F
+#define ICON_MDI_DICE_D12 "\xf3\xb1\x85\x94" // U+F1154
+#define ICON_MDI_DICE_D12_OUTLINE "\xf3\xb0\xa1\xa7" // U+F0867
+#define ICON_MDI_DICE_D20 "\xf3\xb1\x85\x95" // U+F1155
+#define ICON_MDI_DICE_D20_OUTLINE "\xf3\xb0\x97\xaa" // U+F05EA
+#define ICON_MDI_DICE_D4 "\xf3\xb1\x85\x90" // U+F1150
+#define ICON_MDI_DICE_D4_OUTLINE "\xf3\xb0\x97\xab" // U+F05EB
+#define ICON_MDI_DICE_D6 "\xf3\xb1\x85\x91" // U+F1151
+#define ICON_MDI_DICE_D6_OUTLINE "\xf3\xb0\x97\xad" // U+F05ED
+#define ICON_MDI_DICE_D8 "\xf3\xb1\x85\x92" // U+F1152
+#define ICON_MDI_DICE_D8_OUTLINE "\xf3\xb0\x97\xac" // U+F05EC
+#define ICON_MDI_DICE_MULTIPLE "\xf3\xb0\x9d\xae" // U+F076E
+#define ICON_MDI_DICE_MULTIPLE_OUTLINE "\xf3\xb1\x85\x96" // U+F1156
+#define ICON_MDI_DIGITAL_OCEAN "\xf3\xb1\x88\xb7" // U+F1237
+#define ICON_MDI_DIP_SWITCH "\xf3\xb0\x9f\x81" // U+F07C1
+#define ICON_MDI_DIRECTIONS "\xf3\xb0\x87\x90" // U+F01D0
+#define ICON_MDI_DIRECTIONS_FORK "\xf3\xb0\x99\x81" // U+F0641
+#define ICON_MDI_DISC "\xf3\xb0\x97\xae" // U+F05EE
+#define ICON_MDI_DISC_ALERT "\xf3\xb0\x87\x91" // U+F01D1
+#define ICON_MDI_DISC_PLAYER "\xf3\xb0\xa5\xa0" // U+F0960
+#define ICON_MDI_DISHWASHER "\xf3\xb0\xaa\xac" // U+F0AAC
+#define ICON_MDI_DISHWASHER_ALERT "\xf3\xb1\x86\xb8" // U+F11B8
+#define ICON_MDI_DISHWASHER_OFF "\xf3\xb1\x86\xb9" // U+F11B9
+#define ICON_MDI_DISQUS "\xf3\xb0\x87\x92" // U+F01D2
+#define ICON_MDI_DISTRIBUTE_HORIZONTAL_CENTER "\xf3\xb1\x87\x89" // U+F11C9
+#define ICON_MDI_DISTRIBUTE_HORIZONTAL_LEFT "\xf3\xb1\x87\x88" // U+F11C8
+#define ICON_MDI_DISTRIBUTE_HORIZONTAL_RIGHT "\xf3\xb1\x87\x8a" // U+F11CA
+#define ICON_MDI_DISTRIBUTE_VERTICAL_BOTTOM "\xf3\xb1\x87\x8b" // U+F11CB
+#define ICON_MDI_DISTRIBUTE_VERTICAL_CENTER "\xf3\xb1\x87\x8c" // U+F11CC
+#define ICON_MDI_DISTRIBUTE_VERTICAL_TOP "\xf3\xb1\x87\x8d" // U+F11CD
+#define ICON_MDI_DIVERSIFY "\xf3\xb1\xa1\xb7" // U+F1877
+#define ICON_MDI_DIVING "\xf3\xb1\xa5\xb7" // U+F1977
+#define ICON_MDI_DIVING_FLIPPERS "\xf3\xb0\xb6\xbf" // U+F0DBF
+#define ICON_MDI_DIVING_HELMET "\xf3\xb0\xb7\x80" // U+F0DC0
+#define ICON_MDI_DIVING_SCUBA "\xf3\xb1\xad\xb7" // U+F1B77
+#define ICON_MDI_DIVING_SCUBA_FLAG "\xf3\xb0\xb7\x82" // U+F0DC2
+#define ICON_MDI_DIVING_SCUBA_MASK "\xf3\xb0\xb7\x81" // U+F0DC1
+#define ICON_MDI_DIVING_SCUBA_TANK "\xf3\xb0\xb7\x83" // U+F0DC3
+#define ICON_MDI_DIVING_SCUBA_TANK_MULTIPLE "\xf3\xb0\xb7\x84" // U+F0DC4
+#define ICON_MDI_DIVING_SNORKEL "\xf3\xb0\xb7\x85" // U+F0DC5
+#define ICON_MDI_DIVISION "\xf3\xb0\x87\x94" // U+F01D4
+#define ICON_MDI_DIVISION_BOX "\xf3\xb0\x87\x95" // U+F01D5
+#define ICON_MDI_DLNA "\xf3\xb0\xa9\x81" // U+F0A41
+#define ICON_MDI_DNA "\xf3\xb0\x9a\x84" // U+F0684
+#define ICON_MDI_DNS "\xf3\xb0\x87\x96" // U+F01D6
+#define ICON_MDI_DNS_OUTLINE "\xf3\xb0\xae\x8c" // U+F0B8C
+#define ICON_MDI_DOCK_BOTTOM "\xf3\xb1\x82\xa9" // U+F10A9
+#define ICON_MDI_DOCK_LEFT "\xf3\xb1\x82\xaa" // U+F10AA
+#define ICON_MDI_DOCK_RIGHT "\xf3\xb1\x82\xab" // U+F10AB
+#define ICON_MDI_DOCK_TOP "\xf3\xb1\x94\x93" // U+F1513
+#define ICON_MDI_DOCK_WINDOW "\xf3\xb1\x82\xac" // U+F10AC
+#define ICON_MDI_DOCKER "\xf3\xb0\xa1\xa8" // U+F0868
+#define ICON_MDI_DOCTOR "\xf3\xb0\xa9\x82" // U+F0A42
+#define ICON_MDI_DOG "\xf3\xb0\xa9\x83" // U+F0A43
+#define ICON_MDI_DOG_SERVICE "\xf3\xb0\xaa\xad" // U+F0AAD
+#define ICON_MDI_DOG_SIDE "\xf3\xb0\xa9\x84" // U+F0A44
+#define ICON_MDI_DOG_SIDE_OFF "\xf3\xb1\x9b\xae" // U+F16EE
+#define ICON_MDI_DOLBY "\xf3\xb0\x9a\xb3" // U+F06B3
+#define ICON_MDI_DOLLY "\xf3\xb0\xba\x9e" // U+F0E9E
+#define ICON_MDI_DOLPHIN "\xf3\xb1\xa2\xb4" // U+F18B4
+#define ICON_MDI_DOMAIN "\xf3\xb0\x87\x97" // U+F01D7
+#define ICON_MDI_DOMAIN_OFF "\xf3\xb0\xb5\xaf" // U+F0D6F
+#define ICON_MDI_DOMAIN_PLUS "\xf3\xb1\x82\xad" // U+F10AD
+#define ICON_MDI_DOMAIN_REMOVE "\xf3\xb1\x82\xae" // U+F10AE
+#define ICON_MDI_DOMAIN_SWITCH "\xf3\xb1\xb0\xac" // U+F1C2C
+#define ICON_MDI_DOME_LIGHT "\xf3\xb1\x90\x9e" // U+F141E
+#define ICON_MDI_DOMINO_MASK "\xf3\xb1\x80\xa3" // U+F1023
+#define ICON_MDI_DONKEY "\xf3\xb0\x9f\x82" // U+F07C2
+#define ICON_MDI_DOOR "\xf3\xb0\xa0\x9a" // U+F081A
+#define ICON_MDI_DOOR_CLOSED "\xf3\xb0\xa0\x9b" // U+F081B
+#define ICON_MDI_DOOR_CLOSED_CANCEL "\xf3\xb1\xb2\x93" // U+F1C93
+#define ICON_MDI_DOOR_CLOSED_LOCK "\xf3\xb1\x82\xaf" // U+F10AF
+#define ICON_MDI_DOOR_OPEN "\xf3\xb0\xa0\x9c" // U+F081C
+#define ICON_MDI_DOOR_SLIDING "\xf3\xb1\xa0\x9e" // U+F181E
+#define ICON_MDI_DOOR_SLIDING_LOCK "\xf3\xb1\xa0\x9f" // U+F181F
+#define ICON_MDI_DOOR_SLIDING_OPEN "\xf3\xb1\xa0\xa0" // U+F1820
+#define ICON_MDI_DOORBELL "\xf3\xb1\x8b\xa6" // U+F12E6
+#define ICON_MDI_DOORBELL_VIDEO "\xf3\xb0\xa1\xa9" // U+F0869
+#define ICON_MDI_DOT_NET "\xf3\xb0\xaa\xae" // U+F0AAE
+#define ICON_MDI_DOTS_CIRCLE "\xf3\xb1\xa5\xb8" // U+F1978
+#define ICON_MDI_DOTS_GRID "\xf3\xb1\x97\xbc" // U+F15FC
+#define ICON_MDI_DOTS_HEXAGON "\xf3\xb1\x97\xbf" // U+F15FF
+#define ICON_MDI_DOTS_HORIZONTAL "\xf3\xb0\x87\x98" // U+F01D8
+#define ICON_MDI_DOTS_HORIZONTAL_CIRCLE "\xf3\xb0\x9f\x83" // U+F07C3
+#define ICON_MDI_DOTS_HORIZONTAL_CIRCLE_OUTLINE "\xf3\xb0\xae\x8d" // U+F0B8D
+#define ICON_MDI_DOTS_SQUARE "\xf3\xb1\x97\xbd" // U+F15FD
+#define ICON_MDI_DOTS_TRIANGLE "\xf3\xb1\x97\xbe" // U+F15FE
+#define ICON_MDI_DOTS_VERTICAL "\xf3\xb0\x87\x99" // U+F01D9
+#define ICON_MDI_DOTS_VERTICAL_CIRCLE "\xf3\xb0\x9f\x84" // U+F07C4
+#define ICON_MDI_DOTS_VERTICAL_CIRCLE_OUTLINE "\xf3\xb0\xae\x8e" // U+F0B8E
+#define ICON_MDI_DOWNLOAD "\xf3\xb0\x87\x9a" // U+F01DA
+#define ICON_MDI_DOWNLOAD_BOX "\xf3\xb1\x91\xa2" // U+F1462
+#define ICON_MDI_DOWNLOAD_BOX_OUTLINE "\xf3\xb1\x91\xa3" // U+F1463
+#define ICON_MDI_DOWNLOAD_CIRCLE "\xf3\xb1\x91\xa4" // U+F1464
+#define ICON_MDI_DOWNLOAD_CIRCLE_OUTLINE "\xf3\xb1\x91\xa5" // U+F1465
+#define ICON_MDI_DOWNLOAD_LOCK "\xf3\xb1\x8c\xa0" // U+F1320
+#define ICON_MDI_DOWNLOAD_LOCK_OUTLINE "\xf3\xb1\x8c\xa1" // U+F1321
+#define ICON_MDI_DOWNLOAD_MULTIPLE "\xf3\xb0\xa7\xa9" // U+F09E9
+#define ICON_MDI_DOWNLOAD_NETWORK "\xf3\xb0\x9b\xb4" // U+F06F4
+#define ICON_MDI_DOWNLOAD_NETWORK_OUTLINE "\xf3\xb0\xb1\xa6" // U+F0C66
+#define ICON_MDI_DOWNLOAD_OFF "\xf3\xb1\x82\xb0" // U+F10B0
+#define ICON_MDI_DOWNLOAD_OFF_OUTLINE "\xf3\xb1\x82\xb1" // U+F10B1
+#define ICON_MDI_DOWNLOAD_OUTLINE "\xf3\xb0\xae\x8f" // U+F0B8F
+#define ICON_MDI_DRAG "\xf3\xb0\x87\x9b" // U+F01DB
+#define ICON_MDI_DRAG_HORIZONTAL "\xf3\xb0\x87\x9c" // U+F01DC
+#define ICON_MDI_DRAG_HORIZONTAL_VARIANT "\xf3\xb1\x8b\xb0" // U+F12F0
+#define ICON_MDI_DRAG_VARIANT "\xf3\xb0\xae\x90" // U+F0B90
+#define ICON_MDI_DRAG_VERTICAL "\xf3\xb0\x87\x9d" // U+F01DD
+#define ICON_MDI_DRAG_VERTICAL_VARIANT "\xf3\xb1\x8b\xb1" // U+F12F1
+#define ICON_MDI_DRAMA_MASKS "\xf3\xb0\xb4\x82" // U+F0D02
+#define ICON_MDI_DRAW "\xf3\xb0\xbd\x89" // U+F0F49
+#define ICON_MDI_DRAW_PEN "\xf3\xb1\xa6\xb9" // U+F19B9
+#define ICON_MDI_DRAWING "\xf3\xb0\x87\x9e" // U+F01DE
+#define ICON_MDI_DRAWING_BOX "\xf3\xb0\x87\x9f" // U+F01DF
+#define ICON_MDI_DRESSER "\xf3\xb0\xbd\x8a" // U+F0F4A
+#define ICON_MDI_DRESSER_OUTLINE "\xf3\xb0\xbd\x8b" // U+F0F4B
+#define ICON_MDI_DRONE "\xf3\xb0\x87\xa2" // U+F01E2
+#define ICON_MDI_DROPBOX "\xf3\xb0\x87\xa3" // U+F01E3
+#define ICON_MDI_DRUPAL "\xf3\xb0\x87\xa4" // U+F01E4
+#define ICON_MDI_DUCK "\xf3\xb0\x87\xa5" // U+F01E5
+#define ICON_MDI_DUMBBELL "\xf3\xb0\x87\xa6" // U+F01E6
+#define ICON_MDI_DUMP_TRUCK "\xf3\xb0\xb1\xa7" // U+F0C67
+#define ICON_MDI_EAR_HEARING "\xf3\xb0\x9f\x85" // U+F07C5
+#define ICON_MDI_EAR_HEARING_LOOP "\xf3\xb1\xab\xae" // U+F1AEE
+#define ICON_MDI_EAR_HEARING_OFF "\xf3\xb0\xa9\x85" // U+F0A45
+#define ICON_MDI_EARBUDS "\xf3\xb1\xa1\x8f" // U+F184F
+#define ICON_MDI_EARBUDS_OFF "\xf3\xb1\xa1\x90" // U+F1850
+#define ICON_MDI_EARBUDS_OFF_OUTLINE "\xf3\xb1\xa1\x91" // U+F1851
+#define ICON_MDI_EARBUDS_OUTLINE "\xf3\xb1\xa1\x92" // U+F1852
+#define ICON_MDI_EARTH "\xf3\xb0\x87\xa7" // U+F01E7
+#define ICON_MDI_EARTH_ARROW_DOWN "\xf3\xb1\xb2\x87" // U+F1C87
+#define ICON_MDI_EARTH_ARROW_LEFT "\xf3\xb1\xb2\x88" // U+F1C88
+#define ICON_MDI_EARTH_ARROW_RIGHT "\xf3\xb1\x8c\x91" // U+F1311
+#define ICON_MDI_EARTH_ARROW_UP "\xf3\xb1\xb2\x89" // U+F1C89
+#define ICON_MDI_EARTH_BOX "\xf3\xb0\x9b\x8d" // U+F06CD
+#define ICON_MDI_EARTH_BOX_MINUS "\xf3\xb1\x90\x87" // U+F1407
+#define ICON_MDI_EARTH_BOX_OFF "\xf3\xb0\x9b\x8e" // U+F06CE
+#define ICON_MDI_EARTH_BOX_PLUS "\xf3\xb1\x90\x86" // U+F1406
+#define ICON_MDI_EARTH_BOX_REMOVE "\xf3\xb1\x90\x88" // U+F1408
+#define ICON_MDI_EARTH_MINUS "\xf3\xb1\x90\x84" // U+F1404
+#define ICON_MDI_EARTH_OFF "\xf3\xb0\x87\xa8" // U+F01E8
+#define ICON_MDI_EARTH_PLUS "\xf3\xb1\x90\x83" // U+F1403
+#define ICON_MDI_EARTH_REMOVE "\xf3\xb1\x90\x85" // U+F1405
+#define ICON_MDI_EGG "\xf3\xb0\xaa\xaf" // U+F0AAF
+#define ICON_MDI_EGG_EASTER "\xf3\xb0\xaa\xb0" // U+F0AB0
+#define ICON_MDI_EGG_FRIED "\xf3\xb1\xa1\x8a" // U+F184A
+#define ICON_MDI_EGG_OFF "\xf3\xb1\x8f\xb0" // U+F13F0
+#define ICON_MDI_EGG_OFF_OUTLINE "\xf3\xb1\x8f\xb1" // U+F13F1
+#define ICON_MDI_EGG_OUTLINE "\xf3\xb1\x8f\xb2" // U+F13F2
+#define ICON_MDI_EIFFEL_TOWER "\xf3\xb1\x95\xab" // U+F156B
+#define ICON_MDI_EIGHT_TRACK "\xf3\xb0\xa7\xaa" // U+F09EA
+#define ICON_MDI_EJECT "\xf3\xb0\x87\xaa" // U+F01EA
+#define ICON_MDI_EJECT_CIRCLE "\xf3\xb1\xac\xa3" // U+F1B23
+#define ICON_MDI_EJECT_CIRCLE_OUTLINE "\xf3\xb1\xac\xa4" // U+F1B24
+#define ICON_MDI_EJECT_OUTLINE "\xf3\xb0\xae\x91" // U+F0B91
+#define ICON_MDI_ELECTRIC_SWITCH "\xf3\xb0\xba\x9f" // U+F0E9F
+#define ICON_MDI_ELECTRIC_SWITCH_CLOSED "\xf3\xb1\x83\x99" // U+F10D9
+#define ICON_MDI_ELECTRON_FRAMEWORK "\xf3\xb1\x80\xa4" // U+F1024
+#define ICON_MDI_ELEPHANT "\xf3\xb0\x9f\x86" // U+F07C6
+#define ICON_MDI_ELEVATION_DECLINE "\xf3\xb0\x87\xab" // U+F01EB
+#define ICON_MDI_ELEVATION_RISE "\xf3\xb0\x87\xac" // U+F01EC
+#define ICON_MDI_ELEVATOR "\xf3\xb0\x87\xad" // U+F01ED
+#define ICON_MDI_ELEVATOR_DOWN "\xf3\xb1\x8b\x82" // U+F12C2
+#define ICON_MDI_ELEVATOR_PASSENGER "\xf3\xb1\x8e\x81" // U+F1381
+#define ICON_MDI_ELEVATOR_PASSENGER_OFF "\xf3\xb1\xa5\xb9" // U+F1979
+#define ICON_MDI_ELEVATOR_PASSENGER_OFF_OUTLINE "\xf3\xb1\xa5\xba" // U+F197A
+#define ICON_MDI_ELEVATOR_PASSENGER_OUTLINE "\xf3\xb1\xa5\xbb" // U+F197B
+#define ICON_MDI_ELEVATOR_UP "\xf3\xb1\x8b\x81" // U+F12C1
+#define ICON_MDI_ELLIPSE "\xf3\xb0\xba\xa0" // U+F0EA0
+#define ICON_MDI_ELLIPSE_OUTLINE "\xf3\xb0\xba\xa1" // U+F0EA1
+#define ICON_MDI_EMAIL "\xf3\xb0\x87\xae" // U+F01EE
+#define ICON_MDI_EMAIL_ALERT "\xf3\xb0\x9b\x8f" // U+F06CF
+#define ICON_MDI_EMAIL_ALERT_OUTLINE "\xf3\xb0\xb5\x82" // U+F0D42
+#define ICON_MDI_EMAIL_ARROW_LEFT "\xf3\xb1\x83\x9a" // U+F10DA
+#define ICON_MDI_EMAIL_ARROW_LEFT_OUTLINE "\xf3\xb1\x83\x9b" // U+F10DB
+#define ICON_MDI_EMAIL_ARROW_RIGHT "\xf3\xb1\x83\x9c" // U+F10DC
+#define ICON_MDI_EMAIL_ARROW_RIGHT_OUTLINE "\xf3\xb1\x83\x9d" // U+F10DD
+#define ICON_MDI_EMAIL_BOX "\xf3\xb0\xb4\x83" // U+F0D03
+#define ICON_MDI_EMAIL_CHECK "\xf3\xb0\xaa\xb1" // U+F0AB1
+#define ICON_MDI_EMAIL_CHECK_OUTLINE "\xf3\xb0\xaa\xb2" // U+F0AB2
+#define ICON_MDI_EMAIL_EDIT "\xf3\xb0\xbb\xa3" // U+F0EE3
+#define ICON_MDI_EMAIL_EDIT_OUTLINE "\xf3\xb0\xbb\xa4" // U+F0EE4
+#define ICON_MDI_EMAIL_FAST "\xf3\xb1\xa1\xaf" // U+F186F
+#define ICON_MDI_EMAIL_FAST_OUTLINE "\xf3\xb1\xa1\xb0" // U+F1870
+#define ICON_MDI_EMAIL_HEART_OUTLINE "\xf3\xb1\xb1\x9b" // U+F1C5B
+#define ICON_MDI_EMAIL_LOCK "\xf3\xb0\x87\xb1" // U+F01F1
+#define ICON_MDI_EMAIL_LOCK_OUTLINE "\xf3\xb1\xad\xa1" // U+F1B61
+#define ICON_MDI_EMAIL_MARK_AS_UNREAD "\xf3\xb0\xae\x92" // U+F0B92
+#define ICON_MDI_EMAIL_MINUS "\xf3\xb0\xbb\xa5" // U+F0EE5
+#define ICON_MDI_EMAIL_MINUS_OUTLINE "\xf3\xb0\xbb\xa6" // U+F0EE6
+#define ICON_MDI_EMAIL_MULTIPLE "\xf3\xb0\xbb\xa7" // U+F0EE7
+#define ICON_MDI_EMAIL_MULTIPLE_OUTLINE "\xf3\xb0\xbb\xa8" // U+F0EE8
+#define ICON_MDI_EMAIL_NEWSLETTER "\xf3\xb0\xbe\xb1" // U+F0FB1
+#define ICON_MDI_EMAIL_OFF "\xf3\xb1\x8f\xa3" // U+F13E3
+#define ICON_MDI_EMAIL_OFF_OUTLINE "\xf3\xb1\x8f\xa4" // U+F13E4
+#define ICON_MDI_EMAIL_OPEN "\xf3\xb0\x87\xaf" // U+F01EF
+#define ICON_MDI_EMAIL_OPEN_HEART_OUTLINE "\xf3\xb1\xb1\x9c" // U+F1C5C
+#define ICON_MDI_EMAIL_OPEN_MULTIPLE "\xf3\xb0\xbb\xa9" // U+F0EE9
+#define ICON_MDI_EMAIL_OPEN_MULTIPLE_OUTLINE "\xf3\xb0\xbb\xaa" // U+F0EEA
+#define ICON_MDI_EMAIL_OPEN_OUTLINE "\xf3\xb0\x97\xaf" // U+F05EF
+#define ICON_MDI_EMAIL_OUTLINE "\xf3\xb0\x87\xb0" // U+F01F0
+#define ICON_MDI_EMAIL_PLUS "\xf3\xb0\xa7\xab" // U+F09EB
+#define ICON_MDI_EMAIL_PLUS_OUTLINE "\xf3\xb0\xa7\xac" // U+F09EC
+#define ICON_MDI_EMAIL_REMOVE "\xf3\xb1\x99\xa1" // U+F1661
+#define ICON_MDI_EMAIL_REMOVE_OUTLINE "\xf3\xb1\x99\xa2" // U+F1662
+#define ICON_MDI_EMAIL_SEAL "\xf3\xb1\xa5\x9b" // U+F195B
+#define ICON_MDI_EMAIL_SEAL_OUTLINE "\xf3\xb1\xa5\x9c" // U+F195C
+#define ICON_MDI_EMAIL_SEARCH "\xf3\xb0\xa5\xa1" // U+F0961
+#define ICON_MDI_EMAIL_SEARCH_OUTLINE "\xf3\xb0\xa5\xa2" // U+F0962
+#define ICON_MDI_EMAIL_SYNC "\xf3\xb1\x8b\x87" // U+F12C7
+#define ICON_MDI_EMAIL_SYNC_OUTLINE "\xf3\xb1\x8b\x88" // U+F12C8
+#define ICON_MDI_EMAIL_VARIANT "\xf3\xb0\x97\xb0" // U+F05F0
+#define ICON_MDI_EMBER "\xf3\xb0\xac\xb0" // U+F0B30
+#define ICON_MDI_EMBY "\xf3\xb0\x9a\xb4" // U+F06B4
+#define ICON_MDI_EMOTICON "\xf3\xb0\xb1\xa8" // U+F0C68
+#define ICON_MDI_EMOTICON_ANGRY "\xf3\xb0\xb1\xa9" // U+F0C69
+#define ICON_MDI_EMOTICON_ANGRY_OUTLINE "\xf3\xb0\xb1\xaa" // U+F0C6A
+#define ICON_MDI_EMOTICON_CONFUSED "\xf3\xb1\x83\x9e" // U+F10DE
+#define ICON_MDI_EMOTICON_CONFUSED_OUTLINE "\xf3\xb1\x83\x9f" // U+F10DF
+#define ICON_MDI_EMOTICON_COOL "\xf3\xb0\xb1\xab" // U+F0C6B
+#define ICON_MDI_EMOTICON_COOL_OUTLINE "\xf3\xb0\x87\xb3" // U+F01F3
+#define ICON_MDI_EMOTICON_CRY "\xf3\xb0\xb1\xac" // U+F0C6C
+#define ICON_MDI_EMOTICON_CRY_OUTLINE "\xf3\xb0\xb1\xad" // U+F0C6D
+#define ICON_MDI_EMOTICON_DEAD "\xf3\xb0\xb1\xae" // U+F0C6E
+#define ICON_MDI_EMOTICON_DEAD_OUTLINE "\xf3\xb0\x9a\x9b" // U+F069B
+#define ICON_MDI_EMOTICON_DEVIL "\xf3\xb0\xb1\xaf" // U+F0C6F
+#define ICON_MDI_EMOTICON_DEVIL_OUTLINE "\xf3\xb0\x87\xb4" // U+F01F4
+#define ICON_MDI_EMOTICON_EXCITED "\xf3\xb0\xb1\xb0" // U+F0C70
+#define ICON_MDI_EMOTICON_EXCITED_OUTLINE "\xf3\xb0\x9a\x9c" // U+F069C
+#define ICON_MDI_EMOTICON_FROWN "\xf3\xb0\xbd\x8c" // U+F0F4C
+#define ICON_MDI_EMOTICON_FROWN_OUTLINE "\xf3\xb0\xbd\x8d" // U+F0F4D
+#define ICON_MDI_EMOTICON_HAPPY "\xf3\xb0\xb1\xb1" // U+F0C71
+#define ICON_MDI_EMOTICON_HAPPY_OUTLINE "\xf3\xb0\x87\xb5" // U+F01F5
+#define ICON_MDI_EMOTICON_KISS "\xf3\xb0\xb1\xb2" // U+F0C72
+#define ICON_MDI_EMOTICON_KISS_OUTLINE "\xf3\xb0\xb1\xb3" // U+F0C73
+#define ICON_MDI_EMOTICON_LOL "\xf3\xb1\x88\x94" // U+F1214
+#define ICON_MDI_EMOTICON_LOL_OUTLINE "\xf3\xb1\x88\x95" // U+F1215
+#define ICON_MDI_EMOTICON_MINUS "\xf3\xb1\xb2\xb2" // U+F1CB2
+#define ICON_MDI_EMOTICON_MINUS_OUTLINE "\xf3\xb1\xb2\xb3" // U+F1CB3
+#define ICON_MDI_EMOTICON_NEUTRAL "\xf3\xb0\xb1\xb4" // U+F0C74
+#define ICON_MDI_EMOTICON_NEUTRAL_OUTLINE "\xf3\xb0\x87\xb6" // U+F01F6
+#define ICON_MDI_EMOTICON_OUTLINE "\xf3\xb0\x87\xb2" // U+F01F2
+#define ICON_MDI_EMOTICON_PLUS "\xf3\xb1\xb2\xb4" // U+F1CB4
+#define ICON_MDI_EMOTICON_PLUS_OUTLINE "\xf3\xb1\xb2\xb5" // U+F1CB5
+#define ICON_MDI_EMOTICON_POOP "\xf3\xb0\x87\xb7" // U+F01F7
+#define ICON_MDI_EMOTICON_POOP_OUTLINE "\xf3\xb0\xb1\xb5" // U+F0C75
+#define ICON_MDI_EMOTICON_REMOVE "\xf3\xb1\xb2\xb6" // U+F1CB6
+#define ICON_MDI_EMOTICON_REMOVE_OUTLINE "\xf3\xb1\xb2\xb7" // U+F1CB7
+#define ICON_MDI_EMOTICON_SAD "\xf3\xb0\xb1\xb6" // U+F0C76
+#define ICON_MDI_EMOTICON_SAD_OUTLINE "\xf3\xb0\x87\xb8" // U+F01F8
+#define ICON_MDI_EMOTICON_SICK "\xf3\xb1\x95\xbc" // U+F157C
+#define ICON_MDI_EMOTICON_SICK_OUTLINE "\xf3\xb1\x95\xbd" // U+F157D
+#define ICON_MDI_EMOTICON_TONGUE "\xf3\xb0\x87\xb9" // U+F01F9
+#define ICON_MDI_EMOTICON_TONGUE_OUTLINE "\xf3\xb0\xb1\xb7" // U+F0C77
+#define ICON_MDI_EMOTICON_WINK "\xf3\xb0\xb1\xb8" // U+F0C78
+#define ICON_MDI_EMOTICON_WINK_OUTLINE "\xf3\xb0\xb1\xb9" // U+F0C79
+#define ICON_MDI_ENGINE "\xf3\xb0\x87\xba" // U+F01FA
+#define ICON_MDI_ENGINE_OFF "\xf3\xb0\xa9\x86" // U+F0A46
+#define ICON_MDI_ENGINE_OFF_OUTLINE "\xf3\xb0\xa9\x87" // U+F0A47
+#define ICON_MDI_ENGINE_OUTLINE "\xf3\xb0\x87\xbb" // U+F01FB
+#define ICON_MDI_EPSILON "\xf3\xb1\x83\xa0" // U+F10E0
+#define ICON_MDI_EQUAL "\xf3\xb0\x87\xbc" // U+F01FC
+#define ICON_MDI_EQUAL_BOX "\xf3\xb0\x87\xbd" // U+F01FD
+#define ICON_MDI_EQUALIZER "\xf3\xb0\xba\xa2" // U+F0EA2
+#define ICON_MDI_EQUALIZER_OUTLINE "\xf3\xb0\xba\xa3" // U+F0EA3
+#define ICON_MDI_ERASER "\xf3\xb0\x87\xbe" // U+F01FE
+#define ICON_MDI_ERASER_VARIANT "\xf3\xb0\x99\x82" // U+F0642
+#define ICON_MDI_ESCALATOR "\xf3\xb0\x87\xbf" // U+F01FF
+#define ICON_MDI_ESCALATOR_BOX "\xf3\xb1\x8e\x99" // U+F1399
+#define ICON_MDI_ESCALATOR_DOWN "\xf3\xb1\x8b\x80" // U+F12C0
+#define ICON_MDI_ESCALATOR_UP "\xf3\xb1\x8a\xbf" // U+F12BF
+#define ICON_MDI_ESLINT "\xf3\xb0\xb1\xba" // U+F0C7A
+#define ICON_MDI_ET "\xf3\xb0\xaa\xb3" // U+F0AB3
+#define ICON_MDI_ETHEREUM "\xf3\xb0\xa1\xaa" // U+F086A
+#define ICON_MDI_ETHERNET "\xf3\xb0\x88\x80" // U+F0200
+#define ICON_MDI_ETHERNET_CABLE "\xf3\xb0\x88\x81" // U+F0201
+#define ICON_MDI_ETHERNET_CABLE_OFF "\xf3\xb0\x88\x82" // U+F0202
+#define ICON_MDI_EV_PLUG_CCS1 "\xf3\xb1\x94\x99" // U+F1519
+#define ICON_MDI_EV_PLUG_CCS2 "\xf3\xb1\x94\x9a" // U+F151A
+#define ICON_MDI_EV_PLUG_CHADEMO "\xf3\xb1\x94\x9b" // U+F151B
+#define ICON_MDI_EV_PLUG_TESLA "\xf3\xb1\x94\x9c" // U+F151C
+#define ICON_MDI_EV_PLUG_TYPE1 "\xf3\xb1\x94\x9d" // U+F151D
+#define ICON_MDI_EV_PLUG_TYPE2 "\xf3\xb1\x94\x9e" // U+F151E
+#define ICON_MDI_EV_STATION "\xf3\xb0\x97\xb1" // U+F05F1
+#define ICON_MDI_EVERNOTE "\xf3\xb0\x88\x84" // U+F0204
+#define ICON_MDI_EXCAVATOR "\xf3\xb1\x80\xa5" // U+F1025
+#define ICON_MDI_EXCLAMATION "\xf3\xb0\x88\x85" // U+F0205
+#define ICON_MDI_EXCLAMATION_THICK "\xf3\xb1\x88\xb8" // U+F1238
+#define ICON_MDI_EXIT_RUN "\xf3\xb0\xa9\x88" // U+F0A48
+#define ICON_MDI_EXIT_TO_APP "\xf3\xb0\x88\x86" // U+F0206
+#define ICON_MDI_EXPAND_ALL "\xf3\xb0\xaa\xb4" // U+F0AB4
+#define ICON_MDI_EXPAND_ALL_OUTLINE "\xf3\xb0\xaa\xb5" // U+F0AB5
+#define ICON_MDI_EXPANSION_CARD "\xf3\xb0\xa2\xae" // U+F08AE
+#define ICON_MDI_EXPANSION_CARD_VARIANT "\xf3\xb0\xbe\xb2" // U+F0FB2
+#define ICON_MDI_EXPONENT "\xf3\xb0\xa5\xa3" // U+F0963
+#define ICON_MDI_EXPONENT_BOX "\xf3\xb0\xa5\xa4" // U+F0964
+#define ICON_MDI_EXPORT "\xf3\xb0\x88\x87" // U+F0207
+#define ICON_MDI_EXPORT_VARIANT "\xf3\xb0\xae\x93" // U+F0B93
+#define ICON_MDI_EYE "\xf3\xb0\x88\x88" // U+F0208
+#define ICON_MDI_EYE_ARROW_LEFT "\xf3\xb1\xa3\xbd" // U+F18FD
+#define ICON_MDI_EYE_ARROW_LEFT_OUTLINE "\xf3\xb1\xa3\xbe" // U+F18FE
+#define ICON_MDI_EYE_ARROW_RIGHT "\xf3\xb1\xa3\xbf" // U+F18FF
+#define ICON_MDI_EYE_ARROW_RIGHT_OUTLINE "\xf3\xb1\xa4\x80" // U+F1900
+#define ICON_MDI_EYE_CHECK "\xf3\xb0\xb4\x84" // U+F0D04
+#define ICON_MDI_EYE_CHECK_OUTLINE "\xf3\xb0\xb4\x85" // U+F0D05
+#define ICON_MDI_EYE_CIRCLE "\xf3\xb0\xae\x94" // U+F0B94
+#define ICON_MDI_EYE_CIRCLE_OUTLINE "\xf3\xb0\xae\x95" // U+F0B95
+#define ICON_MDI_EYE_CLOSED "\xf3\xb1\xb2\xa3" // U+F1CA3
+#define ICON_MDI_EYE_LOCK "\xf3\xb1\xb0\x86" // U+F1C06
+#define ICON_MDI_EYE_LOCK_OPEN "\xf3\xb1\xb0\x87" // U+F1C07
+#define ICON_MDI_EYE_LOCK_OPEN_OUTLINE "\xf3\xb1\xb0\x88" // U+F1C08
+#define ICON_MDI_EYE_LOCK_OUTLINE "\xf3\xb1\xb0\x89" // U+F1C09
+#define ICON_MDI_EYE_MINUS "\xf3\xb1\x80\xa6" // U+F1026
+#define ICON_MDI_EYE_MINUS_OUTLINE "\xf3\xb1\x80\xa7" // U+F1027
+#define ICON_MDI_EYE_OFF "\xf3\xb0\x88\x89" // U+F0209
+#define ICON_MDI_EYE_OFF_OUTLINE "\xf3\xb0\x9b\x91" // U+F06D1
+#define ICON_MDI_EYE_OUTLINE "\xf3\xb0\x9b\x90" // U+F06D0
+#define ICON_MDI_EYE_PLUS "\xf3\xb0\xa1\xab" // U+F086B
+#define ICON_MDI_EYE_PLUS_OUTLINE "\xf3\xb0\xa1\xac" // U+F086C
+#define ICON_MDI_EYE_REFRESH "\xf3\xb1\xa5\xbc" // U+F197C
+#define ICON_MDI_EYE_REFRESH_OUTLINE "\xf3\xb1\xa5\xbd" // U+F197D
+#define ICON_MDI_EYE_REMOVE "\xf3\xb1\x97\xa3" // U+F15E3
+#define ICON_MDI_EYE_REMOVE_OUTLINE "\xf3\xb1\x97\xa4" // U+F15E4
+#define ICON_MDI_EYE_SETTINGS "\xf3\xb0\xa1\xad" // U+F086D
+#define ICON_MDI_EYE_SETTINGS_OUTLINE "\xf3\xb0\xa1\xae" // U+F086E
+#define ICON_MDI_EYEDROPPER "\xf3\xb0\x88\x8a" // U+F020A
+#define ICON_MDI_EYEDROPPER_MINUS "\xf3\xb1\x8f\x9d" // U+F13DD
+#define ICON_MDI_EYEDROPPER_OFF "\xf3\xb1\x8f\x9f" // U+F13DF
+#define ICON_MDI_EYEDROPPER_PLUS "\xf3\xb1\x8f\x9c" // U+F13DC
+#define ICON_MDI_EYEDROPPER_REMOVE "\xf3\xb1\x8f\x9e" // U+F13DE
+#define ICON_MDI_EYEDROPPER_VARIANT "\xf3\xb0\x88\x8b" // U+F020B
+#define ICON_MDI_FACE_AGENT "\xf3\xb0\xb5\xb0" // U+F0D70
+#define ICON_MDI_FACE_MAN "\xf3\xb0\x99\x83" // U+F0643
+#define ICON_MDI_FACE_MAN_OUTLINE "\xf3\xb0\xae\x96" // U+F0B96
+#define ICON_MDI_FACE_MAN_PROFILE "\xf3\xb0\x99\x84" // U+F0644
+#define ICON_MDI_FACE_MAN_SHIMMER "\xf3\xb1\x97\x8c" // U+F15CC
+#define ICON_MDI_FACE_MAN_SHIMMER_OUTLINE "\xf3\xb1\x97\x8d" // U+F15CD
+#define ICON_MDI_FACE_MASK "\xf3\xb1\x96\x86" // U+F1586
+#define ICON_MDI_FACE_MASK_OUTLINE "\xf3\xb1\x96\x87" // U+F1587
+#define ICON_MDI_FACE_RECOGNITION "\xf3\xb0\xb1\xbb" // U+F0C7B
+#define ICON_MDI_FACE_WOMAN "\xf3\xb1\x81\xb7" // U+F1077
+#define ICON_MDI_FACE_WOMAN_OUTLINE "\xf3\xb1\x81\xb8" // U+F1078
+#define ICON_MDI_FACE_WOMAN_PROFILE "\xf3\xb1\x81\xb6" // U+F1076
+#define ICON_MDI_FACE_WOMAN_SHIMMER "\xf3\xb1\x97\x8e" // U+F15CE
+#define ICON_MDI_FACE_WOMAN_SHIMMER_OUTLINE "\xf3\xb1\x97\x8f" // U+F15CF
+#define ICON_MDI_FACEBOOK "\xf3\xb0\x88\x8c" // U+F020C
+#define ICON_MDI_FACEBOOK_GAMING "\xf3\xb0\x9f\x9d" // U+F07DD
+#define ICON_MDI_FACEBOOK_MESSENGER "\xf3\xb0\x88\x8e" // U+F020E
+#define ICON_MDI_FACEBOOK_WORKPLACE "\xf3\xb0\xac\xb1" // U+F0B31
+#define ICON_MDI_FACTORY "\xf3\xb0\x88\x8f" // U+F020F
+#define ICON_MDI_FAMILY_TREE "\xf3\xb1\x98\x8e" // U+F160E
+#define ICON_MDI_FAN "\xf3\xb0\x88\x90" // U+F0210
+#define ICON_MDI_FAN_ALERT "\xf3\xb1\x91\xac" // U+F146C
+#define ICON_MDI_FAN_AUTO "\xf3\xb1\x9c\x9d" // U+F171D
+#define ICON_MDI_FAN_CHEVRON_DOWN "\xf3\xb1\x91\xad" // U+F146D
+#define ICON_MDI_FAN_CHEVRON_UP "\xf3\xb1\x91\xae" // U+F146E
+#define ICON_MDI_FAN_CLOCK "\xf3\xb1\xa8\xba" // U+F1A3A
+#define ICON_MDI_FAN_MINUS "\xf3\xb1\x91\xb0" // U+F1470
+#define ICON_MDI_FAN_OFF "\xf3\xb0\xa0\x9d" // U+F081D
+#define ICON_MDI_FAN_PLUS "\xf3\xb1\x91\xaf" // U+F146F
+#define ICON_MDI_FAN_REMOVE "\xf3\xb1\x91\xb1" // U+F1471
+#define ICON_MDI_FAN_SPEED_1 "\xf3\xb1\x91\xb2" // U+F1472
+#define ICON_MDI_FAN_SPEED_2 "\xf3\xb1\x91\xb3" // U+F1473
+#define ICON_MDI_FAN_SPEED_3 "\xf3\xb1\x91\xb4" // U+F1474
+#define ICON_MDI_FAST_FORWARD "\xf3\xb0\x88\x91" // U+F0211
+#define ICON_MDI_FAST_FORWARD_10 "\xf3\xb0\xb5\xb1" // U+F0D71
+#define ICON_MDI_FAST_FORWARD_15 "\xf3\xb1\xa4\xba" // U+F193A
+#define ICON_MDI_FAST_FORWARD_30 "\xf3\xb0\xb4\x86" // U+F0D06
+#define ICON_MDI_FAST_FORWARD_45 "\xf3\xb1\xac\x92" // U+F1B12
+#define ICON_MDI_FAST_FORWARD_5 "\xf3\xb1\x87\xb8" // U+F11F8
+#define ICON_MDI_FAST_FORWARD_60 "\xf3\xb1\x98\x8b" // U+F160B
+#define ICON_MDI_FAST_FORWARD_OUTLINE "\xf3\xb0\x9b\x92" // U+F06D2
+#define ICON_MDI_FAUCET "\xf3\xb1\xac\xa9" // U+F1B29
+#define ICON_MDI_FAUCET_VARIANT "\xf3\xb1\xac\xaa" // U+F1B2A
+#define ICON_MDI_FAX "\xf3\xb0\x88\x92" // U+F0212
+#define ICON_MDI_FEATHER "\xf3\xb0\x9b\x93" // U+F06D3
+#define ICON_MDI_FEATURE_SEARCH "\xf3\xb0\xa9\x89" // U+F0A49
+#define ICON_MDI_FEATURE_SEARCH_OUTLINE "\xf3\xb0\xa9\x8a" // U+F0A4A
+#define ICON_MDI_FEDORA "\xf3\xb0\xa3\x9b" // U+F08DB
+#define ICON_MDI_FENCE "\xf3\xb1\x9e\x9a" // U+F179A
+#define ICON_MDI_FENCE_ELECTRIC "\xf3\xb1\x9f\xb6" // U+F17F6
+#define ICON_MDI_FENCING "\xf3\xb1\x93\x81" // U+F14C1
+#define ICON_MDI_FERRIS_WHEEL "\xf3\xb0\xba\xa4" // U+F0EA4
+#define ICON_MDI_FERRY "\xf3\xb0\x88\x93" // U+F0213
+#define ICON_MDI_FILE "\xf3\xb0\x88\x94" // U+F0214
+#define ICON_MDI_FILE_ACCOUNT "\xf3\xb0\x9c\xbb" // U+F073B
+#define ICON_MDI_FILE_ACCOUNT_OUTLINE "\xf3\xb1\x80\xa8" // U+F1028
+#define ICON_MDI_FILE_ALERT "\xf3\xb0\xa9\x8b" // U+F0A4B
+#define ICON_MDI_FILE_ALERT_OUTLINE "\xf3\xb0\xa9\x8c" // U+F0A4C
+#define ICON_MDI_FILE_ARROW_LEFT_RIGHT "\xf3\xb1\xaa\x93" // U+F1A93
+#define ICON_MDI_FILE_ARROW_LEFT_RIGHT_OUTLINE "\xf3\xb1\xaa\x94" // U+F1A94
+#define ICON_MDI_FILE_ARROW_UP_DOWN "\xf3\xb1\xaa\x95" // U+F1A95
+#define ICON_MDI_FILE_ARROW_UP_DOWN_OUTLINE "\xf3\xb1\xaa\x96" // U+F1A96
+#define ICON_MDI_FILE_CABINET "\xf3\xb0\xaa\xb6" // U+F0AB6
+#define ICON_MDI_FILE_CAD "\xf3\xb0\xbb\xab" // U+F0EEB
+#define ICON_MDI_FILE_CAD_BOX "\xf3\xb0\xbb\xac" // U+F0EEC
+#define ICON_MDI_FILE_CANCEL "\xf3\xb0\xb7\x86" // U+F0DC6
+#define ICON_MDI_FILE_CANCEL_OUTLINE "\xf3\xb0\xb7\x87" // U+F0DC7
+#define ICON_MDI_FILE_CERTIFICATE "\xf3\xb1\x86\x86" // U+F1186
+#define ICON_MDI_FILE_CERTIFICATE_OUTLINE "\xf3\xb1\x86\x87" // U+F1187
+#define ICON_MDI_FILE_CHART "\xf3\xb0\x88\x95" // U+F0215
+#define ICON_MDI_FILE_CHART_CHECK "\xf3\xb1\xa7\x86" // U+F19C6
+#define ICON_MDI_FILE_CHART_CHECK_OUTLINE "\xf3\xb1\xa7\x87" // U+F19C7
+#define ICON_MDI_FILE_CHART_OUTLINE "\xf3\xb1\x80\xa9" // U+F1029
+#define ICON_MDI_FILE_CHECK "\xf3\xb0\x88\x96" // U+F0216
+#define ICON_MDI_FILE_CHECK_OUTLINE "\xf3\xb0\xb8\xa9" // U+F0E29
+#define ICON_MDI_FILE_CLOCK "\xf3\xb1\x8b\xa1" // U+F12E1
+#define ICON_MDI_FILE_CLOCK_OUTLINE "\xf3\xb1\x8b\xa2" // U+F12E2
+#define ICON_MDI_FILE_CLOUD "\xf3\xb0\x88\x97" // U+F0217
+#define ICON_MDI_FILE_CLOUD_OUTLINE "\xf3\xb1\x80\xaa" // U+F102A
+#define ICON_MDI_FILE_CODE "\xf3\xb0\x88\xae" // U+F022E
+#define ICON_MDI_FILE_CODE_OUTLINE "\xf3\xb1\x80\xab" // U+F102B
+#define ICON_MDI_FILE_COG "\xf3\xb1\x81\xbb" // U+F107B
+#define ICON_MDI_FILE_COG_OUTLINE "\xf3\xb1\x81\xbc" // U+F107C
+#define ICON_MDI_FILE_COMPARE "\xf3\xb0\xa2\xaa" // U+F08AA
+#define ICON_MDI_FILE_DELIMITED "\xf3\xb0\x88\x98" // U+F0218
+#define ICON_MDI_FILE_DELIMITED_OUTLINE "\xf3\xb0\xba\xa5" // U+F0EA5
+#define ICON_MDI_FILE_DOCUMENT "\xf3\xb0\x88\x99" // U+F0219
+#define ICON_MDI_FILE_DOCUMENT_ALERT "\xf3\xb1\xaa\x97" // U+F1A97
+#define ICON_MDI_FILE_DOCUMENT_ALERT_OUTLINE "\xf3\xb1\xaa\x98" // U+F1A98
+#define ICON_MDI_FILE_DOCUMENT_ARROW_RIGHT "\xf3\xb1\xb0\x8f" // U+F1C0F
+#define ICON_MDI_FILE_DOCUMENT_ARROW_RIGHT_OUTLINE "\xf3\xb1\xb0\x90" // U+F1C10
+#define ICON_MDI_FILE_DOCUMENT_CHECK "\xf3\xb1\xaa\x99" // U+F1A99
+#define ICON_MDI_FILE_DOCUMENT_CHECK_OUTLINE "\xf3\xb1\xaa\x9a" // U+F1A9A
+#define ICON_MDI_FILE_DOCUMENT_EDIT "\xf3\xb0\xb7\x88" // U+F0DC8
+#define ICON_MDI_FILE_DOCUMENT_EDIT_OUTLINE "\xf3\xb0\xb7\x89" // U+F0DC9
+#define ICON_MDI_FILE_DOCUMENT_MINUS "\xf3\xb1\xaa\x9b" // U+F1A9B
+#define ICON_MDI_FILE_DOCUMENT_MINUS_OUTLINE "\xf3\xb1\xaa\x9c" // U+F1A9C
+#define ICON_MDI_FILE_DOCUMENT_MULTIPLE "\xf3\xb1\x94\x97" // U+F1517
+#define ICON_MDI_FILE_DOCUMENT_MULTIPLE_OUTLINE "\xf3\xb1\x94\x98" // U+F1518
+#define ICON_MDI_FILE_DOCUMENT_OUTLINE "\xf3\xb0\xa7\xae" // U+F09EE
+#define ICON_MDI_FILE_DOCUMENT_PLUS "\xf3\xb1\xaa\x9d" // U+F1A9D
+#define ICON_MDI_FILE_DOCUMENT_PLUS_OUTLINE "\xf3\xb1\xaa\x9e" // U+F1A9E
+#define ICON_MDI_FILE_DOCUMENT_REFRESH "\xf3\xb1\xb1\xba" // U+F1C7A
+#define ICON_MDI_FILE_DOCUMENT_REFRESH_OUTLINE "\xf3\xb1\xb1\xbb" // U+F1C7B
+#define ICON_MDI_FILE_DOCUMENT_REMOVE "\xf3\xb1\xaa\x9f" // U+F1A9F
+#define ICON_MDI_FILE_DOCUMENT_REMOVE_OUTLINE "\xf3\xb1\xaa\xa0" // U+F1AA0
+#define ICON_MDI_FILE_DOWNLOAD "\xf3\xb0\xa5\xa5" // U+F0965
+#define ICON_MDI_FILE_DOWNLOAD_OUTLINE "\xf3\xb0\xa5\xa6" // U+F0966
+#define ICON_MDI_FILE_EDIT "\xf3\xb1\x87\xa7" // U+F11E7
+#define ICON_MDI_FILE_EDIT_OUTLINE "\xf3\xb1\x87\xa8" // U+F11E8
+#define ICON_MDI_FILE_EXCEL "\xf3\xb0\x88\x9b" // U+F021B
+#define ICON_MDI_FILE_EXCEL_BOX "\xf3\xb0\x88\x9c" // U+F021C
+#define ICON_MDI_FILE_EXCEL_BOX_OUTLINE "\xf3\xb1\x80\xac" // U+F102C
+#define ICON_MDI_FILE_EXCEL_OUTLINE "\xf3\xb1\x80\xad" // U+F102D
+#define ICON_MDI_FILE_EXPORT "\xf3\xb0\x88\x9d" // U+F021D
+#define ICON_MDI_FILE_EXPORT_OUTLINE "\xf3\xb1\x80\xae" // U+F102E
+#define ICON_MDI_FILE_EYE "\xf3\xb0\xb7\x8a" // U+F0DCA
+#define ICON_MDI_FILE_EYE_OUTLINE "\xf3\xb0\xb7\x8b" // U+F0DCB
+#define ICON_MDI_FILE_FIND "\xf3\xb0\x88\x9e" // U+F021E
+#define ICON_MDI_FILE_FIND_OUTLINE "\xf3\xb0\xae\x97" // U+F0B97
+#define ICON_MDI_FILE_GIF_BOX "\xf3\xb0\xb5\xb8" // U+F0D78
+#define ICON_MDI_FILE_HIDDEN "\xf3\xb0\x98\x93" // U+F0613
+#define ICON_MDI_FILE_IMAGE "\xf3\xb0\x88\x9f" // U+F021F
+#define ICON_MDI_FILE_IMAGE_MARKER "\xf3\xb1\x9d\xb2" // U+F1772
+#define ICON_MDI_FILE_IMAGE_MARKER_OUTLINE "\xf3\xb1\x9d\xb3" // U+F1773
+#define ICON_MDI_FILE_IMAGE_MINUS "\xf3\xb1\xa4\xbb" // U+F193B
+#define ICON_MDI_FILE_IMAGE_MINUS_OUTLINE "\xf3\xb1\xa4\xbc" // U+F193C
+#define ICON_MDI_FILE_IMAGE_OUTLINE "\xf3\xb0\xba\xb0" // U+F0EB0
+#define ICON_MDI_FILE_IMAGE_PLUS "\xf3\xb1\xa4\xbd" // U+F193D
+#define ICON_MDI_FILE_IMAGE_PLUS_OUTLINE "\xf3\xb1\xa4\xbe" // U+F193E
+#define ICON_MDI_FILE_IMAGE_REMOVE "\xf3\xb1\xa4\xbf" // U+F193F
+#define ICON_MDI_FILE_IMAGE_REMOVE_OUTLINE "\xf3\xb1\xa5\x80" // U+F1940
+#define ICON_MDI_FILE_IMPORT "\xf3\xb0\x88\xa0" // U+F0220
+#define ICON_MDI_FILE_IMPORT_OUTLINE "\xf3\xb1\x80\xaf" // U+F102F
+#define ICON_MDI_FILE_JPG_BOX "\xf3\xb0\x88\xa5" // U+F0225
+#define ICON_MDI_FILE_KEY "\xf3\xb1\x86\x84" // U+F1184
+#define ICON_MDI_FILE_KEY_OUTLINE "\xf3\xb1\x86\x85" // U+F1185
+#define ICON_MDI_FILE_LINK "\xf3\xb1\x85\xb7" // U+F1177
+#define ICON_MDI_FILE_LINK_OUTLINE "\xf3\xb1\x85\xb8" // U+F1178
+#define ICON_MDI_FILE_LOCK "\xf3\xb0\x88\xa1" // U+F0221
+#define ICON_MDI_FILE_LOCK_OPEN "\xf3\xb1\xa7\x88" // U+F19C8
+#define ICON_MDI_FILE_LOCK_OPEN_OUTLINE "\xf3\xb1\xa7\x89" // U+F19C9
+#define ICON_MDI_FILE_LOCK_OUTLINE "\xf3\xb1\x80\xb0" // U+F1030
+#define ICON_MDI_FILE_MARKER "\xf3\xb1\x9d\xb4" // U+F1774
+#define ICON_MDI_FILE_MARKER_OUTLINE "\xf3\xb1\x9d\xb5" // U+F1775
+#define ICON_MDI_FILE_MINUS "\xf3\xb1\xaa\xa1" // U+F1AA1
+#define ICON_MDI_FILE_MINUS_OUTLINE "\xf3\xb1\xaa\xa2" // U+F1AA2
+#define ICON_MDI_FILE_MOVE "\xf3\xb0\xaa\xb9" // U+F0AB9
+#define ICON_MDI_FILE_MOVE_OUTLINE "\xf3\xb1\x80\xb1" // U+F1031
+#define ICON_MDI_FILE_MULTIPLE "\xf3\xb0\x88\xa2" // U+F0222
+#define ICON_MDI_FILE_MULTIPLE_OUTLINE "\xf3\xb1\x80\xb2" // U+F1032
+#define ICON_MDI_FILE_MUSIC "\xf3\xb0\x88\xa3" // U+F0223
+#define ICON_MDI_FILE_MUSIC_OUTLINE "\xf3\xb0\xb8\xaa" // U+F0E2A
+#define ICON_MDI_FILE_OUTLINE "\xf3\xb0\x88\xa4" // U+F0224
+#define ICON_MDI_FILE_PDF_BOX "\xf3\xb0\x88\xa6" // U+F0226
+#define ICON_MDI_FILE_PERCENT "\xf3\xb0\xa0\x9e" // U+F081E
+#define ICON_MDI_FILE_PERCENT_OUTLINE "\xf3\xb1\x80\xb3" // U+F1033
+#define ICON_MDI_FILE_PHONE "\xf3\xb1\x85\xb9" // U+F1179
+#define ICON_MDI_FILE_PHONE_OUTLINE "\xf3\xb1\x85\xba" // U+F117A
+#define ICON_MDI_FILE_PLUS "\xf3\xb0\x9d\x92" // U+F0752
+#define ICON_MDI_FILE_PLUS_OUTLINE "\xf3\xb0\xbb\xad" // U+F0EED
+#define ICON_MDI_FILE_PNG_BOX "\xf3\xb0\xb8\xad" // U+F0E2D
+#define ICON_MDI_FILE_POWERPOINT "\xf3\xb0\x88\xa7" // U+F0227
+#define ICON_MDI_FILE_POWERPOINT_BOX "\xf3\xb0\x88\xa8" // U+F0228
+#define ICON_MDI_FILE_POWERPOINT_BOX_OUTLINE "\xf3\xb1\x80\xb4" // U+F1034
+#define ICON_MDI_FILE_POWERPOINT_OUTLINE "\xf3\xb1\x80\xb5" // U+F1035
+#define ICON_MDI_FILE_PRESENTATION_BOX "\xf3\xb0\x88\xa9" // U+F0229
+#define ICON_MDI_FILE_QUESTION "\xf3\xb0\xa1\xaf" // U+F086F
+#define ICON_MDI_FILE_QUESTION_OUTLINE "\xf3\xb1\x80\xb6" // U+F1036
+#define ICON_MDI_FILE_REFRESH "\xf3\xb0\xa4\x98" // U+F0918
+#define ICON_MDI_FILE_REFRESH_OUTLINE "\xf3\xb0\x95\x81" // U+F0541
+#define ICON_MDI_FILE_REMOVE "\xf3\xb0\xae\x98" // U+F0B98
+#define ICON_MDI_FILE_REMOVE_OUTLINE "\xf3\xb1\x80\xb7" // U+F1037
+#define ICON_MDI_FILE_REPLACE "\xf3\xb0\xac\xb2" // U+F0B32
+#define ICON_MDI_FILE_REPLACE_OUTLINE "\xf3\xb0\xac\xb3" // U+F0B33
+#define ICON_MDI_FILE_RESTORE "\xf3\xb0\x99\xb0" // U+F0670
+#define ICON_MDI_FILE_RESTORE_OUTLINE "\xf3\xb1\x80\xb8" // U+F1038
+#define ICON_MDI_FILE_ROTATE_LEFT "\xf3\xb1\xa8\xbb" // U+F1A3B
+#define ICON_MDI_FILE_ROTATE_LEFT_OUTLINE "\xf3\xb1\xa8\xbc" // U+F1A3C
+#define ICON_MDI_FILE_ROTATE_RIGHT "\xf3\xb1\xa8\xbd" // U+F1A3D
+#define ICON_MDI_FILE_ROTATE_RIGHT_OUTLINE "\xf3\xb1\xa8\xbe" // U+F1A3E
+#define ICON_MDI_FILE_SEARCH "\xf3\xb0\xb1\xbc" // U+F0C7C
+#define ICON_MDI_FILE_SEARCH_OUTLINE "\xf3\xb0\xb1\xbd" // U+F0C7D
+#define ICON_MDI_FILE_SEND "\xf3\xb0\x88\xaa" // U+F022A
+#define ICON_MDI_FILE_SEND_OUTLINE "\xf3\xb1\x80\xb9" // U+F1039
+#define ICON_MDI_FILE_SETTINGS "\xf3\xb1\x81\xb9" // U+F1079
+#define ICON_MDI_FILE_SETTINGS_OUTLINE "\xf3\xb1\x81\xba" // U+F107A
+#define ICON_MDI_FILE_SIGN "\xf3\xb1\xa7\x83" // U+F19C3
+#define ICON_MDI_FILE_STAR "\xf3\xb1\x80\xba" // U+F103A
+#define ICON_MDI_FILE_STAR_FOUR_POINTS "\xf3\xb1\xb0\xad" // U+F1C2D
+#define ICON_MDI_FILE_STAR_FOUR_POINTS_OUTLINE "\xf3\xb1\xb0\xae" // U+F1C2E
+#define ICON_MDI_FILE_STAR_OUTLINE "\xf3\xb1\x80\xbb" // U+F103B
+#define ICON_MDI_FILE_SWAP "\xf3\xb0\xbe\xb4" // U+F0FB4
+#define ICON_MDI_FILE_SWAP_OUTLINE "\xf3\xb0\xbe\xb5" // U+F0FB5
+#define ICON_MDI_FILE_SYNC "\xf3\xb1\x88\x96" // U+F1216
+#define ICON_MDI_FILE_SYNC_OUTLINE "\xf3\xb1\x88\x97" // U+F1217
+#define ICON_MDI_FILE_TABLE "\xf3\xb0\xb1\xbe" // U+F0C7E
+#define ICON_MDI_FILE_TABLE_BOX "\xf3\xb1\x83\xa1" // U+F10E1
+#define ICON_MDI_FILE_TABLE_BOX_MULTIPLE "\xf3\xb1\x83\xa2" // U+F10E2
+#define ICON_MDI_FILE_TABLE_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x83\xa3" // U+F10E3
+#define ICON_MDI_FILE_TABLE_BOX_OUTLINE "\xf3\xb1\x83\xa4" // U+F10E4
+#define ICON_MDI_FILE_TABLE_OUTLINE "\xf3\xb0\xb1\xbf" // U+F0C7F
+#define ICON_MDI_FILE_TREE "\xf3\xb0\x99\x85" // U+F0645
+#define ICON_MDI_FILE_TREE_OUTLINE "\xf3\xb1\x8f\x92" // U+F13D2
+#define ICON_MDI_FILE_UNDO "\xf3\xb0\xa3\x9c" // U+F08DC
+#define ICON_MDI_FILE_UNDO_OUTLINE "\xf3\xb1\x80\xbc" // U+F103C
+#define ICON_MDI_FILE_UPLOAD "\xf3\xb0\xa9\x8d" // U+F0A4D
+#define ICON_MDI_FILE_UPLOAD_OUTLINE "\xf3\xb0\xa9\x8e" // U+F0A4E
+#define ICON_MDI_FILE_VIDEO "\xf3\xb0\x88\xab" // U+F022B
+#define ICON_MDI_FILE_VIDEO_OUTLINE "\xf3\xb0\xb8\xac" // U+F0E2C
+#define ICON_MDI_FILE_WORD "\xf3\xb0\x88\xac" // U+F022C
+#define ICON_MDI_FILE_WORD_BOX "\xf3\xb0\x88\xad" // U+F022D
+#define ICON_MDI_FILE_WORD_BOX_OUTLINE "\xf3\xb1\x80\xbd" // U+F103D
+#define ICON_MDI_FILE_WORD_OUTLINE "\xf3\xb1\x80\xbe" // U+F103E
+#define ICON_MDI_FILE_XML_BOX "\xf3\xb1\xad\x8b" // U+F1B4B
+#define ICON_MDI_FILM "\xf3\xb0\x88\xaf" // U+F022F
+#define ICON_MDI_FILMSTRIP "\xf3\xb0\x88\xb0" // U+F0230
+#define ICON_MDI_FILMSTRIP_BOX "\xf3\xb0\x8c\xb2" // U+F0332
+#define ICON_MDI_FILMSTRIP_BOX_MULTIPLE "\xf3\xb0\xb4\x98" // U+F0D18
+#define ICON_MDI_FILMSTRIP_OFF "\xf3\xb0\x88\xb1" // U+F0231
+#define ICON_MDI_FILTER "\xf3\xb0\x88\xb2" // U+F0232
+#define ICON_MDI_FILTER_CHECK "\xf3\xb1\xa3\xac" // U+F18EC
+#define ICON_MDI_FILTER_CHECK_OUTLINE "\xf3\xb1\xa3\xad" // U+F18ED
+#define ICON_MDI_FILTER_COG "\xf3\xb1\xaa\xa3" // U+F1AA3
+#define ICON_MDI_FILTER_COG_OUTLINE "\xf3\xb1\xaa\xa4" // U+F1AA4
+#define ICON_MDI_FILTER_MENU "\xf3\xb1\x83\xa5" // U+F10E5
+#define ICON_MDI_FILTER_MENU_OUTLINE "\xf3\xb1\x83\xa6" // U+F10E6
+#define ICON_MDI_FILTER_MINUS "\xf3\xb0\xbb\xae" // U+F0EEE
+#define ICON_MDI_FILTER_MINUS_OUTLINE "\xf3\xb0\xbb\xaf" // U+F0EEF
+#define ICON_MDI_FILTER_MULTIPLE "\xf3\xb1\xa8\xbf" // U+F1A3F
+#define ICON_MDI_FILTER_MULTIPLE_OUTLINE "\xf3\xb1\xa9\x80" // U+F1A40
+#define ICON_MDI_FILTER_OFF "\xf3\xb1\x93\xaf" // U+F14EF
+#define ICON_MDI_FILTER_OFF_OUTLINE "\xf3\xb1\x93\xb0" // U+F14F0
+#define ICON_MDI_FILTER_OUTLINE "\xf3\xb0\x88\xb3" // U+F0233
+#define ICON_MDI_FILTER_PLUS "\xf3\xb0\xbb\xb0" // U+F0EF0
+#define ICON_MDI_FILTER_PLUS_OUTLINE "\xf3\xb0\xbb\xb1" // U+F0EF1
+#define ICON_MDI_FILTER_REMOVE "\xf3\xb0\x88\xb4" // U+F0234
+#define ICON_MDI_FILTER_REMOVE_OUTLINE "\xf3\xb0\x88\xb5" // U+F0235
+#define ICON_MDI_FILTER_SETTINGS "\xf3\xb1\xaa\xa5" // U+F1AA5
+#define ICON_MDI_FILTER_SETTINGS_OUTLINE "\xf3\xb1\xaa\xa6" // U+F1AA6
+#define ICON_MDI_FILTER_VARIANT "\xf3\xb0\x88\xb6" // U+F0236
+#define ICON_MDI_FILTER_VARIANT_MINUS "\xf3\xb1\x84\x92" // U+F1112
+#define ICON_MDI_FILTER_VARIANT_PLUS "\xf3\xb1\x84\x93" // U+F1113
+#define ICON_MDI_FILTER_VARIANT_REMOVE "\xf3\xb1\x80\xbf" // U+F103F
+#define ICON_MDI_FINANCE "\xf3\xb0\xa0\x9f" // U+F081F
+#define ICON_MDI_FIND_REPLACE "\xf3\xb0\x9b\x94" // U+F06D4
+#define ICON_MDI_FINGERPRINT "\xf3\xb0\x88\xb7" // U+F0237
+#define ICON_MDI_FINGERPRINT_OFF "\xf3\xb0\xba\xb1" // U+F0EB1
+#define ICON_MDI_FIRE "\xf3\xb0\x88\xb8" // U+F0238
+#define ICON_MDI_FIRE_ALERT "\xf3\xb1\x97\x97" // U+F15D7
+#define ICON_MDI_FIRE_CIRCLE "\xf3\xb1\xa0\x87" // U+F1807
+#define ICON_MDI_FIRE_EXTINGUISHER "\xf3\xb0\xbb\xb2" // U+F0EF2
+#define ICON_MDI_FIRE_HYDRANT "\xf3\xb1\x84\xb7" // U+F1137
+#define ICON_MDI_FIRE_HYDRANT_ALERT "\xf3\xb1\x84\xb8" // U+F1138
+#define ICON_MDI_FIRE_HYDRANT_OFF "\xf3\xb1\x84\xb9" // U+F1139
+#define ICON_MDI_FIRE_OFF "\xf3\xb1\x9c\xa2" // U+F1722
+#define ICON_MDI_FIRE_STATION "\xf3\xb1\xb3\x83" // U+F1CC3
+#define ICON_MDI_FIRE_TRUCK "\xf3\xb0\xa2\xab" // U+F08AB
+#define ICON_MDI_FIREBASE "\xf3\xb0\xa5\xa7" // U+F0967
+#define ICON_MDI_FIREFOX "\xf3\xb0\x88\xb9" // U+F0239
+#define ICON_MDI_FIREPLACE "\xf3\xb0\xb8\xae" // U+F0E2E
+#define ICON_MDI_FIREPLACE_OFF "\xf3\xb0\xb8\xaf" // U+F0E2F
+#define ICON_MDI_FIREWIRE "\xf3\xb0\x96\xbe" // U+F05BE
+#define ICON_MDI_FIREWORK "\xf3\xb0\xb8\xb0" // U+F0E30
+#define ICON_MDI_FIREWORK_OFF "\xf3\xb1\x9c\xa3" // U+F1723
+#define ICON_MDI_FISH "\xf3\xb0\x88\xba" // U+F023A
+#define ICON_MDI_FISH_OFF "\xf3\xb1\x8f\xb3" // U+F13F3
+#define ICON_MDI_FISHBOWL "\xf3\xb0\xbb\xb3" // U+F0EF3
+#define ICON_MDI_FISHBOWL_OUTLINE "\xf3\xb0\xbb\xb4" // U+F0EF4
+#define ICON_MDI_FIT_TO_PAGE "\xf3\xb0\xbb\xb5" // U+F0EF5
+#define ICON_MDI_FIT_TO_PAGE_OUTLINE "\xf3\xb0\xbb\xb6" // U+F0EF6
+#define ICON_MDI_FIT_TO_SCREEN "\xf3\xb1\xa3\xb4" // U+F18F4
+#define ICON_MDI_FIT_TO_SCREEN_OUTLINE "\xf3\xb1\xa3\xb5" // U+F18F5
+#define ICON_MDI_FLAG "\xf3\xb0\x88\xbb" // U+F023B
+#define ICON_MDI_FLAG_CHECKERED "\xf3\xb0\x88\xbc" // U+F023C
+#define ICON_MDI_FLAG_MINUS "\xf3\xb0\xae\x99" // U+F0B99
+#define ICON_MDI_FLAG_MINUS_OUTLINE "\xf3\xb1\x82\xb2" // U+F10B2
+#define ICON_MDI_FLAG_OFF "\xf3\xb1\xa3\xae" // U+F18EE
+#define ICON_MDI_FLAG_OFF_OUTLINE "\xf3\xb1\xa3\xaf" // U+F18EF
+#define ICON_MDI_FLAG_OUTLINE "\xf3\xb0\x88\xbd" // U+F023D
+#define ICON_MDI_FLAG_PLUS "\xf3\xb0\xae\x9a" // U+F0B9A
+#define ICON_MDI_FLAG_PLUS_OUTLINE "\xf3\xb1\x82\xb3" // U+F10B3
+#define ICON_MDI_FLAG_REMOVE "\xf3\xb0\xae\x9b" // U+F0B9B
+#define ICON_MDI_FLAG_REMOVE_OUTLINE "\xf3\xb1\x82\xb4" // U+F10B4
+#define ICON_MDI_FLAG_TRIANGLE "\xf3\xb0\x88\xbf" // U+F023F
+#define ICON_MDI_FLAG_VARIANT "\xf3\xb0\x89\x80" // U+F0240
+#define ICON_MDI_FLAG_VARIANT_MINUS "\xf3\xb1\xae\xb4" // U+F1BB4
+#define ICON_MDI_FLAG_VARIANT_MINUS_OUTLINE "\xf3\xb1\xae\xb5" // U+F1BB5
+#define ICON_MDI_FLAG_VARIANT_OFF "\xf3\xb1\xae\xb0" // U+F1BB0
+#define ICON_MDI_FLAG_VARIANT_OFF_OUTLINE "\xf3\xb1\xae\xb1" // U+F1BB1
+#define ICON_MDI_FLAG_VARIANT_OUTLINE "\xf3\xb0\x88\xbe" // U+F023E
+#define ICON_MDI_FLAG_VARIANT_PLUS "\xf3\xb1\xae\xb2" // U+F1BB2
+#define ICON_MDI_FLAG_VARIANT_PLUS_OUTLINE "\xf3\xb1\xae\xb3" // U+F1BB3
+#define ICON_MDI_FLAG_VARIANT_REMOVE "\xf3\xb1\xae\xb6" // U+F1BB6
+#define ICON_MDI_FLAG_VARIANT_REMOVE_OUTLINE "\xf3\xb1\xae\xb7" // U+F1BB7
+#define ICON_MDI_FLARE "\xf3\xb0\xb5\xb2" // U+F0D72
+#define ICON_MDI_FLASH "\xf3\xb0\x89\x81" // U+F0241
+#define ICON_MDI_FLASH_ALERT "\xf3\xb0\xbb\xb7" // U+F0EF7
+#define ICON_MDI_FLASH_ALERT_OUTLINE "\xf3\xb0\xbb\xb8" // U+F0EF8
+#define ICON_MDI_FLASH_AUTO "\xf3\xb0\x89\x82" // U+F0242
+#define ICON_MDI_FLASH_OFF "\xf3\xb0\x89\x83" // U+F0243
+#define ICON_MDI_FLASH_OFF_OUTLINE "\xf3\xb1\xad\x85" // U+F1B45
+#define ICON_MDI_FLASH_OUTLINE "\xf3\xb0\x9b\x95" // U+F06D5
+#define ICON_MDI_FLASH_RED_EYE "\xf3\xb0\x99\xbb" // U+F067B
+#define ICON_MDI_FLASH_TRIANGLE "\xf3\xb1\xac\x9d" // U+F1B1D
+#define ICON_MDI_FLASH_TRIANGLE_OUTLINE "\xf3\xb1\xac\x9e" // U+F1B1E
+#define ICON_MDI_FLASHLIGHT "\xf3\xb0\x89\x84" // U+F0244
+#define ICON_MDI_FLASHLIGHT_OFF "\xf3\xb0\x89\x85" // U+F0245
+#define ICON_MDI_FLASK "\xf3\xb0\x82\x93" // U+F0093
+#define ICON_MDI_FLASK_EMPTY "\xf3\xb0\x82\x94" // U+F0094
+#define ICON_MDI_FLASK_EMPTY_MINUS "\xf3\xb1\x88\xba" // U+F123A
+#define ICON_MDI_FLASK_EMPTY_MINUS_OUTLINE "\xf3\xb1\x88\xbb" // U+F123B
+#define ICON_MDI_FLASK_EMPTY_OFF "\xf3\xb1\x8f\xb4" // U+F13F4
+#define ICON_MDI_FLASK_EMPTY_OFF_OUTLINE "\xf3\xb1\x8f\xb5" // U+F13F5
+#define ICON_MDI_FLASK_EMPTY_OUTLINE "\xf3\xb0\x82\x95" // U+F0095
+#define ICON_MDI_FLASK_EMPTY_PLUS "\xf3\xb1\x88\xbc" // U+F123C
+#define ICON_MDI_FLASK_EMPTY_PLUS_OUTLINE "\xf3\xb1\x88\xbd" // U+F123D
+#define ICON_MDI_FLASK_EMPTY_REMOVE "\xf3\xb1\x88\xbe" // U+F123E
+#define ICON_MDI_FLASK_EMPTY_REMOVE_OUTLINE "\xf3\xb1\x88\xbf" // U+F123F
+#define ICON_MDI_FLASK_MINUS "\xf3\xb1\x89\x80" // U+F1240
+#define ICON_MDI_FLASK_MINUS_OUTLINE "\xf3\xb1\x89\x81" // U+F1241
+#define ICON_MDI_FLASK_OFF "\xf3\xb1\x8f\xb6" // U+F13F6
+#define ICON_MDI_FLASK_OFF_OUTLINE "\xf3\xb1\x8f\xb7" // U+F13F7
+#define ICON_MDI_FLASK_OUTLINE "\xf3\xb0\x82\x96" // U+F0096
+#define ICON_MDI_FLASK_PLUS "\xf3\xb1\x89\x82" // U+F1242
+#define ICON_MDI_FLASK_PLUS_OUTLINE "\xf3\xb1\x89\x83" // U+F1243
+#define ICON_MDI_FLASK_REMOVE "\xf3\xb1\x89\x84" // U+F1244
+#define ICON_MDI_FLASK_REMOVE_OUTLINE "\xf3\xb1\x89\x85" // U+F1245
+#define ICON_MDI_FLASK_ROUND_BOTTOM "\xf3\xb1\x89\x8b" // U+F124B
+#define ICON_MDI_FLASK_ROUND_BOTTOM_EMPTY "\xf3\xb1\x89\x8c" // U+F124C
+#define ICON_MDI_FLASK_ROUND_BOTTOM_EMPTY_OUTLINE "\xf3\xb1\x89\x8d" // U+F124D
+#define ICON_MDI_FLASK_ROUND_BOTTOM_OUTLINE "\xf3\xb1\x89\x8e" // U+F124E
+#define ICON_MDI_FLEUR_DE_LIS "\xf3\xb1\x8c\x83" // U+F1303
+#define ICON_MDI_FLIP_HORIZONTAL "\xf3\xb1\x83\xa7" // U+F10E7
+#define ICON_MDI_FLIP_TO_BACK "\xf3\xb0\x89\x87" // U+F0247
+#define ICON_MDI_FLIP_TO_FRONT "\xf3\xb0\x89\x88" // U+F0248
+#define ICON_MDI_FLIP_VERTICAL "\xf3\xb1\x83\xa8" // U+F10E8
+#define ICON_MDI_FLOOR_LAMP "\xf3\xb0\xa3\x9d" // U+F08DD
+#define ICON_MDI_FLOOR_LAMP_DUAL "\xf3\xb1\x81\x80" // U+F1040
+#define ICON_MDI_FLOOR_LAMP_DUAL_OUTLINE "\xf3\xb1\x9f\x8e" // U+F17CE
+#define ICON_MDI_FLOOR_LAMP_OUTLINE "\xf3\xb1\x9f\x88" // U+F17C8
+#define ICON_MDI_FLOOR_LAMP_TORCHIERE "\xf3\xb1\x9d\x87" // U+F1747
+#define ICON_MDI_FLOOR_LAMP_TORCHIERE_OUTLINE "\xf3\xb1\x9f\x96" // U+F17D6
+#define ICON_MDI_FLOOR_LAMP_TORCHIERE_VARIANT "\xf3\xb1\x81\x81" // U+F1041
+#define ICON_MDI_FLOOR_LAMP_TORCHIERE_VARIANT_OUTLINE "\xf3\xb1\x9f\x8f" // U+F17CF
+#define ICON_MDI_FLOOR_PLAN "\xf3\xb0\xa0\xa1" // U+F0821
+#define ICON_MDI_FLOPPY "\xf3\xb0\x89\x89" // U+F0249
+#define ICON_MDI_FLOPPY_VARIANT "\xf3\xb0\xa7\xaf" // U+F09EF
+#define ICON_MDI_FLOWER "\xf3\xb0\x89\x8a" // U+F024A
+#define ICON_MDI_FLOWER_OUTLINE "\xf3\xb0\xa7\xb0" // U+F09F0
+#define ICON_MDI_FLOWER_POLLEN "\xf3\xb1\xa2\x85" // U+F1885
+#define ICON_MDI_FLOWER_POLLEN_OUTLINE "\xf3\xb1\xa2\x86" // U+F1886
+#define ICON_MDI_FLOWER_POPPY "\xf3\xb0\xb4\x88" // U+F0D08
+#define ICON_MDI_FLOWER_TULIP "\xf3\xb0\xa7\xb1" // U+F09F1
+#define ICON_MDI_FLOWER_TULIP_OUTLINE "\xf3\xb0\xa7\xb2" // U+F09F2
+#define ICON_MDI_FOCUS_AUTO "\xf3\xb0\xbd\x8e" // U+F0F4E
+#define ICON_MDI_FOCUS_FIELD "\xf3\xb0\xbd\x8f" // U+F0F4F
+#define ICON_MDI_FOCUS_FIELD_HORIZONTAL "\xf3\xb0\xbd\x90" // U+F0F50
+#define ICON_MDI_FOCUS_FIELD_VERTICAL "\xf3\xb0\xbd\x91" // U+F0F51
+#define ICON_MDI_FOLDER "\xf3\xb0\x89\x8b" // U+F024B
+#define ICON_MDI_FOLDER_ACCOUNT "\xf3\xb0\x89\x8c" // U+F024C
+#define ICON_MDI_FOLDER_ACCOUNT_OUTLINE "\xf3\xb0\xae\x9c" // U+F0B9C
+#define ICON_MDI_FOLDER_ALERT "\xf3\xb0\xb7\x8c" // U+F0DCC
+#define ICON_MDI_FOLDER_ALERT_OUTLINE "\xf3\xb0\xb7\x8d" // U+F0DCD
+#define ICON_MDI_FOLDER_ARROW_DOWN "\xf3\xb1\xa7\xa8" // U+F19E8
+#define ICON_MDI_FOLDER_ARROW_DOWN_OUTLINE "\xf3\xb1\xa7\xa9" // U+F19E9
+#define ICON_MDI_FOLDER_ARROW_LEFT "\xf3\xb1\xa7\xaa" // U+F19EA
+#define ICON_MDI_FOLDER_ARROW_LEFT_OUTLINE "\xf3\xb1\xa7\xab" // U+F19EB
+#define ICON_MDI_FOLDER_ARROW_LEFT_RIGHT "\xf3\xb1\xa7\xac" // U+F19EC
+#define ICON_MDI_FOLDER_ARROW_LEFT_RIGHT_OUTLINE "\xf3\xb1\xa7\xad" // U+F19ED
+#define ICON_MDI_FOLDER_ARROW_RIGHT "\xf3\xb1\xa7\xae" // U+F19EE
+#define ICON_MDI_FOLDER_ARROW_RIGHT_OUTLINE "\xf3\xb1\xa7\xaf" // U+F19EF
+#define ICON_MDI_FOLDER_ARROW_UP "\xf3\xb1\xa7\xb0" // U+F19F0
+#define ICON_MDI_FOLDER_ARROW_UP_DOWN "\xf3\xb1\xa7\xb1" // U+F19F1
+#define ICON_MDI_FOLDER_ARROW_UP_DOWN_OUTLINE "\xf3\xb1\xa7\xb2" // U+F19F2
+#define ICON_MDI_FOLDER_ARROW_UP_OUTLINE "\xf3\xb1\xa7\xb3" // U+F19F3
+#define ICON_MDI_FOLDER_CANCEL "\xf3\xb1\xa7\xb4" // U+F19F4
+#define ICON_MDI_FOLDER_CANCEL_OUTLINE "\xf3\xb1\xa7\xb5" // U+F19F5
+#define ICON_MDI_FOLDER_CHECK "\xf3\xb1\xa5\xbe" // U+F197E
+#define ICON_MDI_FOLDER_CHECK_OUTLINE "\xf3\xb1\xa5\xbf" // U+F197F
+#define ICON_MDI_FOLDER_CLOCK "\xf3\xb0\xaa\xba" // U+F0ABA
+#define ICON_MDI_FOLDER_CLOCK_OUTLINE "\xf3\xb0\xaa\xbb" // U+F0ABB
+#define ICON_MDI_FOLDER_COG "\xf3\xb1\x81\xbf" // U+F107F
+#define ICON_MDI_FOLDER_COG_OUTLINE "\xf3\xb1\x82\x80" // U+F1080
+#define ICON_MDI_FOLDER_DOWNLOAD "\xf3\xb0\x89\x8d" // U+F024D
+#define ICON_MDI_FOLDER_DOWNLOAD_OUTLINE "\xf3\xb1\x83\xa9" // U+F10E9
+#define ICON_MDI_FOLDER_EDIT "\xf3\xb0\xa3\x9e" // U+F08DE
+#define ICON_MDI_FOLDER_EDIT_OUTLINE "\xf3\xb0\xb7\x8e" // U+F0DCE
+#define ICON_MDI_FOLDER_EYE "\xf3\xb1\x9e\x8a" // U+F178A
+#define ICON_MDI_FOLDER_EYE_OUTLINE "\xf3\xb1\x9e\x8b" // U+F178B
+#define ICON_MDI_FOLDER_FILE "\xf3\xb1\xa7\xb6" // U+F19F6
+#define ICON_MDI_FOLDER_FILE_OUTLINE "\xf3\xb1\xa7\xb7" // U+F19F7
+#define ICON_MDI_FOLDER_GOOGLE_DRIVE "\xf3\xb0\x89\x8e" // U+F024E
+#define ICON_MDI_FOLDER_HEART "\xf3\xb1\x83\xaa" // U+F10EA
+#define ICON_MDI_FOLDER_HEART_OUTLINE "\xf3\xb1\x83\xab" // U+F10EB
+#define ICON_MDI_FOLDER_HIDDEN "\xf3\xb1\x9e\x9e" // U+F179E
+#define ICON_MDI_FOLDER_HOME "\xf3\xb1\x82\xb5" // U+F10B5
+#define ICON_MDI_FOLDER_HOME_OUTLINE "\xf3\xb1\x82\xb6" // U+F10B6
+#define ICON_MDI_FOLDER_IMAGE "\xf3\xb0\x89\x8f" // U+F024F
+#define ICON_MDI_FOLDER_INFORMATION "\xf3\xb1\x82\xb7" // U+F10B7
+#define ICON_MDI_FOLDER_INFORMATION_OUTLINE "\xf3\xb1\x82\xb8" // U+F10B8
+#define ICON_MDI_FOLDER_KEY "\xf3\xb0\xa2\xac" // U+F08AC
+#define ICON_MDI_FOLDER_KEY_NETWORK "\xf3\xb0\xa2\xad" // U+F08AD
+#define ICON_MDI_FOLDER_KEY_NETWORK_OUTLINE "\xf3\xb0\xb2\x80" // U+F0C80
+#define ICON_MDI_FOLDER_KEY_OUTLINE "\xf3\xb1\x83\xac" // U+F10EC
+#define ICON_MDI_FOLDER_LOCK "\xf3\xb0\x89\x90" // U+F0250
+#define ICON_MDI_FOLDER_LOCK_OPEN "\xf3\xb0\x89\x91" // U+F0251
+#define ICON_MDI_FOLDER_LOCK_OPEN_OUTLINE "\xf3\xb1\xaa\xa7" // U+F1AA7
+#define ICON_MDI_FOLDER_LOCK_OUTLINE "\xf3\xb1\xaa\xa8" // U+F1AA8
+#define ICON_MDI_FOLDER_MARKER "\xf3\xb1\x89\xad" // U+F126D
+#define ICON_MDI_FOLDER_MARKER_OUTLINE "\xf3\xb1\x89\xae" // U+F126E
+#define ICON_MDI_FOLDER_MINUS "\xf3\xb1\xad\x89" // U+F1B49
+#define ICON_MDI_FOLDER_MINUS_OUTLINE "\xf3\xb1\xad\x8a" // U+F1B4A
+#define ICON_MDI_FOLDER_MOVE "\xf3\xb0\x89\x92" // U+F0252
+#define ICON_MDI_FOLDER_MOVE_OUTLINE "\xf3\xb1\x89\x86" // U+F1246
+#define ICON_MDI_FOLDER_MULTIPLE "\xf3\xb0\x89\x93" // U+F0253
+#define ICON_MDI_FOLDER_MULTIPLE_IMAGE "\xf3\xb0\x89\x94" // U+F0254
+#define ICON_MDI_FOLDER_MULTIPLE_OUTLINE "\xf3\xb0\x89\x95" // U+F0255
+#define ICON_MDI_FOLDER_MULTIPLE_PLUS "\xf3\xb1\x91\xbe" // U+F147E
+#define ICON_MDI_FOLDER_MULTIPLE_PLUS_OUTLINE "\xf3\xb1\x91\xbf" // U+F147F
+#define ICON_MDI_FOLDER_MUSIC "\xf3\xb1\x8d\x99" // U+F1359
+#define ICON_MDI_FOLDER_MUSIC_OUTLINE "\xf3\xb1\x8d\x9a" // U+F135A
+#define ICON_MDI_FOLDER_NETWORK "\xf3\xb0\xa1\xb0" // U+F0870
+#define ICON_MDI_FOLDER_NETWORK_OUTLINE "\xf3\xb0\xb2\x81" // U+F0C81
+#define ICON_MDI_FOLDER_OFF "\xf3\xb1\xa7\xb8" // U+F19F8
+#define ICON_MDI_FOLDER_OFF_OUTLINE "\xf3\xb1\xa7\xb9" // U+F19F9
+#define ICON_MDI_FOLDER_OPEN "\xf3\xb0\x9d\xb0" // U+F0770
+#define ICON_MDI_FOLDER_OPEN_OUTLINE "\xf3\xb0\xb7\x8f" // U+F0DCF
+#define ICON_MDI_FOLDER_OUTLINE "\xf3\xb0\x89\x96" // U+F0256
+#define ICON_MDI_FOLDER_PLAY "\xf3\xb1\xa7\xba" // U+F19FA
+#define ICON_MDI_FOLDER_PLAY_OUTLINE "\xf3\xb1\xa7\xbb" // U+F19FB
+#define ICON_MDI_FOLDER_PLUS "\xf3\xb0\x89\x97" // U+F0257
+#define ICON_MDI_FOLDER_PLUS_OUTLINE "\xf3\xb0\xae\x9d" // U+F0B9D
+#define ICON_MDI_FOLDER_POUND "\xf3\xb0\xb4\x89" // U+F0D09
+#define ICON_MDI_FOLDER_POUND_OUTLINE "\xf3\xb0\xb4\x8a" // U+F0D0A
+#define ICON_MDI_FOLDER_QUESTION "\xf3\xb1\xa7\x8a" // U+F19CA
+#define ICON_MDI_FOLDER_QUESTION_OUTLINE "\xf3\xb1\xa7\x8b" // U+F19CB
+#define ICON_MDI_FOLDER_REFRESH "\xf3\xb0\x9d\x89" // U+F0749
+#define ICON_MDI_FOLDER_REFRESH_OUTLINE "\xf3\xb0\x95\x82" // U+F0542
+#define ICON_MDI_FOLDER_REMOVE "\xf3\xb0\x89\x98" // U+F0258
+#define ICON_MDI_FOLDER_REMOVE_OUTLINE "\xf3\xb0\xae\x9e" // U+F0B9E
+#define ICON_MDI_FOLDER_SEARCH "\xf3\xb0\xa5\xa8" // U+F0968
+#define ICON_MDI_FOLDER_SEARCH_OUTLINE "\xf3\xb0\xa5\xa9" // U+F0969
+#define ICON_MDI_FOLDER_SETTINGS "\xf3\xb1\x81\xbd" // U+F107D
+#define ICON_MDI_FOLDER_SETTINGS_OUTLINE "\xf3\xb1\x81\xbe" // U+F107E
+#define ICON_MDI_FOLDER_STAR "\xf3\xb0\x9a\x9d" // U+F069D
+#define ICON_MDI_FOLDER_STAR_MULTIPLE "\xf3\xb1\x8f\x93" // U+F13D3
+#define ICON_MDI_FOLDER_STAR_MULTIPLE_OUTLINE "\xf3\xb1\x8f\x94" // U+F13D4
+#define ICON_MDI_FOLDER_STAR_OUTLINE "\xf3\xb0\xae\x9f" // U+F0B9F
+#define ICON_MDI_FOLDER_SWAP "\xf3\xb0\xbe\xb6" // U+F0FB6
+#define ICON_MDI_FOLDER_SWAP_OUTLINE "\xf3\xb0\xbe\xb7" // U+F0FB7
+#define ICON_MDI_FOLDER_SYNC "\xf3\xb0\xb4\x8b" // U+F0D0B
+#define ICON_MDI_FOLDER_SYNC_OUTLINE "\xf3\xb0\xb4\x8c" // U+F0D0C
+#define ICON_MDI_FOLDER_TABLE "\xf3\xb1\x8b\xa3" // U+F12E3
+#define ICON_MDI_FOLDER_TABLE_OUTLINE "\xf3\xb1\x8b\xa4" // U+F12E4
+#define ICON_MDI_FOLDER_TEXT "\xf3\xb0\xb2\x82" // U+F0C82
+#define ICON_MDI_FOLDER_TEXT_OUTLINE "\xf3\xb0\xb2\x83" // U+F0C83
+#define ICON_MDI_FOLDER_UPLOAD "\xf3\xb0\x89\x99" // U+F0259
+#define ICON_MDI_FOLDER_UPLOAD_OUTLINE "\xf3\xb1\x83\xad" // U+F10ED
+#define ICON_MDI_FOLDER_WRENCH "\xf3\xb1\xa7\xbc" // U+F19FC
+#define ICON_MDI_FOLDER_WRENCH_OUTLINE "\xf3\xb1\xa7\xbd" // U+F19FD
+#define ICON_MDI_FOLDER_ZIP "\xf3\xb0\x9b\xab" // U+F06EB
+#define ICON_MDI_FOLDER_ZIP_OUTLINE "\xf3\xb0\x9e\xb9" // U+F07B9
+#define ICON_MDI_FONT_AWESOME "\xf3\xb0\x80\xba" // U+F003A
+#define ICON_MDI_FOOD "\xf3\xb0\x89\x9a" // U+F025A
+#define ICON_MDI_FOOD_APPLE "\xf3\xb0\x89\x9b" // U+F025B
+#define ICON_MDI_FOOD_APPLE_OUTLINE "\xf3\xb0\xb2\x84" // U+F0C84
+#define ICON_MDI_FOOD_CROISSANT "\xf3\xb0\x9f\x88" // U+F07C8
+#define ICON_MDI_FOOD_DRUMSTICK "\xf3\xb1\x90\x9f" // U+F141F
+#define ICON_MDI_FOOD_DRUMSTICK_OFF "\xf3\xb1\x91\xa8" // U+F1468
+#define ICON_MDI_FOOD_DRUMSTICK_OFF_OUTLINE "\xf3\xb1\x91\xa9" // U+F1469
+#define ICON_MDI_FOOD_DRUMSTICK_OUTLINE "\xf3\xb1\x90\xa0" // U+F1420
+#define ICON_MDI_FOOD_FORK_DRINK "\xf3\xb0\x97\xb2" // U+F05F2
+#define ICON_MDI_FOOD_HALAL "\xf3\xb1\x95\xb2" // U+F1572
+#define ICON_MDI_FOOD_HOT_DOG "\xf3\xb1\xa1\x8b" // U+F184B
+#define ICON_MDI_FOOD_KOSHER "\xf3\xb1\x95\xb3" // U+F1573
+#define ICON_MDI_FOOD_OFF "\xf3\xb0\x97\xb3" // U+F05F3
+#define ICON_MDI_FOOD_OFF_OUTLINE "\xf3\xb1\xa4\x95" // U+F1915
+#define ICON_MDI_FOOD_OUTLINE "\xf3\xb1\xa4\x96" // U+F1916
+#define ICON_MDI_FOOD_STEAK "\xf3\xb1\x91\xaa" // U+F146A
+#define ICON_MDI_FOOD_STEAK_OFF "\xf3\xb1\x91\xab" // U+F146B
+#define ICON_MDI_FOOD_TAKEOUT_BOX "\xf3\xb1\xa0\xb6" // U+F1836
+#define ICON_MDI_FOOD_TAKEOUT_BOX_OUTLINE "\xf3\xb1\xa0\xb7" // U+F1837
+#define ICON_MDI_FOOD_TURKEY "\xf3\xb1\x9c\x9c" // U+F171C
+#define ICON_MDI_FOOD_VARIANT "\xf3\xb0\x89\x9c" // U+F025C
+#define ICON_MDI_FOOD_VARIANT_OFF "\xf3\xb1\x8f\xa5" // U+F13E5
+#define ICON_MDI_FOOT_PRINT "\xf3\xb0\xbd\x92" // U+F0F52
+#define ICON_MDI_FOOTBALL "\xf3\xb0\x89\x9d" // U+F025D
+#define ICON_MDI_FOOTBALL_AUSTRALIAN "\xf3\xb0\x89\x9e" // U+F025E
+#define ICON_MDI_FOOTBALL_HELMET "\xf3\xb0\x89\x9f" // U+F025F
+#define ICON_MDI_FOREST "\xf3\xb1\xa2\x97" // U+F1897
+#define ICON_MDI_FOREST_OUTLINE "\xf3\xb1\xb1\xa3" // U+F1C63
+#define ICON_MDI_FORKLIFT "\xf3\xb0\x9f\x89" // U+F07C9
+#define ICON_MDI_FORM_DROPDOWN "\xf3\xb1\x90\x80" // U+F1400
+#define ICON_MDI_FORM_SELECT "\xf3\xb1\x90\x81" // U+F1401
+#define ICON_MDI_FORM_TEXTAREA "\xf3\xb1\x82\x95" // U+F1095
+#define ICON_MDI_FORM_TEXTBOX "\xf3\xb0\x98\x8e" // U+F060E
+#define ICON_MDI_FORM_TEXTBOX_LOCK "\xf3\xb1\x8d\x9d" // U+F135D
+#define ICON_MDI_FORM_TEXTBOX_PASSWORD "\xf3\xb0\x9f\xb5" // U+F07F5
+#define ICON_MDI_FORMAT_ALIGN_BOTTOM "\xf3\xb0\x9d\x93" // U+F0753
+#define ICON_MDI_FORMAT_ALIGN_CENTER "\xf3\xb0\x89\xa0" // U+F0260
+#define ICON_MDI_FORMAT_ALIGN_JUSTIFY "\xf3\xb0\x89\xa1" // U+F0261
+#define ICON_MDI_FORMAT_ALIGN_LEFT "\xf3\xb0\x89\xa2" // U+F0262
+#define ICON_MDI_FORMAT_ALIGN_MIDDLE "\xf3\xb0\x9d\x94" // U+F0754
+#define ICON_MDI_FORMAT_ALIGN_RIGHT "\xf3\xb0\x89\xa3" // U+F0263
+#define ICON_MDI_FORMAT_ALIGN_TOP "\xf3\xb0\x9d\x95" // U+F0755
+#define ICON_MDI_FORMAT_ANNOTATION_MINUS "\xf3\xb0\xaa\xbc" // U+F0ABC
+#define ICON_MDI_FORMAT_ANNOTATION_PLUS "\xf3\xb0\x99\x86" // U+F0646
+#define ICON_MDI_FORMAT_BOLD "\xf3\xb0\x89\xa4" // U+F0264
+#define ICON_MDI_FORMAT_CLEAR "\xf3\xb0\x89\xa5" // U+F0265
+#define ICON_MDI_FORMAT_COLOR_FILL "\xf3\xb0\x89\xa6" // U+F0266
+#define ICON_MDI_FORMAT_COLOR_HIGHLIGHT "\xf3\xb0\xb8\xb1" // U+F0E31
+#define ICON_MDI_FORMAT_COLOR_MARKER_CANCEL "\xf3\xb1\x8c\x93" // U+F1313
+#define ICON_MDI_FORMAT_COLOR_TEXT "\xf3\xb0\x9a\x9e" // U+F069E
+#define ICON_MDI_FORMAT_COLUMNS "\xf3\xb0\xa3\x9f" // U+F08DF
+#define ICON_MDI_FORMAT_FLOAT_CENTER "\xf3\xb0\x89\xa7" // U+F0267
+#define ICON_MDI_FORMAT_FLOAT_LEFT "\xf3\xb0\x89\xa8" // U+F0268
+#define ICON_MDI_FORMAT_FLOAT_NONE "\xf3\xb0\x89\xa9" // U+F0269
+#define ICON_MDI_FORMAT_FLOAT_RIGHT "\xf3\xb0\x89\xaa" // U+F026A
+#define ICON_MDI_FORMAT_FONT "\xf3\xb0\x9b\x96" // U+F06D6
+#define ICON_MDI_FORMAT_FONT_SIZE_DECREASE "\xf3\xb0\xa7\xb3" // U+F09F3
+#define ICON_MDI_FORMAT_FONT_SIZE_INCREASE "\xf3\xb0\xa7\xb4" // U+F09F4
+#define ICON_MDI_FORMAT_HEADER_1 "\xf3\xb0\x89\xab" // U+F026B
+#define ICON_MDI_FORMAT_HEADER_2 "\xf3\xb0\x89\xac" // U+F026C
+#define ICON_MDI_FORMAT_HEADER_3 "\xf3\xb0\x89\xad" // U+F026D
+#define ICON_MDI_FORMAT_HEADER_4 "\xf3\xb0\x89\xae" // U+F026E
+#define ICON_MDI_FORMAT_HEADER_5 "\xf3\xb0\x89\xaf" // U+F026F
+#define ICON_MDI_FORMAT_HEADER_6 "\xf3\xb0\x89\xb0" // U+F0270
+#define ICON_MDI_FORMAT_HEADER_DECREASE "\xf3\xb0\x89\xb1" // U+F0271
+#define ICON_MDI_FORMAT_HEADER_EQUAL "\xf3\xb0\x89\xb2" // U+F0272
+#define ICON_MDI_FORMAT_HEADER_INCREASE "\xf3\xb0\x89\xb3" // U+F0273
+#define ICON_MDI_FORMAT_HEADER_POUND "\xf3\xb0\x89\xb4" // U+F0274
+#define ICON_MDI_FORMAT_HORIZONTAL_ALIGN_CENTER "\xf3\xb0\x98\x9e" // U+F061E
+#define ICON_MDI_FORMAT_HORIZONTAL_ALIGN_LEFT "\xf3\xb0\x98\x9f" // U+F061F
+#define ICON_MDI_FORMAT_HORIZONTAL_ALIGN_RIGHT "\xf3\xb0\x98\xa0" // U+F0620
+#define ICON_MDI_FORMAT_INDENT_DECREASE "\xf3\xb0\x89\xb5" // U+F0275
+#define ICON_MDI_FORMAT_INDENT_INCREASE "\xf3\xb0\x89\xb6" // U+F0276
+#define ICON_MDI_FORMAT_ITALIC "\xf3\xb0\x89\xb7" // U+F0277
+#define ICON_MDI_FORMAT_LETTER_CASE "\xf3\xb0\xac\xb4" // U+F0B34
+#define ICON_MDI_FORMAT_LETTER_CASE_LOWER "\xf3\xb0\xac\xb5" // U+F0B35
+#define ICON_MDI_FORMAT_LETTER_CASE_UPPER "\xf3\xb0\xac\xb6" // U+F0B36
+#define ICON_MDI_FORMAT_LETTER_ENDS_WITH "\xf3\xb0\xbe\xb8" // U+F0FB8
+#define ICON_MDI_FORMAT_LETTER_MATCHES "\xf3\xb0\xbe\xb9" // U+F0FB9
+#define ICON_MDI_FORMAT_LETTER_SPACING "\xf3\xb1\xa5\x96" // U+F1956
+#define ICON_MDI_FORMAT_LETTER_SPACING_VARIANT "\xf3\xb1\xab\xbb" // U+F1AFB
+#define ICON_MDI_FORMAT_LETTER_STARTS_WITH "\xf3\xb0\xbe\xba" // U+F0FBA
+#define ICON_MDI_FORMAT_LINE_HEIGHT "\xf3\xb1\xab\xbc" // U+F1AFC
+#define ICON_MDI_FORMAT_LINE_SPACING "\xf3\xb0\x89\xb8" // U+F0278
+#define ICON_MDI_FORMAT_LINE_STYLE "\xf3\xb0\x97\x88" // U+F05C8
+#define ICON_MDI_FORMAT_LINE_WEIGHT "\xf3\xb0\x97\x89" // U+F05C9
+#define ICON_MDI_FORMAT_LIST_BULLETED "\xf3\xb0\x89\xb9" // U+F0279
+#define ICON_MDI_FORMAT_LIST_BULLETED_SQUARE "\xf3\xb0\xb7\x90" // U+F0DD0
+#define ICON_MDI_FORMAT_LIST_BULLETED_TRIANGLE "\xf3\xb0\xba\xb2" // U+F0EB2
+#define ICON_MDI_FORMAT_LIST_BULLETED_TYPE "\xf3\xb0\x89\xba" // U+F027A
+#define ICON_MDI_FORMAT_LIST_CHECKBOX "\xf3\xb0\xa5\xaa" // U+F096A
+#define ICON_MDI_FORMAT_LIST_CHECKS "\xf3\xb0\x9d\x96" // U+F0756
+#define ICON_MDI_FORMAT_LIST_GROUP "\xf3\xb1\xa1\xa0" // U+F1860
+#define ICON_MDI_FORMAT_LIST_GROUP_PLUS "\xf3\xb1\xad\x96" // U+F1B56
+#define ICON_MDI_FORMAT_LIST_NUMBERED "\xf3\xb0\x89\xbb" // U+F027B
+#define ICON_MDI_FORMAT_LIST_NUMBERED_RTL "\xf3\xb0\xb4\x8d" // U+F0D0D
+#define ICON_MDI_FORMAT_LIST_TEXT "\xf3\xb1\x89\xaf" // U+F126F
+#define ICON_MDI_FORMAT_OVERLINE "\xf3\xb0\xba\xb3" // U+F0EB3
+#define ICON_MDI_FORMAT_PAGE_BREAK "\xf3\xb0\x9b\x97" // U+F06D7
+#define ICON_MDI_FORMAT_PAGE_SPLIT "\xf3\xb1\xa4\x97" // U+F1917
+#define ICON_MDI_FORMAT_PAINT "\xf3\xb0\x89\xbc" // U+F027C
+#define ICON_MDI_FORMAT_PARAGRAPH "\xf3\xb0\x89\xbd" // U+F027D
+#define ICON_MDI_FORMAT_PARAGRAPH_SPACING "\xf3\xb1\xab\xbd" // U+F1AFD
+#define ICON_MDI_FORMAT_PILCROW "\xf3\xb0\x9b\x98" // U+F06D8
+#define ICON_MDI_FORMAT_PILCROW_ARROW_LEFT "\xf3\xb0\x8a\x86" // U+F0286
+#define ICON_MDI_FORMAT_PILCROW_ARROW_RIGHT "\xf3\xb0\x8a\x85" // U+F0285
+#define ICON_MDI_FORMAT_QUOTE_CLOSE "\xf3\xb0\x89\xbe" // U+F027E
+#define ICON_MDI_FORMAT_QUOTE_CLOSE_OUTLINE "\xf3\xb1\x86\xa8" // U+F11A8
+#define ICON_MDI_FORMAT_QUOTE_OPEN "\xf3\xb0\x9d\x97" // U+F0757
+#define ICON_MDI_FORMAT_QUOTE_OPEN_OUTLINE "\xf3\xb1\x86\xa7" // U+F11A7
+#define ICON_MDI_FORMAT_ROTATE_90 "\xf3\xb0\x9a\xaa" // U+F06AA
+#define ICON_MDI_FORMAT_SECTION "\xf3\xb0\x9a\x9f" // U+F069F
+#define ICON_MDI_FORMAT_SIZE "\xf3\xb0\x89\xbf" // U+F027F
+#define ICON_MDI_FORMAT_STRIKETHROUGH "\xf3\xb0\x8a\x80" // U+F0280
+#define ICON_MDI_FORMAT_STRIKETHROUGH_VARIANT "\xf3\xb0\x8a\x81" // U+F0281
+#define ICON_MDI_FORMAT_SUBSCRIPT "\xf3\xb0\x8a\x82" // U+F0282
+#define ICON_MDI_FORMAT_SUPERSCRIPT "\xf3\xb0\x8a\x83" // U+F0283
+#define ICON_MDI_FORMAT_TEXT "\xf3\xb0\x8a\x84" // U+F0284
+#define ICON_MDI_FORMAT_TEXT_ROTATION_ANGLE_DOWN "\xf3\xb0\xbe\xbb" // U+F0FBB
+#define ICON_MDI_FORMAT_TEXT_ROTATION_ANGLE_UP "\xf3\xb0\xbe\xbc" // U+F0FBC
+#define ICON_MDI_FORMAT_TEXT_ROTATION_DOWN "\xf3\xb0\xb5\xb3" // U+F0D73
+#define ICON_MDI_FORMAT_TEXT_ROTATION_DOWN_VERTICAL "\xf3\xb0\xbe\xbd" // U+F0FBD
+#define ICON_MDI_FORMAT_TEXT_ROTATION_NONE "\xf3\xb0\xb5\xb4" // U+F0D74
+#define ICON_MDI_FORMAT_TEXT_ROTATION_UP "\xf3\xb0\xbe\xbe" // U+F0FBE
+#define ICON_MDI_FORMAT_TEXT_ROTATION_VERTICAL "\xf3\xb0\xbe\xbf" // U+F0FBF
+#define ICON_MDI_FORMAT_TEXT_VARIANT "\xf3\xb0\xb8\xb2" // U+F0E32
+#define ICON_MDI_FORMAT_TEXT_VARIANT_OUTLINE "\xf3\xb1\x94\x8f" // U+F150F
+#define ICON_MDI_FORMAT_TEXT_WRAPPING_CLIP "\xf3\xb0\xb4\x8e" // U+F0D0E
+#define ICON_MDI_FORMAT_TEXT_WRAPPING_OVERFLOW "\xf3\xb0\xb4\x8f" // U+F0D0F
+#define ICON_MDI_FORMAT_TEXT_WRAPPING_WRAP "\xf3\xb0\xb4\x90" // U+F0D10
+#define ICON_MDI_FORMAT_TEXTBOX "\xf3\xb0\xb4\x91" // U+F0D11
+#define ICON_MDI_FORMAT_TITLE "\xf3\xb0\x97\xb4" // U+F05F4
+#define ICON_MDI_FORMAT_UNDERLINE "\xf3\xb0\x8a\x87" // U+F0287
+#define ICON_MDI_FORMAT_UNDERLINE_WAVY "\xf3\xb1\xa3\xa9" // U+F18E9
+#define ICON_MDI_FORMAT_VERTICAL_ALIGN_BOTTOM "\xf3\xb0\x98\xa1" // U+F0621
+#define ICON_MDI_FORMAT_VERTICAL_ALIGN_CENTER "\xf3\xb0\x98\xa2" // U+F0622
+#define ICON_MDI_FORMAT_VERTICAL_ALIGN_TOP "\xf3\xb0\x98\xa3" // U+F0623
+#define ICON_MDI_FORMAT_WRAP_INLINE "\xf3\xb0\x8a\x88" // U+F0288
+#define ICON_MDI_FORMAT_WRAP_SQUARE "\xf3\xb0\x8a\x89" // U+F0289
+#define ICON_MDI_FORMAT_WRAP_TIGHT "\xf3\xb0\x8a\x8a" // U+F028A
+#define ICON_MDI_FORMAT_WRAP_TOP_BOTTOM "\xf3\xb0\x8a\x8b" // U+F028B
+#define ICON_MDI_FORUM "\xf3\xb0\x8a\x8c" // U+F028C
+#define ICON_MDI_FORUM_MINUS "\xf3\xb1\xaa\xa9" // U+F1AA9
+#define ICON_MDI_FORUM_MINUS_OUTLINE "\xf3\xb1\xaa\xaa" // U+F1AAA
+#define ICON_MDI_FORUM_OUTLINE "\xf3\xb0\xa0\xa2" // U+F0822
+#define ICON_MDI_FORUM_PLUS "\xf3\xb1\xaa\xab" // U+F1AAB
+#define ICON_MDI_FORUM_PLUS_OUTLINE "\xf3\xb1\xaa\xac" // U+F1AAC
+#define ICON_MDI_FORUM_REMOVE "\xf3\xb1\xaa\xad" // U+F1AAD
+#define ICON_MDI_FORUM_REMOVE_OUTLINE "\xf3\xb1\xaa\xae" // U+F1AAE
+#define ICON_MDI_FORWARD "\xf3\xb0\x8a\x8d" // U+F028D
+#define ICON_MDI_FORWARDBURGER "\xf3\xb0\xb5\xb5" // U+F0D75
+#define ICON_MDI_FOUNTAIN "\xf3\xb0\xa5\xab" // U+F096B
+#define ICON_MDI_FOUNTAIN_PEN "\xf3\xb0\xb4\x92" // U+F0D12
+#define ICON_MDI_FOUNTAIN_PEN_TIP "\xf3\xb0\xb4\x93" // U+F0D13
+#define ICON_MDI_FRACTION_ONE_HALF "\xf3\xb1\xa6\x92" // U+F1992
+#define ICON_MDI_FREEBSD "\xf3\xb0\xa3\xa0" // U+F08E0
+#define ICON_MDI_FRENCH_FRIES "\xf3\xb1\xa5\x97" // U+F1957
+#define ICON_MDI_FREQUENTLY_ASKED_QUESTIONS "\xf3\xb0\xba\xb4" // U+F0EB4
+#define ICON_MDI_FRIDGE "\xf3\xb0\x8a\x90" // U+F0290
+#define ICON_MDI_FRIDGE_ALERT "\xf3\xb1\x86\xb1" // U+F11B1
+#define ICON_MDI_FRIDGE_ALERT_OUTLINE "\xf3\xb1\x86\xb2" // U+F11B2
+#define ICON_MDI_FRIDGE_BOTTOM "\xf3\xb0\x8a\x92" // U+F0292
+#define ICON_MDI_FRIDGE_INDUSTRIAL "\xf3\xb1\x97\xae" // U+F15EE
+#define ICON_MDI_FRIDGE_INDUSTRIAL_ALERT "\xf3\xb1\x97\xaf" // U+F15EF
+#define ICON_MDI_FRIDGE_INDUSTRIAL_ALERT_OUTLINE "\xf3\xb1\x97\xb0" // U+F15F0
+#define ICON_MDI_FRIDGE_INDUSTRIAL_OFF "\xf3\xb1\x97\xb1" // U+F15F1
+#define ICON_MDI_FRIDGE_INDUSTRIAL_OFF_OUTLINE "\xf3\xb1\x97\xb2" // U+F15F2
+#define ICON_MDI_FRIDGE_INDUSTRIAL_OUTLINE "\xf3\xb1\x97\xb3" // U+F15F3
+#define ICON_MDI_FRIDGE_OFF "\xf3\xb1\x86\xaf" // U+F11AF
+#define ICON_MDI_FRIDGE_OFF_OUTLINE "\xf3\xb1\x86\xb0" // U+F11B0
+#define ICON_MDI_FRIDGE_OUTLINE "\xf3\xb0\x8a\x8f" // U+F028F
+#define ICON_MDI_FRIDGE_TOP "\xf3\xb0\x8a\x91" // U+F0291
+#define ICON_MDI_FRIDGE_VARIANT "\xf3\xb1\x97\xb4" // U+F15F4
+#define ICON_MDI_FRIDGE_VARIANT_ALERT "\xf3\xb1\x97\xb5" // U+F15F5
+#define ICON_MDI_FRIDGE_VARIANT_ALERT_OUTLINE "\xf3\xb1\x97\xb6" // U+F15F6
+#define ICON_MDI_FRIDGE_VARIANT_OFF "\xf3\xb1\x97\xb7" // U+F15F7
+#define ICON_MDI_FRIDGE_VARIANT_OFF_OUTLINE "\xf3\xb1\x97\xb8" // U+F15F8
+#define ICON_MDI_FRIDGE_VARIANT_OUTLINE "\xf3\xb1\x97\xb9" // U+F15F9
+#define ICON_MDI_FRUIT_CHERRIES "\xf3\xb1\x81\x82" // U+F1042
+#define ICON_MDI_FRUIT_CHERRIES_OFF "\xf3\xb1\x8f\xb8" // U+F13F8
+#define ICON_MDI_FRUIT_CITRUS "\xf3\xb1\x81\x83" // U+F1043
+#define ICON_MDI_FRUIT_CITRUS_OFF "\xf3\xb1\x8f\xb9" // U+F13F9
+#define ICON_MDI_FRUIT_GRAPES "\xf3\xb1\x81\x84" // U+F1044
+#define ICON_MDI_FRUIT_GRAPES_OUTLINE "\xf3\xb1\x81\x85" // U+F1045
+#define ICON_MDI_FRUIT_PEAR "\xf3\xb1\xa8\x8e" // U+F1A0E
+#define ICON_MDI_FRUIT_PINEAPPLE "\xf3\xb1\x81\x86" // U+F1046
+#define ICON_MDI_FRUIT_WATERMELON "\xf3\xb1\x81\x87" // U+F1047
+#define ICON_MDI_FUEL "\xf3\xb0\x9f\x8a" // U+F07CA
+#define ICON_MDI_FUEL_CELL "\xf3\xb1\xa2\xb5" // U+F18B5
+#define ICON_MDI_FULLSCREEN "\xf3\xb0\x8a\x93" // U+F0293
+#define ICON_MDI_FULLSCREEN_EXIT "\xf3\xb0\x8a\x94" // U+F0294
+#define ICON_MDI_FUNCTION "\xf3\xb0\x8a\x95" // U+F0295
+#define ICON_MDI_FUNCTION_VARIANT "\xf3\xb0\xa1\xb1" // U+F0871
+#define ICON_MDI_FURIGANA_HORIZONTAL "\xf3\xb1\x82\x81" // U+F1081
+#define ICON_MDI_FURIGANA_VERTICAL "\xf3\xb1\x82\x82" // U+F1082
+#define ICON_MDI_FUSE "\xf3\xb0\xb2\x85" // U+F0C85
+#define ICON_MDI_FUSE_ALERT "\xf3\xb1\x90\xad" // U+F142D
+#define ICON_MDI_FUSE_BLADE "\xf3\xb0\xb2\x86" // U+F0C86
+#define ICON_MDI_FUSE_OFF "\xf3\xb1\x90\xac" // U+F142C
+#define ICON_MDI_GAMEPAD "\xf3\xb0\x8a\x96" // U+F0296
+#define ICON_MDI_GAMEPAD_CIRCLE "\xf3\xb0\xb8\xb3" // U+F0E33
+#define ICON_MDI_GAMEPAD_CIRCLE_DOWN "\xf3\xb0\xb8\xb4" // U+F0E34
+#define ICON_MDI_GAMEPAD_CIRCLE_LEFT "\xf3\xb0\xb8\xb5" // U+F0E35
+#define ICON_MDI_GAMEPAD_CIRCLE_OUTLINE "\xf3\xb0\xb8\xb6" // U+F0E36
+#define ICON_MDI_GAMEPAD_CIRCLE_RIGHT "\xf3\xb0\xb8\xb7" // U+F0E37
+#define ICON_MDI_GAMEPAD_CIRCLE_UP "\xf3\xb0\xb8\xb8" // U+F0E38
+#define ICON_MDI_GAMEPAD_DOWN "\xf3\xb0\xb8\xb9" // U+F0E39
+#define ICON_MDI_GAMEPAD_LEFT "\xf3\xb0\xb8\xba" // U+F0E3A
+#define ICON_MDI_GAMEPAD_OUTLINE "\xf3\xb1\xa4\x99" // U+F1919
+#define ICON_MDI_GAMEPAD_RIGHT "\xf3\xb0\xb8\xbb" // U+F0E3B
+#define ICON_MDI_GAMEPAD_ROUND "\xf3\xb0\xb8\xbc" // U+F0E3C
+#define ICON_MDI_GAMEPAD_ROUND_DOWN "\xf3\xb0\xb8\xbd" // U+F0E3D
+#define ICON_MDI_GAMEPAD_ROUND_LEFT "\xf3\xb0\xb8\xbe" // U+F0E3E
+#define ICON_MDI_GAMEPAD_ROUND_OUTLINE "\xf3\xb0\xb8\xbf" // U+F0E3F
+#define ICON_MDI_GAMEPAD_ROUND_RIGHT "\xf3\xb0\xb9\x80" // U+F0E40
+#define ICON_MDI_GAMEPAD_ROUND_UP "\xf3\xb0\xb9\x81" // U+F0E41
+#define ICON_MDI_GAMEPAD_SQUARE "\xf3\xb0\xba\xb5" // U+F0EB5
+#define ICON_MDI_GAMEPAD_SQUARE_OUTLINE "\xf3\xb0\xba\xb6" // U+F0EB6
+#define ICON_MDI_GAMEPAD_UP "\xf3\xb0\xb9\x82" // U+F0E42
+#define ICON_MDI_GAMEPAD_VARIANT "\xf3\xb0\x8a\x97" // U+F0297
+#define ICON_MDI_GAMEPAD_VARIANT_OUTLINE "\xf3\xb0\xba\xb7" // U+F0EB7
+#define ICON_MDI_GAMMA "\xf3\xb1\x83\xae" // U+F10EE
+#define ICON_MDI_GANTRY_CRANE "\xf3\xb0\xb7\x91" // U+F0DD1
+#define ICON_MDI_GARAGE "\xf3\xb0\x9b\x99" // U+F06D9
+#define ICON_MDI_GARAGE_ALERT "\xf3\xb0\xa1\xb2" // U+F0872
+#define ICON_MDI_GARAGE_ALERT_VARIANT "\xf3\xb1\x8b\x95" // U+F12D5
+#define ICON_MDI_GARAGE_LOCK "\xf3\xb1\x9f\xbb" // U+F17FB
+#define ICON_MDI_GARAGE_OPEN "\xf3\xb0\x9b\x9a" // U+F06DA
+#define ICON_MDI_GARAGE_OPEN_VARIANT "\xf3\xb1\x8b\x94" // U+F12D4
+#define ICON_MDI_GARAGE_VARIANT "\xf3\xb1\x8b\x93" // U+F12D3
+#define ICON_MDI_GARAGE_VARIANT_LOCK "\xf3\xb1\x9f\xbc" // U+F17FC
+#define ICON_MDI_GAS_BURNER "\xf3\xb1\xa8\x9b" // U+F1A1B
+#define ICON_MDI_GAS_CYLINDER "\xf3\xb0\x99\x87" // U+F0647
+#define ICON_MDI_GAS_STATION "\xf3\xb0\x8a\x98" // U+F0298
+#define ICON_MDI_GAS_STATION_IN_USE "\xf3\xb1\xb3\x84" // U+F1CC4
+#define ICON_MDI_GAS_STATION_IN_USE_OUTLINE "\xf3\xb1\xb3\x85" // U+F1CC5
+#define ICON_MDI_GAS_STATION_OFF "\xf3\xb1\x90\x89" // U+F1409
+#define ICON_MDI_GAS_STATION_OFF_OUTLINE "\xf3\xb1\x90\x8a" // U+F140A
+#define ICON_MDI_GAS_STATION_OUTLINE "\xf3\xb0\xba\xb8" // U+F0EB8
+#define ICON_MDI_GATE "\xf3\xb0\x8a\x99" // U+F0299
+#define ICON_MDI_GATE_ALERT "\xf3\xb1\x9f\xb8" // U+F17F8
+#define ICON_MDI_GATE_AND "\xf3\xb0\xa3\xa1" // U+F08E1
+#define ICON_MDI_GATE_ARROW_LEFT "\xf3\xb1\x9f\xb7" // U+F17F7
+#define ICON_MDI_GATE_ARROW_RIGHT "\xf3\xb1\x85\xa9" // U+F1169
+#define ICON_MDI_GATE_BUFFER "\xf3\xb1\xab\xbe" // U+F1AFE
+#define ICON_MDI_GATE_NAND "\xf3\xb0\xa3\xa2" // U+F08E2
+#define ICON_MDI_GATE_NOR "\xf3\xb0\xa3\xa3" // U+F08E3
+#define ICON_MDI_GATE_NOT "\xf3\xb0\xa3\xa4" // U+F08E4
+#define ICON_MDI_GATE_OPEN "\xf3\xb1\x85\xaa" // U+F116A
+#define ICON_MDI_GATE_OR "\xf3\xb0\xa3\xa5" // U+F08E5
+#define ICON_MDI_GATE_XNOR "\xf3\xb0\xa3\xa6" // U+F08E6
+#define ICON_MDI_GATE_XOR "\xf3\xb0\xa3\xa7" // U+F08E7
+#define ICON_MDI_GATSBY "\xf3\xb0\xb9\x83" // U+F0E43
+#define ICON_MDI_GAUGE "\xf3\xb0\x8a\x9a" // U+F029A
+#define ICON_MDI_GAUGE_EMPTY "\xf3\xb0\xa1\xb3" // U+F0873
+#define ICON_MDI_GAUGE_FULL "\xf3\xb0\xa1\xb4" // U+F0874
+#define ICON_MDI_GAUGE_LOW "\xf3\xb0\xa1\xb5" // U+F0875
+#define ICON_MDI_GAVEL "\xf3\xb0\x8a\x9b" // U+F029B
+#define ICON_MDI_GENDER_FEMALE "\xf3\xb0\x8a\x9c" // U+F029C
+#define ICON_MDI_GENDER_MALE "\xf3\xb0\x8a\x9d" // U+F029D
+#define ICON_MDI_GENDER_MALE_FEMALE "\xf3\xb0\x8a\x9e" // U+F029E
+#define ICON_MDI_GENDER_MALE_FEMALE_VARIANT "\xf3\xb1\x84\xbf" // U+F113F
+#define ICON_MDI_GENDER_NON_BINARY "\xf3\xb1\x85\x80" // U+F1140
+#define ICON_MDI_GENDER_TRANSGENDER "\xf3\xb0\x8a\x9f" // U+F029F
+#define ICON_MDI_GENERATOR_MOBILE "\xf3\xb1\xb2\x8a" // U+F1C8A
+#define ICON_MDI_GENERATOR_PORTABLE "\xf3\xb1\xb2\x8b" // U+F1C8B
+#define ICON_MDI_GENERATOR_STATIONARY "\xf3\xb1\xb2\x8c" // U+F1C8C
+#define ICON_MDI_GENTOO "\xf3\xb0\xa3\xa8" // U+F08E8
+#define ICON_MDI_GESTURE "\xf3\xb0\x9f\x8b" // U+F07CB
+#define ICON_MDI_GESTURE_DOUBLE_TAP "\xf3\xb0\x9c\xbc" // U+F073C
+#define ICON_MDI_GESTURE_PINCH "\xf3\xb0\xaa\xbd" // U+F0ABD
+#define ICON_MDI_GESTURE_SPREAD "\xf3\xb0\xaa\xbe" // U+F0ABE
+#define ICON_MDI_GESTURE_SWIPE "\xf3\xb0\xb5\xb6" // U+F0D76
+#define ICON_MDI_GESTURE_SWIPE_DOWN "\xf3\xb0\x9c\xbd" // U+F073D
+#define ICON_MDI_GESTURE_SWIPE_HORIZONTAL "\xf3\xb0\xaa\xbf" // U+F0ABF
+#define ICON_MDI_GESTURE_SWIPE_LEFT "\xf3\xb0\x9c\xbe" // U+F073E
+#define ICON_MDI_GESTURE_SWIPE_RIGHT "\xf3\xb0\x9c\xbf" // U+F073F
+#define ICON_MDI_GESTURE_SWIPE_UP "\xf3\xb0\x9d\x80" // U+F0740
+#define ICON_MDI_GESTURE_SWIPE_VERTICAL "\xf3\xb0\xab\x80" // U+F0AC0
+#define ICON_MDI_GESTURE_TAP "\xf3\xb0\x9d\x81" // U+F0741
+#define ICON_MDI_GESTURE_TAP_BOX "\xf3\xb1\x8a\xa9" // U+F12A9
+#define ICON_MDI_GESTURE_TAP_BUTTON "\xf3\xb1\x8a\xa8" // U+F12A8
+#define ICON_MDI_GESTURE_TAP_HOLD "\xf3\xb0\xb5\xb7" // U+F0D77
+#define ICON_MDI_GESTURE_TWO_DOUBLE_TAP "\xf3\xb0\x9d\x82" // U+F0742
+#define ICON_MDI_GESTURE_TWO_TAP "\xf3\xb0\x9d\x83" // U+F0743
+#define ICON_MDI_GHOST "\xf3\xb0\x8a\xa0" // U+F02A0
+#define ICON_MDI_GHOST_OFF "\xf3\xb0\xa7\xb5" // U+F09F5
+#define ICON_MDI_GHOST_OFF_OUTLINE "\xf3\xb1\x99\x9c" // U+F165C
+#define ICON_MDI_GHOST_OUTLINE "\xf3\xb1\x99\x9d" // U+F165D
+#define ICON_MDI_GIFT "\xf3\xb0\xb9\x84" // U+F0E44
+#define ICON_MDI_GIFT_OFF "\xf3\xb1\x9b\xaf" // U+F16EF
+#define ICON_MDI_GIFT_OFF_OUTLINE "\xf3\xb1\x9b\xb0" // U+F16F0
+#define ICON_MDI_GIFT_OPEN "\xf3\xb1\x9b\xb1" // U+F16F1
+#define ICON_MDI_GIFT_OPEN_OUTLINE "\xf3\xb1\x9b\xb2" // U+F16F2
+#define ICON_MDI_GIFT_OUTLINE "\xf3\xb0\x8a\xa1" // U+F02A1
+#define ICON_MDI_GIT "\xf3\xb0\x8a\xa2" // U+F02A2
+#define ICON_MDI_GITHUB "\xf3\xb0\x8a\xa4" // U+F02A4
+#define ICON_MDI_GITLAB "\xf3\xb0\xae\xa0" // U+F0BA0
+#define ICON_MDI_GLASS_COCKTAIL "\xf3\xb0\x8d\x96" // U+F0356
+#define ICON_MDI_GLASS_COCKTAIL_OFF "\xf3\xb1\x97\xa6" // U+F15E6
+#define ICON_MDI_GLASS_FLUTE "\xf3\xb0\x8a\xa5" // U+F02A5
+#define ICON_MDI_GLASS_FRAGILE "\xf3\xb1\xa1\xb3" // U+F1873
+#define ICON_MDI_GLASS_MUG "\xf3\xb0\x8a\xa6" // U+F02A6
+#define ICON_MDI_GLASS_MUG_OFF "\xf3\xb1\x97\xa7" // U+F15E7
+#define ICON_MDI_GLASS_MUG_VARIANT "\xf3\xb1\x84\x96" // U+F1116
+#define ICON_MDI_GLASS_MUG_VARIANT_OFF "\xf3\xb1\x97\xa8" // U+F15E8
+#define ICON_MDI_GLASS_PINT_OUTLINE "\xf3\xb1\x8c\x8d" // U+F130D
+#define ICON_MDI_GLASS_STANGE "\xf3\xb0\x8a\xa7" // U+F02A7
+#define ICON_MDI_GLASS_TULIP "\xf3\xb0\x8a\xa8" // U+F02A8
+#define ICON_MDI_GLASS_WINE "\xf3\xb0\xa1\xb6" // U+F0876
+#define ICON_MDI_GLASSES "\xf3\xb0\x8a\xaa" // U+F02AA
+#define ICON_MDI_GLOBE_LIGHT "\xf3\xb0\x99\xaf" // U+F066F
+#define ICON_MDI_GLOBE_LIGHT_OUTLINE "\xf3\xb1\x8b\x97" // U+F12D7
+#define ICON_MDI_GLOBE_MODEL "\xf3\xb0\xa3\xa9" // U+F08E9
+#define ICON_MDI_GMAIL "\xf3\xb0\x8a\xab" // U+F02AB
+#define ICON_MDI_GNOME "\xf3\xb0\x8a\xac" // U+F02AC
+#define ICON_MDI_GO_KART "\xf3\xb0\xb5\xb9" // U+F0D79
+#define ICON_MDI_GO_KART_TRACK "\xf3\xb0\xb5\xba" // U+F0D7A
+#define ICON_MDI_GOG "\xf3\xb0\xae\xa1" // U+F0BA1
+#define ICON_MDI_GOLD "\xf3\xb1\x89\x8f" // U+F124F
+#define ICON_MDI_GOLF "\xf3\xb0\xa0\xa3" // U+F0823
+#define ICON_MDI_GOLF_CART "\xf3\xb1\x86\xa4" // U+F11A4
+#define ICON_MDI_GOLF_TEE "\xf3\xb1\x82\x83" // U+F1083
+#define ICON_MDI_GONDOLA "\xf3\xb0\x9a\x86" // U+F0686
+#define ICON_MDI_GOODREADS "\xf3\xb0\xb5\xbb" // U+F0D7B
+#define ICON_MDI_GOOGLE "\xf3\xb0\x8a\xad" // U+F02AD
+#define ICON_MDI_GOOGLE_ADS "\xf3\xb0\xb2\x87" // U+F0C87
+#define ICON_MDI_GOOGLE_ANALYTICS "\xf3\xb0\x9f\x8c" // U+F07CC
+#define ICON_MDI_GOOGLE_ASSISTANT "\xf3\xb0\x9f\x8d" // U+F07CD
+#define ICON_MDI_GOOGLE_CARDBOARD "\xf3\xb0\x8a\xae" // U+F02AE
+#define ICON_MDI_GOOGLE_CHROME "\xf3\xb0\x8a\xaf" // U+F02AF
+#define ICON_MDI_GOOGLE_CIRCLES "\xf3\xb0\x8a\xb0" // U+F02B0
+#define ICON_MDI_GOOGLE_CIRCLES_COMMUNITIES "\xf3\xb0\x8a\xb1" // U+F02B1
+#define ICON_MDI_GOOGLE_CIRCLES_EXTENDED "\xf3\xb0\x8a\xb2" // U+F02B2
+#define ICON_MDI_GOOGLE_CIRCLES_GROUP "\xf3\xb0\x8a\xb3" // U+F02B3
+#define ICON_MDI_GOOGLE_CLASSROOM "\xf3\xb0\x8b\x80" // U+F02C0
+#define ICON_MDI_GOOGLE_CLOUD "\xf3\xb1\x87\xb6" // U+F11F6
+#define ICON_MDI_GOOGLE_DOWNASAUR "\xf3\xb1\x8d\xa2" // U+F1362
+#define ICON_MDI_GOOGLE_DRIVE "\xf3\xb0\x8a\xb6" // U+F02B6
+#define ICON_MDI_GOOGLE_EARTH "\xf3\xb0\x8a\xb7" // U+F02B7
+#define ICON_MDI_GOOGLE_FIT "\xf3\xb0\xa5\xac" // U+F096C
+#define ICON_MDI_GOOGLE_GLASS "\xf3\xb0\x8a\xb8" // U+F02B8
+#define ICON_MDI_GOOGLE_HANGOUTS "\xf3\xb0\x8b\x89" // U+F02C9
+#define ICON_MDI_GOOGLE_KEEP "\xf3\xb0\x9b\x9c" // U+F06DC
+#define ICON_MDI_GOOGLE_LENS "\xf3\xb0\xa7\xb6" // U+F09F6
+#define ICON_MDI_GOOGLE_MAPS "\xf3\xb0\x97\xb5" // U+F05F5
+#define ICON_MDI_GOOGLE_MY_BUSINESS "\xf3\xb1\x81\x88" // U+F1048
+#define ICON_MDI_GOOGLE_NEARBY "\xf3\xb0\x8a\xb9" // U+F02B9
+#define ICON_MDI_GOOGLE_PLAY "\xf3\xb0\x8a\xbc" // U+F02BC
+#define ICON_MDI_GOOGLE_PLUS "\xf3\xb0\x8a\xbd" // U+F02BD
+#define ICON_MDI_GOOGLE_PODCAST "\xf3\xb0\xba\xb9" // U+F0EB9
+#define ICON_MDI_GOOGLE_SPREADSHEET "\xf3\xb0\xa7\xb7" // U+F09F7
+#define ICON_MDI_GOOGLE_STREET_VIEW "\xf3\xb0\xb2\x88" // U+F0C88
+#define ICON_MDI_GOOGLE_TRANSLATE "\xf3\xb0\x8a\xbf" // U+F02BF
+#define ICON_MDI_GRADIENT_HORIZONTAL "\xf3\xb1\x9d\x8a" // U+F174A
+#define ICON_MDI_GRADIENT_VERTICAL "\xf3\xb0\x9a\xa0" // U+F06A0
+#define ICON_MDI_GRAIN "\xf3\xb0\xb5\xbc" // U+F0D7C
+#define ICON_MDI_GRAPH "\xf3\xb1\x81\x89" // U+F1049
+#define ICON_MDI_GRAPH_OUTLINE "\xf3\xb1\x81\x8a" // U+F104A
+#define ICON_MDI_GRAPHQL "\xf3\xb0\xa1\xb7" // U+F0877
+#define ICON_MDI_GRASS "\xf3\xb1\x94\x90" // U+F1510
+#define ICON_MDI_GRAVE_STONE "\xf3\xb0\xae\xa2" // U+F0BA2
+#define ICON_MDI_GREASE_PENCIL "\xf3\xb0\x99\x88" // U+F0648
+#define ICON_MDI_GREATER_THAN "\xf3\xb0\xa5\xad" // U+F096D
+#define ICON_MDI_GREATER_THAN_OR_EQUAL "\xf3\xb0\xa5\xae" // U+F096E
+#define ICON_MDI_GREENHOUSE "\xf3\xb0\x80\xad" // U+F002D
+#define ICON_MDI_GRID "\xf3\xb0\x8b\x81" // U+F02C1
+#define ICON_MDI_GRID_LARGE "\xf3\xb0\x9d\x98" // U+F0758
+#define ICON_MDI_GRID_OFF "\xf3\xb0\x8b\x82" // U+F02C2
+#define ICON_MDI_GRILL "\xf3\xb0\xb9\x85" // U+F0E45
+#define ICON_MDI_GRILL_OUTLINE "\xf3\xb1\x86\x8a" // U+F118A
+#define ICON_MDI_GROUP "\xf3\xb0\x8b\x83" // U+F02C3
+#define ICON_MDI_GUITAR_ACOUSTIC "\xf3\xb0\x9d\xb1" // U+F0771
+#define ICON_MDI_GUITAR_ELECTRIC "\xf3\xb0\x8b\x84" // U+F02C4
+#define ICON_MDI_GUITAR_PICK "\xf3\xb0\x8b\x85" // U+F02C5
+#define ICON_MDI_GUITAR_PICK_OUTLINE "\xf3\xb0\x8b\x86" // U+F02C6
+#define ICON_MDI_GUY_FAWKES_MASK "\xf3\xb0\xa0\xa5" // U+F0825
+#define ICON_MDI_GYMNASTICS "\xf3\xb1\xa9\x81" // U+F1A41
+#define ICON_MDI_HAIL "\xf3\xb0\xab\x81" // U+F0AC1
+#define ICON_MDI_HAIR_DRYER "\xf3\xb1\x83\xaf" // U+F10EF
+#define ICON_MDI_HAIR_DRYER_OUTLINE "\xf3\xb1\x83\xb0" // U+F10F0
+#define ICON_MDI_HALLOWEEN "\xf3\xb0\xae\xa3" // U+F0BA3
+#define ICON_MDI_HAMBURGER "\xf3\xb0\x9a\x85" // U+F0685
+#define ICON_MDI_HAMBURGER_CHECK "\xf3\xb1\x9d\xb6" // U+F1776
+#define ICON_MDI_HAMBURGER_MINUS "\xf3\xb1\x9d\xb7" // U+F1777
+#define ICON_MDI_HAMBURGER_OFF "\xf3\xb1\x9d\xb8" // U+F1778
+#define ICON_MDI_HAMBURGER_PLUS "\xf3\xb1\x9d\xb9" // U+F1779
+#define ICON_MDI_HAMBURGER_REMOVE "\xf3\xb1\x9d\xba" // U+F177A
+#define ICON_MDI_HAMMER "\xf3\xb0\xa3\xaa" // U+F08EA
+#define ICON_MDI_HAMMER_SCREWDRIVER "\xf3\xb1\x8c\xa2" // U+F1322
+#define ICON_MDI_HAMMER_SICKLE "\xf3\xb1\xa2\x87" // U+F1887
+#define ICON_MDI_HAMMER_WRENCH "\xf3\xb1\x8c\xa3" // U+F1323
+#define ICON_MDI_HAND_BACK_LEFT "\xf3\xb0\xb9\x86" // U+F0E46
+#define ICON_MDI_HAND_BACK_LEFT_OFF "\xf3\xb1\xa0\xb0" // U+F1830
+#define ICON_MDI_HAND_BACK_LEFT_OFF_OUTLINE "\xf3\xb1\xa0\xb2" // U+F1832
+#define ICON_MDI_HAND_BACK_LEFT_OUTLINE "\xf3\xb1\xa0\xac" // U+F182C
+#define ICON_MDI_HAND_BACK_RIGHT "\xf3\xb0\xb9\x87" // U+F0E47
+#define ICON_MDI_HAND_BACK_RIGHT_OFF "\xf3\xb1\xa0\xb1" // U+F1831
+#define ICON_MDI_HAND_BACK_RIGHT_OFF_OUTLINE "\xf3\xb1\xa0\xb3" // U+F1833
+#define ICON_MDI_HAND_BACK_RIGHT_OUTLINE "\xf3\xb1\xa0\xad" // U+F182D
+#define ICON_MDI_HAND_CLAP "\xf3\xb1\xa5\x8b" // U+F194B
+#define ICON_MDI_HAND_CLAP_OFF "\xf3\xb1\xa9\x82" // U+F1A42
+#define ICON_MDI_HAND_COIN "\xf3\xb1\xa2\x8f" // U+F188F
+#define ICON_MDI_HAND_COIN_OUTLINE "\xf3\xb1\xa2\x90" // U+F1890
+#define ICON_MDI_HAND_CYCLE "\xf3\xb1\xae\x9c" // U+F1B9C
+#define ICON_MDI_HAND_EXTENDED "\xf3\xb1\xa2\xb6" // U+F18B6
+#define ICON_MDI_HAND_EXTENDED_OUTLINE "\xf3\xb1\xa2\xb7" // U+F18B7
+#define ICON_MDI_HAND_FRONT_LEFT "\xf3\xb1\xa0\xab" // U+F182B
+#define ICON_MDI_HAND_FRONT_LEFT_OUTLINE "\xf3\xb1\xa0\xae" // U+F182E
+#define ICON_MDI_HAND_FRONT_RIGHT "\xf3\xb0\xa9\x8f" // U+F0A4F
+#define ICON_MDI_HAND_FRONT_RIGHT_OUTLINE "\xf3\xb1\xa0\xaf" // U+F182F
+#define ICON_MDI_HAND_HEART "\xf3\xb1\x83\xb1" // U+F10F1
+#define ICON_MDI_HAND_HEART_OUTLINE "\xf3\xb1\x95\xbe" // U+F157E
+#define ICON_MDI_HAND_OKAY "\xf3\xb0\xa9\x90" // U+F0A50
+#define ICON_MDI_HAND_PEACE "\xf3\xb0\xa9\x91" // U+F0A51
+#define ICON_MDI_HAND_PEACE_VARIANT "\xf3\xb0\xa9\x92" // U+F0A52
+#define ICON_MDI_HAND_POINTING_DOWN "\xf3\xb0\xa9\x93" // U+F0A53
+#define ICON_MDI_HAND_POINTING_LEFT "\xf3\xb0\xa9\x94" // U+F0A54
+#define ICON_MDI_HAND_POINTING_RIGHT "\xf3\xb0\x8b\x87" // U+F02C7
+#define ICON_MDI_HAND_POINTING_UP "\xf3\xb0\xa9\x95" // U+F0A55
+#define ICON_MDI_HAND_SAW "\xf3\xb0\xb9\x88" // U+F0E48
+#define ICON_MDI_HAND_WASH "\xf3\xb1\x95\xbf" // U+F157F
+#define ICON_MDI_HAND_WASH_OUTLINE "\xf3\xb1\x96\x80" // U+F1580
+#define ICON_MDI_HAND_WATER "\xf3\xb1\x8e\x9f" // U+F139F
+#define ICON_MDI_HAND_WAVE "\xf3\xb1\xa0\xa1" // U+F1821
+#define ICON_MDI_HAND_WAVE_OUTLINE "\xf3\xb1\xa0\xa2" // U+F1822
+#define ICON_MDI_HANDBALL "\xf3\xb0\xbd\x93" // U+F0F53
+#define ICON_MDI_HANDCUFFS "\xf3\xb1\x84\xbe" // U+F113E
+#define ICON_MDI_HANDS_PRAY "\xf3\xb0\x95\xb9" // U+F0579
+#define ICON_MDI_HANDSHAKE "\xf3\xb1\x88\x98" // U+F1218
+#define ICON_MDI_HANDSHAKE_OUTLINE "\xf3\xb1\x96\xa1" // U+F15A1
+#define ICON_MDI_HANGER "\xf3\xb0\x8b\x88" // U+F02C8
+#define ICON_MDI_HARD_HAT "\xf3\xb0\xa5\xaf" // U+F096F
+#define ICON_MDI_HARDDISK "\xf3\xb0\x8b\x8a" // U+F02CA
+#define ICON_MDI_HARDDISK_PLUS "\xf3\xb1\x81\x8b" // U+F104B
+#define ICON_MDI_HARDDISK_REMOVE "\xf3\xb1\x81\x8c" // U+F104C
+#define ICON_MDI_HAT_FEDORA "\xf3\xb0\xae\xa4" // U+F0BA4
+#define ICON_MDI_HAZARD_LIGHTS "\xf3\xb0\xb2\x89" // U+F0C89
+#define ICON_MDI_HDMI_PORT "\xf3\xb1\xae\xb8" // U+F1BB8
+#define ICON_MDI_HDR "\xf3\xb0\xb5\xbd" // U+F0D7D
+#define ICON_MDI_HDR_OFF "\xf3\xb0\xb5\xbe" // U+F0D7E
+#define ICON_MDI_HEAD "\xf3\xb1\x8d\x9e" // U+F135E
+#define ICON_MDI_HEAD_ALERT "\xf3\xb1\x8c\xb8" // U+F1338
+#define ICON_MDI_HEAD_ALERT_OUTLINE "\xf3\xb1\x8c\xb9" // U+F1339
+#define ICON_MDI_HEAD_CHECK "\xf3\xb1\x8c\xba" // U+F133A
+#define ICON_MDI_HEAD_CHECK_OUTLINE "\xf3\xb1\x8c\xbb" // U+F133B
+#define ICON_MDI_HEAD_COG "\xf3\xb1\x8c\xbc" // U+F133C
+#define ICON_MDI_HEAD_COG_OUTLINE "\xf3\xb1\x8c\xbd" // U+F133D
+#define ICON_MDI_HEAD_DOTS_HORIZONTAL "\xf3\xb1\x8c\xbe" // U+F133E
+#define ICON_MDI_HEAD_DOTS_HORIZONTAL_OUTLINE "\xf3\xb1\x8c\xbf" // U+F133F
+#define ICON_MDI_HEAD_FLASH "\xf3\xb1\x8d\x80" // U+F1340
+#define ICON_MDI_HEAD_FLASH_OUTLINE "\xf3\xb1\x8d\x81" // U+F1341
+#define ICON_MDI_HEAD_HEART "\xf3\xb1\x8d\x82" // U+F1342
+#define ICON_MDI_HEAD_HEART_OUTLINE "\xf3\xb1\x8d\x83" // U+F1343
+#define ICON_MDI_HEAD_LIGHTBULB "\xf3\xb1\x8d\x84" // U+F1344
+#define ICON_MDI_HEAD_LIGHTBULB_OUTLINE "\xf3\xb1\x8d\x85" // U+F1345
+#define ICON_MDI_HEAD_MINUS "\xf3\xb1\x8d\x86" // U+F1346
+#define ICON_MDI_HEAD_MINUS_OUTLINE "\xf3\xb1\x8d\x87" // U+F1347
+#define ICON_MDI_HEAD_OUTLINE "\xf3\xb1\x8d\x9f" // U+F135F
+#define ICON_MDI_HEAD_PLUS "\xf3\xb1\x8d\x88" // U+F1348
+#define ICON_MDI_HEAD_PLUS_OUTLINE "\xf3\xb1\x8d\x89" // U+F1349
+#define ICON_MDI_HEAD_QUESTION "\xf3\xb1\x8d\x8a" // U+F134A
+#define ICON_MDI_HEAD_QUESTION_OUTLINE "\xf3\xb1\x8d\x8b" // U+F134B
+#define ICON_MDI_HEAD_REMOVE "\xf3\xb1\x8d\x8c" // U+F134C
+#define ICON_MDI_HEAD_REMOVE_OUTLINE "\xf3\xb1\x8d\x8d" // U+F134D
+#define ICON_MDI_HEAD_SNOWFLAKE "\xf3\xb1\x8d\x8e" // U+F134E
+#define ICON_MDI_HEAD_SNOWFLAKE_OUTLINE "\xf3\xb1\x8d\x8f" // U+F134F
+#define ICON_MDI_HEAD_SYNC "\xf3\xb1\x8d\x90" // U+F1350
+#define ICON_MDI_HEAD_SYNC_OUTLINE "\xf3\xb1\x8d\x91" // U+F1351
+#define ICON_MDI_HEADPHONES "\xf3\xb0\x8b\x8b" // U+F02CB
+#define ICON_MDI_HEADPHONES_BLUETOOTH "\xf3\xb0\xa5\xb0" // U+F0970
+#define ICON_MDI_HEADPHONES_BOX "\xf3\xb0\x8b\x8c" // U+F02CC
+#define ICON_MDI_HEADPHONES_OFF "\xf3\xb0\x9f\x8e" // U+F07CE
+#define ICON_MDI_HEADPHONES_SETTINGS "\xf3\xb0\x8b\x8d" // U+F02CD
+#define ICON_MDI_HEADSET "\xf3\xb0\x8b\x8e" // U+F02CE
+#define ICON_MDI_HEADSET_DOCK "\xf3\xb0\x8b\x8f" // U+F02CF
+#define ICON_MDI_HEADSET_OFF "\xf3\xb0\x8b\x90" // U+F02D0
+#define ICON_MDI_HEART "\xf3\xb0\x8b\x91" // U+F02D1
+#define ICON_MDI_HEART_BOX "\xf3\xb0\x8b\x92" // U+F02D2
+#define ICON_MDI_HEART_BOX_OUTLINE "\xf3\xb0\x8b\x93" // U+F02D3
+#define ICON_MDI_HEART_BROKEN "\xf3\xb0\x8b\x94" // U+F02D4
+#define ICON_MDI_HEART_BROKEN_OUTLINE "\xf3\xb0\xb4\x94" // U+F0D14
+#define ICON_MDI_HEART_CIRCLE "\xf3\xb0\xa5\xb1" // U+F0971
+#define ICON_MDI_HEART_CIRCLE_OUTLINE "\xf3\xb0\xa5\xb2" // U+F0972
+#define ICON_MDI_HEART_COG "\xf3\xb1\x99\xa3" // U+F1663
+#define ICON_MDI_HEART_COG_OUTLINE "\xf3\xb1\x99\xa4" // U+F1664
+#define ICON_MDI_HEART_FLASH "\xf3\xb0\xbb\xb9" // U+F0EF9
+#define ICON_MDI_HEART_HALF "\xf3\xb0\x9b\x9f" // U+F06DF
+#define ICON_MDI_HEART_HALF_FULL "\xf3\xb0\x9b\x9e" // U+F06DE
+#define ICON_MDI_HEART_HALF_OUTLINE "\xf3\xb0\x9b\xa0" // U+F06E0
+#define ICON_MDI_HEART_MINUS "\xf3\xb1\x90\xaf" // U+F142F
+#define ICON_MDI_HEART_MINUS_OUTLINE "\xf3\xb1\x90\xb2" // U+F1432
+#define ICON_MDI_HEART_MULTIPLE "\xf3\xb0\xa9\x96" // U+F0A56
+#define ICON_MDI_HEART_MULTIPLE_OUTLINE "\xf3\xb0\xa9\x97" // U+F0A57
+#define ICON_MDI_HEART_OFF "\xf3\xb0\x9d\x99" // U+F0759
+#define ICON_MDI_HEART_OFF_OUTLINE "\xf3\xb1\x90\xb4" // U+F1434
+#define ICON_MDI_HEART_OUTLINE "\xf3\xb0\x8b\x95" // U+F02D5
+#define ICON_MDI_HEART_PLUS "\xf3\xb1\x90\xae" // U+F142E
+#define ICON_MDI_HEART_PLUS_OUTLINE "\xf3\xb1\x90\xb1" // U+F1431
+#define ICON_MDI_HEART_PULSE "\xf3\xb0\x97\xb6" // U+F05F6
+#define ICON_MDI_HEART_REMOVE "\xf3\xb1\x90\xb0" // U+F1430
+#define ICON_MDI_HEART_REMOVE_OUTLINE "\xf3\xb1\x90\xb3" // U+F1433
+#define ICON_MDI_HEART_SEARCH "\xf3\xb1\xb2\x8d" // U+F1C8D
+#define ICON_MDI_HEART_SETTINGS "\xf3\xb1\x99\xa5" // U+F1665
+#define ICON_MDI_HEART_SETTINGS_OUTLINE "\xf3\xb1\x99\xa6" // U+F1666
+#define ICON_MDI_HEAT_PUMP "\xf3\xb1\xa9\x83" // U+F1A43
+#define ICON_MDI_HEAT_PUMP_OUTLINE "\xf3\xb1\xa9\x84" // U+F1A44
+#define ICON_MDI_HEAT_WAVE "\xf3\xb1\xa9\x85" // U+F1A45
+#define ICON_MDI_HEATING_COIL "\xf3\xb1\xaa\xaf" // U+F1AAF
+#define ICON_MDI_HELICOPTER "\xf3\xb0\xab\x82" // U+F0AC2
+#define ICON_MDI_HELP "\xf3\xb0\x8b\x96" // U+F02D6
+#define ICON_MDI_HELP_BOX "\xf3\xb0\x9e\x8b" // U+F078B
+#define ICON_MDI_HELP_BOX_MULTIPLE "\xf3\xb1\xb0\x8a" // U+F1C0A
+#define ICON_MDI_HELP_BOX_MULTIPLE_OUTLINE "\xf3\xb1\xb0\x8b" // U+F1C0B
+#define ICON_MDI_HELP_BOX_OUTLINE "\xf3\xb1\xb0\x8c" // U+F1C0C
+#define ICON_MDI_HELP_CIRCLE "\xf3\xb0\x8b\x97" // U+F02D7
+#define ICON_MDI_HELP_CIRCLE_OUTLINE "\xf3\xb0\x98\xa5" // U+F0625
+#define ICON_MDI_HELP_NETWORK "\xf3\xb0\x9b\xb5" // U+F06F5
+#define ICON_MDI_HELP_NETWORK_OUTLINE "\xf3\xb0\xb2\x8a" // U+F0C8A
+#define ICON_MDI_HELP_RHOMBUS "\xf3\xb0\xae\xa5" // U+F0BA5
+#define ICON_MDI_HELP_RHOMBUS_OUTLINE "\xf3\xb0\xae\xa6" // U+F0BA6
+#define ICON_MDI_HEXADECIMAL "\xf3\xb1\x8a\xa7" // U+F12A7
+#define ICON_MDI_HEXAGON "\xf3\xb0\x8b\x98" // U+F02D8
+#define ICON_MDI_HEXAGON_MULTIPLE "\xf3\xb0\x9b\xa1" // U+F06E1
+#define ICON_MDI_HEXAGON_MULTIPLE_OUTLINE "\xf3\xb1\x83\xb2" // U+F10F2
+#define ICON_MDI_HEXAGON_OUTLINE "\xf3\xb0\x8b\x99" // U+F02D9
+#define ICON_MDI_HEXAGON_SLICE_1 "\xf3\xb0\xab\x83" // U+F0AC3
+#define ICON_MDI_HEXAGON_SLICE_2 "\xf3\xb0\xab\x84" // U+F0AC4
+#define ICON_MDI_HEXAGON_SLICE_3 "\xf3\xb0\xab\x85" // U+F0AC5
+#define ICON_MDI_HEXAGON_SLICE_4 "\xf3\xb0\xab\x86" // U+F0AC6
+#define ICON_MDI_HEXAGON_SLICE_5 "\xf3\xb0\xab\x87" // U+F0AC7
+#define ICON_MDI_HEXAGON_SLICE_6 "\xf3\xb0\xab\x88" // U+F0AC8
+#define ICON_MDI_HEXAGRAM "\xf3\xb0\xab\x89" // U+F0AC9
+#define ICON_MDI_HEXAGRAM_OUTLINE "\xf3\xb0\xab\x8a" // U+F0ACA
+#define ICON_MDI_HIGH_DEFINITION "\xf3\xb0\x9f\x8f" // U+F07CF
+#define ICON_MDI_HIGH_DEFINITION_BOX "\xf3\xb0\xa1\xb8" // U+F0878
+#define ICON_MDI_HIGHWAY "\xf3\xb0\x97\xb7" // U+F05F7
+#define ICON_MDI_HIKING "\xf3\xb0\xb5\xbf" // U+F0D7F
+#define ICON_MDI_HISTORY "\xf3\xb0\x8b\x9a" // U+F02DA
+#define ICON_MDI_HOCKEY_PUCK "\xf3\xb0\xa1\xb9" // U+F0879
+#define ICON_MDI_HOCKEY_STICKS "\xf3\xb0\xa1\xba" // U+F087A
+#define ICON_MDI_HOLOLENS "\xf3\xb0\x8b\x9b" // U+F02DB
+#define ICON_MDI_HOME "\xf3\xb0\x8b\x9c" // U+F02DC
+#define ICON_MDI_HOME_ACCOUNT "\xf3\xb0\xa0\xa6" // U+F0826
+#define ICON_MDI_HOME_ALERT "\xf3\xb0\xa1\xbb" // U+F087B
+#define ICON_MDI_HOME_ALERT_OUTLINE "\xf3\xb1\x97\x90" // U+F15D0
+#define ICON_MDI_HOME_ANALYTICS "\xf3\xb0\xba\xba" // U+F0EBA
+#define ICON_MDI_HOME_ASSISTANT "\xf3\xb0\x9f\x90" // U+F07D0
+#define ICON_MDI_HOME_AUTOMATION "\xf3\xb0\x9f\x91" // U+F07D1
+#define ICON_MDI_HOME_BATTERY "\xf3\xb1\xa4\x81" // U+F1901
+#define ICON_MDI_HOME_BATTERY_OUTLINE "\xf3\xb1\xa4\x82" // U+F1902
+#define ICON_MDI_HOME_CIRCLE "\xf3\xb0\x9f\x92" // U+F07D2
+#define ICON_MDI_HOME_CIRCLE_OUTLINE "\xf3\xb1\x81\x8d" // U+F104D
+#define ICON_MDI_HOME_CITY "\xf3\xb0\xb4\x95" // U+F0D15
+#define ICON_MDI_HOME_CITY_OUTLINE "\xf3\xb0\xb4\x96" // U+F0D16
+#define ICON_MDI_HOME_CLOCK "\xf3\xb1\xa8\x92" // U+F1A12
+#define ICON_MDI_HOME_CLOCK_OUTLINE "\xf3\xb1\xa8\x93" // U+F1A13
+#define ICON_MDI_HOME_EDIT "\xf3\xb1\x85\x99" // U+F1159
+#define ICON_MDI_HOME_EDIT_OUTLINE "\xf3\xb1\x85\x9a" // U+F115A
+#define ICON_MDI_HOME_EXPORT_OUTLINE "\xf3\xb0\xbe\x9b" // U+F0F9B
+#define ICON_MDI_HOME_FLOOD "\xf3\xb0\xbb\xba" // U+F0EFA
+#define ICON_MDI_HOME_FLOOR_0 "\xf3\xb0\xb7\x92" // U+F0DD2
+#define ICON_MDI_HOME_FLOOR_1 "\xf3\xb0\xb6\x80" // U+F0D80
+#define ICON_MDI_HOME_FLOOR_2 "\xf3\xb0\xb6\x81" // U+F0D81
+#define ICON_MDI_HOME_FLOOR_3 "\xf3\xb0\xb6\x82" // U+F0D82
+#define ICON_MDI_HOME_FLOOR_A "\xf3\xb0\xb6\x83" // U+F0D83
+#define ICON_MDI_HOME_FLOOR_B "\xf3\xb0\xb6\x84" // U+F0D84
+#define ICON_MDI_HOME_FLOOR_G "\xf3\xb0\xb6\x85" // U+F0D85
+#define ICON_MDI_HOME_FLOOR_L "\xf3\xb0\xb6\x86" // U+F0D86
+#define ICON_MDI_HOME_FLOOR_NEGATIVE_1 "\xf3\xb0\xb7\x93" // U+F0DD3
+#define ICON_MDI_HOME_GROUP "\xf3\xb0\xb7\x94" // U+F0DD4
+#define ICON_MDI_HOME_GROUP_MINUS "\xf3\xb1\xa7\x81" // U+F19C1
+#define ICON_MDI_HOME_GROUP_PLUS "\xf3\xb1\xa7\x80" // U+F19C0
+#define ICON_MDI_HOME_GROUP_REMOVE "\xf3\xb1\xa7\x82" // U+F19C2
+#define ICON_MDI_HOME_HEART "\xf3\xb0\xa0\xa7" // U+F0827
+#define ICON_MDI_HOME_IMPORT_OUTLINE "\xf3\xb0\xbe\x9c" // U+F0F9C
+#define ICON_MDI_HOME_LIGHTBULB "\xf3\xb1\x89\x91" // U+F1251
+#define ICON_MDI_HOME_LIGHTBULB_OUTLINE "\xf3\xb1\x89\x92" // U+F1252
+#define ICON_MDI_HOME_LIGHTNING_BOLT "\xf3\xb1\xa4\x83" // U+F1903
+#define ICON_MDI_HOME_LIGHTNING_BOLT_OUTLINE "\xf3\xb1\xa4\x84" // U+F1904
+#define ICON_MDI_HOME_LOCK "\xf3\xb0\xa3\xab" // U+F08EB
+#define ICON_MDI_HOME_LOCK_OPEN "\xf3\xb0\xa3\xac" // U+F08EC
+#define ICON_MDI_HOME_MAP_MARKER "\xf3\xb0\x97\xb8" // U+F05F8
+#define ICON_MDI_HOME_MINUS "\xf3\xb0\xa5\xb4" // U+F0974
+#define ICON_MDI_HOME_MINUS_OUTLINE "\xf3\xb1\x8f\x95" // U+F13D5
+#define ICON_MDI_HOME_MODERN "\xf3\xb0\x8b\x9d" // U+F02DD
+#define ICON_MDI_HOME_OFF "\xf3\xb1\xa9\x86" // U+F1A46
+#define ICON_MDI_HOME_OFF_OUTLINE "\xf3\xb1\xa9\x87" // U+F1A47
+#define ICON_MDI_HOME_OUTLINE "\xf3\xb0\x9a\xa1" // U+F06A1
+#define ICON_MDI_HOME_PERCENT "\xf3\xb1\xb1\xbc" // U+F1C7C
+#define ICON_MDI_HOME_PERCENT_OUTLINE "\xf3\xb1\xb1\xbd" // U+F1C7D
+#define ICON_MDI_HOME_PLUS "\xf3\xb0\xa5\xb5" // U+F0975
+#define ICON_MDI_HOME_PLUS_OUTLINE "\xf3\xb1\x8f\x96" // U+F13D6
+#define ICON_MDI_HOME_REMOVE "\xf3\xb1\x89\x87" // U+F1247
+#define ICON_MDI_HOME_REMOVE_OUTLINE "\xf3\xb1\x8f\x97" // U+F13D7
+#define ICON_MDI_HOME_ROOF "\xf3\xb1\x84\xab" // U+F112B
+#define ICON_MDI_HOME_SEARCH "\xf3\xb1\x8e\xb0" // U+F13B0
+#define ICON_MDI_HOME_SEARCH_OUTLINE "\xf3\xb1\x8e\xb1" // U+F13B1
+#define ICON_MDI_HOME_SILO "\xf3\xb1\xae\xa0" // U+F1BA0
+#define ICON_MDI_HOME_SILO_OUTLINE "\xf3\xb1\xae\xa1" // U+F1BA1
+#define ICON_MDI_HOME_SOUND_IN "\xf3\xb1\xb0\xaf" // U+F1C2F
+#define ICON_MDI_HOME_SOUND_IN_OUTLINE "\xf3\xb1\xb0\xb0" // U+F1C30
+#define ICON_MDI_HOME_SOUND_OUT "\xf3\xb1\xb0\xb1" // U+F1C31
+#define ICON_MDI_HOME_SOUND_OUT_OUTLINE "\xf3\xb1\xb0\xb2" // U+F1C32
+#define ICON_MDI_HOME_SWITCH "\xf3\xb1\x9e\x94" // U+F1794
+#define ICON_MDI_HOME_SWITCH_OUTLINE "\xf3\xb1\x9e\x95" // U+F1795
+#define ICON_MDI_HOME_THERMOMETER "\xf3\xb0\xbd\x94" // U+F0F54
+#define ICON_MDI_HOME_THERMOMETER_OUTLINE "\xf3\xb0\xbd\x95" // U+F0F55
+#define ICON_MDI_HOME_VARIANT "\xf3\xb0\x8b\x9e" // U+F02DE
+#define ICON_MDI_HOME_VARIANT_OUTLINE "\xf3\xb0\xae\xa7" // U+F0BA7
+#define ICON_MDI_HOOK "\xf3\xb0\x9b\xa2" // U+F06E2
+#define ICON_MDI_HOOK_OFF "\xf3\xb0\x9b\xa3" // U+F06E3
+#define ICON_MDI_HOOP_HOUSE "\xf3\xb0\xb9\x96" // U+F0E56
+#define ICON_MDI_HOPS "\xf3\xb0\x8b\x9f" // U+F02DF
+#define ICON_MDI_HORIZONTAL_ROTATE_CLOCKWISE "\xf3\xb1\x83\xb3" // U+F10F3
+#define ICON_MDI_HORIZONTAL_ROTATE_COUNTERCLOCKWISE "\xf3\xb1\x83\xb4" // U+F10F4
+#define ICON_MDI_HORSE "\xf3\xb1\x96\xbf" // U+F15BF
+#define ICON_MDI_HORSE_HUMAN "\xf3\xb1\x97\x80" // U+F15C0
+#define ICON_MDI_HORSE_VARIANT "\xf3\xb1\x97\x81" // U+F15C1
+#define ICON_MDI_HORSE_VARIANT_FAST "\xf3\xb1\xa1\xae" // U+F186E
+#define ICON_MDI_HORSESHOE "\xf3\xb0\xa9\x98" // U+F0A58
+#define ICON_MDI_HOSPITAL "\xf3\xb0\xbf\xb6" // U+F0FF6
+#define ICON_MDI_HOSPITAL_BOX "\xf3\xb0\x8b\xa0" // U+F02E0
+#define ICON_MDI_HOSPITAL_BOX_OUTLINE "\xf3\xb0\xbf\xb7" // U+F0FF7
+#define ICON_MDI_HOSPITAL_BUILDING "\xf3\xb0\x8b\xa1" // U+F02E1
+#define ICON_MDI_HOSPITAL_MARKER "\xf3\xb0\x8b\xa2" // U+F02E2
+#define ICON_MDI_HOT_TUB "\xf3\xb0\xa0\xa8" // U+F0828
+#define ICON_MDI_HOURS_12 "\xf3\xb1\xb2\x94" // U+F1C94
+#define ICON_MDI_HOURS_24 "\xf3\xb1\x91\xb8" // U+F1478
+#define ICON_MDI_HUB "\xf3\xb1\xb2\x95" // U+F1C95
+#define ICON_MDI_HUB_OUTLINE "\xf3\xb1\xb2\x96" // U+F1C96
+#define ICON_MDI_HUBSPOT "\xf3\xb0\xb4\x97" // U+F0D17
+#define ICON_MDI_HULU "\xf3\xb0\xa0\xa9" // U+F0829
+#define ICON_MDI_HUMAN "\xf3\xb0\x8b\xa6" // U+F02E6
+#define ICON_MDI_HUMAN_BABY_CHANGING_TABLE "\xf3\xb1\x8e\x8b" // U+F138B
+#define ICON_MDI_HUMAN_CANE "\xf3\xb1\x96\x81" // U+F1581
+#define ICON_MDI_HUMAN_CAPACITY_DECREASE "\xf3\xb1\x96\x9b" // U+F159B
+#define ICON_MDI_HUMAN_CAPACITY_INCREASE "\xf3\xb1\x96\x9c" // U+F159C
+#define ICON_MDI_HUMAN_CHILD "\xf3\xb0\x8b\xa7" // U+F02E7
+#define ICON_MDI_HUMAN_DOLLY "\xf3\xb1\xa6\x80" // U+F1980
+#define ICON_MDI_HUMAN_EDIT "\xf3\xb1\x93\xa8" // U+F14E8
+#define ICON_MDI_HUMAN_FEMALE "\xf3\xb0\x99\x89" // U+F0649
+#define ICON_MDI_HUMAN_FEMALE_BOY "\xf3\xb0\xa9\x99" // U+F0A59
+#define ICON_MDI_HUMAN_FEMALE_DANCE "\xf3\xb1\x97\x89" // U+F15C9
+#define ICON_MDI_HUMAN_FEMALE_FEMALE "\xf3\xb0\xa9\x9a" // U+F0A5A
+#define ICON_MDI_HUMAN_FEMALE_FEMALE_CHILD "\xf3\xb1\xb2\x8e" // U+F1C8E
+#define ICON_MDI_HUMAN_FEMALE_GIRL "\xf3\xb0\xa9\x9b" // U+F0A5B
+#define ICON_MDI_HUMAN_GREETING "\xf3\xb1\x9f\x84" // U+F17C4
+#define ICON_MDI_HUMAN_GREETING_PROXIMITY "\xf3\xb1\x96\x9d" // U+F159D
+#define ICON_MDI_HUMAN_GREETING_VARIANT "\xf3\xb0\x99\x8a" // U+F064A
+#define ICON_MDI_HUMAN_HANDSDOWN "\xf3\xb0\x99\x8b" // U+F064B
+#define ICON_MDI_HUMAN_HANDSUP "\xf3\xb0\x99\x8c" // U+F064C
+#define ICON_MDI_HUMAN_MALE "\xf3\xb0\x99\x8d" // U+F064D
+#define ICON_MDI_HUMAN_MALE_BOARD "\xf3\xb0\xa2\x90" // U+F0890
+#define ICON_MDI_HUMAN_MALE_BOARD_POLL "\xf3\xb0\xa1\x86" // U+F0846
+#define ICON_MDI_HUMAN_MALE_BOY "\xf3\xb0\xa9\x9c" // U+F0A5C
+#define ICON_MDI_HUMAN_MALE_CHILD "\xf3\xb1\x8e\x8c" // U+F138C
+#define ICON_MDI_HUMAN_MALE_FEMALE "\xf3\xb0\x8b\xa8" // U+F02E8
+#define ICON_MDI_HUMAN_MALE_FEMALE_CHILD "\xf3\xb1\xa0\xa3" // U+F1823
+#define ICON_MDI_HUMAN_MALE_GIRL "\xf3\xb0\xa9\x9d" // U+F0A5D
+#define ICON_MDI_HUMAN_MALE_HEIGHT "\xf3\xb0\xbb\xbb" // U+F0EFB
+#define ICON_MDI_HUMAN_MALE_HEIGHT_VARIANT "\xf3\xb0\xbb\xbc" // U+F0EFC
+#define ICON_MDI_HUMAN_MALE_MALE "\xf3\xb0\xa9\x9e" // U+F0A5E
+#define ICON_MDI_HUMAN_MALE_MALE_CHILD "\xf3\xb1\xb2\x8f" // U+F1C8F
+#define ICON_MDI_HUMAN_NON_BINARY "\xf3\xb1\xa1\x88" // U+F1848
+#define ICON_MDI_HUMAN_PREGNANT "\xf3\xb0\x97\x8f" // U+F05CF
+#define ICON_MDI_HUMAN_QUEUE "\xf3\xb1\x95\xb1" // U+F1571
+#define ICON_MDI_HUMAN_SCOOTER "\xf3\xb1\x87\xa9" // U+F11E9
+#define ICON_MDI_HUMAN_WALKER "\xf3\xb1\xad\xb1" // U+F1B71
+#define ICON_MDI_HUMAN_WHEELCHAIR "\xf3\xb1\x8e\x8d" // U+F138D
+#define ICON_MDI_HUMAN_WHITE_CANE "\xf3\xb1\xa6\x81" // U+F1981
+#define ICON_MDI_HUMBLE_BUNDLE "\xf3\xb0\x9d\x84" // U+F0744
+#define ICON_MDI_HVAC "\xf3\xb1\x8d\x92" // U+F1352
+#define ICON_MDI_HVAC_OFF "\xf3\xb1\x96\x9e" // U+F159E
+#define ICON_MDI_HYDRAULIC_OIL_LEVEL "\xf3\xb1\x8c\xa4" // U+F1324
+#define ICON_MDI_HYDRAULIC_OIL_TEMPERATURE "\xf3\xb1\x8c\xa5" // U+F1325
+#define ICON_MDI_HYDRO_POWER "\xf3\xb1\x8b\xa5" // U+F12E5
+#define ICON_MDI_HYDROGEN_STATION "\xf3\xb1\xa2\x94" // U+F1894
+#define ICON_MDI_ICE_CREAM "\xf3\xb0\xa0\xaa" // U+F082A
+#define ICON_MDI_ICE_CREAM_OFF "\xf3\xb0\xb9\x92" // U+F0E52
+#define ICON_MDI_ICE_POP "\xf3\xb0\xbb\xbd" // U+F0EFD
+#define ICON_MDI_ID_CARD "\xf3\xb0\xbf\x80" // U+F0FC0
+#define ICON_MDI_IDENTIFIER "\xf3\xb0\xbb\xbe" // U+F0EFE
+#define ICON_MDI_IDEOGRAM_CJK "\xf3\xb1\x8c\xb1" // U+F1331
+#define ICON_MDI_IDEOGRAM_CJK_VARIANT "\xf3\xb1\x8c\xb2" // U+F1332
+#define ICON_MDI_IMAGE "\xf3\xb0\x8b\xa9" // U+F02E9
+#define ICON_MDI_IMAGE_ALBUM "\xf3\xb0\x8b\xaa" // U+F02EA
+#define ICON_MDI_IMAGE_AREA "\xf3\xb0\x8b\xab" // U+F02EB
+#define ICON_MDI_IMAGE_AREA_CLOSE "\xf3\xb0\x8b\xac" // U+F02EC
+#define ICON_MDI_IMAGE_AUTO_ADJUST "\xf3\xb0\xbf\x81" // U+F0FC1
+#define ICON_MDI_IMAGE_BROKEN "\xf3\xb0\x8b\xad" // U+F02ED
+#define ICON_MDI_IMAGE_BROKEN_VARIANT "\xf3\xb0\x8b\xae" // U+F02EE
+#define ICON_MDI_IMAGE_CHECK "\xf3\xb1\xac\xa5" // U+F1B25
+#define ICON_MDI_IMAGE_CHECK_OUTLINE "\xf3\xb1\xac\xa6" // U+F1B26
+#define ICON_MDI_IMAGE_EDIT "\xf3\xb1\x87\xa3" // U+F11E3
+#define ICON_MDI_IMAGE_EDIT_OUTLINE "\xf3\xb1\x87\xa4" // U+F11E4
+#define ICON_MDI_IMAGE_FILTER_BLACK_WHITE "\xf3\xb0\x8b\xb0" // U+F02F0
+#define ICON_MDI_IMAGE_FILTER_CENTER_FOCUS "\xf3\xb0\x8b\xb1" // U+F02F1
+#define ICON_MDI_IMAGE_FILTER_CENTER_FOCUS_STRONG "\xf3\xb0\xbb\xbf" // U+F0EFF
+#define ICON_MDI_IMAGE_FILTER_CENTER_FOCUS_STRONG_OUTLINE "\xf3\xb0\xbc\x80" // U+F0F00
+#define ICON_MDI_IMAGE_FILTER_CENTER_FOCUS_WEAK "\xf3\xb0\x8b\xb2" // U+F02F2
+#define ICON_MDI_IMAGE_FILTER_DRAMA "\xf3\xb0\x8b\xb3" // U+F02F3
+#define ICON_MDI_IMAGE_FILTER_DRAMA_OUTLINE "\xf3\xb1\xaf\xbf" // U+F1BFF
+#define ICON_MDI_IMAGE_FILTER_FRAMES "\xf3\xb0\x8b\xb4" // U+F02F4
+#define ICON_MDI_IMAGE_FILTER_HDR "\xf3\xb0\x8b\xb5" // U+F02F5
+#define ICON_MDI_IMAGE_FILTER_HDR_OUTLINE "\xf3\xb1\xb1\xa4" // U+F1C64
+#define ICON_MDI_IMAGE_FILTER_NONE "\xf3\xb0\x8b\xb6" // U+F02F6
+#define ICON_MDI_IMAGE_FILTER_TILT_SHIFT "\xf3\xb0\x8b\xb7" // U+F02F7
+#define ICON_MDI_IMAGE_FILTER_VINTAGE "\xf3\xb0\x8b\xb8" // U+F02F8
+#define ICON_MDI_IMAGE_FRAME "\xf3\xb0\xb9\x89" // U+F0E49
+#define ICON_MDI_IMAGE_LOCK "\xf3\xb1\xaa\xb0" // U+F1AB0
+#define ICON_MDI_IMAGE_LOCK_OUTLINE "\xf3\xb1\xaa\xb1" // U+F1AB1
+#define ICON_MDI_IMAGE_MARKER "\xf3\xb1\x9d\xbb" // U+F177B
+#define ICON_MDI_IMAGE_MARKER_OUTLINE "\xf3\xb1\x9d\xbc" // U+F177C
+#define ICON_MDI_IMAGE_MINUS "\xf3\xb1\x90\x99" // U+F1419
+#define ICON_MDI_IMAGE_MINUS_OUTLINE "\xf3\xb1\xad\x87" // U+F1B47
+#define ICON_MDI_IMAGE_MOVE "\xf3\xb0\xa7\xb8" // U+F09F8
+#define ICON_MDI_IMAGE_MULTIPLE "\xf3\xb0\x8b\xb9" // U+F02F9
+#define ICON_MDI_IMAGE_MULTIPLE_OUTLINE "\xf3\xb0\x8b\xaf" // U+F02EF
+#define ICON_MDI_IMAGE_OFF "\xf3\xb0\xa0\xab" // U+F082B
+#define ICON_MDI_IMAGE_OFF_OUTLINE "\xf3\xb1\x87\x91" // U+F11D1
+#define ICON_MDI_IMAGE_OUTLINE "\xf3\xb0\xa5\xb6" // U+F0976
+#define ICON_MDI_IMAGE_PLUS "\xf3\xb0\xa1\xbc" // U+F087C
+#define ICON_MDI_IMAGE_PLUS_OUTLINE "\xf3\xb1\xad\x86" // U+F1B46
+#define ICON_MDI_IMAGE_REFRESH "\xf3\xb1\xa7\xbe" // U+F19FE
+#define ICON_MDI_IMAGE_REFRESH_OUTLINE "\xf3\xb1\xa7\xbf" // U+F19FF
+#define ICON_MDI_IMAGE_REMOVE "\xf3\xb1\x90\x98" // U+F1418
+#define ICON_MDI_IMAGE_REMOVE_OUTLINE "\xf3\xb1\xad\x88" // U+F1B48
+#define ICON_MDI_IMAGE_SEARCH "\xf3\xb0\xa5\xb7" // U+F0977
+#define ICON_MDI_IMAGE_SEARCH_OUTLINE "\xf3\xb0\xa5\xb8" // U+F0978
+#define ICON_MDI_IMAGE_SIZE_SELECT_ACTUAL "\xf3\xb0\xb2\x8d" // U+F0C8D
+#define ICON_MDI_IMAGE_SIZE_SELECT_LARGE "\xf3\xb0\xb2\x8e" // U+F0C8E
+#define ICON_MDI_IMAGE_SIZE_SELECT_SMALL "\xf3\xb0\xb2\x8f" // U+F0C8F
+#define ICON_MDI_IMAGE_SYNC "\xf3\xb1\xa8\x80" // U+F1A00
+#define ICON_MDI_IMAGE_SYNC_OUTLINE "\xf3\xb1\xa8\x81" // U+F1A01
+#define ICON_MDI_IMAGE_TEXT "\xf3\xb1\x98\x8d" // U+F160D
+#define ICON_MDI_IMPORT "\xf3\xb0\x8b\xba" // U+F02FA
+#define ICON_MDI_INBOX "\xf3\xb0\x9a\x87" // U+F0687
+#define ICON_MDI_INBOX_ARROW_DOWN "\xf3\xb0\x8b\xbb" // U+F02FB
+#define ICON_MDI_INBOX_ARROW_DOWN_OUTLINE "\xf3\xb1\x89\xb0" // U+F1270
+#define ICON_MDI_INBOX_ARROW_UP "\xf3\xb0\x8f\x91" // U+F03D1
+#define ICON_MDI_INBOX_ARROW_UP_OUTLINE "\xf3\xb1\x89\xb1" // U+F1271
+#define ICON_MDI_INBOX_FULL "\xf3\xb1\x89\xb2" // U+F1272
+#define ICON_MDI_INBOX_FULL_OUTLINE "\xf3\xb1\x89\xb3" // U+F1273
+#define ICON_MDI_INBOX_MULTIPLE "\xf3\xb0\xa2\xb0" // U+F08B0
+#define ICON_MDI_INBOX_MULTIPLE_OUTLINE "\xf3\xb0\xae\xa8" // U+F0BA8
+#define ICON_MDI_INBOX_OUTLINE "\xf3\xb1\x89\xb4" // U+F1274
+#define ICON_MDI_INBOX_REMOVE "\xf3\xb1\x96\x9f" // U+F159F
+#define ICON_MDI_INBOX_REMOVE_OUTLINE "\xf3\xb1\x96\xa0" // U+F15A0
+#define ICON_MDI_INCOGNITO "\xf3\xb0\x97\xb9" // U+F05F9
+#define ICON_MDI_INCOGNITO_CIRCLE "\xf3\xb1\x90\xa1" // U+F1421
+#define ICON_MDI_INCOGNITO_CIRCLE_OFF "\xf3\xb1\x90\xa2" // U+F1422
+#define ICON_MDI_INCOGNITO_OFF "\xf3\xb0\x81\xb5" // U+F0075
+#define ICON_MDI_INDUCTION "\xf3\xb1\xa1\x8c" // U+F184C
+#define ICON_MDI_INFINITY "\xf3\xb0\x9b\xa4" // U+F06E4
+#define ICON_MDI_INFORMATION "\xf3\xb0\x8b\xbc" // U+F02FC
+#define ICON_MDI_INFORMATION_BOX "\xf3\xb1\xb1\xa5" // U+F1C65
+#define ICON_MDI_INFORMATION_BOX_OUTLINE "\xf3\xb1\xb1\xa6" // U+F1C66
+#define ICON_MDI_INFORMATION_OFF "\xf3\xb1\x9e\x8c" // U+F178C
+#define ICON_MDI_INFORMATION_OFF_OUTLINE "\xf3\xb1\x9e\x8d" // U+F178D
+#define ICON_MDI_INFORMATION_OUTLINE "\xf3\xb0\x8b\xbd" // U+F02FD
+#define ICON_MDI_INFORMATION_SLAB_BOX "\xf3\xb1\xb1\xa7" // U+F1C67
+#define ICON_MDI_INFORMATION_SLAB_BOX_OUTLINE "\xf3\xb1\xb1\xa8" // U+F1C68
+#define ICON_MDI_INFORMATION_SLAB_CIRCLE "\xf3\xb1\xb1\xa9" // U+F1C69
+#define ICON_MDI_INFORMATION_SLAB_CIRCLE_OUTLINE "\xf3\xb1\xb1\xaa" // U+F1C6A
+#define ICON_MDI_INFORMATION_SLAB_SYMBOL "\xf3\xb1\xb1\xab" // U+F1C6B
+#define ICON_MDI_INFORMATION_SYMBOL "\xf3\xb1\xb1\xac" // U+F1C6C
+#define ICON_MDI_INFORMATION_VARIANT "\xf3\xb0\x99\x8e" // U+F064E
+#define ICON_MDI_INFORMATION_VARIANT_BOX "\xf3\xb1\xb1\xad" // U+F1C6D
+#define ICON_MDI_INFORMATION_VARIANT_BOX_OUTLINE "\xf3\xb1\xb1\xae" // U+F1C6E
+#define ICON_MDI_INFORMATION_VARIANT_CIRCLE "\xf3\xb1\xb1\xaf" // U+F1C6F
+#define ICON_MDI_INFORMATION_VARIANT_CIRCLE_OUTLINE "\xf3\xb1\xb1\xb0" // U+F1C70
+#define ICON_MDI_INSTAGRAM "\xf3\xb0\x8b\xbe" // U+F02FE
+#define ICON_MDI_INSTRUMENT_TRIANGLE "\xf3\xb1\x81\x8e" // U+F104E
+#define ICON_MDI_INTEGRATED_CIRCUIT_CHIP "\xf3\xb1\xa4\x93" // U+F1913
+#define ICON_MDI_INVERT_COLORS "\xf3\xb0\x8c\x81" // U+F0301
+#define ICON_MDI_INVERT_COLORS_OFF "\xf3\xb0\xb9\x8a" // U+F0E4A
+#define ICON_MDI_IOBROKER "\xf3\xb1\x8b\xa8" // U+F12E8
+#define ICON_MDI_IP "\xf3\xb0\xa9\x9f" // U+F0A5F
+#define ICON_MDI_IP_NETWORK "\xf3\xb0\xa9\xa0" // U+F0A60
+#define ICON_MDI_IP_NETWORK_OUTLINE "\xf3\xb0\xb2\x90" // U+F0C90
+#define ICON_MDI_IP_OUTLINE "\xf3\xb1\xa6\x82" // U+F1982
+#define ICON_MDI_IPOD "\xf3\xb0\xb2\x91" // U+F0C91
+#define ICON_MDI_IRON "\xf3\xb1\xa0\xa4" // U+F1824
+#define ICON_MDI_IRON_BOARD "\xf3\xb1\xa0\xb8" // U+F1838
+#define ICON_MDI_IRON_OUTLINE "\xf3\xb1\xa0\xa5" // U+F1825
+#define ICON_MDI_ISLAND "\xf3\xb1\x81\x8f" // U+F104F
+#define ICON_MDI_ISLAND_VARIANT "\xf3\xb1\xb3\x86" // U+F1CC6
+#define ICON_MDI_IV_BAG "\xf3\xb1\x82\xb9" // U+F10B9
+#define ICON_MDI_JABBER "\xf3\xb0\xb7\x95" // U+F0DD5
+#define ICON_MDI_JEEPNEY "\xf3\xb0\x8c\x82" // U+F0302
+#define ICON_MDI_JELLYFISH "\xf3\xb0\xbc\x81" // U+F0F01
+#define ICON_MDI_JELLYFISH_OUTLINE "\xf3\xb0\xbc\x82" // U+F0F02
+#define ICON_MDI_JIRA "\xf3\xb0\x8c\x83" // U+F0303
+#define ICON_MDI_JQUERY "\xf3\xb0\xa1\xbd" // U+F087D
+#define ICON_MDI_JSFIDDLE "\xf3\xb0\x8c\x84" // U+F0304
+#define ICON_MDI_JUMP_ROPE "\xf3\xb1\x8b\xbf" // U+F12FF
+#define ICON_MDI_KABADDI "\xf3\xb0\xb6\x87" // U+F0D87
+#define ICON_MDI_KANGAROO "\xf3\xb1\x95\x98" // U+F1558
+#define ICON_MDI_KARATE "\xf3\xb0\xa0\xac" // U+F082C
+#define ICON_MDI_KAYAKING "\xf3\xb0\xa2\xaf" // U+F08AF
+#define ICON_MDI_KEG "\xf3\xb0\x8c\x85" // U+F0305
+#define ICON_MDI_KETTLE "\xf3\xb0\x97\xba" // U+F05FA
+#define ICON_MDI_KETTLE_ALERT "\xf3\xb1\x8c\x97" // U+F1317
+#define ICON_MDI_KETTLE_ALERT_OUTLINE "\xf3\xb1\x8c\x98" // U+F1318
+#define ICON_MDI_KETTLE_OFF "\xf3\xb1\x8c\x9b" // U+F131B
+#define ICON_MDI_KETTLE_OFF_OUTLINE "\xf3\xb1\x8c\x9c" // U+F131C
+#define ICON_MDI_KETTLE_OUTLINE "\xf3\xb0\xbd\x96" // U+F0F56
+#define ICON_MDI_KETTLE_POUR_OVER "\xf3\xb1\x9c\xbc" // U+F173C
+#define ICON_MDI_KETTLE_STEAM "\xf3\xb1\x8c\x99" // U+F1319
+#define ICON_MDI_KETTLE_STEAM_OUTLINE "\xf3\xb1\x8c\x9a" // U+F131A
+#define ICON_MDI_KETTLEBELL "\xf3\xb1\x8c\x80" // U+F1300
+#define ICON_MDI_KEY "\xf3\xb0\x8c\x86" // U+F0306
+#define ICON_MDI_KEY_ALERT "\xf3\xb1\xa6\x83" // U+F1983
+#define ICON_MDI_KEY_ALERT_OUTLINE "\xf3\xb1\xa6\x84" // U+F1984
+#define ICON_MDI_KEY_ARROW_RIGHT "\xf3\xb1\x8c\x92" // U+F1312
+#define ICON_MDI_KEY_CHAIN "\xf3\xb1\x95\xb4" // U+F1574
+#define ICON_MDI_KEY_CHAIN_VARIANT "\xf3\xb1\x95\xb5" // U+F1575
+#define ICON_MDI_KEY_CHANGE "\xf3\xb0\x8c\x87" // U+F0307
+#define ICON_MDI_KEY_LINK "\xf3\xb1\x86\x9f" // U+F119F
+#define ICON_MDI_KEY_MINUS "\xf3\xb0\x8c\x88" // U+F0308
+#define ICON_MDI_KEY_OUTLINE "\xf3\xb0\xb7\x96" // U+F0DD6
+#define ICON_MDI_KEY_PLUS "\xf3\xb0\x8c\x89" // U+F0309
+#define ICON_MDI_KEY_REMOVE "\xf3\xb0\x8c\x8a" // U+F030A
+#define ICON_MDI_KEY_STAR "\xf3\xb1\x86\x9e" // U+F119E
+#define ICON_MDI_KEY_VARIANT "\xf3\xb0\x8c\x8b" // U+F030B
+#define ICON_MDI_KEY_WIRELESS "\xf3\xb0\xbf\x82" // U+F0FC2
+#define ICON_MDI_KEYBOARD "\xf3\xb0\x8c\x8c" // U+F030C
+#define ICON_MDI_KEYBOARD_BACKSPACE "\xf3\xb0\x8c\x8d" // U+F030D
+#define ICON_MDI_KEYBOARD_CAPS "\xf3\xb0\x8c\x8e" // U+F030E
+#define ICON_MDI_KEYBOARD_CLOSE "\xf3\xb0\x8c\x8f" // U+F030F
+#define ICON_MDI_KEYBOARD_CLOSE_OUTLINE "\xf3\xb1\xb0\x80" // U+F1C00
+#define ICON_MDI_KEYBOARD_ESC "\xf3\xb1\x8a\xb7" // U+F12B7
+#define ICON_MDI_KEYBOARD_F1 "\xf3\xb1\x8a\xab" // U+F12AB
+#define ICON_MDI_KEYBOARD_F10 "\xf3\xb1\x8a\xb4" // U+F12B4
+#define ICON_MDI_KEYBOARD_F11 "\xf3\xb1\x8a\xb5" // U+F12B5
+#define ICON_MDI_KEYBOARD_F12 "\xf3\xb1\x8a\xb6" // U+F12B6
+#define ICON_MDI_KEYBOARD_F2 "\xf3\xb1\x8a\xac" // U+F12AC
+#define ICON_MDI_KEYBOARD_F3 "\xf3\xb1\x8a\xad" // U+F12AD
+#define ICON_MDI_KEYBOARD_F4 "\xf3\xb1\x8a\xae" // U+F12AE
+#define ICON_MDI_KEYBOARD_F5 "\xf3\xb1\x8a\xaf" // U+F12AF
+#define ICON_MDI_KEYBOARD_F6 "\xf3\xb1\x8a\xb0" // U+F12B0
+#define ICON_MDI_KEYBOARD_F7 "\xf3\xb1\x8a\xb1" // U+F12B1
+#define ICON_MDI_KEYBOARD_F8 "\xf3\xb1\x8a\xb2" // U+F12B2
+#define ICON_MDI_KEYBOARD_F9 "\xf3\xb1\x8a\xb3" // U+F12B3
+#define ICON_MDI_KEYBOARD_OFF "\xf3\xb0\x8c\x90" // U+F0310
+#define ICON_MDI_KEYBOARD_OFF_OUTLINE "\xf3\xb0\xb9\x8b" // U+F0E4B
+#define ICON_MDI_KEYBOARD_OUTLINE "\xf3\xb0\xa5\xbb" // U+F097B
+#define ICON_MDI_KEYBOARD_RETURN "\xf3\xb0\x8c\x91" // U+F0311
+#define ICON_MDI_KEYBOARD_SETTINGS "\xf3\xb0\xa7\xb9" // U+F09F9
+#define ICON_MDI_KEYBOARD_SETTINGS_OUTLINE "\xf3\xb0\xa7\xba" // U+F09FA
+#define ICON_MDI_KEYBOARD_SPACE "\xf3\xb1\x81\x90" // U+F1050
+#define ICON_MDI_KEYBOARD_TAB "\xf3\xb0\x8c\x92" // U+F0312
+#define ICON_MDI_KEYBOARD_TAB_REVERSE "\xf3\xb0\x8c\xa5" // U+F0325
+#define ICON_MDI_KEYBOARD_VARIANT "\xf3\xb0\x8c\x93" // U+F0313
+#define ICON_MDI_KHANDA "\xf3\xb1\x83\xbd" // U+F10FD
+#define ICON_MDI_KICKSTARTER "\xf3\xb0\x9d\x85" // U+F0745
+#define ICON_MDI_KITE "\xf3\xb1\xa6\x85" // U+F1985
+#define ICON_MDI_KITE_OUTLINE "\xf3\xb1\xa6\x86" // U+F1986
+#define ICON_MDI_KITESURFING "\xf3\xb1\x9d\x84" // U+F1744
+#define ICON_MDI_KLINGON "\xf3\xb1\x8d\x9b" // U+F135B
+#define ICON_MDI_KNIFE "\xf3\xb0\xa7\xbb" // U+F09FB
+#define ICON_MDI_KNIFE_MILITARY "\xf3\xb0\xa7\xbc" // U+F09FC
+#define ICON_MDI_KNOB "\xf3\xb1\xae\x96" // U+F1B96
+#define ICON_MDI_KOALA "\xf3\xb1\x9c\xbf" // U+F173F
+#define ICON_MDI_KODI "\xf3\xb0\x8c\x94" // U+F0314
+#define ICON_MDI_KUBERNETES "\xf3\xb1\x83\xbe" // U+F10FE
+#define ICON_MDI_LABEL "\xf3\xb0\x8c\x95" // U+F0315
+#define ICON_MDI_LABEL_MULTIPLE "\xf3\xb1\x8d\xb5" // U+F1375
+#define ICON_MDI_LABEL_MULTIPLE_OUTLINE "\xf3\xb1\x8d\xb6" // U+F1376
+#define ICON_MDI_LABEL_OFF "\xf3\xb0\xab\x8b" // U+F0ACB
+#define ICON_MDI_LABEL_OFF_OUTLINE "\xf3\xb0\xab\x8c" // U+F0ACC
+#define ICON_MDI_LABEL_OUTLINE "\xf3\xb0\x8c\x96" // U+F0316
+#define ICON_MDI_LABEL_PERCENT "\xf3\xb1\x8b\xaa" // U+F12EA
+#define ICON_MDI_LABEL_PERCENT_OUTLINE "\xf3\xb1\x8b\xab" // U+F12EB
+#define ICON_MDI_LABEL_VARIANT "\xf3\xb0\xab\x8d" // U+F0ACD
+#define ICON_MDI_LABEL_VARIANT_OUTLINE "\xf3\xb0\xab\x8e" // U+F0ACE
+#define ICON_MDI_LADDER "\xf3\xb1\x96\xa2" // U+F15A2
+#define ICON_MDI_LADYBUG "\xf3\xb0\xa0\xad" // U+F082D
+#define ICON_MDI_LAMBDA "\xf3\xb0\x98\xa7" // U+F0627
+#define ICON_MDI_LAMP "\xf3\xb0\x9a\xb5" // U+F06B5
+#define ICON_MDI_LAMP_OUTLINE "\xf3\xb1\x9f\x90" // U+F17D0
+#define ICON_MDI_LAMPS "\xf3\xb1\x95\xb6" // U+F1576
+#define ICON_MDI_LAMPS_OUTLINE "\xf3\xb1\x9f\x91" // U+F17D1
+#define ICON_MDI_LAN "\xf3\xb0\x8c\x97" // U+F0317
+#define ICON_MDI_LAN_CHECK "\xf3\xb1\x8a\xaa" // U+F12AA
+#define ICON_MDI_LAN_CONNECT "\xf3\xb0\x8c\x98" // U+F0318
+#define ICON_MDI_LAN_DISCONNECT "\xf3\xb0\x8c\x99" // U+F0319
+#define ICON_MDI_LAN_PENDING "\xf3\xb0\x8c\x9a" // U+F031A
+#define ICON_MDI_LAND_FIELDS "\xf3\xb1\xaa\xb2" // U+F1AB2
+#define ICON_MDI_LAND_PLOTS "\xf3\xb1\xaa\xb3" // U+F1AB3
+#define ICON_MDI_LAND_PLOTS_CIRCLE "\xf3\xb1\xaa\xb4" // U+F1AB4
+#define ICON_MDI_LAND_PLOTS_CIRCLE_VARIANT "\xf3\xb1\xaa\xb5" // U+F1AB5
+#define ICON_MDI_LAND_PLOTS_MARKER "\xf3\xb1\xb1\x9d" // U+F1C5D
+#define ICON_MDI_LAND_ROWS_HORIZONTAL "\xf3\xb1\xaa\xb6" // U+F1AB6
+#define ICON_MDI_LAND_ROWS_VERTICAL "\xf3\xb1\xaa\xb7" // U+F1AB7
+#define ICON_MDI_LANDSLIDE "\xf3\xb1\xa9\x88" // U+F1A48
+#define ICON_MDI_LANDSLIDE_OUTLINE "\xf3\xb1\xa9\x89" // U+F1A49
+#define ICON_MDI_LANGUAGE_C "\xf3\xb0\x99\xb1" // U+F0671
+#define ICON_MDI_LANGUAGE_CPP "\xf3\xb0\x99\xb2" // U+F0672
+#define ICON_MDI_LANGUAGE_CSHARP "\xf3\xb0\x8c\x9b" // U+F031B
+#define ICON_MDI_LANGUAGE_CSS3 "\xf3\xb0\x8c\x9c" // U+F031C
+#define ICON_MDI_LANGUAGE_FORTRAN "\xf3\xb1\x88\x9a" // U+F121A
+#define ICON_MDI_LANGUAGE_GO "\xf3\xb0\x9f\x93" // U+F07D3
+#define ICON_MDI_LANGUAGE_HASKELL "\xf3\xb0\xb2\x92" // U+F0C92
+#define ICON_MDI_LANGUAGE_HTML5 "\xf3\xb0\x8c\x9d" // U+F031D
+#define ICON_MDI_LANGUAGE_JAVA "\xf3\xb0\xac\xb7" // U+F0B37
+#define ICON_MDI_LANGUAGE_JAVASCRIPT "\xf3\xb0\x8c\x9e" // U+F031E
+#define ICON_MDI_LANGUAGE_KOTLIN "\xf3\xb1\x88\x99" // U+F1219
+#define ICON_MDI_LANGUAGE_LUA "\xf3\xb0\xa2\xb1" // U+F08B1
+#define ICON_MDI_LANGUAGE_MARKDOWN "\xf3\xb0\x8d\x94" // U+F0354
+#define ICON_MDI_LANGUAGE_MARKDOWN_OUTLINE "\xf3\xb0\xbd\x9b" // U+F0F5B
+#define ICON_MDI_LANGUAGE_PHP "\xf3\xb0\x8c\x9f" // U+F031F
+#define ICON_MDI_LANGUAGE_PYTHON "\xf3\xb0\x8c\xa0" // U+F0320
+#define ICON_MDI_LANGUAGE_R "\xf3\xb0\x9f\x94" // U+F07D4
+#define ICON_MDI_LANGUAGE_RUBY "\xf3\xb0\xb4\xad" // U+F0D2D
+#define ICON_MDI_LANGUAGE_RUBY_ON_RAILS "\xf3\xb0\xab\x8f" // U+F0ACF
+#define ICON_MDI_LANGUAGE_RUST "\xf3\xb1\x98\x97" // U+F1617
+#define ICON_MDI_LANGUAGE_SWIFT "\xf3\xb0\x9b\xa5" // U+F06E5
+#define ICON_MDI_LANGUAGE_TYPESCRIPT "\xf3\xb0\x9b\xa6" // U+F06E6
+#define ICON_MDI_LANGUAGE_XAML "\xf3\xb0\x99\xb3" // U+F0673
+#define ICON_MDI_LAPTOP "\xf3\xb0\x8c\xa2" // U+F0322
+#define ICON_MDI_LAPTOP_ACCOUNT "\xf3\xb1\xa9\x8a" // U+F1A4A
+#define ICON_MDI_LAPTOP_OFF "\xf3\xb0\x9b\xa7" // U+F06E7
+#define ICON_MDI_LARAVEL "\xf3\xb0\xab\x90" // U+F0AD0
+#define ICON_MDI_LASER_POINTER "\xf3\xb1\x92\x84" // U+F1484
+#define ICON_MDI_LASSO "\xf3\xb0\xbc\x83" // U+F0F03
+#define ICON_MDI_LASTPASS "\xf3\xb0\x91\x86" // U+F0446
+#define ICON_MDI_LATITUDE "\xf3\xb0\xbd\x97" // U+F0F57
+#define ICON_MDI_LAUNCH "\xf3\xb0\x8c\xa7" // U+F0327
+#define ICON_MDI_LAVA_LAMP "\xf3\xb0\x9f\x95" // U+F07D5
+#define ICON_MDI_LAYERS "\xf3\xb0\x8c\xa8" // U+F0328
+#define ICON_MDI_LAYERS_EDIT "\xf3\xb1\xa2\x92" // U+F1892
+#define ICON_MDI_LAYERS_MINUS "\xf3\xb0\xb9\x8c" // U+F0E4C
+#define ICON_MDI_LAYERS_OFF "\xf3\xb0\x8c\xa9" // U+F0329
+#define ICON_MDI_LAYERS_OFF_OUTLINE "\xf3\xb0\xa7\xbd" // U+F09FD
+#define ICON_MDI_LAYERS_OUTLINE "\xf3\xb0\xa7\xbe" // U+F09FE
+#define ICON_MDI_LAYERS_PLUS "\xf3\xb0\xb9\x8d" // U+F0E4D
+#define ICON_MDI_LAYERS_REMOVE "\xf3\xb0\xb9\x8e" // U+F0E4E
+#define ICON_MDI_LAYERS_SEARCH "\xf3\xb1\x88\x86" // U+F1206
+#define ICON_MDI_LAYERS_SEARCH_OUTLINE "\xf3\xb1\x88\x87" // U+F1207
+#define ICON_MDI_LAYERS_TRIPLE "\xf3\xb0\xbd\x98" // U+F0F58
+#define ICON_MDI_LAYERS_TRIPLE_OUTLINE "\xf3\xb0\xbd\x99" // U+F0F59
+#define ICON_MDI_LEAD_PENCIL "\xf3\xb0\x99\x8f" // U+F064F
+#define ICON_MDI_LEAF "\xf3\xb0\x8c\xaa" // U+F032A
+#define ICON_MDI_LEAF_CIRCLE "\xf3\xb1\xa4\x85" // U+F1905
+#define ICON_MDI_LEAF_CIRCLE_OUTLINE "\xf3\xb1\xa4\x86" // U+F1906
+#define ICON_MDI_LEAF_MAPLE "\xf3\xb0\xb2\x93" // U+F0C93
+#define ICON_MDI_LEAF_MAPLE_OFF "\xf3\xb1\x8b\x9a" // U+F12DA
+#define ICON_MDI_LEAF_OFF "\xf3\xb1\x8b\x99" // U+F12D9
+#define ICON_MDI_LEAK "\xf3\xb0\xb7\x97" // U+F0DD7
+#define ICON_MDI_LEAK_OFF "\xf3\xb0\xb7\x98" // U+F0DD8
+#define ICON_MDI_LECTERN "\xf3\xb1\xab\xb0" // U+F1AF0
+#define ICON_MDI_LED_OFF "\xf3\xb0\x8c\xab" // U+F032B
+#define ICON_MDI_LED_ON "\xf3\xb0\x8c\xac" // U+F032C
+#define ICON_MDI_LED_OUTLINE "\xf3\xb0\x8c\xad" // U+F032D
+#define ICON_MDI_LED_STRIP "\xf3\xb0\x9f\x96" // U+F07D6
+#define ICON_MDI_LED_STRIP_VARIANT "\xf3\xb1\x81\x91" // U+F1051
+#define ICON_MDI_LED_STRIP_VARIANT_OFF "\xf3\xb1\xa9\x8b" // U+F1A4B
+#define ICON_MDI_LED_VARIANT_OFF "\xf3\xb0\x8c\xae" // U+F032E
+#define ICON_MDI_LED_VARIANT_ON "\xf3\xb0\x8c\xaf" // U+F032F
+#define ICON_MDI_LED_VARIANT_OUTLINE "\xf3\xb0\x8c\xb0" // U+F0330
+#define ICON_MDI_LEEK "\xf3\xb1\x85\xbd" // U+F117D
+#define ICON_MDI_LESS_THAN "\xf3\xb0\xa5\xbc" // U+F097C
+#define ICON_MDI_LESS_THAN_OR_EQUAL "\xf3\xb0\xa5\xbd" // U+F097D
+#define ICON_MDI_LIBRARY "\xf3\xb0\x8c\xb1" // U+F0331
+#define ICON_MDI_LIBRARY_OUTLINE "\xf3\xb1\xa8\xa2" // U+F1A22
+#define ICON_MDI_LIBRARY_SHELVES "\xf3\xb0\xae\xa9" // U+F0BA9
+#define ICON_MDI_LICENSE "\xf3\xb0\xbf\x83" // U+F0FC3
+#define ICON_MDI_LIFEBUOY "\xf3\xb0\xa1\xbe" // U+F087E
+#define ICON_MDI_LIGHT_FLOOD_DOWN "\xf3\xb1\xa6\x87" // U+F1987
+#define ICON_MDI_LIGHT_FLOOD_UP "\xf3\xb1\xa6\x88" // U+F1988
+#define ICON_MDI_LIGHT_RECESSED "\xf3\xb1\x9e\x9b" // U+F179B
+#define ICON_MDI_LIGHT_SWITCH "\xf3\xb0\xa5\xbe" // U+F097E
+#define ICON_MDI_LIGHT_SWITCH_OFF "\xf3\xb1\xa8\xa4" // U+F1A24
+#define ICON_MDI_LIGHTBULB "\xf3\xb0\x8c\xb5" // U+F0335
+#define ICON_MDI_LIGHTBULB_ALERT "\xf3\xb1\xa7\xa1" // U+F19E1
+#define ICON_MDI_LIGHTBULB_ALERT_OUTLINE "\xf3\xb1\xa7\xa2" // U+F19E2
+#define ICON_MDI_LIGHTBULB_AUTO "\xf3\xb1\xa0\x80" // U+F1800
+#define ICON_MDI_LIGHTBULB_AUTO_OUTLINE "\xf3\xb1\xa0\x81" // U+F1801
+#define ICON_MDI_LIGHTBULB_CFL "\xf3\xb1\x88\x88" // U+F1208
+#define ICON_MDI_LIGHTBULB_CFL_OFF "\xf3\xb1\x88\x89" // U+F1209
+#define ICON_MDI_LIGHTBULB_CFL_SPIRAL "\xf3\xb1\x89\xb5" // U+F1275
+#define ICON_MDI_LIGHTBULB_CFL_SPIRAL_OFF "\xf3\xb1\x8b\x83" // U+F12C3
+#define ICON_MDI_LIGHTBULB_FLUORESCENT_TUBE "\xf3\xb1\xa0\x84" // U+F1804
+#define ICON_MDI_LIGHTBULB_FLUORESCENT_TUBE_OUTLINE "\xf3\xb1\xa0\x85" // U+F1805
+#define ICON_MDI_LIGHTBULB_GROUP "\xf3\xb1\x89\x93" // U+F1253
+#define ICON_MDI_LIGHTBULB_GROUP_OFF "\xf3\xb1\x8b\x8d" // U+F12CD
+#define ICON_MDI_LIGHTBULB_GROUP_OFF_OUTLINE "\xf3\xb1\x8b\x8e" // U+F12CE
+#define ICON_MDI_LIGHTBULB_GROUP_OUTLINE "\xf3\xb1\x89\x94" // U+F1254
+#define ICON_MDI_LIGHTBULB_MULTIPLE "\xf3\xb1\x89\x95" // U+F1255
+#define ICON_MDI_LIGHTBULB_MULTIPLE_OFF "\xf3\xb1\x8b\x8f" // U+F12CF
+#define ICON_MDI_LIGHTBULB_MULTIPLE_OFF_OUTLINE "\xf3\xb1\x8b\x90" // U+F12D0
+#define ICON_MDI_LIGHTBULB_MULTIPLE_OUTLINE "\xf3\xb1\x89\x96" // U+F1256
+#define ICON_MDI_LIGHTBULB_NIGHT "\xf3\xb1\xa9\x8c" // U+F1A4C
+#define ICON_MDI_LIGHTBULB_NIGHT_OUTLINE "\xf3\xb1\xa9\x8d" // U+F1A4D
+#define ICON_MDI_LIGHTBULB_OFF "\xf3\xb0\xb9\x8f" // U+F0E4F
+#define ICON_MDI_LIGHTBULB_OFF_OUTLINE "\xf3\xb0\xb9\x90" // U+F0E50
+#define ICON_MDI_LIGHTBULB_ON "\xf3\xb0\x9b\xa8" // U+F06E8
+#define ICON_MDI_LIGHTBULB_ON_10 "\xf3\xb1\xa9\x8e" // U+F1A4E
+#define ICON_MDI_LIGHTBULB_ON_20 "\xf3\xb1\xa9\x8f" // U+F1A4F
+#define ICON_MDI_LIGHTBULB_ON_30 "\xf3\xb1\xa9\x90" // U+F1A50
+#define ICON_MDI_LIGHTBULB_ON_40 "\xf3\xb1\xa9\x91" // U+F1A51
+#define ICON_MDI_LIGHTBULB_ON_50 "\xf3\xb1\xa9\x92" // U+F1A52
+#define ICON_MDI_LIGHTBULB_ON_60 "\xf3\xb1\xa9\x93" // U+F1A53
+#define ICON_MDI_LIGHTBULB_ON_70 "\xf3\xb1\xa9\x94" // U+F1A54
+#define ICON_MDI_LIGHTBULB_ON_80 "\xf3\xb1\xa9\x95" // U+F1A55
+#define ICON_MDI_LIGHTBULB_ON_90 "\xf3\xb1\xa9\x96" // U+F1A56
+#define ICON_MDI_LIGHTBULB_ON_OUTLINE "\xf3\xb0\x9b\xa9" // U+F06E9
+#define ICON_MDI_LIGHTBULB_OUTLINE "\xf3\xb0\x8c\xb6" // U+F0336
+#define ICON_MDI_LIGHTBULB_QUESTION "\xf3\xb1\xa7\xa3" // U+F19E3
+#define ICON_MDI_LIGHTBULB_QUESTION_OUTLINE "\xf3\xb1\xa7\xa4" // U+F19E4
+#define ICON_MDI_LIGHTBULB_SPOT "\xf3\xb1\x9f\xb4" // U+F17F4
+#define ICON_MDI_LIGHTBULB_SPOT_OFF "\xf3\xb1\x9f\xb5" // U+F17F5
+#define ICON_MDI_LIGHTBULB_VARIANT "\xf3\xb1\xa0\x82" // U+F1802
+#define ICON_MDI_LIGHTBULB_VARIANT_OUTLINE "\xf3\xb1\xa0\x83" // U+F1803
+#define ICON_MDI_LIGHTHOUSE "\xf3\xb0\xa7\xbf" // U+F09FF
+#define ICON_MDI_LIGHTHOUSE_ON "\xf3\xb0\xa8\x80" // U+F0A00
+#define ICON_MDI_LIGHTNING_BOLT "\xf3\xb1\x90\x8b" // U+F140B
+#define ICON_MDI_LIGHTNING_BOLT_CIRCLE "\xf3\xb0\xa0\xa0" // U+F0820
+#define ICON_MDI_LIGHTNING_BOLT_OUTLINE "\xf3\xb1\x90\x8c" // U+F140C
+#define ICON_MDI_LINE_SCAN "\xf3\xb0\x98\xa4" // U+F0624
+#define ICON_MDI_LINGERIE "\xf3\xb1\x91\xb6" // U+F1476
+#define ICON_MDI_LINK "\xf3\xb0\x8c\xb7" // U+F0337
+#define ICON_MDI_LINK_BOX "\xf3\xb0\xb4\x9a" // U+F0D1A
+#define ICON_MDI_LINK_BOX_OUTLINE "\xf3\xb0\xb4\x9b" // U+F0D1B
+#define ICON_MDI_LINK_BOX_VARIANT "\xf3\xb0\xb4\x9c" // U+F0D1C
+#define ICON_MDI_LINK_BOX_VARIANT_OUTLINE "\xf3\xb0\xb4\x9d" // U+F0D1D
+#define ICON_MDI_LINK_CIRCLE "\xf3\xb1\xb2\xac" // U+F1CAC
+#define ICON_MDI_LINK_CIRCLE_OUTLINE "\xf3\xb1\xb2\xad" // U+F1CAD
+#define ICON_MDI_LINK_EDIT "\xf3\xb1\xb2\xae" // U+F1CAE
+#define ICON_MDI_LINK_LOCK "\xf3\xb1\x82\xba" // U+F10BA
+#define ICON_MDI_LINK_OFF "\xf3\xb0\x8c\xb8" // U+F0338
+#define ICON_MDI_LINK_PLUS "\xf3\xb0\xb2\x94" // U+F0C94
+#define ICON_MDI_LINK_VARIANT "\xf3\xb0\x8c\xb9" // U+F0339
+#define ICON_MDI_LINK_VARIANT_MINUS "\xf3\xb1\x83\xbf" // U+F10FF
+#define ICON_MDI_LINK_VARIANT_OFF "\xf3\xb0\x8c\xba" // U+F033A
+#define ICON_MDI_LINK_VARIANT_PLUS "\xf3\xb1\x84\x80" // U+F1100
+#define ICON_MDI_LINK_VARIANT_REMOVE "\xf3\xb1\x84\x81" // U+F1101
+#define ICON_MDI_LINKEDIN "\xf3\xb0\x8c\xbb" // U+F033B
+#define ICON_MDI_LINUX "\xf3\xb0\x8c\xbd" // U+F033D
+#define ICON_MDI_LINUX_MINT "\xf3\xb0\xa3\xad" // U+F08ED
+#define ICON_MDI_LIPSTICK "\xf3\xb1\x8e\xb5" // U+F13B5
+#define ICON_MDI_LIQUID_SPOT "\xf3\xb1\xa0\xa6" // U+F1826
+#define ICON_MDI_LIQUOR "\xf3\xb1\xa4\x9e" // U+F191E
+#define ICON_MDI_LIST_BOX "\xf3\xb1\xad\xbb" // U+F1B7B
+#define ICON_MDI_LIST_BOX_OUTLINE "\xf3\xb1\xad\xbc" // U+F1B7C
+#define ICON_MDI_LIST_STATUS "\xf3\xb1\x96\xab" // U+F15AB
+#define ICON_MDI_LITECOIN "\xf3\xb0\xa9\xa1" // U+F0A61
+#define ICON_MDI_LOADING "\xf3\xb0\x9d\xb2" // U+F0772
+#define ICON_MDI_LOCATION_ENTER "\xf3\xb0\xbf\x84" // U+F0FC4
+#define ICON_MDI_LOCATION_EXIT "\xf3\xb0\xbf\x85" // U+F0FC5
+#define ICON_MDI_LOCK "\xf3\xb0\x8c\xbe" // U+F033E
+#define ICON_MDI_LOCK_ALERT "\xf3\xb0\xa3\xae" // U+F08EE
+#define ICON_MDI_LOCK_ALERT_OUTLINE "\xf3\xb1\x97\x91" // U+F15D1
+#define ICON_MDI_LOCK_CHECK "\xf3\xb1\x8e\x9a" // U+F139A
+#define ICON_MDI_LOCK_CHECK_OUTLINE "\xf3\xb1\x9a\xa8" // U+F16A8
+#define ICON_MDI_LOCK_CLOCK "\xf3\xb0\xa5\xbf" // U+F097F
+#define ICON_MDI_LOCK_MINUS "\xf3\xb1\x9a\xa9" // U+F16A9
+#define ICON_MDI_LOCK_MINUS_OUTLINE "\xf3\xb1\x9a\xaa" // U+F16AA
+#define ICON_MDI_LOCK_OFF "\xf3\xb1\x99\xb1" // U+F1671
+#define ICON_MDI_LOCK_OFF_OUTLINE "\xf3\xb1\x99\xb2" // U+F1672
+#define ICON_MDI_LOCK_OPEN "\xf3\xb0\x8c\xbf" // U+F033F
+#define ICON_MDI_LOCK_OPEN_ALERT "\xf3\xb1\x8e\x9b" // U+F139B
+#define ICON_MDI_LOCK_OPEN_ALERT_OUTLINE "\xf3\xb1\x97\x92" // U+F15D2
+#define ICON_MDI_LOCK_OPEN_CHECK "\xf3\xb1\x8e\x9c" // U+F139C
+#define ICON_MDI_LOCK_OPEN_CHECK_OUTLINE "\xf3\xb1\x9a\xab" // U+F16AB
+#define ICON_MDI_LOCK_OPEN_MINUS "\xf3\xb1\x9a\xac" // U+F16AC
+#define ICON_MDI_LOCK_OPEN_MINUS_OUTLINE "\xf3\xb1\x9a\xad" // U+F16AD
+#define ICON_MDI_LOCK_OPEN_OUTLINE "\xf3\xb0\x8d\x80" // U+F0340
+#define ICON_MDI_LOCK_OPEN_PLUS "\xf3\xb1\x9a\xae" // U+F16AE
+#define ICON_MDI_LOCK_OPEN_PLUS_OUTLINE "\xf3\xb1\x9a\xaf" // U+F16AF
+#define ICON_MDI_LOCK_OPEN_REMOVE "\xf3\xb1\x9a\xb0" // U+F16B0
+#define ICON_MDI_LOCK_OPEN_REMOVE_OUTLINE "\xf3\xb1\x9a\xb1" // U+F16B1
+#define ICON_MDI_LOCK_OPEN_VARIANT "\xf3\xb0\xbf\x86" // U+F0FC6
+#define ICON_MDI_LOCK_OPEN_VARIANT_OUTLINE "\xf3\xb0\xbf\x87" // U+F0FC7
+#define ICON_MDI_LOCK_OUTLINE "\xf3\xb0\x8d\x81" // U+F0341
+#define ICON_MDI_LOCK_PATTERN "\xf3\xb0\x9b\xaa" // U+F06EA
+#define ICON_MDI_LOCK_PERCENT "\xf3\xb1\xb0\x92" // U+F1C12
+#define ICON_MDI_LOCK_PERCENT_OPEN "\xf3\xb1\xb0\x93" // U+F1C13
+#define ICON_MDI_LOCK_PERCENT_OPEN_OUTLINE "\xf3\xb1\xb0\x94" // U+F1C14
+#define ICON_MDI_LOCK_PERCENT_OPEN_VARIANT "\xf3\xb1\xb0\x95" // U+F1C15
+#define ICON_MDI_LOCK_PERCENT_OPEN_VARIANT_OUTLINE "\xf3\xb1\xb0\x96" // U+F1C16
+#define ICON_MDI_LOCK_PERCENT_OUTLINE "\xf3\xb1\xb0\x97" // U+F1C17
+#define ICON_MDI_LOCK_PLUS "\xf3\xb0\x97\xbb" // U+F05FB
+#define ICON_MDI_LOCK_PLUS_OUTLINE "\xf3\xb1\x9a\xb2" // U+F16B2
+#define ICON_MDI_LOCK_QUESTION "\xf3\xb0\xa3\xaf" // U+F08EF
+#define ICON_MDI_LOCK_REMOVE "\xf3\xb1\x9a\xb3" // U+F16B3
+#define ICON_MDI_LOCK_REMOVE_OUTLINE "\xf3\xb1\x9a\xb4" // U+F16B4
+#define ICON_MDI_LOCK_RESET "\xf3\xb0\x9d\xb3" // U+F0773
+#define ICON_MDI_LOCK_SMART "\xf3\xb0\xa2\xb2" // U+F08B2
+#define ICON_MDI_LOCKER "\xf3\xb0\x9f\x97" // U+F07D7
+#define ICON_MDI_LOCKER_MULTIPLE "\xf3\xb0\x9f\x98" // U+F07D8
+#define ICON_MDI_LOGIN "\xf3\xb0\x8d\x82" // U+F0342
+#define ICON_MDI_LOGIN_VARIANT "\xf3\xb0\x97\xbc" // U+F05FC
+#define ICON_MDI_LOGOUT "\xf3\xb0\x8d\x83" // U+F0343
+#define ICON_MDI_LOGOUT_VARIANT "\xf3\xb0\x97\xbd" // U+F05FD
+#define ICON_MDI_LONGITUDE "\xf3\xb0\xbd\x9a" // U+F0F5A
+#define ICON_MDI_LOOKS "\xf3\xb0\x8d\x84" // U+F0344
+#define ICON_MDI_LOTION "\xf3\xb1\x96\x82" // U+F1582
+#define ICON_MDI_LOTION_OUTLINE "\xf3\xb1\x96\x83" // U+F1583
+#define ICON_MDI_LOTION_PLUS "\xf3\xb1\x96\x84" // U+F1584
+#define ICON_MDI_LOTION_PLUS_OUTLINE "\xf3\xb1\x96\x85" // U+F1585
+#define ICON_MDI_LOUPE "\xf3\xb0\x8d\x85" // U+F0345
+#define ICON_MDI_LUMX "\xf3\xb0\x8d\x86" // U+F0346
+#define ICON_MDI_LUNGS "\xf3\xb1\x82\x84" // U+F1084
+#define ICON_MDI_MACE "\xf3\xb1\xa1\x83" // U+F1843
+#define ICON_MDI_MAGAZINE_PISTOL "\xf3\xb0\x8c\xa4" // U+F0324
+#define ICON_MDI_MAGAZINE_RIFLE "\xf3\xb0\x8c\xa3" // U+F0323
+#define ICON_MDI_MAGIC_STAFF "\xf3\xb1\xa1\x84" // U+F1844
+#define ICON_MDI_MAGNET "\xf3\xb0\x8d\x87" // U+F0347
+#define ICON_MDI_MAGNET_ON "\xf3\xb0\x8d\x88" // U+F0348
+#define ICON_MDI_MAGNIFY "\xf3\xb0\x8d\x89" // U+F0349
+#define ICON_MDI_MAGNIFY_CLOSE "\xf3\xb0\xa6\x80" // U+F0980
+#define ICON_MDI_MAGNIFY_EXPAND "\xf3\xb1\xa1\xb4" // U+F1874
+#define ICON_MDI_MAGNIFY_MINUS "\xf3\xb0\x8d\x8a" // U+F034A
+#define ICON_MDI_MAGNIFY_MINUS_CURSOR "\xf3\xb0\xa9\xa2" // U+F0A62
+#define ICON_MDI_MAGNIFY_MINUS_OUTLINE "\xf3\xb0\x9b\xac" // U+F06EC
+#define ICON_MDI_MAGNIFY_PLUS "\xf3\xb0\x8d\x8b" // U+F034B
+#define ICON_MDI_MAGNIFY_PLUS_CURSOR "\xf3\xb0\xa9\xa3" // U+F0A63
+#define ICON_MDI_MAGNIFY_PLUS_OUTLINE "\xf3\xb0\x9b\xad" // U+F06ED
+#define ICON_MDI_MAGNIFY_REMOVE_CURSOR "\xf3\xb1\x88\x8c" // U+F120C
+#define ICON_MDI_MAGNIFY_REMOVE_OUTLINE "\xf3\xb1\x88\x8d" // U+F120D
+#define ICON_MDI_MAGNIFY_SCAN "\xf3\xb1\x89\xb6" // U+F1276
+#define ICON_MDI_MAIL "\xf3\xb0\xba\xbb" // U+F0EBB
+#define ICON_MDI_MAILBOX "\xf3\xb0\x9b\xae" // U+F06EE
+#define ICON_MDI_MAILBOX_OPEN "\xf3\xb0\xb6\x88" // U+F0D88
+#define ICON_MDI_MAILBOX_OPEN_OUTLINE "\xf3\xb0\xb6\x89" // U+F0D89
+#define ICON_MDI_MAILBOX_OPEN_UP "\xf3\xb0\xb6\x8a" // U+F0D8A
+#define ICON_MDI_MAILBOX_OPEN_UP_OUTLINE "\xf3\xb0\xb6\x8b" // U+F0D8B
+#define ICON_MDI_MAILBOX_OUTLINE "\xf3\xb0\xb6\x8c" // U+F0D8C
+#define ICON_MDI_MAILBOX_UP "\xf3\xb0\xb6\x8d" // U+F0D8D
+#define ICON_MDI_MAILBOX_UP_OUTLINE "\xf3\xb0\xb6\x8e" // U+F0D8E
+#define ICON_MDI_MANJARO "\xf3\xb1\x98\x8a" // U+F160A
+#define ICON_MDI_MAP "\xf3\xb0\x8d\x8d" // U+F034D
+#define ICON_MDI_MAP_CHECK "\xf3\xb0\xba\xbc" // U+F0EBC
+#define ICON_MDI_MAP_CHECK_OUTLINE "\xf3\xb0\xba\xbd" // U+F0EBD
+#define ICON_MDI_MAP_CLOCK "\xf3\xb0\xb4\x9e" // U+F0D1E
+#define ICON_MDI_MAP_CLOCK_OUTLINE "\xf3\xb0\xb4\x9f" // U+F0D1F
+#define ICON_MDI_MAP_LEGEND "\xf3\xb0\xa8\x81" // U+F0A01
+#define ICON_MDI_MAP_MARKER "\xf3\xb0\x8d\x8e" // U+F034E
+#define ICON_MDI_MAP_MARKER_ACCOUNT "\xf3\xb1\xa3\xa3" // U+F18E3
+#define ICON_MDI_MAP_MARKER_ACCOUNT_OUTLINE "\xf3\xb1\xa3\xa4" // U+F18E4
+#define ICON_MDI_MAP_MARKER_ALERT "\xf3\xb0\xbc\x85" // U+F0F05
+#define ICON_MDI_MAP_MARKER_ALERT_OUTLINE "\xf3\xb0\xbc\x86" // U+F0F06
+#define ICON_MDI_MAP_MARKER_CHECK "\xf3\xb0\xb2\x95" // U+F0C95
+#define ICON_MDI_MAP_MARKER_CHECK_OUTLINE "\xf3\xb1\x8b\xbb" // U+F12FB
+#define ICON_MDI_MAP_MARKER_CIRCLE "\xf3\xb0\x8d\x8f" // U+F034F
+#define ICON_MDI_MAP_MARKER_DISTANCE "\xf3\xb0\xa3\xb0" // U+F08F0
+#define ICON_MDI_MAP_MARKER_DOWN "\xf3\xb1\x84\x82" // U+F1102
+#define ICON_MDI_MAP_MARKER_LEFT "\xf3\xb1\x8b\x9b" // U+F12DB
+#define ICON_MDI_MAP_MARKER_LEFT_OUTLINE "\xf3\xb1\x8b\x9d" // U+F12DD
+#define ICON_MDI_MAP_MARKER_MINUS "\xf3\xb0\x99\x90" // U+F0650
+#define ICON_MDI_MAP_MARKER_MINUS_OUTLINE "\xf3\xb1\x8b\xb9" // U+F12F9
+#define ICON_MDI_MAP_MARKER_MULTIPLE "\xf3\xb0\x8d\x90" // U+F0350
+#define ICON_MDI_MAP_MARKER_MULTIPLE_OUTLINE "\xf3\xb1\x89\xb7" // U+F1277
+#define ICON_MDI_MAP_MARKER_OFF "\xf3\xb0\x8d\x91" // U+F0351
+#define ICON_MDI_MAP_MARKER_OFF_OUTLINE "\xf3\xb1\x8b\xbd" // U+F12FD
+#define ICON_MDI_MAP_MARKER_OUTLINE "\xf3\xb0\x9f\x99" // U+F07D9
+#define ICON_MDI_MAP_MARKER_PATH "\xf3\xb0\xb4\xa0" // U+F0D20
+#define ICON_MDI_MAP_MARKER_PLUS "\xf3\xb0\x99\x91" // U+F0651
+#define ICON_MDI_MAP_MARKER_PLUS_OUTLINE "\xf3\xb1\x8b\xb8" // U+F12F8
+#define ICON_MDI_MAP_MARKER_QUESTION "\xf3\xb0\xbc\x87" // U+F0F07
+#define ICON_MDI_MAP_MARKER_QUESTION_OUTLINE "\xf3\xb0\xbc\x88" // U+F0F08
+#define ICON_MDI_MAP_MARKER_RADIUS "\xf3\xb0\x8d\x92" // U+F0352
+#define ICON_MDI_MAP_MARKER_RADIUS_OUTLINE "\xf3\xb1\x8b\xbc" // U+F12FC
+#define ICON_MDI_MAP_MARKER_REMOVE "\xf3\xb0\xbc\x89" // U+F0F09
+#define ICON_MDI_MAP_MARKER_REMOVE_OUTLINE "\xf3\xb1\x8b\xba" // U+F12FA
+#define ICON_MDI_MAP_MARKER_REMOVE_VARIANT "\xf3\xb0\xbc\x8a" // U+F0F0A
+#define ICON_MDI_MAP_MARKER_RIGHT "\xf3\xb1\x8b\x9c" // U+F12DC
+#define ICON_MDI_MAP_MARKER_RIGHT_OUTLINE "\xf3\xb1\x8b\x9e" // U+F12DE
+#define ICON_MDI_MAP_MARKER_STAR "\xf3\xb1\x98\x88" // U+F1608
+#define ICON_MDI_MAP_MARKER_STAR_OUTLINE "\xf3\xb1\x98\x89" // U+F1609
+#define ICON_MDI_MAP_MARKER_UP "\xf3\xb1\x84\x83" // U+F1103
+#define ICON_MDI_MAP_MINUS "\xf3\xb0\xa6\x81" // U+F0981
+#define ICON_MDI_MAP_OUTLINE "\xf3\xb0\xa6\x82" // U+F0982
+#define ICON_MDI_MAP_PLUS "\xf3\xb0\xa6\x83" // U+F0983
+#define ICON_MDI_MAP_SEARCH "\xf3\xb0\xa6\x84" // U+F0984
+#define ICON_MDI_MAP_SEARCH_OUTLINE "\xf3\xb0\xa6\x85" // U+F0985
+#define ICON_MDI_MAPBOX "\xf3\xb0\xae\xaa" // U+F0BAA
+#define ICON_MDI_MARGIN "\xf3\xb0\x8d\x93" // U+F0353
+#define ICON_MDI_MARKER "\xf3\xb0\x99\x92" // U+F0652
+#define ICON_MDI_MARKER_CANCEL "\xf3\xb0\xb7\x99" // U+F0DD9
+#define ICON_MDI_MARKER_CHECK "\xf3\xb0\x8d\x95" // U+F0355
+#define ICON_MDI_MASTODON "\xf3\xb0\xab\x91" // U+F0AD1
+#define ICON_MDI_MATERIAL_DESIGN "\xf3\xb0\xa6\x86" // U+F0986
+#define ICON_MDI_MATERIAL_UI "\xf3\xb0\x8d\x97" // U+F0357
+#define ICON_MDI_MATH_COMPASS "\xf3\xb0\x8d\x98" // U+F0358
+#define ICON_MDI_MATH_COS "\xf3\xb0\xb2\x96" // U+F0C96
+#define ICON_MDI_MATH_INTEGRAL "\xf3\xb0\xbf\x88" // U+F0FC8
+#define ICON_MDI_MATH_INTEGRAL_BOX "\xf3\xb0\xbf\x89" // U+F0FC9
+#define ICON_MDI_MATH_LOG "\xf3\xb1\x82\x85" // U+F1085
+#define ICON_MDI_MATH_NORM "\xf3\xb0\xbf\x8a" // U+F0FCA
+#define ICON_MDI_MATH_NORM_BOX "\xf3\xb0\xbf\x8b" // U+F0FCB
+#define ICON_MDI_MATH_SIN "\xf3\xb0\xb2\x97" // U+F0C97
+#define ICON_MDI_MATH_TAN "\xf3\xb0\xb2\x98" // U+F0C98
+#define ICON_MDI_MATRIX "\xf3\xb0\x98\xa8" // U+F0628
+#define ICON_MDI_MEDAL "\xf3\xb0\xa6\x87" // U+F0987
+#define ICON_MDI_MEDAL_OUTLINE "\xf3\xb1\x8c\xa6" // U+F1326
+#define ICON_MDI_MEDICAL_BAG "\xf3\xb0\x9b\xaf" // U+F06EF
+#define ICON_MDI_MEDICAL_COTTON_SWAB "\xf3\xb1\xaa\xb8" // U+F1AB8
+#define ICON_MDI_MEDICATION "\xf3\xb1\xac\x94" // U+F1B14
+#define ICON_MDI_MEDICATION_OUTLINE "\xf3\xb1\xac\x95" // U+F1B15
+#define ICON_MDI_MEDITATION "\xf3\xb1\x85\xbb" // U+F117B
+#define ICON_MDI_MEMORY "\xf3\xb0\x8d\x9b" // U+F035B
+#define ICON_MDI_MEMORY_ARROW_DOWN "\xf3\xb1\xb2\xa6" // U+F1CA6
+#define ICON_MDI_MENORAH "\xf3\xb1\x9f\x94" // U+F17D4
+#define ICON_MDI_MENORAH_FIRE "\xf3\xb1\x9f\x95" // U+F17D5
+#define ICON_MDI_MENU "\xf3\xb0\x8d\x9c" // U+F035C
+#define ICON_MDI_MENU_CLOSE "\xf3\xb1\xb2\x90" // U+F1C90
+#define ICON_MDI_MENU_DOWN "\xf3\xb0\x8d\x9d" // U+F035D
+#define ICON_MDI_MENU_DOWN_OUTLINE "\xf3\xb0\x9a\xb6" // U+F06B6
+#define ICON_MDI_MENU_LEFT "\xf3\xb0\x8d\x9e" // U+F035E
+#define ICON_MDI_MENU_LEFT_OUTLINE "\xf3\xb0\xa8\x82" // U+F0A02
+#define ICON_MDI_MENU_OPEN "\xf3\xb0\xae\xab" // U+F0BAB
+#define ICON_MDI_MENU_RIGHT "\xf3\xb0\x8d\x9f" // U+F035F
+#define ICON_MDI_MENU_RIGHT_OUTLINE "\xf3\xb0\xa8\x83" // U+F0A03
+#define ICON_MDI_MENU_SWAP "\xf3\xb0\xa9\xa4" // U+F0A64
+#define ICON_MDI_MENU_SWAP_OUTLINE "\xf3\xb0\xa9\xa5" // U+F0A65
+#define ICON_MDI_MENU_UP "\xf3\xb0\x8d\xa0" // U+F0360
+#define ICON_MDI_MENU_UP_OUTLINE "\xf3\xb0\x9a\xb7" // U+F06B7
+#define ICON_MDI_MERGE "\xf3\xb0\xbd\x9c" // U+F0F5C
+#define ICON_MDI_MESSAGE "\xf3\xb0\x8d\xa1" // U+F0361
+#define ICON_MDI_MESSAGE_ALERT "\xf3\xb0\x8d\xa2" // U+F0362
+#define ICON_MDI_MESSAGE_ALERT_OUTLINE "\xf3\xb0\xa8\x84" // U+F0A04
+#define ICON_MDI_MESSAGE_ARROW_LEFT "\xf3\xb1\x8b\xb2" // U+F12F2
+#define ICON_MDI_MESSAGE_ARROW_LEFT_OUTLINE "\xf3\xb1\x8b\xb3" // U+F12F3
+#define ICON_MDI_MESSAGE_ARROW_RIGHT "\xf3\xb1\x8b\xb4" // U+F12F4
+#define ICON_MDI_MESSAGE_ARROW_RIGHT_OUTLINE "\xf3\xb1\x8b\xb5" // U+F12F5
+#define ICON_MDI_MESSAGE_BADGE "\xf3\xb1\xa5\x81" // U+F1941
+#define ICON_MDI_MESSAGE_BADGE_OUTLINE "\xf3\xb1\xa5\x82" // U+F1942
+#define ICON_MDI_MESSAGE_BOOKMARK "\xf3\xb1\x96\xac" // U+F15AC
+#define ICON_MDI_MESSAGE_BOOKMARK_OUTLINE "\xf3\xb1\x96\xad" // U+F15AD
+#define ICON_MDI_MESSAGE_BULLETED "\xf3\xb0\x9a\xa2" // U+F06A2
+#define ICON_MDI_MESSAGE_BULLETED_OFF "\xf3\xb0\x9a\xa3" // U+F06A3
+#define ICON_MDI_MESSAGE_CHECK "\xf3\xb1\xae\x8a" // U+F1B8A
+#define ICON_MDI_MESSAGE_CHECK_OUTLINE "\xf3\xb1\xae\x8b" // U+F1B8B
+#define ICON_MDI_MESSAGE_COG "\xf3\xb0\x9b\xb1" // U+F06F1
+#define ICON_MDI_MESSAGE_COG_OUTLINE "\xf3\xb1\x85\xb2" // U+F1172
+#define ICON_MDI_MESSAGE_DRAW "\xf3\xb0\x8d\xa3" // U+F0363
+#define ICON_MDI_MESSAGE_FAST "\xf3\xb1\xa7\x8c" // U+F19CC
+#define ICON_MDI_MESSAGE_FAST_OUTLINE "\xf3\xb1\xa7\x8d" // U+F19CD
+#define ICON_MDI_MESSAGE_FLASH "\xf3\xb1\x96\xa9" // U+F15A9
+#define ICON_MDI_MESSAGE_FLASH_OUTLINE "\xf3\xb1\x96\xaa" // U+F15AA
+#define ICON_MDI_MESSAGE_IMAGE "\xf3\xb0\x8d\xa4" // U+F0364
+#define ICON_MDI_MESSAGE_IMAGE_OUTLINE "\xf3\xb1\x85\xac" // U+F116C
+#define ICON_MDI_MESSAGE_LOCK "\xf3\xb0\xbf\x8c" // U+F0FCC
+#define ICON_MDI_MESSAGE_LOCK_OUTLINE "\xf3\xb1\x85\xad" // U+F116D
+#define ICON_MDI_MESSAGE_MINUS "\xf3\xb1\x85\xae" // U+F116E
+#define ICON_MDI_MESSAGE_MINUS_OUTLINE "\xf3\xb1\x85\xaf" // U+F116F
+#define ICON_MDI_MESSAGE_OFF "\xf3\xb1\x99\x8d" // U+F164D
+#define ICON_MDI_MESSAGE_OFF_OUTLINE "\xf3\xb1\x99\x8e" // U+F164E
+#define ICON_MDI_MESSAGE_OUTLINE "\xf3\xb0\x8d\xa5" // U+F0365
+#define ICON_MDI_MESSAGE_PLUS "\xf3\xb0\x99\x93" // U+F0653
+#define ICON_MDI_MESSAGE_PLUS_OUTLINE "\xf3\xb1\x82\xbb" // U+F10BB
+#define ICON_MDI_MESSAGE_PROCESSING "\xf3\xb0\x8d\xa6" // U+F0366
+#define ICON_MDI_MESSAGE_PROCESSING_OUTLINE "\xf3\xb1\x85\xb0" // U+F1170
+#define ICON_MDI_MESSAGE_QUESTION "\xf3\xb1\x9c\xba" // U+F173A
+#define ICON_MDI_MESSAGE_QUESTION_OUTLINE "\xf3\xb1\x9c\xbb" // U+F173B
+#define ICON_MDI_MESSAGE_REPLY "\xf3\xb0\x8d\xa7" // U+F0367
+#define ICON_MDI_MESSAGE_REPLY_OUTLINE "\xf3\xb1\x9c\xbd" // U+F173D
+#define ICON_MDI_MESSAGE_REPLY_TEXT "\xf3\xb0\x8d\xa8" // U+F0368
+#define ICON_MDI_MESSAGE_REPLY_TEXT_OUTLINE "\xf3\xb1\x9c\xbe" // U+F173E
+#define ICON_MDI_MESSAGE_SETTINGS "\xf3\xb0\x9b\xb0" // U+F06F0
+#define ICON_MDI_MESSAGE_SETTINGS_OUTLINE "\xf3\xb1\x85\xb1" // U+F1171
+#define ICON_MDI_MESSAGE_STAR "\xf3\xb0\x9a\x9a" // U+F069A
+#define ICON_MDI_MESSAGE_STAR_OUTLINE "\xf3\xb1\x89\x90" // U+F1250
+#define ICON_MDI_MESSAGE_TEXT "\xf3\xb0\x8d\xa9" // U+F0369
+#define ICON_MDI_MESSAGE_TEXT_CLOCK "\xf3\xb1\x85\xb3" // U+F1173
+#define ICON_MDI_MESSAGE_TEXT_CLOCK_OUTLINE "\xf3\xb1\x85\xb4" // U+F1174
+#define ICON_MDI_MESSAGE_TEXT_FAST "\xf3\xb1\xa7\x8e" // U+F19CE
+#define ICON_MDI_MESSAGE_TEXT_FAST_OUTLINE "\xf3\xb1\xa7\x8f" // U+F19CF
+#define ICON_MDI_MESSAGE_TEXT_LOCK "\xf3\xb0\xbf\x8d" // U+F0FCD
+#define ICON_MDI_MESSAGE_TEXT_LOCK_OUTLINE "\xf3\xb1\x85\xb5" // U+F1175
+#define ICON_MDI_MESSAGE_TEXT_OUTLINE "\xf3\xb0\x8d\xaa" // U+F036A
+#define ICON_MDI_MESSAGE_VIDEO "\xf3\xb0\x8d\xab" // U+F036B
+#define ICON_MDI_METEOR "\xf3\xb0\x98\xa9" // U+F0629
+#define ICON_MDI_METER_ELECTRIC "\xf3\xb1\xa9\x97" // U+F1A57
+#define ICON_MDI_METER_ELECTRIC_OUTLINE "\xf3\xb1\xa9\x98" // U+F1A58
+#define ICON_MDI_METER_GAS "\xf3\xb1\xa9\x99" // U+F1A59
+#define ICON_MDI_METER_GAS_OUTLINE "\xf3\xb1\xa9\x9a" // U+F1A5A
+#define ICON_MDI_METRONOME "\xf3\xb0\x9f\x9a" // U+F07DA
+#define ICON_MDI_METRONOME_TICK "\xf3\xb0\x9f\x9b" // U+F07DB
+#define ICON_MDI_MICRO_SD "\xf3\xb0\x9f\x9c" // U+F07DC
+#define ICON_MDI_MICROPHONE "\xf3\xb0\x8d\xac" // U+F036C
+#define ICON_MDI_MICROPHONE_MESSAGE "\xf3\xb0\x94\x8a" // U+F050A
+#define ICON_MDI_MICROPHONE_MESSAGE_OFF "\xf3\xb0\x94\x8b" // U+F050B
+#define ICON_MDI_MICROPHONE_MINUS "\xf3\xb0\xa2\xb3" // U+F08B3
+#define ICON_MDI_MICROPHONE_OFF "\xf3\xb0\x8d\xad" // U+F036D
+#define ICON_MDI_MICROPHONE_OUTLINE "\xf3\xb0\x8d\xae" // U+F036E
+#define ICON_MDI_MICROPHONE_PLUS "\xf3\xb0\xa2\xb4" // U+F08B4
+#define ICON_MDI_MICROPHONE_QUESTION "\xf3\xb1\xa6\x89" // U+F1989
+#define ICON_MDI_MICROPHONE_QUESTION_OUTLINE "\xf3\xb1\xa6\x8a" // U+F198A
+#define ICON_MDI_MICROPHONE_SETTINGS "\xf3\xb0\x8d\xaf" // U+F036F
+#define ICON_MDI_MICROPHONE_VARIANT "\xf3\xb0\x8d\xb0" // U+F0370
+#define ICON_MDI_MICROPHONE_VARIANT_OFF "\xf3\xb0\x8d\xb1" // U+F0371
+#define ICON_MDI_MICROSCOPE "\xf3\xb0\x99\x94" // U+F0654
+#define ICON_MDI_MICROSOFT "\xf3\xb0\x8d\xb2" // U+F0372
+#define ICON_MDI_MICROSOFT_ACCESS "\xf3\xb1\x8e\x8e" // U+F138E
+#define ICON_MDI_MICROSOFT_AZURE "\xf3\xb0\xa0\x85" // U+F0805
+#define ICON_MDI_MICROSOFT_AZURE_DEVOPS "\xf3\xb0\xbf\x95" // U+F0FD5
+#define ICON_MDI_MICROSOFT_BING "\xf3\xb0\x82\xa4" // U+F00A4
+#define ICON_MDI_MICROSOFT_DYNAMICS_365 "\xf3\xb0\xa6\x88" // U+F0988
+#define ICON_MDI_MICROSOFT_EDGE "\xf3\xb0\x87\xa9" // U+F01E9
+#define ICON_MDI_MICROSOFT_EXCEL "\xf3\xb1\x8e\x8f" // U+F138F
+#define ICON_MDI_MICROSOFT_INTERNET_EXPLORER "\xf3\xb0\x8c\x80" // U+F0300
+#define ICON_MDI_MICROSOFT_OFFICE "\xf3\xb0\x8f\x86" // U+F03C6
+#define ICON_MDI_MICROSOFT_ONEDRIVE "\xf3\xb0\x8f\x8a" // U+F03CA
+#define ICON_MDI_MICROSOFT_ONENOTE "\xf3\xb0\x9d\x87" // U+F0747
+#define ICON_MDI_MICROSOFT_OUTLOOK "\xf3\xb0\xb4\xa2" // U+F0D22
+#define ICON_MDI_MICROSOFT_POWERPOINT "\xf3\xb1\x8e\x90" // U+F1390
+#define ICON_MDI_MICROSOFT_SHAREPOINT "\xf3\xb1\x8e\x91" // U+F1391
+#define ICON_MDI_MICROSOFT_TEAMS "\xf3\xb0\x8a\xbb" // U+F02BB
+#define ICON_MDI_MICROSOFT_VISUAL_STUDIO "\xf3\xb0\x98\x90" // U+F0610
+#define ICON_MDI_MICROSOFT_VISUAL_STUDIO_CODE "\xf3\xb0\xa8\x9e" // U+F0A1E
+#define ICON_MDI_MICROSOFT_WINDOWS "\xf3\xb0\x96\xb3" // U+F05B3
+#define ICON_MDI_MICROSOFT_WINDOWS_CLASSIC "\xf3\xb0\xa8\xa1" // U+F0A21
+#define ICON_MDI_MICROSOFT_WORD "\xf3\xb1\x8e\x92" // U+F1392
+#define ICON_MDI_MICROSOFT_XBOX "\xf3\xb0\x96\xb9" // U+F05B9
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER "\xf3\xb0\x96\xba" // U+F05BA
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_ALERT "\xf3\xb0\x9d\x8b" // U+F074B
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_CHARGING "\xf3\xb0\xa8\xa2" // U+F0A22
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_EMPTY "\xf3\xb0\x9d\x8c" // U+F074C
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_FULL "\xf3\xb0\x9d\x8d" // U+F074D
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_LOW "\xf3\xb0\x9d\x8e" // U+F074E
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_MEDIUM "\xf3\xb0\x9d\x8f" // U+F074F
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_UNKNOWN "\xf3\xb0\x9d\x90" // U+F0750
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_MENU "\xf3\xb0\xb9\xaf" // U+F0E6F
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_OFF "\xf3\xb0\x96\xbb" // U+F05BB
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_VIEW "\xf3\xb0\xb9\xb0" // U+F0E70
+#define ICON_MDI_MICROWAVE "\xf3\xb0\xb2\x99" // U+F0C99
+#define ICON_MDI_MICROWAVE_OFF "\xf3\xb1\x90\xa3" // U+F1423
+#define ICON_MDI_MIDDLEWARE "\xf3\xb0\xbd\x9d" // U+F0F5D
+#define ICON_MDI_MIDDLEWARE_OUTLINE "\xf3\xb0\xbd\x9e" // U+F0F5E
+#define ICON_MDI_MIDI "\xf3\xb0\xa3\xb1" // U+F08F1
+#define ICON_MDI_MIDI_PORT "\xf3\xb0\xa3\xb2" // U+F08F2
+#define ICON_MDI_MINE "\xf3\xb0\xb7\x9a" // U+F0DDA
+#define ICON_MDI_MINECRAFT "\xf3\xb0\x8d\xb3" // U+F0373
+#define ICON_MDI_MINI_SD "\xf3\xb0\xa8\x85" // U+F0A05
+#define ICON_MDI_MINIDISC "\xf3\xb0\xa8\x86" // U+F0A06
+#define ICON_MDI_MINUS "\xf3\xb0\x8d\xb4" // U+F0374
+#define ICON_MDI_MINUS_BOX "\xf3\xb0\x8d\xb5" // U+F0375
+#define ICON_MDI_MINUS_BOX_MULTIPLE "\xf3\xb1\x85\x81" // U+F1141
+#define ICON_MDI_MINUS_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x85\x82" // U+F1142
+#define ICON_MDI_MINUS_BOX_OUTLINE "\xf3\xb0\x9b\xb2" // U+F06F2
+#define ICON_MDI_MINUS_CIRCLE "\xf3\xb0\x8d\xb6" // U+F0376
+#define ICON_MDI_MINUS_CIRCLE_MULTIPLE "\xf3\xb0\x8d\x9a" // U+F035A
+#define ICON_MDI_MINUS_CIRCLE_MULTIPLE_OUTLINE "\xf3\xb0\xab\x93" // U+F0AD3
+#define ICON_MDI_MINUS_CIRCLE_OFF "\xf3\xb1\x91\x99" // U+F1459
+#define ICON_MDI_MINUS_CIRCLE_OFF_OUTLINE "\xf3\xb1\x91\x9a" // U+F145A
+#define ICON_MDI_MINUS_CIRCLE_OUTLINE "\xf3\xb0\x8d\xb7" // U+F0377
+#define ICON_MDI_MINUS_NETWORK "\xf3\xb0\x8d\xb8" // U+F0378
+#define ICON_MDI_MINUS_NETWORK_OUTLINE "\xf3\xb0\xb2\x9a" // U+F0C9A
+#define ICON_MDI_MINUS_THICK "\xf3\xb1\x98\xb9" // U+F1639
+#define ICON_MDI_MIRROR "\xf3\xb1\x87\xbd" // U+F11FD
+#define ICON_MDI_MIRROR_RECTANGLE "\xf3\xb1\x9e\x9f" // U+F179F
+#define ICON_MDI_MIRROR_VARIANT "\xf3\xb1\x9e\xa0" // U+F17A0
+#define ICON_MDI_MIXED_MARTIAL_ARTS "\xf3\xb0\xb6\x8f" // U+F0D8F
+#define ICON_MDI_MIXED_REALITY "\xf3\xb0\xa1\xbf" // U+F087F
+#define ICON_MDI_MOLECULE "\xf3\xb0\xae\xac" // U+F0BAC
+#define ICON_MDI_MOLECULE_CO "\xf3\xb1\x8b\xbe" // U+F12FE
+#define ICON_MDI_MOLECULE_CO2 "\xf3\xb0\x9f\xa4" // U+F07E4
+#define ICON_MDI_MONITOR "\xf3\xb0\x8d\xb9" // U+F0379
+#define ICON_MDI_MONITOR_ACCOUNT "\xf3\xb1\xa9\x9b" // U+F1A5B
+#define ICON_MDI_MONITOR_ARROW_DOWN "\xf3\xb1\xa7\x90" // U+F19D0
+#define ICON_MDI_MONITOR_ARROW_DOWN_VARIANT "\xf3\xb1\xa7\x91" // U+F19D1
+#define ICON_MDI_MONITOR_CELLPHONE "\xf3\xb0\xa6\x89" // U+F0989
+#define ICON_MDI_MONITOR_CELLPHONE_STAR "\xf3\xb0\xa6\x8a" // U+F098A
+#define ICON_MDI_MONITOR_DASHBOARD "\xf3\xb0\xa8\x87" // U+F0A07
+#define ICON_MDI_MONITOR_EDIT "\xf3\xb1\x8b\x86" // U+F12C6
+#define ICON_MDI_MONITOR_EYE "\xf3\xb1\x8e\xb4" // U+F13B4
+#define ICON_MDI_MONITOR_LOCK "\xf3\xb0\xb7\x9b" // U+F0DDB
+#define ICON_MDI_MONITOR_MULTIPLE "\xf3\xb0\x8d\xba" // U+F037A
+#define ICON_MDI_MONITOR_OFF "\xf3\xb0\xb6\x90" // U+F0D90
+#define ICON_MDI_MONITOR_SCREENSHOT "\xf3\xb0\xb9\x91" // U+F0E51
+#define ICON_MDI_MONITOR_SHARE "\xf3\xb1\x92\x83" // U+F1483
+#define ICON_MDI_MONITOR_SHIMMER "\xf3\xb1\x84\x84" // U+F1104
+#define ICON_MDI_MONITOR_SMALL "\xf3\xb1\xa1\xb6" // U+F1876
+#define ICON_MDI_MONITOR_SPEAKER "\xf3\xb0\xbd\x9f" // U+F0F5F
+#define ICON_MDI_MONITOR_SPEAKER_OFF "\xf3\xb0\xbd\xa0" // U+F0F60
+#define ICON_MDI_MONITOR_STAR "\xf3\xb0\xb7\x9c" // U+F0DDC
+#define ICON_MDI_MONITOR_VERTICAL "\xf3\xb1\xb0\xb3" // U+F1C33
+#define ICON_MDI_MOON_FIRST_QUARTER "\xf3\xb0\xbd\xa1" // U+F0F61
+#define ICON_MDI_MOON_FULL "\xf3\xb0\xbd\xa2" // U+F0F62
+#define ICON_MDI_MOON_LAST_QUARTER "\xf3\xb0\xbd\xa3" // U+F0F63
+#define ICON_MDI_MOON_NEW "\xf3\xb0\xbd\xa4" // U+F0F64
+#define ICON_MDI_MOON_WANING_CRESCENT "\xf3\xb0\xbd\xa5" // U+F0F65
+#define ICON_MDI_MOON_WANING_GIBBOUS "\xf3\xb0\xbd\xa6" // U+F0F66
+#define ICON_MDI_MOON_WAXING_CRESCENT "\xf3\xb0\xbd\xa7" // U+F0F67
+#define ICON_MDI_MOON_WAXING_GIBBOUS "\xf3\xb0\xbd\xa8" // U+F0F68
+#define ICON_MDI_MOPED "\xf3\xb1\x82\x86" // U+F1086
+#define ICON_MDI_MOPED_ELECTRIC "\xf3\xb1\x96\xb7" // U+F15B7
+#define ICON_MDI_MOPED_ELECTRIC_OUTLINE "\xf3\xb1\x96\xb8" // U+F15B8
+#define ICON_MDI_MOPED_OUTLINE "\xf3\xb1\x96\xb9" // U+F15B9
+#define ICON_MDI_MORE "\xf3\xb0\x8d\xbb" // U+F037B
+#define ICON_MDI_MORTAR_PESTLE "\xf3\xb1\x9d\x88" // U+F1748
+#define ICON_MDI_MORTAR_PESTLE_PLUS "\xf3\xb0\x8f\xb1" // U+F03F1
+#define ICON_MDI_MOSQUE "\xf3\xb0\xb5\x85" // U+F0D45
+#define ICON_MDI_MOSQUE_OUTLINE "\xf3\xb1\xa0\xa7" // U+F1827
+#define ICON_MDI_MOTHER_HEART "\xf3\xb1\x8c\x94" // U+F1314
+#define ICON_MDI_MOTHER_NURSE "\xf3\xb0\xb4\xa1" // U+F0D21
+#define ICON_MDI_MOTION "\xf3\xb1\x96\xb2" // U+F15B2
+#define ICON_MDI_MOTION_OUTLINE "\xf3\xb1\x96\xb3" // U+F15B3
+#define ICON_MDI_MOTION_PAUSE "\xf3\xb1\x96\x90" // U+F1590
+#define ICON_MDI_MOTION_PAUSE_OUTLINE "\xf3\xb1\x96\x92" // U+F1592
+#define ICON_MDI_MOTION_PLAY "\xf3\xb1\x96\x8f" // U+F158F
+#define ICON_MDI_MOTION_PLAY_OUTLINE "\xf3\xb1\x96\x91" // U+F1591
+#define ICON_MDI_MOTION_SENSOR "\xf3\xb0\xb6\x91" // U+F0D91
+#define ICON_MDI_MOTION_SENSOR_OFF "\xf3\xb1\x90\xb5" // U+F1435
+#define ICON_MDI_MOTORBIKE "\xf3\xb0\x8d\xbc" // U+F037C
+#define ICON_MDI_MOTORBIKE_ELECTRIC "\xf3\xb1\x96\xba" // U+F15BA
+#define ICON_MDI_MOTORBIKE_OFF "\xf3\xb1\xac\x96" // U+F1B16
+#define ICON_MDI_MOUSE "\xf3\xb0\x8d\xbd" // U+F037D
+#define ICON_MDI_MOUSE_BLUETOOTH "\xf3\xb0\xa6\x8b" // U+F098B
+#define ICON_MDI_MOUSE_MOVE_DOWN "\xf3\xb1\x95\x90" // U+F1550
+#define ICON_MDI_MOUSE_MOVE_UP "\xf3\xb1\x95\x91" // U+F1551
+#define ICON_MDI_MOUSE_MOVE_VERTICAL "\xf3\xb1\x95\x92" // U+F1552
+#define ICON_MDI_MOUSE_OFF "\xf3\xb0\x8d\xbe" // U+F037E
+#define ICON_MDI_MOUSE_VARIANT "\xf3\xb0\x8d\xbf" // U+F037F
+#define ICON_MDI_MOUSE_VARIANT_OFF "\xf3\xb0\x8e\x80" // U+F0380
+#define ICON_MDI_MOVE_RESIZE "\xf3\xb0\x99\x95" // U+F0655
+#define ICON_MDI_MOVE_RESIZE_VARIANT "\xf3\xb0\x99\x96" // U+F0656
+#define ICON_MDI_MOVIE "\xf3\xb0\x8e\x81" // U+F0381
+#define ICON_MDI_MOVIE_CHECK "\xf3\xb1\x9b\xb3" // U+F16F3
+#define ICON_MDI_MOVIE_CHECK_OUTLINE "\xf3\xb1\x9b\xb4" // U+F16F4
+#define ICON_MDI_MOVIE_COG "\xf3\xb1\x9b\xb5" // U+F16F5
+#define ICON_MDI_MOVIE_COG_OUTLINE "\xf3\xb1\x9b\xb6" // U+F16F6
+#define ICON_MDI_MOVIE_EDIT "\xf3\xb1\x84\xa2" // U+F1122
+#define ICON_MDI_MOVIE_EDIT_OUTLINE "\xf3\xb1\x84\xa3" // U+F1123
+#define ICON_MDI_MOVIE_FILTER "\xf3\xb1\x84\xa4" // U+F1124
+#define ICON_MDI_MOVIE_FILTER_OUTLINE "\xf3\xb1\x84\xa5" // U+F1125
+#define ICON_MDI_MOVIE_MINUS "\xf3\xb1\x9b\xb7" // U+F16F7
+#define ICON_MDI_MOVIE_MINUS_OUTLINE "\xf3\xb1\x9b\xb8" // U+F16F8
+#define ICON_MDI_MOVIE_OFF "\xf3\xb1\x9b\xb9" // U+F16F9
+#define ICON_MDI_MOVIE_OFF_OUTLINE "\xf3\xb1\x9b\xba" // U+F16FA
+#define ICON_MDI_MOVIE_OPEN "\xf3\xb0\xbf\x8e" // U+F0FCE
+#define ICON_MDI_MOVIE_OPEN_CHECK "\xf3\xb1\x9b\xbb" // U+F16FB
+#define ICON_MDI_MOVIE_OPEN_CHECK_OUTLINE "\xf3\xb1\x9b\xbc" // U+F16FC
+#define ICON_MDI_MOVIE_OPEN_COG "\xf3\xb1\x9b\xbd" // U+F16FD
+#define ICON_MDI_MOVIE_OPEN_COG_OUTLINE "\xf3\xb1\x9b\xbe" // U+F16FE
+#define ICON_MDI_MOVIE_OPEN_EDIT "\xf3\xb1\x9b\xbf" // U+F16FF
+#define ICON_MDI_MOVIE_OPEN_EDIT_OUTLINE "\xf3\xb1\x9c\x80" // U+F1700
+#define ICON_MDI_MOVIE_OPEN_MINUS "\xf3\xb1\x9c\x81" // U+F1701
+#define ICON_MDI_MOVIE_OPEN_MINUS_OUTLINE "\xf3\xb1\x9c\x82" // U+F1702
+#define ICON_MDI_MOVIE_OPEN_OFF "\xf3\xb1\x9c\x83" // U+F1703
+#define ICON_MDI_MOVIE_OPEN_OFF_OUTLINE "\xf3\xb1\x9c\x84" // U+F1704
+#define ICON_MDI_MOVIE_OPEN_OUTLINE "\xf3\xb0\xbf\x8f" // U+F0FCF
+#define ICON_MDI_MOVIE_OPEN_PLAY "\xf3\xb1\x9c\x85" // U+F1705
+#define ICON_MDI_MOVIE_OPEN_PLAY_OUTLINE "\xf3\xb1\x9c\x86" // U+F1706
+#define ICON_MDI_MOVIE_OPEN_PLUS "\xf3\xb1\x9c\x87" // U+F1707
+#define ICON_MDI_MOVIE_OPEN_PLUS_OUTLINE "\xf3\xb1\x9c\x88" // U+F1708
+#define ICON_MDI_MOVIE_OPEN_REMOVE "\xf3\xb1\x9c\x89" // U+F1709
+#define ICON_MDI_MOVIE_OPEN_REMOVE_OUTLINE "\xf3\xb1\x9c\x8a" // U+F170A
+#define ICON_MDI_MOVIE_OPEN_SETTINGS "\xf3\xb1\x9c\x8b" // U+F170B
+#define ICON_MDI_MOVIE_OPEN_SETTINGS_OUTLINE "\xf3\xb1\x9c\x8c" // U+F170C
+#define ICON_MDI_MOVIE_OPEN_STAR "\xf3\xb1\x9c\x8d" // U+F170D
+#define ICON_MDI_MOVIE_OPEN_STAR_OUTLINE "\xf3\xb1\x9c\x8e" // U+F170E
+#define ICON_MDI_MOVIE_OUTLINE "\xf3\xb0\xb7\x9d" // U+F0DDD
+#define ICON_MDI_MOVIE_PLAY "\xf3\xb1\x9c\x8f" // U+F170F
+#define ICON_MDI_MOVIE_PLAY_OUTLINE "\xf3\xb1\x9c\x90" // U+F1710
+#define ICON_MDI_MOVIE_PLUS "\xf3\xb1\x9c\x91" // U+F1711
+#define ICON_MDI_MOVIE_PLUS_OUTLINE "\xf3\xb1\x9c\x92" // U+F1712
+#define ICON_MDI_MOVIE_REMOVE "\xf3\xb1\x9c\x93" // U+F1713
+#define ICON_MDI_MOVIE_REMOVE_OUTLINE "\xf3\xb1\x9c\x94" // U+F1714
+#define ICON_MDI_MOVIE_ROLL "\xf3\xb0\x9f\x9e" // U+F07DE
+#define ICON_MDI_MOVIE_SEARCH "\xf3\xb1\x87\x92" // U+F11D2
+#define ICON_MDI_MOVIE_SEARCH_OUTLINE "\xf3\xb1\x87\x93" // U+F11D3
+#define ICON_MDI_MOVIE_SETTINGS "\xf3\xb1\x9c\x95" // U+F1715
+#define ICON_MDI_MOVIE_SETTINGS_OUTLINE "\xf3\xb1\x9c\x96" // U+F1716
+#define ICON_MDI_MOVIE_STAR "\xf3\xb1\x9c\x97" // U+F1717
+#define ICON_MDI_MOVIE_STAR_OUTLINE "\xf3\xb1\x9c\x98" // U+F1718
+#define ICON_MDI_MOWER "\xf3\xb1\x99\xaf" // U+F166F
+#define ICON_MDI_MOWER_BAG "\xf3\xb1\x99\xb0" // U+F1670
+#define ICON_MDI_MOWER_BAG_ON "\xf3\xb1\xad\xa0" // U+F1B60
+#define ICON_MDI_MOWER_ON "\xf3\xb1\xad\x9f" // U+F1B5F
+#define ICON_MDI_MUFFIN "\xf3\xb0\xa6\x8c" // U+F098C
+#define ICON_MDI_MULTICAST "\xf3\xb1\xa2\x93" // U+F1893
+#define ICON_MDI_MULTIMEDIA "\xf3\xb1\xae\x97" // U+F1B97
+#define ICON_MDI_MULTIPLICATION "\xf3\xb0\x8e\x82" // U+F0382
+#define ICON_MDI_MULTIPLICATION_BOX "\xf3\xb0\x8e\x83" // U+F0383
+#define ICON_MDI_MUSHROOM "\xf3\xb0\x9f\x9f" // U+F07DF
+#define ICON_MDI_MUSHROOM_OFF "\xf3\xb1\x8f\xba" // U+F13FA
+#define ICON_MDI_MUSHROOM_OFF_OUTLINE "\xf3\xb1\x8f\xbb" // U+F13FB
+#define ICON_MDI_MUSHROOM_OUTLINE "\xf3\xb0\x9f\xa0" // U+F07E0
+#define ICON_MDI_MUSIC "\xf3\xb0\x9d\x9a" // U+F075A
+#define ICON_MDI_MUSIC_ACCIDENTAL_DOUBLE_FLAT "\xf3\xb0\xbd\xa9" // U+F0F69
+#define ICON_MDI_MUSIC_ACCIDENTAL_DOUBLE_SHARP "\xf3\xb0\xbd\xaa" // U+F0F6A
+#define ICON_MDI_MUSIC_ACCIDENTAL_FLAT "\xf3\xb0\xbd\xab" // U+F0F6B
+#define ICON_MDI_MUSIC_ACCIDENTAL_NATURAL "\xf3\xb0\xbd\xac" // U+F0F6C
+#define ICON_MDI_MUSIC_ACCIDENTAL_SHARP "\xf3\xb0\xbd\xad" // U+F0F6D
+#define ICON_MDI_MUSIC_BOX "\xf3\xb0\x8e\x84" // U+F0384
+#define ICON_MDI_MUSIC_BOX_MULTIPLE "\xf3\xb0\x8c\xb3" // U+F0333
+#define ICON_MDI_MUSIC_BOX_MULTIPLE_OUTLINE "\xf3\xb0\xbc\x84" // U+F0F04
+#define ICON_MDI_MUSIC_BOX_OUTLINE "\xf3\xb0\x8e\x85" // U+F0385
+#define ICON_MDI_MUSIC_CIRCLE "\xf3\xb0\x8e\x86" // U+F0386
+#define ICON_MDI_MUSIC_CIRCLE_OUTLINE "\xf3\xb0\xab\x94" // U+F0AD4
+#define ICON_MDI_MUSIC_CLEF_ALTO "\xf3\xb0\xbd\xae" // U+F0F6E
+#define ICON_MDI_MUSIC_CLEF_BASS "\xf3\xb0\xbd\xaf" // U+F0F6F
+#define ICON_MDI_MUSIC_CLEF_TREBLE "\xf3\xb0\xbd\xb0" // U+F0F70
+#define ICON_MDI_MUSIC_NOTE "\xf3\xb0\x8e\x87" // U+F0387
+#define ICON_MDI_MUSIC_NOTE_BLUETOOTH "\xf3\xb0\x97\xbe" // U+F05FE
+#define ICON_MDI_MUSIC_NOTE_BLUETOOTH_OFF "\xf3\xb0\x97\xbf" // U+F05FF
+#define ICON_MDI_MUSIC_NOTE_EIGHTH "\xf3\xb0\x8e\x88" // U+F0388
+#define ICON_MDI_MUSIC_NOTE_EIGHTH_DOTTED "\xf3\xb0\xbd\xb1" // U+F0F71
+#define ICON_MDI_MUSIC_NOTE_HALF "\xf3\xb0\x8e\x89" // U+F0389
+#define ICON_MDI_MUSIC_NOTE_HALF_DOTTED "\xf3\xb0\xbd\xb2" // U+F0F72
+#define ICON_MDI_MUSIC_NOTE_MINUS "\xf3\xb1\xae\x89" // U+F1B89
+#define ICON_MDI_MUSIC_NOTE_OFF "\xf3\xb0\x8e\x8a" // U+F038A
+#define ICON_MDI_MUSIC_NOTE_OFF_OUTLINE "\xf3\xb0\xbd\xb3" // U+F0F73
+#define ICON_MDI_MUSIC_NOTE_OUTLINE "\xf3\xb0\xbd\xb4" // U+F0F74
+#define ICON_MDI_MUSIC_NOTE_PLUS "\xf3\xb0\xb7\x9e" // U+F0DDE
+#define ICON_MDI_MUSIC_NOTE_QUARTER "\xf3\xb0\x8e\x8b" // U+F038B
+#define ICON_MDI_MUSIC_NOTE_QUARTER_DOTTED "\xf3\xb0\xbd\xb5" // U+F0F75
+#define ICON_MDI_MUSIC_NOTE_SIXTEENTH "\xf3\xb0\x8e\x8c" // U+F038C
+#define ICON_MDI_MUSIC_NOTE_SIXTEENTH_DOTTED "\xf3\xb0\xbd\xb6" // U+F0F76
+#define ICON_MDI_MUSIC_NOTE_WHOLE "\xf3\xb0\x8e\x8d" // U+F038D
+#define ICON_MDI_MUSIC_NOTE_WHOLE_DOTTED "\xf3\xb0\xbd\xb7" // U+F0F77
+#define ICON_MDI_MUSIC_OFF "\xf3\xb0\x9d\x9b" // U+F075B
+#define ICON_MDI_MUSIC_REST_EIGHTH "\xf3\xb0\xbd\xb8" // U+F0F78
+#define ICON_MDI_MUSIC_REST_HALF "\xf3\xb0\xbd\xb9" // U+F0F79
+#define ICON_MDI_MUSIC_REST_QUARTER "\xf3\xb0\xbd\xba" // U+F0F7A
+#define ICON_MDI_MUSIC_REST_SIXTEENTH "\xf3\xb0\xbd\xbb" // U+F0F7B
+#define ICON_MDI_MUSIC_REST_WHOLE "\xf3\xb0\xbd\xbc" // U+F0F7C
+#define ICON_MDI_MUSTACHE "\xf3\xb1\x97\x9e" // U+F15DE
+#define ICON_MDI_NAIL "\xf3\xb0\xb7\x9f" // U+F0DDF
+#define ICON_MDI_NAS "\xf3\xb0\xa3\xb3" // U+F08F3
+#define ICON_MDI_NATIVESCRIPT "\xf3\xb0\xa2\x80" // U+F0880
+#define ICON_MDI_NATURE "\xf3\xb0\x8e\x8e" // U+F038E
+#define ICON_MDI_NATURE_OUTLINE "\xf3\xb1\xb1\xb1" // U+F1C71
+#define ICON_MDI_NATURE_PEOPLE "\xf3\xb0\x8e\x8f" // U+F038F
+#define ICON_MDI_NATURE_PEOPLE_OUTLINE "\xf3\xb1\xb1\xb2" // U+F1C72
+#define ICON_MDI_NAVIGATION "\xf3\xb0\x8e\x90" // U+F0390
+#define ICON_MDI_NAVIGATION_OUTLINE "\xf3\xb1\x98\x87" // U+F1607
+#define ICON_MDI_NAVIGATION_VARIANT "\xf3\xb1\xa3\xb0" // U+F18F0
+#define ICON_MDI_NAVIGATION_VARIANT_OUTLINE "\xf3\xb1\xa3\xb1" // U+F18F1
+#define ICON_MDI_NEAR_ME "\xf3\xb0\x97\x8d" // U+F05CD
+#define ICON_MDI_NECKLACE "\xf3\xb0\xbc\x8b" // U+F0F0B
+#define ICON_MDI_NEEDLE "\xf3\xb0\x8e\x91" // U+F0391
+#define ICON_MDI_NEEDLE_OFF "\xf3\xb1\xa7\x92" // U+F19D2
+#define ICON_MDI_NETFLIX "\xf3\xb0\x9d\x86" // U+F0746
+#define ICON_MDI_NETWORK "\xf3\xb0\x9b\xb3" // U+F06F3
+#define ICON_MDI_NETWORK_OFF "\xf3\xb0\xb2\x9b" // U+F0C9B
+#define ICON_MDI_NETWORK_OFF_OUTLINE "\xf3\xb0\xb2\x9c" // U+F0C9C
+#define ICON_MDI_NETWORK_OUTLINE "\xf3\xb0\xb2\x9d" // U+F0C9D
+#define ICON_MDI_NETWORK_POS "\xf3\xb1\xab\x8b" // U+F1ACB
+#define ICON_MDI_NETWORK_STRENGTH_1 "\xf3\xb0\xa3\xb4" // U+F08F4
+#define ICON_MDI_NETWORK_STRENGTH_1_ALERT "\xf3\xb0\xa3\xb5" // U+F08F5
+#define ICON_MDI_NETWORK_STRENGTH_2 "\xf3\xb0\xa3\xb6" // U+F08F6
+#define ICON_MDI_NETWORK_STRENGTH_2_ALERT "\xf3\xb0\xa3\xb7" // U+F08F7
+#define ICON_MDI_NETWORK_STRENGTH_3 "\xf3\xb0\xa3\xb8" // U+F08F8
+#define ICON_MDI_NETWORK_STRENGTH_3_ALERT "\xf3\xb0\xa3\xb9" // U+F08F9
+#define ICON_MDI_NETWORK_STRENGTH_4 "\xf3\xb0\xa3\xba" // U+F08FA
+#define ICON_MDI_NETWORK_STRENGTH_4_ALERT "\xf3\xb0\xa3\xbb" // U+F08FB
+#define ICON_MDI_NETWORK_STRENGTH_4_COG "\xf3\xb1\xa4\x9a" // U+F191A
+#define ICON_MDI_NETWORK_STRENGTH_OFF "\xf3\xb0\xa3\xbc" // U+F08FC
+#define ICON_MDI_NETWORK_STRENGTH_OFF_OUTLINE "\xf3\xb0\xa3\xbd" // U+F08FD
+#define ICON_MDI_NETWORK_STRENGTH_OUTLINE "\xf3\xb0\xa3\xbe" // U+F08FE
+#define ICON_MDI_NEW_BOX "\xf3\xb0\x8e\x94" // U+F0394
+#define ICON_MDI_NEWSPAPER "\xf3\xb0\x8e\x95" // U+F0395
+#define ICON_MDI_NEWSPAPER_CHECK "\xf3\xb1\xa5\x83" // U+F1943
+#define ICON_MDI_NEWSPAPER_MINUS "\xf3\xb0\xbc\x8c" // U+F0F0C
+#define ICON_MDI_NEWSPAPER_PLUS "\xf3\xb0\xbc\x8d" // U+F0F0D
+#define ICON_MDI_NEWSPAPER_REMOVE "\xf3\xb1\xa5\x84" // U+F1944
+#define ICON_MDI_NEWSPAPER_VARIANT "\xf3\xb1\x80\x81" // U+F1001
+#define ICON_MDI_NEWSPAPER_VARIANT_MULTIPLE "\xf3\xb1\x80\x82" // U+F1002
+#define ICON_MDI_NEWSPAPER_VARIANT_MULTIPLE_OUTLINE "\xf3\xb1\x80\x83" // U+F1003
+#define ICON_MDI_NEWSPAPER_VARIANT_OUTLINE "\xf3\xb1\x80\x84" // U+F1004
+#define ICON_MDI_NFC "\xf3\xb0\x8e\x96" // U+F0396
+#define ICON_MDI_NFC_SEARCH_VARIANT "\xf3\xb0\xb9\x93" // U+F0E53
+#define ICON_MDI_NFC_TAP "\xf3\xb0\x8e\x97" // U+F0397
+#define ICON_MDI_NFC_VARIANT "\xf3\xb0\x8e\x98" // U+F0398
+#define ICON_MDI_NFC_VARIANT_OFF "\xf3\xb0\xb9\x94" // U+F0E54
+#define ICON_MDI_NINJA "\xf3\xb0\x9d\xb4" // U+F0774
+#define ICON_MDI_NINTENDO_GAME_BOY "\xf3\xb1\x8e\x93" // U+F1393
+#define ICON_MDI_NINTENDO_SWITCH "\xf3\xb0\x9f\xa1" // U+F07E1
+#define ICON_MDI_NINTENDO_WII "\xf3\xb0\x96\xab" // U+F05AB
+#define ICON_MDI_NINTENDO_WIIU "\xf3\xb0\x9c\xad" // U+F072D
+#define ICON_MDI_NIX "\xf3\xb1\x84\x85" // U+F1105
+#define ICON_MDI_NODEJS "\xf3\xb0\x8e\x99" // U+F0399
+#define ICON_MDI_NOODLES "\xf3\xb1\x85\xbe" // U+F117E
+#define ICON_MDI_NOT_EQUAL "\xf3\xb0\xa6\x8d" // U+F098D
+#define ICON_MDI_NOT_EQUAL_VARIANT "\xf3\xb0\xa6\x8e" // U+F098E
+#define ICON_MDI_NOTE "\xf3\xb0\x8e\x9a" // U+F039A
+#define ICON_MDI_NOTE_ALERT "\xf3\xb1\x9d\xbd" // U+F177D
+#define ICON_MDI_NOTE_ALERT_OUTLINE "\xf3\xb1\x9d\xbe" // U+F177E
+#define ICON_MDI_NOTE_CHECK "\xf3\xb1\x9d\xbf" // U+F177F
+#define ICON_MDI_NOTE_CHECK_OUTLINE "\xf3\xb1\x9e\x80" // U+F1780
+#define ICON_MDI_NOTE_EDIT "\xf3\xb1\x9e\x81" // U+F1781
+#define ICON_MDI_NOTE_EDIT_OUTLINE "\xf3\xb1\x9e\x82" // U+F1782
+#define ICON_MDI_NOTE_MINUS "\xf3\xb1\x99\x8f" // U+F164F
+#define ICON_MDI_NOTE_MINUS_OUTLINE "\xf3\xb1\x99\x90" // U+F1650
+#define ICON_MDI_NOTE_MULTIPLE "\xf3\xb0\x9a\xb8" // U+F06B8
+#define ICON_MDI_NOTE_MULTIPLE_OUTLINE "\xf3\xb0\x9a\xb9" // U+F06B9
+#define ICON_MDI_NOTE_OFF "\xf3\xb1\x9e\x83" // U+F1783
+#define ICON_MDI_NOTE_OFF_OUTLINE "\xf3\xb1\x9e\x84" // U+F1784
+#define ICON_MDI_NOTE_OUTLINE "\xf3\xb0\x8e\x9b" // U+F039B
+#define ICON_MDI_NOTE_PLUS "\xf3\xb0\x8e\x9c" // U+F039C
+#define ICON_MDI_NOTE_PLUS_OUTLINE "\xf3\xb0\x8e\x9d" // U+F039D
+#define ICON_MDI_NOTE_REMOVE "\xf3\xb1\x99\x91" // U+F1651
+#define ICON_MDI_NOTE_REMOVE_OUTLINE "\xf3\xb1\x99\x92" // U+F1652
+#define ICON_MDI_NOTE_SEARCH "\xf3\xb1\x99\x93" // U+F1653
+#define ICON_MDI_NOTE_SEARCH_OUTLINE "\xf3\xb1\x99\x94" // U+F1654
+#define ICON_MDI_NOTE_TEXT "\xf3\xb0\x8e\x9e" // U+F039E
+#define ICON_MDI_NOTE_TEXT_OUTLINE "\xf3\xb1\x87\x97" // U+F11D7
+#define ICON_MDI_NOTEBOOK "\xf3\xb0\xa0\xae" // U+F082E
+#define ICON_MDI_NOTEBOOK_CHECK "\xf3\xb1\x93\xb5" // U+F14F5
+#define ICON_MDI_NOTEBOOK_CHECK_OUTLINE "\xf3\xb1\x93\xb6" // U+F14F6
+#define ICON_MDI_NOTEBOOK_EDIT "\xf3\xb1\x93\xa7" // U+F14E7
+#define ICON_MDI_NOTEBOOK_EDIT_OUTLINE "\xf3\xb1\x93\xa9" // U+F14E9
+#define ICON_MDI_NOTEBOOK_HEART "\xf3\xb1\xa8\x8b" // U+F1A0B
+#define ICON_MDI_NOTEBOOK_HEART_OUTLINE "\xf3\xb1\xa8\x8c" // U+F1A0C
+#define ICON_MDI_NOTEBOOK_MINUS "\xf3\xb1\x98\x90" // U+F1610
+#define ICON_MDI_NOTEBOOK_MINUS_OUTLINE "\xf3\xb1\x98\x91" // U+F1611
+#define ICON_MDI_NOTEBOOK_MULTIPLE "\xf3\xb0\xb9\x95" // U+F0E55
+#define ICON_MDI_NOTEBOOK_OUTLINE "\xf3\xb0\xba\xbf" // U+F0EBF
+#define ICON_MDI_NOTEBOOK_PLUS "\xf3\xb1\x98\x92" // U+F1612
+#define ICON_MDI_NOTEBOOK_PLUS_OUTLINE "\xf3\xb1\x98\x93" // U+F1613
+#define ICON_MDI_NOTEBOOK_REMOVE "\xf3\xb1\x98\x94" // U+F1614
+#define ICON_MDI_NOTEBOOK_REMOVE_OUTLINE "\xf3\xb1\x98\x95" // U+F1615
+#define ICON_MDI_NOTIFICATION_CLEAR_ALL "\xf3\xb0\x8e\x9f" // U+F039F
+#define ICON_MDI_NPM "\xf3\xb0\x9b\xb7" // U+F06F7
+#define ICON_MDI_NUKE "\xf3\xb0\x9a\xa4" // U+F06A4
+#define ICON_MDI_NULL "\xf3\xb0\x9f\xa2" // U+F07E2
+#define ICON_MDI_NUMERIC "\xf3\xb0\x8e\xa0" // U+F03A0
+#define ICON_MDI_NUMERIC_0 "\xf3\xb0\xac\xb9" // U+F0B39
+#define ICON_MDI_NUMERIC_0_BOX "\xf3\xb0\x8e\xa1" // U+F03A1
+#define ICON_MDI_NUMERIC_0_BOX_MULTIPLE "\xf3\xb0\xbc\x8e" // U+F0F0E
+#define ICON_MDI_NUMERIC_0_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xa2" // U+F03A2
+#define ICON_MDI_NUMERIC_0_BOX_OUTLINE "\xf3\xb0\x8e\xa3" // U+F03A3
+#define ICON_MDI_NUMERIC_0_CIRCLE "\xf3\xb0\xb2\x9e" // U+F0C9E
+#define ICON_MDI_NUMERIC_0_CIRCLE_OUTLINE "\xf3\xb0\xb2\x9f" // U+F0C9F
+#define ICON_MDI_NUMERIC_1 "\xf3\xb0\xac\xba" // U+F0B3A
+#define ICON_MDI_NUMERIC_1_BOX "\xf3\xb0\x8e\xa4" // U+F03A4
+#define ICON_MDI_NUMERIC_1_BOX_MULTIPLE "\xf3\xb0\xbc\x8f" // U+F0F0F
+#define ICON_MDI_NUMERIC_1_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xa5" // U+F03A5
+#define ICON_MDI_NUMERIC_1_BOX_OUTLINE "\xf3\xb0\x8e\xa6" // U+F03A6
+#define ICON_MDI_NUMERIC_1_CIRCLE "\xf3\xb0\xb2\xa0" // U+F0CA0
+#define ICON_MDI_NUMERIC_1_CIRCLE_OUTLINE "\xf3\xb0\xb2\xa1" // U+F0CA1
+#define ICON_MDI_NUMERIC_10 "\xf3\xb0\xbf\xa9" // U+F0FE9
+#define ICON_MDI_NUMERIC_10_BOX "\xf3\xb0\xbd\xbd" // U+F0F7D
+#define ICON_MDI_NUMERIC_10_BOX_MULTIPLE "\xf3\xb0\xbf\xaa" // U+F0FEA
+#define ICON_MDI_NUMERIC_10_BOX_MULTIPLE_OUTLINE "\xf3\xb0\xbf\xab" // U+F0FEB
+#define ICON_MDI_NUMERIC_10_BOX_OUTLINE "\xf3\xb0\xbd\xbe" // U+F0F7E
+#define ICON_MDI_NUMERIC_10_CIRCLE "\xf3\xb0\xbf\xac" // U+F0FEC
+#define ICON_MDI_NUMERIC_10_CIRCLE_OUTLINE "\xf3\xb0\xbf\xad" // U+F0FED
+#define ICON_MDI_NUMERIC_2 "\xf3\xb0\xac\xbb" // U+F0B3B
+#define ICON_MDI_NUMERIC_2_BOX "\xf3\xb0\x8e\xa7" // U+F03A7
+#define ICON_MDI_NUMERIC_2_BOX_MULTIPLE "\xf3\xb0\xbc\x90" // U+F0F10
+#define ICON_MDI_NUMERIC_2_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xa8" // U+F03A8
+#define ICON_MDI_NUMERIC_2_BOX_OUTLINE "\xf3\xb0\x8e\xa9" // U+F03A9
+#define ICON_MDI_NUMERIC_2_CIRCLE "\xf3\xb0\xb2\xa2" // U+F0CA2
+#define ICON_MDI_NUMERIC_2_CIRCLE_OUTLINE "\xf3\xb0\xb2\xa3" // U+F0CA3
+#define ICON_MDI_NUMERIC_3 "\xf3\xb0\xac\xbc" // U+F0B3C
+#define ICON_MDI_NUMERIC_3_BOX "\xf3\xb0\x8e\xaa" // U+F03AA
+#define ICON_MDI_NUMERIC_3_BOX_MULTIPLE "\xf3\xb0\xbc\x91" // U+F0F11
+#define ICON_MDI_NUMERIC_3_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xab" // U+F03AB
+#define ICON_MDI_NUMERIC_3_BOX_OUTLINE "\xf3\xb0\x8e\xac" // U+F03AC
+#define ICON_MDI_NUMERIC_3_CIRCLE "\xf3\xb0\xb2\xa4" // U+F0CA4
+#define ICON_MDI_NUMERIC_3_CIRCLE_OUTLINE "\xf3\xb0\xb2\xa5" // U+F0CA5
+#define ICON_MDI_NUMERIC_4 "\xf3\xb0\xac\xbd" // U+F0B3D
+#define ICON_MDI_NUMERIC_4_BOX "\xf3\xb0\x8e\xad" // U+F03AD
+#define ICON_MDI_NUMERIC_4_BOX_MULTIPLE "\xf3\xb0\xbc\x92" // U+F0F12
+#define ICON_MDI_NUMERIC_4_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xb2" // U+F03B2
+#define ICON_MDI_NUMERIC_4_BOX_OUTLINE "\xf3\xb0\x8e\xae" // U+F03AE
+#define ICON_MDI_NUMERIC_4_CIRCLE "\xf3\xb0\xb2\xa6" // U+F0CA6
+#define ICON_MDI_NUMERIC_4_CIRCLE_OUTLINE "\xf3\xb0\xb2\xa7" // U+F0CA7
+#define ICON_MDI_NUMERIC_5 "\xf3\xb0\xac\xbe" // U+F0B3E
+#define ICON_MDI_NUMERIC_5_BOX "\xf3\xb0\x8e\xb1" // U+F03B1
+#define ICON_MDI_NUMERIC_5_BOX_MULTIPLE "\xf3\xb0\xbc\x93" // U+F0F13
+#define ICON_MDI_NUMERIC_5_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xaf" // U+F03AF
+#define ICON_MDI_NUMERIC_5_BOX_OUTLINE "\xf3\xb0\x8e\xb0" // U+F03B0
+#define ICON_MDI_NUMERIC_5_CIRCLE "\xf3\xb0\xb2\xa8" // U+F0CA8
+#define ICON_MDI_NUMERIC_5_CIRCLE_OUTLINE "\xf3\xb0\xb2\xa9" // U+F0CA9
+#define ICON_MDI_NUMERIC_6 "\xf3\xb0\xac\xbf" // U+F0B3F
+#define ICON_MDI_NUMERIC_6_BOX "\xf3\xb0\x8e\xb3" // U+F03B3
+#define ICON_MDI_NUMERIC_6_BOX_MULTIPLE "\xf3\xb0\xbc\x94" // U+F0F14
+#define ICON_MDI_NUMERIC_6_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xb4" // U+F03B4
+#define ICON_MDI_NUMERIC_6_BOX_OUTLINE "\xf3\xb0\x8e\xb5" // U+F03B5
+#define ICON_MDI_NUMERIC_6_CIRCLE "\xf3\xb0\xb2\xaa" // U+F0CAA
+#define ICON_MDI_NUMERIC_6_CIRCLE_OUTLINE "\xf3\xb0\xb2\xab" // U+F0CAB
+#define ICON_MDI_NUMERIC_7 "\xf3\xb0\xad\x80" // U+F0B40
+#define ICON_MDI_NUMERIC_7_BOX "\xf3\xb0\x8e\xb6" // U+F03B6
+#define ICON_MDI_NUMERIC_7_BOX_MULTIPLE "\xf3\xb0\xbc\x95" // U+F0F15
+#define ICON_MDI_NUMERIC_7_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xb7" // U+F03B7
+#define ICON_MDI_NUMERIC_7_BOX_OUTLINE "\xf3\xb0\x8e\xb8" // U+F03B8
+#define ICON_MDI_NUMERIC_7_CIRCLE "\xf3\xb0\xb2\xac" // U+F0CAC
+#define ICON_MDI_NUMERIC_7_CIRCLE_OUTLINE "\xf3\xb0\xb2\xad" // U+F0CAD
+#define ICON_MDI_NUMERIC_8 "\xf3\xb0\xad\x81" // U+F0B41
+#define ICON_MDI_NUMERIC_8_BOX "\xf3\xb0\x8e\xb9" // U+F03B9
+#define ICON_MDI_NUMERIC_8_BOX_MULTIPLE "\xf3\xb0\xbc\x96" // U+F0F16
+#define ICON_MDI_NUMERIC_8_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xba" // U+F03BA
+#define ICON_MDI_NUMERIC_8_BOX_OUTLINE "\xf3\xb0\x8e\xbb" // U+F03BB
+#define ICON_MDI_NUMERIC_8_CIRCLE "\xf3\xb0\xb2\xae" // U+F0CAE
+#define ICON_MDI_NUMERIC_8_CIRCLE_OUTLINE "\xf3\xb0\xb2\xaf" // U+F0CAF
+#define ICON_MDI_NUMERIC_9 "\xf3\xb0\xad\x82" // U+F0B42
+#define ICON_MDI_NUMERIC_9_BOX "\xf3\xb0\x8e\xbc" // U+F03BC
+#define ICON_MDI_NUMERIC_9_BOX_MULTIPLE "\xf3\xb0\xbc\x97" // U+F0F17
+#define ICON_MDI_NUMERIC_9_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xbd" // U+F03BD
+#define ICON_MDI_NUMERIC_9_BOX_OUTLINE "\xf3\xb0\x8e\xbe" // U+F03BE
+#define ICON_MDI_NUMERIC_9_CIRCLE "\xf3\xb0\xb2\xb0" // U+F0CB0
+#define ICON_MDI_NUMERIC_9_CIRCLE_OUTLINE "\xf3\xb0\xb2\xb1" // U+F0CB1
+#define ICON_MDI_NUMERIC_9_PLUS "\xf3\xb0\xbf\xae" // U+F0FEE
+#define ICON_MDI_NUMERIC_9_PLUS_BOX "\xf3\xb0\x8e\xbf" // U+F03BF
+#define ICON_MDI_NUMERIC_9_PLUS_BOX_MULTIPLE "\xf3\xb0\xbc\x98" // U+F0F18
+#define ICON_MDI_NUMERIC_9_PLUS_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8f\x80" // U+F03C0
+#define ICON_MDI_NUMERIC_9_PLUS_BOX_OUTLINE "\xf3\xb0\x8f\x81" // U+F03C1
+#define ICON_MDI_NUMERIC_9_PLUS_CIRCLE "\xf3\xb0\xb2\xb2" // U+F0CB2
+#define ICON_MDI_NUMERIC_9_PLUS_CIRCLE_OUTLINE "\xf3\xb0\xb2\xb3" // U+F0CB3
+#define ICON_MDI_NUMERIC_NEGATIVE_1 "\xf3\xb1\x81\x92" // U+F1052
+#define ICON_MDI_NUMERIC_OFF "\xf3\xb1\xa7\x93" // U+F19D3
+#define ICON_MDI_NUMERIC_POSITIVE_1 "\xf3\xb1\x97\x8b" // U+F15CB
+#define ICON_MDI_NUT "\xf3\xb0\x9b\xb8" // U+F06F8
+#define ICON_MDI_NUTRITION "\xf3\xb0\x8f\x82" // U+F03C2
+#define ICON_MDI_NUXT "\xf3\xb1\x84\x86" // U+F1106
+#define ICON_MDI_OAR "\xf3\xb0\x99\xbc" // U+F067C
+#define ICON_MDI_OCARINA "\xf3\xb0\xb7\xa0" // U+F0DE0
+#define ICON_MDI_OCI "\xf3\xb1\x8b\xa9" // U+F12E9
+#define ICON_MDI_OCR "\xf3\xb1\x84\xba" // U+F113A
+#define ICON_MDI_OCTAGON "\xf3\xb0\x8f\x83" // U+F03C3
+#define ICON_MDI_OCTAGON_OUTLINE "\xf3\xb0\x8f\x84" // U+F03C4
+#define ICON_MDI_OCTAGRAM "\xf3\xb0\x9b\xb9" // U+F06F9
+#define ICON_MDI_OCTAGRAM_EDIT "\xf3\xb1\xb0\xb4" // U+F1C34
+#define ICON_MDI_OCTAGRAM_EDIT_OUTLINE "\xf3\xb1\xb0\xb5" // U+F1C35
+#define ICON_MDI_OCTAGRAM_MINUS "\xf3\xb1\xb0\xb6" // U+F1C36
+#define ICON_MDI_OCTAGRAM_MINUS_OUTLINE "\xf3\xb1\xb0\xb7" // U+F1C37
+#define ICON_MDI_OCTAGRAM_OUTLINE "\xf3\xb0\x9d\xb5" // U+F0775
+#define ICON_MDI_OCTAGRAM_PLUS "\xf3\xb1\xb0\xb8" // U+F1C38
+#define ICON_MDI_OCTAGRAM_PLUS_OUTLINE "\xf3\xb1\xb0\xb9" // U+F1C39
+#define ICON_MDI_OCTAHEDRON "\xf3\xb1\xa5\x90" // U+F1950
+#define ICON_MDI_OCTAHEDRON_OFF "\xf3\xb1\xa5\x91" // U+F1951
+#define ICON_MDI_ODNOKLASSNIKI "\xf3\xb0\x8f\x85" // U+F03C5
+#define ICON_MDI_OFFER "\xf3\xb1\x88\x9b" // U+F121B
+#define ICON_MDI_OFFICE_BUILDING "\xf3\xb0\xa6\x91" // U+F0991
+#define ICON_MDI_OFFICE_BUILDING_COG "\xf3\xb1\xa5\x89" // U+F1949
+#define ICON_MDI_OFFICE_BUILDING_COG_OUTLINE "\xf3\xb1\xa5\x8a" // U+F194A
+#define ICON_MDI_OFFICE_BUILDING_MARKER "\xf3\xb1\x94\xa0" // U+F1520
+#define ICON_MDI_OFFICE_BUILDING_MARKER_OUTLINE "\xf3\xb1\x94\xa1" // U+F1521
+#define ICON_MDI_OFFICE_BUILDING_MINUS "\xf3\xb1\xae\xaa" // U+F1BAA
+#define ICON_MDI_OFFICE_BUILDING_MINUS_OUTLINE "\xf3\xb1\xae\xab" // U+F1BAB
+#define ICON_MDI_OFFICE_BUILDING_OUTLINE "\xf3\xb1\x94\x9f" // U+F151F
+#define ICON_MDI_OFFICE_BUILDING_PLUS "\xf3\xb1\xae\xa8" // U+F1BA8
+#define ICON_MDI_OFFICE_BUILDING_PLUS_OUTLINE "\xf3\xb1\xae\xa9" // U+F1BA9
+#define ICON_MDI_OFFICE_BUILDING_REMOVE "\xf3\xb1\xae\xac" // U+F1BAC
+#define ICON_MDI_OFFICE_BUILDING_REMOVE_OUTLINE "\xf3\xb1\xae\xad" // U+F1BAD
+#define ICON_MDI_OIL "\xf3\xb0\x8f\x87" // U+F03C7
+#define ICON_MDI_OIL_LAMP "\xf3\xb0\xbc\x99" // U+F0F19
+#define ICON_MDI_OIL_LEVEL "\xf3\xb1\x81\x93" // U+F1053
+#define ICON_MDI_OIL_TEMPERATURE "\xf3\xb0\xbf\xb8" // U+F0FF8
+#define ICON_MDI_OM "\xf3\xb0\xa5\xb3" // U+F0973
+#define ICON_MDI_OMEGA "\xf3\xb0\x8f\x89" // U+F03C9
+#define ICON_MDI_ONE_UP "\xf3\xb0\xae\xad" // U+F0BAD
+#define ICON_MDI_ONEPASSWORD "\xf3\xb0\xa2\x81" // U+F0881
+#define ICON_MDI_OPACITY "\xf3\xb0\x97\x8c" // U+F05CC
+#define ICON_MDI_OPEN_IN_APP "\xf3\xb0\x8f\x8b" // U+F03CB
+#define ICON_MDI_OPEN_IN_NEW "\xf3\xb0\x8f\x8c" // U+F03CC
+#define ICON_MDI_OPEN_SOURCE_INITIATIVE "\xf3\xb0\xae\xae" // U+F0BAE
+#define ICON_MDI_OPENID "\xf3\xb0\x8f\x8d" // U+F03CD
+#define ICON_MDI_OPERA "\xf3\xb0\x8f\x8e" // U+F03CE
+#define ICON_MDI_ORBIT "\xf3\xb0\x80\x98" // U+F0018
+#define ICON_MDI_ORBIT_VARIANT "\xf3\xb1\x97\x9b" // U+F15DB
+#define ICON_MDI_ORDER_ALPHABETICAL_ASCENDING "\xf3\xb0\x88\x8d" // U+F020D
+#define ICON_MDI_ORDER_ALPHABETICAL_DESCENDING "\xf3\xb0\xb4\x87" // U+F0D07
+#define ICON_MDI_ORDER_BOOL_ASCENDING "\xf3\xb0\x8a\xbe" // U+F02BE
+#define ICON_MDI_ORDER_BOOL_ASCENDING_VARIANT "\xf3\xb0\xa6\x8f" // U+F098F
+#define ICON_MDI_ORDER_BOOL_DESCENDING "\xf3\xb1\x8e\x84" // U+F1384
+#define ICON_MDI_ORDER_BOOL_DESCENDING_VARIANT "\xf3\xb0\xa6\x90" // U+F0990
+#define ICON_MDI_ORDER_NUMERIC_ASCENDING "\xf3\xb0\x95\x85" // U+F0545
+#define ICON_MDI_ORDER_NUMERIC_DESCENDING "\xf3\xb0\x95\x86" // U+F0546
+#define ICON_MDI_ORIGIN "\xf3\xb0\xad\x83" // U+F0B43
+#define ICON_MDI_ORNAMENT "\xf3\xb0\x8f\x8f" // U+F03CF
+#define ICON_MDI_ORNAMENT_VARIANT "\xf3\xb0\x8f\x90" // U+F03D0
+#define ICON_MDI_OUTDOOR_LAMP "\xf3\xb1\x81\x94" // U+F1054
+#define ICON_MDI_OVERSCAN "\xf3\xb1\x80\x85" // U+F1005
+#define ICON_MDI_OWL "\xf3\xb0\x8f\x92" // U+F03D2
+#define ICON_MDI_PAC_MAN "\xf3\xb0\xae\xaf" // U+F0BAF
+#define ICON_MDI_PACKAGE "\xf3\xb0\x8f\x93" // U+F03D3
+#define ICON_MDI_PACKAGE_CHECK "\xf3\xb1\xad\x91" // U+F1B51
+#define ICON_MDI_PACKAGE_DOWN "\xf3\xb0\x8f\x94" // U+F03D4
+#define ICON_MDI_PACKAGE_UP "\xf3\xb0\x8f\x95" // U+F03D5
+#define ICON_MDI_PACKAGE_VARIANT "\xf3\xb0\x8f\x96" // U+F03D6
+#define ICON_MDI_PACKAGE_VARIANT_CLOSED "\xf3\xb0\x8f\x97" // U+F03D7
+#define ICON_MDI_PACKAGE_VARIANT_CLOSED_CHECK "\xf3\xb1\xad\x92" // U+F1B52
+#define ICON_MDI_PACKAGE_VARIANT_CLOSED_MINUS "\xf3\xb1\xa7\x94" // U+F19D4
+#define ICON_MDI_PACKAGE_VARIANT_CLOSED_PLUS "\xf3\xb1\xa7\x95" // U+F19D5
+#define ICON_MDI_PACKAGE_VARIANT_CLOSED_REMOVE "\xf3\xb1\xa7\x96" // U+F19D6
+#define ICON_MDI_PACKAGE_VARIANT_MINUS "\xf3\xb1\xa7\x97" // U+F19D7
+#define ICON_MDI_PACKAGE_VARIANT_PLUS "\xf3\xb1\xa7\x98" // U+F19D8
+#define ICON_MDI_PACKAGE_VARIANT_REMOVE "\xf3\xb1\xa7\x99" // U+F19D9
+#define ICON_MDI_PAGE_FIRST "\xf3\xb0\x98\x80" // U+F0600
+#define ICON_MDI_PAGE_LAST "\xf3\xb0\x98\x81" // U+F0601
+#define ICON_MDI_PAGE_LAYOUT_BODY "\xf3\xb0\x9b\xba" // U+F06FA
+#define ICON_MDI_PAGE_LAYOUT_FOOTER "\xf3\xb0\x9b\xbb" // U+F06FB
+#define ICON_MDI_PAGE_LAYOUT_HEADER "\xf3\xb0\x9b\xbc" // U+F06FC
+#define ICON_MDI_PAGE_LAYOUT_HEADER_FOOTER "\xf3\xb0\xbd\xbf" // U+F0F7F
+#define ICON_MDI_PAGE_LAYOUT_SIDEBAR_LEFT "\xf3\xb0\x9b\xbd" // U+F06FD
+#define ICON_MDI_PAGE_LAYOUT_SIDEBAR_RIGHT "\xf3\xb0\x9b\xbe" // U+F06FE
+#define ICON_MDI_PAGE_NEXT "\xf3\xb0\xae\xb0" // U+F0BB0
+#define ICON_MDI_PAGE_NEXT_OUTLINE "\xf3\xb0\xae\xb1" // U+F0BB1
+#define ICON_MDI_PAGE_PREVIOUS "\xf3\xb0\xae\xb2" // U+F0BB2
+#define ICON_MDI_PAGE_PREVIOUS_OUTLINE "\xf3\xb0\xae\xb3" // U+F0BB3
+#define ICON_MDI_PAIL "\xf3\xb1\x90\x97" // U+F1417
+#define ICON_MDI_PAIL_MINUS "\xf3\xb1\x90\xb7" // U+F1437
+#define ICON_MDI_PAIL_MINUS_OUTLINE "\xf3\xb1\x90\xbc" // U+F143C
+#define ICON_MDI_PAIL_OFF "\xf3\xb1\x90\xb9" // U+F1439
+#define ICON_MDI_PAIL_OFF_OUTLINE "\xf3\xb1\x90\xbe" // U+F143E
+#define ICON_MDI_PAIL_OUTLINE "\xf3\xb1\x90\xba" // U+F143A
+#define ICON_MDI_PAIL_PLUS "\xf3\xb1\x90\xb6" // U+F1436
+#define ICON_MDI_PAIL_PLUS_OUTLINE "\xf3\xb1\x90\xbb" // U+F143B
+#define ICON_MDI_PAIL_REMOVE "\xf3\xb1\x90\xb8" // U+F1438
+#define ICON_MDI_PAIL_REMOVE_OUTLINE "\xf3\xb1\x90\xbd" // U+F143D
+#define ICON_MDI_PALETTE "\xf3\xb0\x8f\x98" // U+F03D8
+#define ICON_MDI_PALETTE_ADVANCED "\xf3\xb0\x8f\x99" // U+F03D9
+#define ICON_MDI_PALETTE_OUTLINE "\xf3\xb0\xb8\x8c" // U+F0E0C
+#define ICON_MDI_PALETTE_SWATCH "\xf3\xb0\xa2\xb5" // U+F08B5
+#define ICON_MDI_PALETTE_SWATCH_OUTLINE "\xf3\xb1\x8d\x9c" // U+F135C
+#define ICON_MDI_PALETTE_SWATCH_VARIANT "\xf3\xb1\xa5\x9a" // U+F195A
+#define ICON_MDI_PALM_TREE "\xf3\xb1\x81\x95" // U+F1055
+#define ICON_MDI_PAN "\xf3\xb0\xae\xb4" // U+F0BB4
+#define ICON_MDI_PAN_BOTTOM_LEFT "\xf3\xb0\xae\xb5" // U+F0BB5
+#define ICON_MDI_PAN_BOTTOM_RIGHT "\xf3\xb0\xae\xb6" // U+F0BB6
+#define ICON_MDI_PAN_DOWN "\xf3\xb0\xae\xb7" // U+F0BB7
+#define ICON_MDI_PAN_HORIZONTAL "\xf3\xb0\xae\xb8" // U+F0BB8
+#define ICON_MDI_PAN_LEFT "\xf3\xb0\xae\xb9" // U+F0BB9
+#define ICON_MDI_PAN_RIGHT "\xf3\xb0\xae\xba" // U+F0BBA
+#define ICON_MDI_PAN_TOP_LEFT "\xf3\xb0\xae\xbb" // U+F0BBB
+#define ICON_MDI_PAN_TOP_RIGHT "\xf3\xb0\xae\xbc" // U+F0BBC
+#define ICON_MDI_PAN_UP "\xf3\xb0\xae\xbd" // U+F0BBD
+#define ICON_MDI_PAN_VERTICAL "\xf3\xb0\xae\xbe" // U+F0BBE
+#define ICON_MDI_PANDA "\xf3\xb0\x8f\x9a" // U+F03DA
+#define ICON_MDI_PANDORA "\xf3\xb0\x8f\x9b" // U+F03DB
+#define ICON_MDI_PANORAMA "\xf3\xb0\x8f\x9c" // U+F03DC
+#define ICON_MDI_PANORAMA_FISHEYE "\xf3\xb0\x8f\x9d" // U+F03DD
+#define ICON_MDI_PANORAMA_HORIZONTAL "\xf3\xb1\xa4\xa8" // U+F1928
+#define ICON_MDI_PANORAMA_HORIZONTAL_OUTLINE "\xf3\xb0\x8f\x9e" // U+F03DE
+#define ICON_MDI_PANORAMA_OUTLINE "\xf3\xb1\xa6\x8c" // U+F198C
+#define ICON_MDI_PANORAMA_SPHERE "\xf3\xb1\xa6\x8d" // U+F198D
+#define ICON_MDI_PANORAMA_SPHERE_OUTLINE "\xf3\xb1\xa6\x8e" // U+F198E
+#define ICON_MDI_PANORAMA_VARIANT "\xf3\xb1\xa6\x8f" // U+F198F
+#define ICON_MDI_PANORAMA_VARIANT_OUTLINE "\xf3\xb1\xa6\x90" // U+F1990
+#define ICON_MDI_PANORAMA_VERTICAL "\xf3\xb1\xa4\xa9" // U+F1929
+#define ICON_MDI_PANORAMA_VERTICAL_OUTLINE "\xf3\xb0\x8f\x9f" // U+F03DF
+#define ICON_MDI_PANORAMA_WIDE_ANGLE "\xf3\xb1\xa5\x9f" // U+F195F
+#define ICON_MDI_PANORAMA_WIDE_ANGLE_OUTLINE "\xf3\xb0\x8f\xa0" // U+F03E0
+#define ICON_MDI_PAPER_CUT_VERTICAL "\xf3\xb0\x8f\xa1" // U+F03E1
+#define ICON_MDI_PAPER_ROLL "\xf3\xb1\x85\x97" // U+F1157
+#define ICON_MDI_PAPER_ROLL_OUTLINE "\xf3\xb1\x85\x98" // U+F1158
+#define ICON_MDI_PAPERCLIP "\xf3\xb0\x8f\xa2" // U+F03E2
+#define ICON_MDI_PAPERCLIP_CHECK "\xf3\xb1\xab\x86" // U+F1AC6
+#define ICON_MDI_PAPERCLIP_LOCK "\xf3\xb1\xa7\x9a" // U+F19DA
+#define ICON_MDI_PAPERCLIP_MINUS "\xf3\xb1\xab\x87" // U+F1AC7
+#define ICON_MDI_PAPERCLIP_OFF "\xf3\xb1\xab\x88" // U+F1AC8
+#define ICON_MDI_PAPERCLIP_PLUS "\xf3\xb1\xab\x89" // U+F1AC9
+#define ICON_MDI_PAPERCLIP_REMOVE "\xf3\xb1\xab\x8a" // U+F1ACA
+#define ICON_MDI_PARACHUTE "\xf3\xb0\xb2\xb4" // U+F0CB4
+#define ICON_MDI_PARACHUTE_OUTLINE "\xf3\xb0\xb2\xb5" // U+F0CB5
+#define ICON_MDI_PARAGLIDING "\xf3\xb1\x9d\x85" // U+F1745
+#define ICON_MDI_PARKING "\xf3\xb0\x8f\xa3" // U+F03E3
+#define ICON_MDI_PARTY_POPPER "\xf3\xb1\x81\x96" // U+F1056
+#define ICON_MDI_PASSPORT "\xf3\xb0\x9f\xa3" // U+F07E3
+#define ICON_MDI_PASSPORT_ALERT "\xf3\xb1\xb2\xb8" // U+F1CB8
+#define ICON_MDI_PASSPORT_BIOMETRIC "\xf3\xb0\xb7\xa1" // U+F0DE1
+#define ICON_MDI_PASSPORT_CANCEL "\xf3\xb1\xb2\xb9" // U+F1CB9
+#define ICON_MDI_PASSPORT_CHECK "\xf3\xb1\xb2\xba" // U+F1CBA
+#define ICON_MDI_PASSPORT_MINUS "\xf3\xb1\xb2\xbb" // U+F1CBB
+#define ICON_MDI_PASSPORT_PLUS "\xf3\xb1\xb2\xbc" // U+F1CBC
+#define ICON_MDI_PASSPORT_REMOVE "\xf3\xb1\xb2\xbd" // U+F1CBD
+#define ICON_MDI_PASTA "\xf3\xb1\x85\xa0" // U+F1160
+#define ICON_MDI_PATIO_HEATER "\xf3\xb0\xbe\x80" // U+F0F80
+#define ICON_MDI_PATREON "\xf3\xb0\xa2\x82" // U+F0882
+#define ICON_MDI_PAUSE "\xf3\xb0\x8f\xa4" // U+F03E4
+#define ICON_MDI_PAUSE_BOX "\xf3\xb0\x82\xbc" // U+F00BC
+#define ICON_MDI_PAUSE_BOX_OUTLINE "\xf3\xb1\xad\xba" // U+F1B7A
+#define ICON_MDI_PAUSE_CIRCLE "\xf3\xb0\x8f\xa5" // U+F03E5
+#define ICON_MDI_PAUSE_CIRCLE_OUTLINE "\xf3\xb0\x8f\xa6" // U+F03E6
+#define ICON_MDI_PAUSE_OCTAGON "\xf3\xb0\x8f\xa7" // U+F03E7
+#define ICON_MDI_PAUSE_OCTAGON_OUTLINE "\xf3\xb0\x8f\xa8" // U+F03E8
+#define ICON_MDI_PAW "\xf3\xb0\x8f\xa9" // U+F03E9
+#define ICON_MDI_PAW_OFF "\xf3\xb0\x99\x97" // U+F0657
+#define ICON_MDI_PAW_OFF_OUTLINE "\xf3\xb1\x99\xb6" // U+F1676
+#define ICON_MDI_PAW_OUTLINE "\xf3\xb1\x99\xb5" // U+F1675
+#define ICON_MDI_PEACE "\xf3\xb0\xa2\x84" // U+F0884
+#define ICON_MDI_PEANUT "\xf3\xb0\xbf\xbc" // U+F0FFC
+#define ICON_MDI_PEANUT_OFF "\xf3\xb0\xbf\xbd" // U+F0FFD
+#define ICON_MDI_PEANUT_OFF_OUTLINE "\xf3\xb0\xbf\xbf" // U+F0FFF
+#define ICON_MDI_PEANUT_OUTLINE "\xf3\xb0\xbf\xbe" // U+F0FFE
+#define ICON_MDI_PEN "\xf3\xb0\x8f\xaa" // U+F03EA
+#define ICON_MDI_PEN_LOCK "\xf3\xb0\xb7\xa2" // U+F0DE2
+#define ICON_MDI_PEN_MINUS "\xf3\xb0\xb7\xa3" // U+F0DE3
+#define ICON_MDI_PEN_OFF "\xf3\xb0\xb7\xa4" // U+F0DE4
+#define ICON_MDI_PEN_PLUS "\xf3\xb0\xb7\xa5" // U+F0DE5
+#define ICON_MDI_PEN_REMOVE "\xf3\xb0\xb7\xa6" // U+F0DE6
+#define ICON_MDI_PENCIL "\xf3\xb0\x8f\xab" // U+F03EB
+#define ICON_MDI_PENCIL_BOX "\xf3\xb0\x8f\xac" // U+F03EC
+#define ICON_MDI_PENCIL_BOX_MULTIPLE "\xf3\xb1\x85\x84" // U+F1144
+#define ICON_MDI_PENCIL_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x85\x85" // U+F1145
+#define ICON_MDI_PENCIL_BOX_OUTLINE "\xf3\xb0\x8f\xad" // U+F03ED
+#define ICON_MDI_PENCIL_CIRCLE "\xf3\xb0\x9b\xbf" // U+F06FF
+#define ICON_MDI_PENCIL_CIRCLE_OUTLINE "\xf3\xb0\x9d\xb6" // U+F0776
+#define ICON_MDI_PENCIL_LOCK "\xf3\xb0\x8f\xae" // U+F03EE
+#define ICON_MDI_PENCIL_LOCK_OUTLINE "\xf3\xb0\xb7\xa7" // U+F0DE7
+#define ICON_MDI_PENCIL_MINUS "\xf3\xb0\xb7\xa8" // U+F0DE8
+#define ICON_MDI_PENCIL_MINUS_OUTLINE "\xf3\xb0\xb7\xa9" // U+F0DE9
+#define ICON_MDI_PENCIL_OFF "\xf3\xb0\x8f\xaf" // U+F03EF
+#define ICON_MDI_PENCIL_OFF_OUTLINE "\xf3\xb0\xb7\xaa" // U+F0DEA
+#define ICON_MDI_PENCIL_OUTLINE "\xf3\xb0\xb2\xb6" // U+F0CB6
+#define ICON_MDI_PENCIL_PLUS "\xf3\xb0\xb7\xab" // U+F0DEB
+#define ICON_MDI_PENCIL_PLUS_OUTLINE "\xf3\xb0\xb7\xac" // U+F0DEC
+#define ICON_MDI_PENCIL_REMOVE "\xf3\xb0\xb7\xad" // U+F0DED
+#define ICON_MDI_PENCIL_REMOVE_OUTLINE "\xf3\xb0\xb7\xae" // U+F0DEE
+#define ICON_MDI_PENCIL_RULER "\xf3\xb1\x8d\x93" // U+F1353
+#define ICON_MDI_PENCIL_RULER_OUTLINE "\xf3\xb1\xb0\x91" // U+F1C11
+#define ICON_MDI_PENGUIN "\xf3\xb0\xbb\x80" // U+F0EC0
+#define ICON_MDI_PENTAGON "\xf3\xb0\x9c\x81" // U+F0701
+#define ICON_MDI_PENTAGON_OUTLINE "\xf3\xb0\x9c\x80" // U+F0700
+#define ICON_MDI_PENTAGRAM "\xf3\xb1\x99\xa7" // U+F1667
+#define ICON_MDI_PERCENT "\xf3\xb0\x8f\xb0" // U+F03F0
+#define ICON_MDI_PERCENT_BOX "\xf3\xb1\xa8\x82" // U+F1A02
+#define ICON_MDI_PERCENT_BOX_OUTLINE "\xf3\xb1\xa8\x83" // U+F1A03
+#define ICON_MDI_PERCENT_CIRCLE "\xf3\xb1\xa8\x84" // U+F1A04
+#define ICON_MDI_PERCENT_CIRCLE_OUTLINE "\xf3\xb1\xa8\x85" // U+F1A05
+#define ICON_MDI_PERCENT_OUTLINE "\xf3\xb1\x89\xb8" // U+F1278
+#define ICON_MDI_PERIODIC_TABLE "\xf3\xb0\xa2\xb6" // U+F08B6
+#define ICON_MDI_PERSPECTIVE_LESS "\xf3\xb0\xb4\xa3" // U+F0D23
+#define ICON_MDI_PERSPECTIVE_MORE "\xf3\xb0\xb4\xa4" // U+F0D24
+#define ICON_MDI_PH "\xf3\xb1\x9f\x85" // U+F17C5
+#define ICON_MDI_PHONE "\xf3\xb0\x8f\xb2" // U+F03F2
+#define ICON_MDI_PHONE_ALERT "\xf3\xb0\xbc\x9a" // U+F0F1A
+#define ICON_MDI_PHONE_ALERT_OUTLINE "\xf3\xb1\x86\x8e" // U+F118E
+#define ICON_MDI_PHONE_BLUETOOTH "\xf3\xb0\x8f\xb3" // U+F03F3
+#define ICON_MDI_PHONE_BLUETOOTH_OUTLINE "\xf3\xb1\x86\x8f" // U+F118F
+#define ICON_MDI_PHONE_CANCEL "\xf3\xb1\x82\xbc" // U+F10BC
+#define ICON_MDI_PHONE_CANCEL_OUTLINE "\xf3\xb1\x86\x90" // U+F1190
+#define ICON_MDI_PHONE_CHECK "\xf3\xb1\x86\xa9" // U+F11A9
+#define ICON_MDI_PHONE_CHECK_OUTLINE "\xf3\xb1\x86\xaa" // U+F11AA
+#define ICON_MDI_PHONE_CLASSIC "\xf3\xb0\x98\x82" // U+F0602
+#define ICON_MDI_PHONE_CLASSIC_OFF "\xf3\xb1\x89\xb9" // U+F1279
+#define ICON_MDI_PHONE_CLOCK "\xf3\xb1\xa7\x9b" // U+F19DB
+#define ICON_MDI_PHONE_DIAL "\xf3\xb1\x95\x99" // U+F1559
+#define ICON_MDI_PHONE_DIAL_OUTLINE "\xf3\xb1\x95\x9a" // U+F155A
+#define ICON_MDI_PHONE_FORWARD "\xf3\xb0\x8f\xb4" // U+F03F4
+#define ICON_MDI_PHONE_FORWARD_OUTLINE "\xf3\xb1\x86\x91" // U+F1191
+#define ICON_MDI_PHONE_HANGUP "\xf3\xb0\x8f\xb5" // U+F03F5
+#define ICON_MDI_PHONE_HANGUP_OUTLINE "\xf3\xb1\x86\x92" // U+F1192
+#define ICON_MDI_PHONE_IN_TALK "\xf3\xb0\x8f\xb6" // U+F03F6
+#define ICON_MDI_PHONE_IN_TALK_OUTLINE "\xf3\xb1\x86\x82" // U+F1182
+#define ICON_MDI_PHONE_INCOMING "\xf3\xb0\x8f\xb7" // U+F03F7
+#define ICON_MDI_PHONE_INCOMING_OUTGOING "\xf3\xb1\xac\xbf" // U+F1B3F
+#define ICON_MDI_PHONE_INCOMING_OUTGOING_OUTLINE "\xf3\xb1\xad\x80" // U+F1B40
+#define ICON_MDI_PHONE_INCOMING_OUTLINE "\xf3\xb1\x86\x93" // U+F1193
+#define ICON_MDI_PHONE_LOCK "\xf3\xb0\x8f\xb8" // U+F03F8
+#define ICON_MDI_PHONE_LOCK_OUTLINE "\xf3\xb1\x86\x94" // U+F1194
+#define ICON_MDI_PHONE_LOG "\xf3\xb0\x8f\xb9" // U+F03F9
+#define ICON_MDI_PHONE_LOG_OUTLINE "\xf3\xb1\x86\x95" // U+F1195
+#define ICON_MDI_PHONE_MESSAGE "\xf3\xb1\x86\x96" // U+F1196
+#define ICON_MDI_PHONE_MESSAGE_OUTLINE "\xf3\xb1\x86\x97" // U+F1197
+#define ICON_MDI_PHONE_MINUS "\xf3\xb0\x99\x98" // U+F0658
+#define ICON_MDI_PHONE_MINUS_OUTLINE "\xf3\xb1\x86\x98" // U+F1198
+#define ICON_MDI_PHONE_MISSED "\xf3\xb0\x8f\xba" // U+F03FA
+#define ICON_MDI_PHONE_MISSED_OUTLINE "\xf3\xb1\x86\xa5" // U+F11A5
+#define ICON_MDI_PHONE_OFF "\xf3\xb0\xb7\xaf" // U+F0DEF
+#define ICON_MDI_PHONE_OFF_OUTLINE "\xf3\xb1\x86\xa6" // U+F11A6
+#define ICON_MDI_PHONE_OUTGOING "\xf3\xb0\x8f\xbb" // U+F03FB
+#define ICON_MDI_PHONE_OUTGOING_OUTLINE "\xf3\xb1\x86\x99" // U+F1199
+#define ICON_MDI_PHONE_OUTLINE "\xf3\xb0\xb7\xb0" // U+F0DF0
+#define ICON_MDI_PHONE_PAUSED "\xf3\xb0\x8f\xbc" // U+F03FC
+#define ICON_MDI_PHONE_PAUSED_OUTLINE "\xf3\xb1\x86\x9a" // U+F119A
+#define ICON_MDI_PHONE_PLUS "\xf3\xb0\x99\x99" // U+F0659
+#define ICON_MDI_PHONE_PLUS_OUTLINE "\xf3\xb1\x86\x9b" // U+F119B
+#define ICON_MDI_PHONE_REFRESH "\xf3\xb1\xa6\x93" // U+F1993
+#define ICON_MDI_PHONE_REFRESH_OUTLINE "\xf3\xb1\xa6\x94" // U+F1994
+#define ICON_MDI_PHONE_REMOVE "\xf3\xb1\x94\xaf" // U+F152F
+#define ICON_MDI_PHONE_REMOVE_OUTLINE "\xf3\xb1\x94\xb0" // U+F1530
+#define ICON_MDI_PHONE_RETURN "\xf3\xb0\xa0\xaf" // U+F082F
+#define ICON_MDI_PHONE_RETURN_OUTLINE "\xf3\xb1\x86\x9c" // U+F119C
+#define ICON_MDI_PHONE_RING "\xf3\xb1\x86\xab" // U+F11AB
+#define ICON_MDI_PHONE_RING_OUTLINE "\xf3\xb1\x86\xac" // U+F11AC
+#define ICON_MDI_PHONE_ROTATE_LANDSCAPE "\xf3\xb0\xa2\x85" // U+F0885
+#define ICON_MDI_PHONE_ROTATE_PORTRAIT "\xf3\xb0\xa2\x86" // U+F0886
+#define ICON_MDI_PHONE_SETTINGS "\xf3\xb0\x8f\xbd" // U+F03FD
+#define ICON_MDI_PHONE_SETTINGS_OUTLINE "\xf3\xb1\x86\x9d" // U+F119D
+#define ICON_MDI_PHONE_SYNC "\xf3\xb1\xa6\x95" // U+F1995
+#define ICON_MDI_PHONE_SYNC_OUTLINE "\xf3\xb1\xa6\x96" // U+F1996
+#define ICON_MDI_PHONE_VOIP "\xf3\xb0\x8f\xbe" // U+F03FE
+#define ICON_MDI_PI "\xf3\xb0\x8f\xbf" // U+F03FF
+#define ICON_MDI_PI_BOX "\xf3\xb0\x90\x80" // U+F0400
+#define ICON_MDI_PI_HOLE "\xf3\xb0\xb7\xb1" // U+F0DF1
+#define ICON_MDI_PIANO "\xf3\xb0\x99\xbd" // U+F067D
+#define ICON_MDI_PIANO_OFF "\xf3\xb0\x9a\x98" // U+F0698
+#define ICON_MDI_PICKAXE "\xf3\xb0\xa2\xb7" // U+F08B7
+#define ICON_MDI_PICTURE_IN_PICTURE_BOTTOM_RIGHT "\xf3\xb0\xb9\x97" // U+F0E57
+#define ICON_MDI_PICTURE_IN_PICTURE_BOTTOM_RIGHT_OUTLINE "\xf3\xb0\xb9\x98" // U+F0E58
+#define ICON_MDI_PICTURE_IN_PICTURE_TOP_RIGHT "\xf3\xb0\xb9\x99" // U+F0E59
+#define ICON_MDI_PICTURE_IN_PICTURE_TOP_RIGHT_OUTLINE "\xf3\xb0\xb9\x9a" // U+F0E5A
+#define ICON_MDI_PIER "\xf3\xb0\xa2\x87" // U+F0887
+#define ICON_MDI_PIER_CRANE "\xf3\xb0\xa2\x88" // U+F0888
+#define ICON_MDI_PIG "\xf3\xb0\x90\x81" // U+F0401
+#define ICON_MDI_PIG_VARIANT "\xf3\xb1\x80\x86" // U+F1006
+#define ICON_MDI_PIG_VARIANT_OUTLINE "\xf3\xb1\x99\xb8" // U+F1678
+#define ICON_MDI_PIGGY_BANK "\xf3\xb1\x80\x87" // U+F1007
+#define ICON_MDI_PIGGY_BANK_OUTLINE "\xf3\xb1\x99\xb9" // U+F1679
+#define ICON_MDI_PILL "\xf3\xb0\x90\x82" // U+F0402
+#define ICON_MDI_PILL_MULTIPLE "\xf3\xb1\xad\x8c" // U+F1B4C
+#define ICON_MDI_PILL_OFF "\xf3\xb1\xa9\x9c" // U+F1A5C
+#define ICON_MDI_PILLAR "\xf3\xb0\x9c\x82" // U+F0702
+#define ICON_MDI_PIN "\xf3\xb0\x90\x83" // U+F0403
+#define ICON_MDI_PIN_OFF "\xf3\xb0\x90\x84" // U+F0404
+#define ICON_MDI_PIN_OFF_OUTLINE "\xf3\xb0\xa4\xb0" // U+F0930
+#define ICON_MDI_PIN_OUTLINE "\xf3\xb0\xa4\xb1" // U+F0931
+#define ICON_MDI_PINE_TREE "\xf3\xb0\x90\x85" // U+F0405
+#define ICON_MDI_PINE_TREE_BOX "\xf3\xb0\x90\x86" // U+F0406
+#define ICON_MDI_PINE_TREE_FIRE "\xf3\xb1\x90\x9a" // U+F141A
+#define ICON_MDI_PINE_TREE_VARIANT "\xf3\xb1\xb1\xb3" // U+F1C73
+#define ICON_MDI_PINE_TREE_VARIANT_OUTLINE "\xf3\xb1\xb1\xb4" // U+F1C74
+#define ICON_MDI_PINTEREST "\xf3\xb0\x90\x87" // U+F0407
+#define ICON_MDI_PINWHEEL "\xf3\xb0\xab\x95" // U+F0AD5
+#define ICON_MDI_PINWHEEL_OUTLINE "\xf3\xb0\xab\x96" // U+F0AD6
+#define ICON_MDI_PIPE "\xf3\xb0\x9f\xa5" // U+F07E5
+#define ICON_MDI_PIPE_DISCONNECTED "\xf3\xb0\x9f\xa6" // U+F07E6
+#define ICON_MDI_PIPE_LEAK "\xf3\xb0\xa2\x89" // U+F0889
+#define ICON_MDI_PIPE_VALVE "\xf3\xb1\xa1\x8d" // U+F184D
+#define ICON_MDI_PIPE_WRENCH "\xf3\xb1\x8d\x94" // U+F1354
+#define ICON_MDI_PIRATE "\xf3\xb0\xa8\x88" // U+F0A08
+#define ICON_MDI_PISTOL "\xf3\xb0\x9c\x83" // U+F0703
+#define ICON_MDI_PISTON "\xf3\xb0\xa2\x8a" // U+F088A
+#define ICON_MDI_PITCHFORK "\xf3\xb1\x95\x93" // U+F1553
+#define ICON_MDI_PIZZA "\xf3\xb0\x90\x89" // U+F0409
+#define ICON_MDI_PLANE_CAR "\xf3\xb1\xab\xbf" // U+F1AFF
+#define ICON_MDI_PLANE_TRAIN "\xf3\xb1\xac\x80" // U+F1B00
+#define ICON_MDI_PLAY "\xf3\xb0\x90\x8a" // U+F040A
+#define ICON_MDI_PLAY_BOX "\xf3\xb1\x89\xba" // U+F127A
+#define ICON_MDI_PLAY_BOX_EDIT_OUTLINE "\xf3\xb1\xb0\xba" // U+F1C3A
+#define ICON_MDI_PLAY_BOX_LOCK "\xf3\xb1\xa8\x96" // U+F1A16
+#define ICON_MDI_PLAY_BOX_LOCK_OPEN "\xf3\xb1\xa8\x97" // U+F1A17
+#define ICON_MDI_PLAY_BOX_LOCK_OPEN_OUTLINE "\xf3\xb1\xa8\x98" // U+F1A18
+#define ICON_MDI_PLAY_BOX_LOCK_OUTLINE "\xf3\xb1\xa8\x99" // U+F1A19
+#define ICON_MDI_PLAY_BOX_MULTIPLE "\xf3\xb0\xb4\x99" // U+F0D19
+#define ICON_MDI_PLAY_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x8f\xa6" // U+F13E6
+#define ICON_MDI_PLAY_BOX_OUTLINE "\xf3\xb0\x90\x8b" // U+F040B
+#define ICON_MDI_PLAY_CIRCLE "\xf3\xb0\x90\x8c" // U+F040C
+#define ICON_MDI_PLAY_CIRCLE_OUTLINE "\xf3\xb0\x90\x8d" // U+F040D
+#define ICON_MDI_PLAY_NETWORK "\xf3\xb0\xa2\x8b" // U+F088B
+#define ICON_MDI_PLAY_NETWORK_OUTLINE "\xf3\xb0\xb2\xb7" // U+F0CB7
+#define ICON_MDI_PLAY_OUTLINE "\xf3\xb0\xbc\x9b" // U+F0F1B
+#define ICON_MDI_PLAY_PAUSE "\xf3\xb0\x90\x8e" // U+F040E
+#define ICON_MDI_PLAY_PROTECTED_CONTENT "\xf3\xb0\x90\x8f" // U+F040F
+#define ICON_MDI_PLAY_SPEED "\xf3\xb0\xa3\xbf" // U+F08FF
+#define ICON_MDI_PLAYLIST_CHECK "\xf3\xb0\x97\x87" // U+F05C7
+#define ICON_MDI_PLAYLIST_EDIT "\xf3\xb0\xa4\x80" // U+F0900
+#define ICON_MDI_PLAYLIST_MINUS "\xf3\xb0\x90\x90" // U+F0410
+#define ICON_MDI_PLAYLIST_MUSIC "\xf3\xb0\xb2\xb8" // U+F0CB8
+#define ICON_MDI_PLAYLIST_MUSIC_OUTLINE "\xf3\xb0\xb2\xb9" // U+F0CB9
+#define ICON_MDI_PLAYLIST_PLAY "\xf3\xb0\x90\x91" // U+F0411
+#define ICON_MDI_PLAYLIST_PLUS "\xf3\xb0\x90\x92" // U+F0412
+#define ICON_MDI_PLAYLIST_REMOVE "\xf3\xb0\x90\x93" // U+F0413
+#define ICON_MDI_PLAYLIST_STAR "\xf3\xb0\xb7\xb2" // U+F0DF2
+#define ICON_MDI_PLEX "\xf3\xb0\x9a\xba" // U+F06BA
+#define ICON_MDI_PLIERS "\xf3\xb1\xa6\xa4" // U+F19A4
+#define ICON_MDI_PLUS "\xf3\xb0\x90\x95" // U+F0415
+#define ICON_MDI_PLUS_BOX "\xf3\xb0\x90\x96" // U+F0416
+#define ICON_MDI_PLUS_BOX_MULTIPLE "\xf3\xb0\x8c\xb4" // U+F0334
+#define ICON_MDI_PLUS_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x85\x83" // U+F1143
+#define ICON_MDI_PLUS_BOX_OUTLINE "\xf3\xb0\x9c\x84" // U+F0704
+#define ICON_MDI_PLUS_CIRCLE "\xf3\xb0\x90\x97" // U+F0417
+#define ICON_MDI_PLUS_CIRCLE_MULTIPLE "\xf3\xb0\x8d\x8c" // U+F034C
+#define ICON_MDI_PLUS_CIRCLE_MULTIPLE_OUTLINE "\xf3\xb0\x90\x98" // U+F0418
+#define ICON_MDI_PLUS_CIRCLE_OUTLINE "\xf3\xb0\x90\x99" // U+F0419
+#define ICON_MDI_PLUS_LOCK "\xf3\xb1\xa9\x9d" // U+F1A5D
+#define ICON_MDI_PLUS_LOCK_OPEN "\xf3\xb1\xa9\x9e" // U+F1A5E
+#define ICON_MDI_PLUS_MINUS "\xf3\xb0\xa6\x92" // U+F0992
+#define ICON_MDI_PLUS_MINUS_BOX "\xf3\xb0\xa6\x93" // U+F0993
+#define ICON_MDI_PLUS_MINUS_VARIANT "\xf3\xb1\x93\x89" // U+F14C9
+#define ICON_MDI_PLUS_NETWORK "\xf3\xb0\x90\x9a" // U+F041A
+#define ICON_MDI_PLUS_NETWORK_OUTLINE "\xf3\xb0\xb2\xba" // U+F0CBA
+#define ICON_MDI_PLUS_OUTLINE "\xf3\xb0\x9c\x85" // U+F0705
+#define ICON_MDI_PLUS_THICK "\xf3\xb1\x87\xac" // U+F11EC
+#define ICON_MDI_POCKET "\xf3\xb1\xb2\xbe" // U+F1CBE
+#define ICON_MDI_PODCAST "\xf3\xb0\xa6\x94" // U+F0994
+#define ICON_MDI_PODIUM "\xf3\xb0\xb4\xa5" // U+F0D25
+#define ICON_MDI_PODIUM_BRONZE "\xf3\xb0\xb4\xa6" // U+F0D26
+#define ICON_MDI_PODIUM_GOLD "\xf3\xb0\xb4\xa7" // U+F0D27
+#define ICON_MDI_PODIUM_SILVER "\xf3\xb0\xb4\xa8" // U+F0D28
+#define ICON_MDI_POINT_OF_SALE "\xf3\xb0\xb6\x92" // U+F0D92
+#define ICON_MDI_POKEBALL "\xf3\xb0\x90\x9d" // U+F041D
+#define ICON_MDI_POKEMON_GO "\xf3\xb0\xa8\x89" // U+F0A09
+#define ICON_MDI_POKER_CHIP "\xf3\xb0\xa0\xb0" // U+F0830
+#define ICON_MDI_POLAROID "\xf3\xb0\x90\x9e" // U+F041E
+#define ICON_MDI_POLICE_BADGE "\xf3\xb1\x85\xa7" // U+F1167
+#define ICON_MDI_POLICE_BADGE_OUTLINE "\xf3\xb1\x85\xa8" // U+F1168
+#define ICON_MDI_POLICE_STATION "\xf3\xb1\xa0\xb9" // U+F1839
+#define ICON_MDI_POLL "\xf3\xb0\x90\x9f" // U+F041F
+#define ICON_MDI_POLO "\xf3\xb1\x93\x83" // U+F14C3
+#define ICON_MDI_POLYMER "\xf3\xb0\x90\xa1" // U+F0421
+#define ICON_MDI_POOL "\xf3\xb0\x98\x86" // U+F0606
+#define ICON_MDI_POOL_THERMOMETER "\xf3\xb1\xa9\x9f" // U+F1A5F
+#define ICON_MDI_POPCORN "\xf3\xb0\x90\xa2" // U+F0422
+#define ICON_MDI_POST "\xf3\xb1\x80\x88" // U+F1008
+#define ICON_MDI_POST_LAMP "\xf3\xb1\xa9\xa0" // U+F1A60
+#define ICON_MDI_POST_OUTLINE "\xf3\xb1\x80\x89" // U+F1009
+#define ICON_MDI_POSTAGE_STAMP "\xf3\xb0\xb2\xbb" // U+F0CBB
+#define ICON_MDI_POT "\xf3\xb0\x8b\xa5" // U+F02E5
+#define ICON_MDI_POT_MIX "\xf3\xb0\x99\x9b" // U+F065B
+#define ICON_MDI_POT_MIX_OUTLINE "\xf3\xb0\x99\xb7" // U+F0677
+#define ICON_MDI_POT_OUTLINE "\xf3\xb0\x8b\xbf" // U+F02FF
+#define ICON_MDI_POT_STEAM "\xf3\xb0\x99\x9a" // U+F065A
+#define ICON_MDI_POT_STEAM_OUTLINE "\xf3\xb0\x8c\xa6" // U+F0326
+#define ICON_MDI_POUND "\xf3\xb0\x90\xa3" // U+F0423
+#define ICON_MDI_POUND_BOX "\xf3\xb0\x90\xa4" // U+F0424
+#define ICON_MDI_POUND_BOX_OUTLINE "\xf3\xb1\x85\xbf" // U+F117F
+#define ICON_MDI_POWER "\xf3\xb0\x90\xa5" // U+F0425
+#define ICON_MDI_POWER_CYCLE "\xf3\xb0\xa4\x81" // U+F0901
+#define ICON_MDI_POWER_OFF "\xf3\xb0\xa4\x82" // U+F0902
+#define ICON_MDI_POWER_ON "\xf3\xb0\xa4\x83" // U+F0903
+#define ICON_MDI_POWER_PLUG "\xf3\xb0\x9a\xa5" // U+F06A5
+#define ICON_MDI_POWER_PLUG_BATTERY "\xf3\xb1\xb0\xbb" // U+F1C3B
+#define ICON_MDI_POWER_PLUG_BATTERY_OUTLINE "\xf3\xb1\xb0\xbc" // U+F1C3C
+#define ICON_MDI_POWER_PLUG_OFF "\xf3\xb0\x9a\xa6" // U+F06A6
+#define ICON_MDI_POWER_PLUG_OFF_OUTLINE "\xf3\xb1\x90\xa4" // U+F1424
+#define ICON_MDI_POWER_PLUG_OUTLINE "\xf3\xb1\x90\xa5" // U+F1425
+#define ICON_MDI_POWER_SETTINGS "\xf3\xb0\x90\xa6" // U+F0426
+#define ICON_MDI_POWER_SLEEP "\xf3\xb0\xa4\x84" // U+F0904
+#define ICON_MDI_POWER_SOCKET "\xf3\xb0\x90\xa7" // U+F0427
+#define ICON_MDI_POWER_SOCKET_AU "\xf3\xb0\xa4\x85" // U+F0905
+#define ICON_MDI_POWER_SOCKET_CH "\xf3\xb0\xbe\xb3" // U+F0FB3
+#define ICON_MDI_POWER_SOCKET_DE "\xf3\xb1\x84\x87" // U+F1107
+#define ICON_MDI_POWER_SOCKET_EU "\xf3\xb0\x9f\xa7" // U+F07E7
+#define ICON_MDI_POWER_SOCKET_FR "\xf3\xb1\x84\x88" // U+F1108
+#define ICON_MDI_POWER_SOCKET_IT "\xf3\xb1\x93\xbf" // U+F14FF
+#define ICON_MDI_POWER_SOCKET_JP "\xf3\xb1\x84\x89" // U+F1109
+#define ICON_MDI_POWER_SOCKET_UK "\xf3\xb0\x9f\xa8" // U+F07E8
+#define ICON_MDI_POWER_SOCKET_US "\xf3\xb0\x9f\xa9" // U+F07E9
+#define ICON_MDI_POWER_STANDBY "\xf3\xb0\xa4\x86" // U+F0906
+#define ICON_MDI_POWERSHELL "\xf3\xb0\xa8\x8a" // U+F0A0A
+#define ICON_MDI_PRESCRIPTION "\xf3\xb0\x9c\x86" // U+F0706
+#define ICON_MDI_PRESENTATION "\xf3\xb0\x90\xa8" // U+F0428
+#define ICON_MDI_PRESENTATION_PLAY "\xf3\xb0\x90\xa9" // U+F0429
+#define ICON_MDI_PRETZEL "\xf3\xb1\x95\xa2" // U+F1562
+#define ICON_MDI_PRINTER "\xf3\xb0\x90\xaa" // U+F042A
+#define ICON_MDI_PRINTER_3D "\xf3\xb0\x90\xab" // U+F042B
+#define ICON_MDI_PRINTER_3D_NOZZLE "\xf3\xb0\xb9\x9b" // U+F0E5B
+#define ICON_MDI_PRINTER_3D_NOZZLE_ALERT "\xf3\xb1\x87\x80" // U+F11C0
+#define ICON_MDI_PRINTER_3D_NOZZLE_ALERT_OUTLINE "\xf3\xb1\x87\x81" // U+F11C1
+#define ICON_MDI_PRINTER_3D_NOZZLE_HEAT "\xf3\xb1\xa2\xb8" // U+F18B8
+#define ICON_MDI_PRINTER_3D_NOZZLE_HEAT_OUTLINE "\xf3\xb1\xa2\xb9" // U+F18B9
+#define ICON_MDI_PRINTER_3D_NOZZLE_OFF "\xf3\xb1\xac\x99" // U+F1B19
+#define ICON_MDI_PRINTER_3D_NOZZLE_OFF_OUTLINE "\xf3\xb1\xac\x9a" // U+F1B1A
+#define ICON_MDI_PRINTER_3D_NOZZLE_OUTLINE "\xf3\xb0\xb9\x9c" // U+F0E5C
+#define ICON_MDI_PRINTER_3D_OFF "\xf3\xb1\xac\x8e" // U+F1B0E
+#define ICON_MDI_PRINTER_ALERT "\xf3\xb0\x90\xac" // U+F042C
+#define ICON_MDI_PRINTER_CHECK "\xf3\xb1\x85\x86" // U+F1146
+#define ICON_MDI_PRINTER_EYE "\xf3\xb1\x91\x98" // U+F1458
+#define ICON_MDI_PRINTER_OFF "\xf3\xb0\xb9\x9d" // U+F0E5D
+#define ICON_MDI_PRINTER_OFF_OUTLINE "\xf3\xb1\x9e\x85" // U+F1785
+#define ICON_MDI_PRINTER_OUTLINE "\xf3\xb1\x9e\x86" // U+F1786
+#define ICON_MDI_PRINTER_POS "\xf3\xb1\x81\x97" // U+F1057
+#define ICON_MDI_PRINTER_POS_ALERT "\xf3\xb1\xae\xbc" // U+F1BBC
+#define ICON_MDI_PRINTER_POS_ALERT_OUTLINE "\xf3\xb1\xae\xbd" // U+F1BBD
+#define ICON_MDI_PRINTER_POS_CANCEL "\xf3\xb1\xae\xbe" // U+F1BBE
+#define ICON_MDI_PRINTER_POS_CANCEL_OUTLINE "\xf3\xb1\xae\xbf" // U+F1BBF
+#define ICON_MDI_PRINTER_POS_CHECK "\xf3\xb1\xaf\x80" // U+F1BC0
+#define ICON_MDI_PRINTER_POS_CHECK_OUTLINE "\xf3\xb1\xaf\x81" // U+F1BC1
+#define ICON_MDI_PRINTER_POS_COG "\xf3\xb1\xaf\x82" // U+F1BC2
+#define ICON_MDI_PRINTER_POS_COG_OUTLINE "\xf3\xb1\xaf\x83" // U+F1BC3
+#define ICON_MDI_PRINTER_POS_EDIT "\xf3\xb1\xaf\x84" // U+F1BC4
+#define ICON_MDI_PRINTER_POS_EDIT_OUTLINE "\xf3\xb1\xaf\x85" // U+F1BC5
+#define ICON_MDI_PRINTER_POS_MINUS "\xf3\xb1\xaf\x86" // U+F1BC6
+#define ICON_MDI_PRINTER_POS_MINUS_OUTLINE "\xf3\xb1\xaf\x87" // U+F1BC7
+#define ICON_MDI_PRINTER_POS_NETWORK "\xf3\xb1\xaf\x88" // U+F1BC8
+#define ICON_MDI_PRINTER_POS_NETWORK_OUTLINE "\xf3\xb1\xaf\x89" // U+F1BC9
+#define ICON_MDI_PRINTER_POS_OFF "\xf3\xb1\xaf\x8a" // U+F1BCA
+#define ICON_MDI_PRINTER_POS_OFF_OUTLINE "\xf3\xb1\xaf\x8b" // U+F1BCB
+#define ICON_MDI_PRINTER_POS_OUTLINE "\xf3\xb1\xaf\x8c" // U+F1BCC
+#define ICON_MDI_PRINTER_POS_PAUSE "\xf3\xb1\xaf\x8d" // U+F1BCD
+#define ICON_MDI_PRINTER_POS_PAUSE_OUTLINE "\xf3\xb1\xaf\x8e" // U+F1BCE
+#define ICON_MDI_PRINTER_POS_PLAY "\xf3\xb1\xaf\x8f" // U+F1BCF
+#define ICON_MDI_PRINTER_POS_PLAY_OUTLINE "\xf3\xb1\xaf\x90" // U+F1BD0
+#define ICON_MDI_PRINTER_POS_PLUS "\xf3\xb1\xaf\x91" // U+F1BD1
+#define ICON_MDI_PRINTER_POS_PLUS_OUTLINE "\xf3\xb1\xaf\x92" // U+F1BD2
+#define ICON_MDI_PRINTER_POS_REFRESH "\xf3\xb1\xaf\x93" // U+F1BD3
+#define ICON_MDI_PRINTER_POS_REFRESH_OUTLINE "\xf3\xb1\xaf\x94" // U+F1BD4
+#define ICON_MDI_PRINTER_POS_REMOVE "\xf3\xb1\xaf\x95" // U+F1BD5
+#define ICON_MDI_PRINTER_POS_REMOVE_OUTLINE "\xf3\xb1\xaf\x96" // U+F1BD6
+#define ICON_MDI_PRINTER_POS_STAR "\xf3\xb1\xaf\x97" // U+F1BD7
+#define ICON_MDI_PRINTER_POS_STAR_OUTLINE "\xf3\xb1\xaf\x98" // U+F1BD8
+#define ICON_MDI_PRINTER_POS_STOP "\xf3\xb1\xaf\x99" // U+F1BD9
+#define ICON_MDI_PRINTER_POS_STOP_OUTLINE "\xf3\xb1\xaf\x9a" // U+F1BDA
+#define ICON_MDI_PRINTER_POS_SYNC "\xf3\xb1\xaf\x9b" // U+F1BDB
+#define ICON_MDI_PRINTER_POS_SYNC_OUTLINE "\xf3\xb1\xaf\x9c" // U+F1BDC
+#define ICON_MDI_PRINTER_POS_WRENCH "\xf3\xb1\xaf\x9d" // U+F1BDD
+#define ICON_MDI_PRINTER_POS_WRENCH_OUTLINE "\xf3\xb1\xaf\x9e" // U+F1BDE
+#define ICON_MDI_PRINTER_SEARCH "\xf3\xb1\x91\x97" // U+F1457
+#define ICON_MDI_PRINTER_SETTINGS "\xf3\xb0\x9c\x87" // U+F0707
+#define ICON_MDI_PRINTER_WIRELESS "\xf3\xb0\xa8\x8b" // U+F0A0B
+#define ICON_MDI_PRIORITY_HIGH "\xf3\xb0\x98\x83" // U+F0603
+#define ICON_MDI_PRIORITY_LOW "\xf3\xb0\x98\x84" // U+F0604
+#define ICON_MDI_PROFESSIONAL_HEXAGON "\xf3\xb0\x90\xad" // U+F042D
+#define ICON_MDI_PROGRESS_ALERT "\xf3\xb0\xb2\xbc" // U+F0CBC
+#define ICON_MDI_PROGRESS_CHECK "\xf3\xb0\xa6\x95" // U+F0995
+#define ICON_MDI_PROGRESS_CLOCK "\xf3\xb0\xa6\x96" // U+F0996
+#define ICON_MDI_PROGRESS_CLOSE "\xf3\xb1\x84\x8a" // U+F110A
+#define ICON_MDI_PROGRESS_DOWNLOAD "\xf3\xb0\xa6\x97" // U+F0997
+#define ICON_MDI_PROGRESS_HELPER "\xf3\xb1\xae\xa2" // U+F1BA2
+#define ICON_MDI_PROGRESS_PENCIL "\xf3\xb1\x9e\x87" // U+F1787
+#define ICON_MDI_PROGRESS_QUESTION "\xf3\xb1\x94\xa2" // U+F1522
+#define ICON_MDI_PROGRESS_STAR "\xf3\xb1\x9e\x88" // U+F1788
+#define ICON_MDI_PROGRESS_STAR_FOUR_POINTS "\xf3\xb1\xb0\xbd" // U+F1C3D
+#define ICON_MDI_PROGRESS_UPLOAD "\xf3\xb0\xa6\x98" // U+F0998
+#define ICON_MDI_PROGRESS_WRENCH "\xf3\xb0\xb2\xbd" // U+F0CBD
+#define ICON_MDI_PROJECTOR "\xf3\xb0\x90\xae" // U+F042E
+#define ICON_MDI_PROJECTOR_OFF "\xf3\xb1\xa8\xa3" // U+F1A23
+#define ICON_MDI_PROJECTOR_SCREEN "\xf3\xb0\x90\xaf" // U+F042F
+#define ICON_MDI_PROJECTOR_SCREEN_OFF "\xf3\xb1\xa0\x8d" // U+F180D
+#define ICON_MDI_PROJECTOR_SCREEN_OFF_OUTLINE "\xf3\xb1\xa0\x8e" // U+F180E
+#define ICON_MDI_PROJECTOR_SCREEN_OUTLINE "\xf3\xb1\x9c\xa4" // U+F1724
+#define ICON_MDI_PROJECTOR_SCREEN_VARIANT "\xf3\xb1\xa0\x8f" // U+F180F
+#define ICON_MDI_PROJECTOR_SCREEN_VARIANT_OFF "\xf3\xb1\xa0\x90" // U+F1810
+#define ICON_MDI_PROJECTOR_SCREEN_VARIANT_OFF_OUTLINE "\xf3\xb1\xa0\x91" // U+F1811
+#define ICON_MDI_PROJECTOR_SCREEN_VARIANT_OUTLINE "\xf3\xb1\xa0\x92" // U+F1812
+#define ICON_MDI_PROPANE_TANK "\xf3\xb1\x8d\x97" // U+F1357
+#define ICON_MDI_PROPANE_TANK_OUTLINE "\xf3\xb1\x8d\x98" // U+F1358
+#define ICON_MDI_PROTOCOL "\xf3\xb0\xbf\x98" // U+F0FD8
+#define ICON_MDI_PUBLISH "\xf3\xb0\x9a\xa7" // U+F06A7
+#define ICON_MDI_PUBLISH_OFF "\xf3\xb1\xa5\x85" // U+F1945
+#define ICON_MDI_PULSE "\xf3\xb0\x90\xb0" // U+F0430
+#define ICON_MDI_PUMP "\xf3\xb1\x90\x82" // U+F1402
+#define ICON_MDI_PUMP_OFF "\xf3\xb1\xac\xa2" // U+F1B22
+#define ICON_MDI_PUMPKIN "\xf3\xb0\xae\xbf" // U+F0BBF
+#define ICON_MDI_PURSE "\xf3\xb0\xbc\x9c" // U+F0F1C
+#define ICON_MDI_PURSE_OUTLINE "\xf3\xb0\xbc\x9d" // U+F0F1D
+#define ICON_MDI_PUZZLE "\xf3\xb0\x90\xb1" // U+F0431
+#define ICON_MDI_PUZZLE_CHECK "\xf3\xb1\x90\xa6" // U+F1426
+#define ICON_MDI_PUZZLE_CHECK_OUTLINE "\xf3\xb1\x90\xa7" // U+F1427
+#define ICON_MDI_PUZZLE_EDIT "\xf3\xb1\x93\x93" // U+F14D3
+#define ICON_MDI_PUZZLE_EDIT_OUTLINE "\xf3\xb1\x93\x99" // U+F14D9
+#define ICON_MDI_PUZZLE_HEART "\xf3\xb1\x93\x94" // U+F14D4
+#define ICON_MDI_PUZZLE_HEART_OUTLINE "\xf3\xb1\x93\x9a" // U+F14DA
+#define ICON_MDI_PUZZLE_MINUS "\xf3\xb1\x93\x91" // U+F14D1
+#define ICON_MDI_PUZZLE_MINUS_OUTLINE "\xf3\xb1\x93\x97" // U+F14D7
+#define ICON_MDI_PUZZLE_OUTLINE "\xf3\xb0\xa9\xa6" // U+F0A66
+#define ICON_MDI_PUZZLE_PLUS "\xf3\xb1\x93\x90" // U+F14D0
+#define ICON_MDI_PUZZLE_PLUS_OUTLINE "\xf3\xb1\x93\x96" // U+F14D6
+#define ICON_MDI_PUZZLE_REMOVE "\xf3\xb1\x93\x92" // U+F14D2
+#define ICON_MDI_PUZZLE_REMOVE_OUTLINE "\xf3\xb1\x93\x98" // U+F14D8
+#define ICON_MDI_PUZZLE_STAR "\xf3\xb1\x93\x95" // U+F14D5
+#define ICON_MDI_PUZZLE_STAR_OUTLINE "\xf3\xb1\x93\x9b" // U+F14DB
+#define ICON_MDI_PYRAMID "\xf3\xb1\xa5\x92" // U+F1952
+#define ICON_MDI_PYRAMID_OFF "\xf3\xb1\xa5\x93" // U+F1953
+#define ICON_MDI_QI "\xf3\xb0\xa6\x99" // U+F0999
+#define ICON_MDI_QQCHAT "\xf3\xb0\x98\x85" // U+F0605
+#define ICON_MDI_QRCODE "\xf3\xb0\x90\xb2" // U+F0432
+#define ICON_MDI_QRCODE_EDIT "\xf3\xb0\xa2\xb8" // U+F08B8
+#define ICON_MDI_QRCODE_MINUS "\xf3\xb1\x86\x8c" // U+F118C
+#define ICON_MDI_QRCODE_PLUS "\xf3\xb1\x86\x8b" // U+F118B
+#define ICON_MDI_QRCODE_REMOVE "\xf3\xb1\x86\x8d" // U+F118D
+#define ICON_MDI_QRCODE_SCAN "\xf3\xb0\x90\xb3" // U+F0433
+#define ICON_MDI_QUADCOPTER "\xf3\xb0\x90\xb4" // U+F0434
+#define ICON_MDI_QUALITY_HIGH "\xf3\xb0\x90\xb5" // U+F0435
+#define ICON_MDI_QUALITY_LOW "\xf3\xb0\xa8\x8c" // U+F0A0C
+#define ICON_MDI_QUALITY_MEDIUM "\xf3\xb0\xa8\x8d" // U+F0A0D
+#define ICON_MDI_QUEUE_FIRST_IN_LAST_OUT "\xf3\xb1\xb2\xaf" // U+F1CAF
+#define ICON_MDI_QUORA "\xf3\xb0\xb4\xa9" // U+F0D29
+#define ICON_MDI_RABBIT "\xf3\xb0\xa4\x87" // U+F0907
+#define ICON_MDI_RABBIT_VARIANT "\xf3\xb1\xa9\xa1" // U+F1A61
+#define ICON_MDI_RABBIT_VARIANT_OUTLINE "\xf3\xb1\xa9\xa2" // U+F1A62
+#define ICON_MDI_RACING_HELMET "\xf3\xb0\xb6\x93" // U+F0D93
+#define ICON_MDI_RACQUETBALL "\xf3\xb0\xb6\x94" // U+F0D94
+#define ICON_MDI_RADAR "\xf3\xb0\x90\xb7" // U+F0437
+#define ICON_MDI_RADIATOR "\xf3\xb0\x90\xb8" // U+F0438
+#define ICON_MDI_RADIATOR_DISABLED "\xf3\xb0\xab\x97" // U+F0AD7
+#define ICON_MDI_RADIATOR_OFF "\xf3\xb0\xab\x98" // U+F0AD8
+#define ICON_MDI_RADIO "\xf3\xb0\x90\xb9" // U+F0439
+#define ICON_MDI_RADIO_AM "\xf3\xb0\xb2\xbe" // U+F0CBE
+#define ICON_MDI_RADIO_FM "\xf3\xb0\xb2\xbf" // U+F0CBF
+#define ICON_MDI_RADIO_HANDHELD "\xf3\xb0\x90\xba" // U+F043A
+#define ICON_MDI_RADIO_OFF "\xf3\xb1\x88\x9c" // U+F121C
+#define ICON_MDI_RADIO_TOWER "\xf3\xb0\x90\xbb" // U+F043B
+#define ICON_MDI_RADIOACTIVE "\xf3\xb0\x90\xbc" // U+F043C
+#define ICON_MDI_RADIOACTIVE_CIRCLE "\xf3\xb1\xa1\x9d" // U+F185D
+#define ICON_MDI_RADIOACTIVE_CIRCLE_OUTLINE "\xf3\xb1\xa1\x9e" // U+F185E
+#define ICON_MDI_RADIOACTIVE_OFF "\xf3\xb0\xbb\x81" // U+F0EC1
+#define ICON_MDI_RADIOBOX_BLANK "\xf3\xb0\x90\xbd" // U+F043D
+#define ICON_MDI_RADIOBOX_INDETERMINATE_VARIANT "\xf3\xb1\xb1\x9e" // U+F1C5E
+#define ICON_MDI_RADIOBOX_MARKED "\xf3\xb0\x90\xbe" // U+F043E
+#define ICON_MDI_RADIOLOGY_BOX "\xf3\xb1\x93\x85" // U+F14C5
+#define ICON_MDI_RADIOLOGY_BOX_OUTLINE "\xf3\xb1\x93\x86" // U+F14C6
+#define ICON_MDI_RADIUS "\xf3\xb0\xb3\x80" // U+F0CC0
+#define ICON_MDI_RADIUS_OUTLINE "\xf3\xb0\xb3\x81" // U+F0CC1
+#define ICON_MDI_RAILROAD_LIGHT "\xf3\xb0\xbc\x9e" // U+F0F1E
+#define ICON_MDI_RAKE "\xf3\xb1\x95\x84" // U+F1544
+#define ICON_MDI_RASPBERRY_PI "\xf3\xb0\x90\xbf" // U+F043F
+#define ICON_MDI_RAW "\xf3\xb1\xa8\x8f" // U+F1A0F
+#define ICON_MDI_RAW_OFF "\xf3\xb1\xa8\x90" // U+F1A10
+#define ICON_MDI_RAY_END "\xf3\xb0\x91\x80" // U+F0440
+#define ICON_MDI_RAY_END_ARROW "\xf3\xb0\x91\x81" // U+F0441
+#define ICON_MDI_RAY_START "\xf3\xb0\x91\x82" // U+F0442
+#define ICON_MDI_RAY_START_ARROW "\xf3\xb0\x91\x83" // U+F0443
+#define ICON_MDI_RAY_START_END "\xf3\xb0\x91\x84" // U+F0444
+#define ICON_MDI_RAY_START_VERTEX_END "\xf3\xb1\x97\x98" // U+F15D8
+#define ICON_MDI_RAY_VERTEX "\xf3\xb0\x91\x85" // U+F0445
+#define ICON_MDI_RAZOR_DOUBLE_EDGE "\xf3\xb1\xa6\x97" // U+F1997
+#define ICON_MDI_RAZOR_SINGLE_EDGE "\xf3\xb1\xa6\x98" // U+F1998
+#define ICON_MDI_REACT "\xf3\xb0\x9c\x88" // U+F0708
+#define ICON_MDI_READ "\xf3\xb0\x91\x87" // U+F0447
+#define ICON_MDI_RECEIPT "\xf3\xb0\xa0\xa4" // U+F0824
+#define ICON_MDI_RECEIPT_CLOCK "\xf3\xb1\xb0\xbe" // U+F1C3E
+#define ICON_MDI_RECEIPT_CLOCK_OUTLINE "\xf3\xb1\xb0\xbf" // U+F1C3F
+#define ICON_MDI_RECEIPT_OUTLINE "\xf3\xb0\x93\xb7" // U+F04F7
+#define ICON_MDI_RECEIPT_SEND "\xf3\xb1\xb1\x80" // U+F1C40
+#define ICON_MDI_RECEIPT_SEND_OUTLINE "\xf3\xb1\xb1\x81" // U+F1C41
+#define ICON_MDI_RECEIPT_TEXT "\xf3\xb0\x91\x89" // U+F0449
+#define ICON_MDI_RECEIPT_TEXT_ARROW_LEFT "\xf3\xb1\xb1\x82" // U+F1C42
+#define ICON_MDI_RECEIPT_TEXT_ARROW_LEFT_OUTLINE "\xf3\xb1\xb1\x83" // U+F1C43
+#define ICON_MDI_RECEIPT_TEXT_ARROW_RIGHT "\xf3\xb1\xb1\x84" // U+F1C44
+#define ICON_MDI_RECEIPT_TEXT_ARROW_RIGHT_OUTLINE "\xf3\xb1\xb1\x85" // U+F1C45
+#define ICON_MDI_RECEIPT_TEXT_CHECK "\xf3\xb1\xa9\xa3" // U+F1A63
+#define ICON_MDI_RECEIPT_TEXT_CHECK_OUTLINE "\xf3\xb1\xa9\xa4" // U+F1A64
+#define ICON_MDI_RECEIPT_TEXT_CLOCK "\xf3\xb1\xb1\x86" // U+F1C46
+#define ICON_MDI_RECEIPT_TEXT_CLOCK_OUTLINE "\xf3\xb1\xb1\x87" // U+F1C47
+#define ICON_MDI_RECEIPT_TEXT_EDIT "\xf3\xb1\xb1\x88" // U+F1C48
+#define ICON_MDI_RECEIPT_TEXT_EDIT_OUTLINE "\xf3\xb1\xb1\x89" // U+F1C49
+#define ICON_MDI_RECEIPT_TEXT_MINUS "\xf3\xb1\xa9\xa5" // U+F1A65
+#define ICON_MDI_RECEIPT_TEXT_MINUS_OUTLINE "\xf3\xb1\xa9\xa6" // U+F1A66
+#define ICON_MDI_RECEIPT_TEXT_OUTLINE "\xf3\xb1\xa7\x9c" // U+F19DC
+#define ICON_MDI_RECEIPT_TEXT_PLUS "\xf3\xb1\xa9\xa7" // U+F1A67
+#define ICON_MDI_RECEIPT_TEXT_PLUS_OUTLINE "\xf3\xb1\xa9\xa8" // U+F1A68
+#define ICON_MDI_RECEIPT_TEXT_REMOVE "\xf3\xb1\xa9\xa9" // U+F1A69
+#define ICON_MDI_RECEIPT_TEXT_REMOVE_OUTLINE "\xf3\xb1\xa9\xaa" // U+F1A6A
+#define ICON_MDI_RECEIPT_TEXT_SEND "\xf3\xb1\xb1\x8a" // U+F1C4A
+#define ICON_MDI_RECEIPT_TEXT_SEND_OUTLINE "\xf3\xb1\xb1\x8b" // U+F1C4B
+#define ICON_MDI_RECORD "\xf3\xb0\x91\x8a" // U+F044A
+#define ICON_MDI_RECORD_CIRCLE "\xf3\xb0\xbb\x82" // U+F0EC2
+#define ICON_MDI_RECORD_CIRCLE_OUTLINE "\xf3\xb0\xbb\x83" // U+F0EC3
+#define ICON_MDI_RECORD_PLAYER "\xf3\xb0\xa6\x9a" // U+F099A
+#define ICON_MDI_RECORD_REC "\xf3\xb0\x91\x8b" // U+F044B
+#define ICON_MDI_RECTANGLE "\xf3\xb0\xb9\x9e" // U+F0E5E
+#define ICON_MDI_RECTANGLE_OUTLINE "\xf3\xb0\xb9\x9f" // U+F0E5F
+#define ICON_MDI_RECYCLE "\xf3\xb0\x91\x8c" // U+F044C
+#define ICON_MDI_RECYCLE_VARIANT "\xf3\xb1\x8e\x9d" // U+F139D
+#define ICON_MDI_REDDIT "\xf3\xb0\x91\x8d" // U+F044D
+#define ICON_MDI_REDHAT "\xf3\xb1\x84\x9b" // U+F111B
+#define ICON_MDI_REDO "\xf3\xb0\x91\x8e" // U+F044E
+#define ICON_MDI_REDO_VARIANT "\xf3\xb0\x91\x8f" // U+F044F
+#define ICON_MDI_REFLECT_HORIZONTAL "\xf3\xb0\xa8\x8e" // U+F0A0E
+#define ICON_MDI_REFLECT_VERTICAL "\xf3\xb0\xa8\x8f" // U+F0A0F
+#define ICON_MDI_REFRESH "\xf3\xb0\x91\x90" // U+F0450
+#define ICON_MDI_REFRESH_AUTO "\xf3\xb1\xa3\xb2" // U+F18F2
+#define ICON_MDI_REFRESH_CIRCLE "\xf3\xb1\x8d\xb7" // U+F1377
+#define ICON_MDI_REGEX "\xf3\xb0\x91\x91" // U+F0451
+#define ICON_MDI_REGISTERED_TRADEMARK "\xf3\xb0\xa9\xa7" // U+F0A67
+#define ICON_MDI_REITERATE "\xf3\xb1\x96\x88" // U+F1588
+#define ICON_MDI_RELATION_MANY_TO_MANY "\xf3\xb1\x92\x96" // U+F1496
+#define ICON_MDI_RELATION_MANY_TO_ONE "\xf3\xb1\x92\x97" // U+F1497
+#define ICON_MDI_RELATION_MANY_TO_ONE_OR_MANY "\xf3\xb1\x92\x98" // U+F1498
+#define ICON_MDI_RELATION_MANY_TO_ONLY_ONE "\xf3\xb1\x92\x99" // U+F1499
+#define ICON_MDI_RELATION_MANY_TO_ZERO_OR_MANY "\xf3\xb1\x92\x9a" // U+F149A
+#define ICON_MDI_RELATION_MANY_TO_ZERO_OR_ONE "\xf3\xb1\x92\x9b" // U+F149B
+#define ICON_MDI_RELATION_ONE_OR_MANY_TO_MANY "\xf3\xb1\x92\x9c" // U+F149C
+#define ICON_MDI_RELATION_ONE_OR_MANY_TO_ONE "\xf3\xb1\x92\x9d" // U+F149D
+#define ICON_MDI_RELATION_ONE_OR_MANY_TO_ONE_OR_MANY "\xf3\xb1\x92\x9e" // U+F149E
+#define ICON_MDI_RELATION_ONE_OR_MANY_TO_ONLY_ONE "\xf3\xb1\x92\x9f" // U+F149F
+#define ICON_MDI_RELATION_ONE_OR_MANY_TO_ZERO_OR_MANY "\xf3\xb1\x92\xa0" // U+F14A0
+#define ICON_MDI_RELATION_ONE_OR_MANY_TO_ZERO_OR_ONE "\xf3\xb1\x92\xa1" // U+F14A1
+#define ICON_MDI_RELATION_ONE_TO_MANY "\xf3\xb1\x92\xa2" // U+F14A2
+#define ICON_MDI_RELATION_ONE_TO_ONE "\xf3\xb1\x92\xa3" // U+F14A3
+#define ICON_MDI_RELATION_ONE_TO_ONE_OR_MANY "\xf3\xb1\x92\xa4" // U+F14A4
+#define ICON_MDI_RELATION_ONE_TO_ONLY_ONE "\xf3\xb1\x92\xa5" // U+F14A5
+#define ICON_MDI_RELATION_ONE_TO_ZERO_OR_MANY "\xf3\xb1\x92\xa6" // U+F14A6
+#define ICON_MDI_RELATION_ONE_TO_ZERO_OR_ONE "\xf3\xb1\x92\xa7" // U+F14A7
+#define ICON_MDI_RELATION_ONLY_ONE_TO_MANY "\xf3\xb1\x92\xa8" // U+F14A8
+#define ICON_MDI_RELATION_ONLY_ONE_TO_ONE "\xf3\xb1\x92\xa9" // U+F14A9
+#define ICON_MDI_RELATION_ONLY_ONE_TO_ONE_OR_MANY "\xf3\xb1\x92\xaa" // U+F14AA
+#define ICON_MDI_RELATION_ONLY_ONE_TO_ONLY_ONE "\xf3\xb1\x92\xab" // U+F14AB
+#define ICON_MDI_RELATION_ONLY_ONE_TO_ZERO_OR_MANY "\xf3\xb1\x92\xac" // U+F14AC
+#define ICON_MDI_RELATION_ONLY_ONE_TO_ZERO_OR_ONE "\xf3\xb1\x92\xad" // U+F14AD
+#define ICON_MDI_RELATION_ZERO_OR_MANY_TO_MANY "\xf3\xb1\x92\xae" // U+F14AE
+#define ICON_MDI_RELATION_ZERO_OR_MANY_TO_ONE "\xf3\xb1\x92\xaf" // U+F14AF
+#define ICON_MDI_RELATION_ZERO_OR_MANY_TO_ONE_OR_MANY "\xf3\xb1\x92\xb0" // U+F14B0
+#define ICON_MDI_RELATION_ZERO_OR_MANY_TO_ONLY_ONE "\xf3\xb1\x92\xb1" // U+F14B1
+#define ICON_MDI_RELATION_ZERO_OR_MANY_TO_ZERO_OR_MANY "\xf3\xb1\x92\xb2" // U+F14B2
+#define ICON_MDI_RELATION_ZERO_OR_MANY_TO_ZERO_OR_ONE "\xf3\xb1\x92\xb3" // U+F14B3
+#define ICON_MDI_RELATION_ZERO_OR_ONE_TO_MANY "\xf3\xb1\x92\xb4" // U+F14B4
+#define ICON_MDI_RELATION_ZERO_OR_ONE_TO_ONE "\xf3\xb1\x92\xb5" // U+F14B5
+#define ICON_MDI_RELATION_ZERO_OR_ONE_TO_ONE_OR_MANY "\xf3\xb1\x92\xb6" // U+F14B6
+#define ICON_MDI_RELATION_ZERO_OR_ONE_TO_ONLY_ONE "\xf3\xb1\x92\xb7" // U+F14B7
+#define ICON_MDI_RELATION_ZERO_OR_ONE_TO_ZERO_OR_MANY "\xf3\xb1\x92\xb8" // U+F14B8
+#define ICON_MDI_RELATION_ZERO_OR_ONE_TO_ZERO_OR_ONE "\xf3\xb1\x92\xb9" // U+F14B9
+#define ICON_MDI_RELATIVE_SCALE "\xf3\xb0\x91\x92" // U+F0452
+#define ICON_MDI_RELOAD "\xf3\xb0\x91\x93" // U+F0453
+#define ICON_MDI_RELOAD_ALERT "\xf3\xb1\x84\x8b" // U+F110B
+#define ICON_MDI_REMINDER "\xf3\xb0\xa2\x8c" // U+F088C
+#define ICON_MDI_REMOTE "\xf3\xb0\x91\x94" // U+F0454
+#define ICON_MDI_REMOTE_DESKTOP "\xf3\xb0\xa2\xb9" // U+F08B9
+#define ICON_MDI_REMOTE_OFF "\xf3\xb0\xbb\x84" // U+F0EC4
+#define ICON_MDI_REMOTE_TV "\xf3\xb0\xbb\x85" // U+F0EC5
+#define ICON_MDI_REMOTE_TV_OFF "\xf3\xb0\xbb\x86" // U+F0EC6
+#define ICON_MDI_RENAME "\xf3\xb1\xb0\x98" // U+F1C18
+#define ICON_MDI_RENAME_BOX "\xf3\xb0\x91\x95" // U+F0455
+#define ICON_MDI_RENAME_BOX_OUTLINE "\xf3\xb1\xb0\x99" // U+F1C19
+#define ICON_MDI_RENAME_OUTLINE "\xf3\xb1\xb0\x9a" // U+F1C1A
+#define ICON_MDI_REORDER_HORIZONTAL "\xf3\xb0\x9a\x88" // U+F0688
+#define ICON_MDI_REORDER_VERTICAL "\xf3\xb0\x9a\x89" // U+F0689
+#define ICON_MDI_REPEAT "\xf3\xb0\x91\x96" // U+F0456
+#define ICON_MDI_REPEAT_OFF "\xf3\xb0\x91\x97" // U+F0457
+#define ICON_MDI_REPEAT_ONCE "\xf3\xb0\x91\x98" // U+F0458
+#define ICON_MDI_REPEAT_VARIANT "\xf3\xb0\x95\x87" // U+F0547
+#define ICON_MDI_REPLAY "\xf3\xb0\x91\x99" // U+F0459
+#define ICON_MDI_REPLY "\xf3\xb0\x91\x9a" // U+F045A
+#define ICON_MDI_REPLY_ALL "\xf3\xb0\x91\x9b" // U+F045B
+#define ICON_MDI_REPLY_ALL_OUTLINE "\xf3\xb0\xbc\x9f" // U+F0F1F
+#define ICON_MDI_REPLY_CIRCLE "\xf3\xb1\x86\xae" // U+F11AE
+#define ICON_MDI_REPLY_OUTLINE "\xf3\xb0\xbc\xa0" // U+F0F20
+#define ICON_MDI_REPRODUCTION "\xf3\xb0\x91\x9c" // U+F045C
+#define ICON_MDI_RESISTOR "\xf3\xb0\xad\x84" // U+F0B44
+#define ICON_MDI_RESISTOR_NODES "\xf3\xb0\xad\x85" // U+F0B45
+#define ICON_MDI_RESIZE "\xf3\xb0\xa9\xa8" // U+F0A68
+#define ICON_MDI_RESIZE_BOTTOM_RIGHT "\xf3\xb0\x91\x9d" // U+F045D
+#define ICON_MDI_RESPONSIVE "\xf3\xb0\x91\x9e" // U+F045E
+#define ICON_MDI_RESTART "\xf3\xb0\x9c\x89" // U+F0709
+#define ICON_MDI_RESTART_ALERT "\xf3\xb1\x84\x8c" // U+F110C
+#define ICON_MDI_RESTART_OFF "\xf3\xb0\xb6\x95" // U+F0D95
+#define ICON_MDI_RESTORE "\xf3\xb0\xa6\x9b" // U+F099B
+#define ICON_MDI_RESTORE_ALERT "\xf3\xb1\x84\x8d" // U+F110D
+#define ICON_MDI_REWIND "\xf3\xb0\x91\x9f" // U+F045F
+#define ICON_MDI_REWIND_10 "\xf3\xb0\xb4\xaa" // U+F0D2A
+#define ICON_MDI_REWIND_15 "\xf3\xb1\xa5\x86" // U+F1946
+#define ICON_MDI_REWIND_30 "\xf3\xb0\xb6\x96" // U+F0D96
+#define ICON_MDI_REWIND_45 "\xf3\xb1\xac\x93" // U+F1B13
+#define ICON_MDI_REWIND_5 "\xf3\xb1\x87\xb9" // U+F11F9
+#define ICON_MDI_REWIND_60 "\xf3\xb1\x98\x8c" // U+F160C
+#define ICON_MDI_REWIND_OUTLINE "\xf3\xb0\x9c\x8a" // U+F070A
+#define ICON_MDI_RHOMBUS "\xf3\xb0\x9c\x8b" // U+F070B
+#define ICON_MDI_RHOMBUS_MEDIUM "\xf3\xb0\xa8\x90" // U+F0A10
+#define ICON_MDI_RHOMBUS_MEDIUM_OUTLINE "\xf3\xb1\x93\x9c" // U+F14DC
+#define ICON_MDI_RHOMBUS_OUTLINE "\xf3\xb0\x9c\x8c" // U+F070C
+#define ICON_MDI_RHOMBUS_SPLIT "\xf3\xb0\xa8\x91" // U+F0A11
+#define ICON_MDI_RHOMBUS_SPLIT_OUTLINE "\xf3\xb1\x93\x9d" // U+F14DD
+#define ICON_MDI_RIBBON "\xf3\xb0\x91\xa0" // U+F0460
+#define ICON_MDI_RICE "\xf3\xb0\x9f\xaa" // U+F07EA
+#define ICON_MDI_RICKSHAW "\xf3\xb1\x96\xbb" // U+F15BB
+#define ICON_MDI_RICKSHAW_ELECTRIC "\xf3\xb1\x96\xbc" // U+F15BC
+#define ICON_MDI_RING "\xf3\xb0\x9f\xab" // U+F07EB
+#define ICON_MDI_RIVET "\xf3\xb0\xb9\xa0" // U+F0E60
+#define ICON_MDI_ROAD "\xf3\xb0\x91\xa1" // U+F0461
+#define ICON_MDI_ROAD_VARIANT "\xf3\xb0\x91\xa2" // U+F0462
+#define ICON_MDI_ROBBER "\xf3\xb1\x81\x98" // U+F1058
+#define ICON_MDI_ROBOT "\xf3\xb0\x9a\xa9" // U+F06A9
+#define ICON_MDI_ROBOT_ANGRY "\xf3\xb1\x9a\x9d" // U+F169D
+#define ICON_MDI_ROBOT_ANGRY_OUTLINE "\xf3\xb1\x9a\x9e" // U+F169E
+#define ICON_MDI_ROBOT_CONFUSED "\xf3\xb1\x9a\x9f" // U+F169F
+#define ICON_MDI_ROBOT_CONFUSED_OUTLINE "\xf3\xb1\x9a\xa0" // U+F16A0
+#define ICON_MDI_ROBOT_DEAD "\xf3\xb1\x9a\xa1" // U+F16A1
+#define ICON_MDI_ROBOT_DEAD_OUTLINE "\xf3\xb1\x9a\xa2" // U+F16A2
+#define ICON_MDI_ROBOT_EXCITED "\xf3\xb1\x9a\xa3" // U+F16A3
+#define ICON_MDI_ROBOT_EXCITED_OUTLINE "\xf3\xb1\x9a\xa4" // U+F16A4
+#define ICON_MDI_ROBOT_HAPPY "\xf3\xb1\x9c\x99" // U+F1719
+#define ICON_MDI_ROBOT_HAPPY_OUTLINE "\xf3\xb1\x9c\x9a" // U+F171A
+#define ICON_MDI_ROBOT_INDUSTRIAL "\xf3\xb0\xad\x86" // U+F0B46
+#define ICON_MDI_ROBOT_INDUSTRIAL_OUTLINE "\xf3\xb1\xa8\x9a" // U+F1A1A
+#define ICON_MDI_ROBOT_LOVE "\xf3\xb1\x9a\xa5" // U+F16A5
+#define ICON_MDI_ROBOT_LOVE_OUTLINE "\xf3\xb1\x9a\xa6" // U+F16A6
+#define ICON_MDI_ROBOT_MOWER "\xf3\xb1\x87\xb7" // U+F11F7
+#define ICON_MDI_ROBOT_MOWER_OUTLINE "\xf3\xb1\x87\xb3" // U+F11F3
+#define ICON_MDI_ROBOT_OFF "\xf3\xb1\x9a\xa7" // U+F16A7
+#define ICON_MDI_ROBOT_OFF_OUTLINE "\xf3\xb1\x99\xbb" // U+F167B
+#define ICON_MDI_ROBOT_OUTLINE "\xf3\xb1\x99\xba" // U+F167A
+#define ICON_MDI_ROBOT_VACUUM "\xf3\xb0\x9c\x8d" // U+F070D
+#define ICON_MDI_ROBOT_VACUUM_ALERT "\xf3\xb1\xad\x9d" // U+F1B5D
+#define ICON_MDI_ROBOT_VACUUM_OFF "\xf3\xb1\xb0\x81" // U+F1C01
+#define ICON_MDI_ROBOT_VACUUM_VARIANT "\xf3\xb0\xa4\x88" // U+F0908
+#define ICON_MDI_ROBOT_VACUUM_VARIANT_ALERT "\xf3\xb1\xad\x9e" // U+F1B5E
+#define ICON_MDI_ROBOT_VACUUM_VARIANT_OFF "\xf3\xb1\xb0\x82" // U+F1C02
+#define ICON_MDI_ROCKET "\xf3\xb0\x91\xa3" // U+F0463
+#define ICON_MDI_ROCKET_LAUNCH "\xf3\xb1\x93\x9e" // U+F14DE
+#define ICON_MDI_ROCKET_LAUNCH_OUTLINE "\xf3\xb1\x93\x9f" // U+F14DF
+#define ICON_MDI_ROCKET_OUTLINE "\xf3\xb1\x8e\xaf" // U+F13AF
+#define ICON_MDI_RODENT "\xf3\xb1\x8c\xa7" // U+F1327
+#define ICON_MDI_ROLLER_SHADE "\xf3\xb1\xa9\xab" // U+F1A6B
+#define ICON_MDI_ROLLER_SHADE_CLOSED "\xf3\xb1\xa9\xac" // U+F1A6C
+#define ICON_MDI_ROLLER_SKATE "\xf3\xb0\xb4\xab" // U+F0D2B
+#define ICON_MDI_ROLLER_SKATE_OFF "\xf3\xb0\x85\x85" // U+F0145
+#define ICON_MDI_ROLLERBLADE "\xf3\xb0\xb4\xac" // U+F0D2C
+#define ICON_MDI_ROLLERBLADE_OFF "\xf3\xb0\x80\xae" // U+F002E
+#define ICON_MDI_ROLLUPJS "\xf3\xb0\xaf\x80" // U+F0BC0
+#define ICON_MDI_ROLODEX "\xf3\xb1\xaa\xb9" // U+F1AB9
+#define ICON_MDI_ROLODEX_OUTLINE "\xf3\xb1\xaa\xba" // U+F1ABA
+#define ICON_MDI_ROMAN_NUMERAL_1 "\xf3\xb1\x82\x88" // U+F1088
+#define ICON_MDI_ROMAN_NUMERAL_10 "\xf3\xb1\x82\x91" // U+F1091
+#define ICON_MDI_ROMAN_NUMERAL_2 "\xf3\xb1\x82\x89" // U+F1089
+#define ICON_MDI_ROMAN_NUMERAL_3 "\xf3\xb1\x82\x8a" // U+F108A
+#define ICON_MDI_ROMAN_NUMERAL_4 "\xf3\xb1\x82\x8b" // U+F108B
+#define ICON_MDI_ROMAN_NUMERAL_5 "\xf3\xb1\x82\x8c" // U+F108C
+#define ICON_MDI_ROMAN_NUMERAL_6 "\xf3\xb1\x82\x8d" // U+F108D
+#define ICON_MDI_ROMAN_NUMERAL_7 "\xf3\xb1\x82\x8e" // U+F108E
+#define ICON_MDI_ROMAN_NUMERAL_8 "\xf3\xb1\x82\x8f" // U+F108F
+#define ICON_MDI_ROMAN_NUMERAL_9 "\xf3\xb1\x82\x90" // U+F1090
+#define ICON_MDI_ROOM_SERVICE "\xf3\xb0\xa2\x8d" // U+F088D
+#define ICON_MDI_ROOM_SERVICE_OUTLINE "\xf3\xb0\xb6\x97" // U+F0D97
+#define ICON_MDI_ROTATE_360 "\xf3\xb1\xa6\x99" // U+F1999
+#define ICON_MDI_ROTATE_3D "\xf3\xb0\xbb\x87" // U+F0EC7
+#define ICON_MDI_ROTATE_3D_VARIANT "\xf3\xb0\x91\xa4" // U+F0464
+#define ICON_MDI_ROTATE_LEFT "\xf3\xb0\x91\xa5" // U+F0465
+#define ICON_MDI_ROTATE_LEFT_VARIANT "\xf3\xb0\x91\xa6" // U+F0466
+#define ICON_MDI_ROTATE_ORBIT "\xf3\xb0\xb6\x98" // U+F0D98
+#define ICON_MDI_ROTATE_RIGHT "\xf3\xb0\x91\xa7" // U+F0467
+#define ICON_MDI_ROTATE_RIGHT_VARIANT "\xf3\xb0\x91\xa8" // U+F0468
+#define ICON_MDI_ROUNDED_CORNER "\xf3\xb0\x98\x87" // U+F0607
+#define ICON_MDI_ROUTER "\xf3\xb1\x87\xa2" // U+F11E2
+#define ICON_MDI_ROUTER_NETWORK "\xf3\xb1\x82\x87" // U+F1087
+#define ICON_MDI_ROUTER_NETWORK_WIRELESS "\xf3\xb1\xb2\x97" // U+F1C97
+#define ICON_MDI_ROUTER_WIRELESS "\xf3\xb0\x91\xa9" // U+F0469
+#define ICON_MDI_ROUTER_WIRELESS_OFF "\xf3\xb1\x96\xa3" // U+F15A3
+#define ICON_MDI_ROUTER_WIRELESS_SETTINGS "\xf3\xb0\xa9\xa9" // U+F0A69
+#define ICON_MDI_ROUTES "\xf3\xb0\x91\xaa" // U+F046A
+#define ICON_MDI_ROUTES_CLOCK "\xf3\xb1\x81\x99" // U+F1059
+#define ICON_MDI_ROWING "\xf3\xb0\x98\x88" // U+F0608
+#define ICON_MDI_RSS "\xf3\xb0\x91\xab" // U+F046B
+#define ICON_MDI_RSS_BOX "\xf3\xb0\x91\xac" // U+F046C
+#define ICON_MDI_RSS_OFF "\xf3\xb0\xbc\xa1" // U+F0F21
+#define ICON_MDI_RUG "\xf3\xb1\x91\xb5" // U+F1475
+#define ICON_MDI_RUGBY "\xf3\xb0\xb6\x99" // U+F0D99
+#define ICON_MDI_RULER "\xf3\xb0\x91\xad" // U+F046D
+#define ICON_MDI_RULER_SQUARE "\xf3\xb0\xb3\x82" // U+F0CC2
+#define ICON_MDI_RULER_SQUARE_COMPASS "\xf3\xb0\xba\xbe" // U+F0EBE
+#define ICON_MDI_RUN "\xf3\xb0\x9c\x8e" // U+F070E
+#define ICON_MDI_RUN_FAST "\xf3\xb0\x91\xae" // U+F046E
+#define ICON_MDI_RV_TRUCK "\xf3\xb1\x87\x94" // U+F11D4
+#define ICON_MDI_SACK "\xf3\xb0\xb4\xae" // U+F0D2E
+#define ICON_MDI_SACK_OUTLINE "\xf3\xb1\xb1\x8c" // U+F1C4C
+#define ICON_MDI_SACK_PERCENT "\xf3\xb0\xb4\xaf" // U+F0D2F
+#define ICON_MDI_SAFE "\xf3\xb0\xa9\xaa" // U+F0A6A
+#define ICON_MDI_SAFE_SQUARE "\xf3\xb1\x89\xbc" // U+F127C
+#define ICON_MDI_SAFE_SQUARE_OUTLINE "\xf3\xb1\x89\xbd" // U+F127D
+#define ICON_MDI_SAFETY_GOGGLES "\xf3\xb0\xb4\xb0" // U+F0D30
+#define ICON_MDI_SAIL_BOAT "\xf3\xb0\xbb\x88" // U+F0EC8
+#define ICON_MDI_SAIL_BOAT_SINK "\xf3\xb1\xab\xaf" // U+F1AEF
+#define ICON_MDI_SALE "\xf3\xb0\x91\xaf" // U+F046F
+#define ICON_MDI_SALE_OUTLINE "\xf3\xb1\xa8\x86" // U+F1A06
+#define ICON_MDI_SALESFORCE "\xf3\xb0\xa2\x8e" // U+F088E
+#define ICON_MDI_SASS "\xf3\xb0\x9f\xac" // U+F07EC
+#define ICON_MDI_SATELLITE "\xf3\xb0\x91\xb0" // U+F0470
+#define ICON_MDI_SATELLITE_UPLINK "\xf3\xb0\xa4\x89" // U+F0909
+#define ICON_MDI_SATELLITE_VARIANT "\xf3\xb0\x91\xb1" // U+F0471
+#define ICON_MDI_SAUSAGE "\xf3\xb0\xa2\xba" // U+F08BA
+#define ICON_MDI_SAUSAGE_OFF "\xf3\xb1\x9e\x89" // U+F1789
+#define ICON_MDI_SAW_BLADE "\xf3\xb0\xb9\xa1" // U+F0E61
+#define ICON_MDI_SAWTOOTH_WAVE "\xf3\xb1\x91\xba" // U+F147A
+#define ICON_MDI_SAXOPHONE "\xf3\xb0\x98\x89" // U+F0609
+#define ICON_MDI_SCALE "\xf3\xb0\x91\xb2" // U+F0472
+#define ICON_MDI_SCALE_BALANCE "\xf3\xb0\x97\x91" // U+F05D1
+#define ICON_MDI_SCALE_BATHROOM "\xf3\xb0\x91\xb3" // U+F0473
+#define ICON_MDI_SCALE_OFF "\xf3\xb1\x81\x9a" // U+F105A
+#define ICON_MDI_SCALE_UNBALANCED "\xf3\xb1\xa6\xb8" // U+F19B8
+#define ICON_MDI_SCAN_HELPER "\xf3\xb1\x8f\x98" // U+F13D8
+#define ICON_MDI_SCANNER "\xf3\xb0\x9a\xab" // U+F06AB
+#define ICON_MDI_SCANNER_OFF "\xf3\xb0\xa4\x8a" // U+F090A
+#define ICON_MDI_SCATTER_PLOT "\xf3\xb0\xbb\x89" // U+F0EC9
+#define ICON_MDI_SCATTER_PLOT_OUTLINE "\xf3\xb0\xbb\x8a" // U+F0ECA
+#define ICON_MDI_SCENT "\xf3\xb1\xa5\x98" // U+F1958
+#define ICON_MDI_SCENT_OFF "\xf3\xb1\xa5\x99" // U+F1959
+#define ICON_MDI_SCHOOL "\xf3\xb0\x91\xb4" // U+F0474
+#define ICON_MDI_SCHOOL_OUTLINE "\xf3\xb1\x86\x80" // U+F1180
+#define ICON_MDI_SCISSORS_CUTTING "\xf3\xb0\xa9\xab" // U+F0A6B
+#define ICON_MDI_SCOOTER "\xf3\xb1\x96\xbd" // U+F15BD
+#define ICON_MDI_SCOOTER_ELECTRIC "\xf3\xb1\x96\xbe" // U+F15BE
+#define ICON_MDI_SCOREBOARD "\xf3\xb1\x89\xbe" // U+F127E
+#define ICON_MDI_SCOREBOARD_OUTLINE "\xf3\xb1\x89\xbf" // U+F127F
+#define ICON_MDI_SCREEN_ROTATION "\xf3\xb0\x91\xb5" // U+F0475
+#define ICON_MDI_SCREEN_ROTATION_LOCK "\xf3\xb0\x91\xb8" // U+F0478
+#define ICON_MDI_SCREW_FLAT_TOP "\xf3\xb0\xb7\xb3" // U+F0DF3
+#define ICON_MDI_SCREW_LAG "\xf3\xb0\xb7\xb4" // U+F0DF4
+#define ICON_MDI_SCREW_MACHINE_FLAT_TOP "\xf3\xb0\xb7\xb5" // U+F0DF5
+#define ICON_MDI_SCREW_MACHINE_ROUND_TOP "\xf3\xb0\xb7\xb6" // U+F0DF6
+#define ICON_MDI_SCREW_ROUND_TOP "\xf3\xb0\xb7\xb7" // U+F0DF7
+#define ICON_MDI_SCREWDRIVER "\xf3\xb0\x91\xb6" // U+F0476
+#define ICON_MDI_SCRIPT "\xf3\xb0\xaf\x81" // U+F0BC1
+#define ICON_MDI_SCRIPT_OUTLINE "\xf3\xb0\x91\xb7" // U+F0477
+#define ICON_MDI_SCRIPT_TEXT "\xf3\xb0\xaf\x82" // U+F0BC2
+#define ICON_MDI_SCRIPT_TEXT_KEY "\xf3\xb1\x9c\xa5" // U+F1725
+#define ICON_MDI_SCRIPT_TEXT_KEY_OUTLINE "\xf3\xb1\x9c\xa6" // U+F1726
+#define ICON_MDI_SCRIPT_TEXT_OUTLINE "\xf3\xb0\xaf\x83" // U+F0BC3
+#define ICON_MDI_SCRIPT_TEXT_PLAY "\xf3\xb1\x9c\xa7" // U+F1727
+#define ICON_MDI_SCRIPT_TEXT_PLAY_OUTLINE "\xf3\xb1\x9c\xa8" // U+F1728
+#define ICON_MDI_SD "\xf3\xb0\x91\xb9" // U+F0479
+#define ICON_MDI_SEAL "\xf3\xb0\x91\xba" // U+F047A
+#define ICON_MDI_SEAL_VARIANT "\xf3\xb0\xbf\x99" // U+F0FD9
+#define ICON_MDI_SEARCH_WEB "\xf3\xb0\x9c\x8f" // U+F070F
+#define ICON_MDI_SEAT "\xf3\xb0\xb3\x83" // U+F0CC3
+#define ICON_MDI_SEAT_FLAT "\xf3\xb0\x91\xbb" // U+F047B
+#define ICON_MDI_SEAT_FLAT_ANGLED "\xf3\xb0\x91\xbc" // U+F047C
+#define ICON_MDI_SEAT_INDIVIDUAL_SUITE "\xf3\xb0\x91\xbd" // U+F047D
+#define ICON_MDI_SEAT_LEGROOM_EXTRA "\xf3\xb0\x91\xbe" // U+F047E
+#define ICON_MDI_SEAT_LEGROOM_NORMAL "\xf3\xb0\x91\xbf" // U+F047F
+#define ICON_MDI_SEAT_LEGROOM_REDUCED "\xf3\xb0\x92\x80" // U+F0480
+#define ICON_MDI_SEAT_OUTLINE "\xf3\xb0\xb3\x84" // U+F0CC4
+#define ICON_MDI_SEAT_PASSENGER "\xf3\xb1\x89\x89" // U+F1249
+#define ICON_MDI_SEAT_RECLINE_EXTRA "\xf3\xb0\x92\x81" // U+F0481
+#define ICON_MDI_SEAT_RECLINE_NORMAL "\xf3\xb0\x92\x82" // U+F0482
+#define ICON_MDI_SEATBELT "\xf3\xb0\xb3\x85" // U+F0CC5
+#define ICON_MDI_SECURITY "\xf3\xb0\x92\x83" // U+F0483
+#define ICON_MDI_SECURITY_NETWORK "\xf3\xb0\x92\x84" // U+F0484
+#define ICON_MDI_SEED "\xf3\xb0\xb9\xa2" // U+F0E62
+#define ICON_MDI_SEED_OFF "\xf3\xb1\x8f\xbd" // U+F13FD
+#define ICON_MDI_SEED_OFF_OUTLINE "\xf3\xb1\x8f\xbe" // U+F13FE
+#define ICON_MDI_SEED_OUTLINE "\xf3\xb0\xb9\xa3" // U+F0E63
+#define ICON_MDI_SEED_PLUS "\xf3\xb1\xa9\xad" // U+F1A6D
+#define ICON_MDI_SEED_PLUS_OUTLINE "\xf3\xb1\xa9\xae" // U+F1A6E
+#define ICON_MDI_SEESAW "\xf3\xb1\x96\xa4" // U+F15A4
+#define ICON_MDI_SEGMENT "\xf3\xb0\xbb\x8b" // U+F0ECB
+#define ICON_MDI_SELECT "\xf3\xb0\x92\x85" // U+F0485
+#define ICON_MDI_SELECT_ALL "\xf3\xb0\x92\x86" // U+F0486
+#define ICON_MDI_SELECT_ARROW_DOWN "\xf3\xb1\xad\x99" // U+F1B59
+#define ICON_MDI_SELECT_ARROW_UP "\xf3\xb1\xad\x98" // U+F1B58
+#define ICON_MDI_SELECT_COLOR "\xf3\xb0\xb4\xb1" // U+F0D31
+#define ICON_MDI_SELECT_COMPARE "\xf3\xb0\xab\x99" // U+F0AD9
+#define ICON_MDI_SELECT_DRAG "\xf3\xb0\xa9\xac" // U+F0A6C
+#define ICON_MDI_SELECT_GROUP "\xf3\xb0\xbe\x82" // U+F0F82
+#define ICON_MDI_SELECT_INVERSE "\xf3\xb0\x92\x87" // U+F0487
+#define ICON_MDI_SELECT_MARKER "\xf3\xb1\x8a\x80" // U+F1280
+#define ICON_MDI_SELECT_MULTIPLE "\xf3\xb1\x8a\x81" // U+F1281
+#define ICON_MDI_SELECT_MULTIPLE_MARKER "\xf3\xb1\x8a\x82" // U+F1282
+#define ICON_MDI_SELECT_OFF "\xf3\xb0\x92\x88" // U+F0488
+#define ICON_MDI_SELECT_PLACE "\xf3\xb0\xbf\x9a" // U+F0FDA
+#define ICON_MDI_SELECT_REMOVE "\xf3\xb1\x9f\x81" // U+F17C1
+#define ICON_MDI_SELECT_SEARCH "\xf3\xb1\x88\x84" // U+F1204
+#define ICON_MDI_SELECTION "\xf3\xb0\x92\x89" // U+F0489
+#define ICON_MDI_SELECTION_DRAG "\xf3\xb0\xa9\xad" // U+F0A6D
+#define ICON_MDI_SELECTION_ELLIPSE "\xf3\xb0\xb4\xb2" // U+F0D32
+#define ICON_MDI_SELECTION_ELLIPSE_ARROW_INSIDE "\xf3\xb0\xbc\xa2" // U+F0F22
+#define ICON_MDI_SELECTION_ELLIPSE_REMOVE "\xf3\xb1\x9f\x82" // U+F17C2
+#define ICON_MDI_SELECTION_MARKER "\xf3\xb1\x8a\x83" // U+F1283
+#define ICON_MDI_SELECTION_MULTIPLE "\xf3\xb1\x8a\x85" // U+F1285
+#define ICON_MDI_SELECTION_MULTIPLE_MARKER "\xf3\xb1\x8a\x84" // U+F1284
+#define ICON_MDI_SELECTION_OFF "\xf3\xb0\x9d\xb7" // U+F0777
+#define ICON_MDI_SELECTION_REMOVE "\xf3\xb1\x9f\x83" // U+F17C3
+#define ICON_MDI_SELECTION_SEARCH "\xf3\xb1\x88\x85" // U+F1205
+#define ICON_MDI_SEMANTIC_WEB "\xf3\xb1\x8c\x96" // U+F1316
+#define ICON_MDI_SEND "\xf3\xb0\x92\x8a" // U+F048A
+#define ICON_MDI_SEND_CHECK "\xf3\xb1\x85\xa1" // U+F1161
+#define ICON_MDI_SEND_CHECK_OUTLINE "\xf3\xb1\x85\xa2" // U+F1162
+#define ICON_MDI_SEND_CIRCLE "\xf3\xb0\xb7\xb8" // U+F0DF8
+#define ICON_MDI_SEND_CIRCLE_OUTLINE "\xf3\xb0\xb7\xb9" // U+F0DF9
+#define ICON_MDI_SEND_CLOCK "\xf3\xb1\x85\xa3" // U+F1163
+#define ICON_MDI_SEND_CLOCK_OUTLINE "\xf3\xb1\x85\xa4" // U+F1164
+#define ICON_MDI_SEND_LOCK "\xf3\xb0\x9f\xad" // U+F07ED
+#define ICON_MDI_SEND_LOCK_OUTLINE "\xf3\xb1\x85\xa6" // U+F1166
+#define ICON_MDI_SEND_OUTLINE "\xf3\xb1\x85\xa5" // U+F1165
+#define ICON_MDI_SEND_VARIANT "\xf3\xb1\xb1\x8d" // U+F1C4D
+#define ICON_MDI_SEND_VARIANT_CLOCK "\xf3\xb1\xb1\xbe" // U+F1C7E
+#define ICON_MDI_SEND_VARIANT_CLOCK_OUTLINE "\xf3\xb1\xb1\xbf" // U+F1C7F
+#define ICON_MDI_SEND_VARIANT_OUTLINE "\xf3\xb1\xb1\x8e" // U+F1C4E
+#define ICON_MDI_SERIAL_PORT "\xf3\xb0\x99\x9c" // U+F065C
+#define ICON_MDI_SERVER "\xf3\xb0\x92\x8b" // U+F048B
+#define ICON_MDI_SERVER_MINUS "\xf3\xb0\x92\x8c" // U+F048C
+#define ICON_MDI_SERVER_MINUS_OUTLINE "\xf3\xb1\xb2\x98" // U+F1C98
+#define ICON_MDI_SERVER_NETWORK "\xf3\xb0\x92\x8d" // U+F048D
+#define ICON_MDI_SERVER_NETWORK_OFF "\xf3\xb0\x92\x8e" // U+F048E
+#define ICON_MDI_SERVER_NETWORK_OUTLINE "\xf3\xb1\xb2\x99" // U+F1C99
+#define ICON_MDI_SERVER_OFF "\xf3\xb0\x92\x8f" // U+F048F
+#define ICON_MDI_SERVER_OUTLINE "\xf3\xb1\xb2\x9a" // U+F1C9A
+#define ICON_MDI_SERVER_PLUS "\xf3\xb0\x92\x90" // U+F0490
+#define ICON_MDI_SERVER_PLUS_OUTLINE "\xf3\xb1\xb2\x9b" // U+F1C9B
+#define ICON_MDI_SERVER_REMOVE "\xf3\xb0\x92\x91" // U+F0491
+#define ICON_MDI_SERVER_SECURITY "\xf3\xb0\x92\x92" // U+F0492
+#define ICON_MDI_SET_ALL "\xf3\xb0\x9d\xb8" // U+F0778
+#define ICON_MDI_SET_CENTER "\xf3\xb0\x9d\xb9" // U+F0779
+#define ICON_MDI_SET_CENTER_RIGHT "\xf3\xb0\x9d\xba" // U+F077A
+#define ICON_MDI_SET_LEFT "\xf3\xb0\x9d\xbb" // U+F077B
+#define ICON_MDI_SET_LEFT_CENTER "\xf3\xb0\x9d\xbc" // U+F077C
+#define ICON_MDI_SET_LEFT_RIGHT "\xf3\xb0\x9d\xbd" // U+F077D
+#define ICON_MDI_SET_MERGE "\xf3\xb1\x93\xa0" // U+F14E0
+#define ICON_MDI_SET_NONE "\xf3\xb0\x9d\xbe" // U+F077E
+#define ICON_MDI_SET_RIGHT "\xf3\xb0\x9d\xbf" // U+F077F
+#define ICON_MDI_SET_SPLIT "\xf3\xb1\x93\xa1" // U+F14E1
+#define ICON_MDI_SET_SQUARE "\xf3\xb1\x91\x9d" // U+F145D
+#define ICON_MDI_SET_TOP_BOX "\xf3\xb0\xa6\x9f" // U+F099F
+#define ICON_MDI_SETTINGS_HELPER "\xf3\xb0\xa9\xae" // U+F0A6E
+#define ICON_MDI_SHAKER "\xf3\xb1\x84\x8e" // U+F110E
+#define ICON_MDI_SHAKER_OUTLINE "\xf3\xb1\x84\x8f" // U+F110F
+#define ICON_MDI_SHAPE "\xf3\xb0\xa0\xb1" // U+F0831
+#define ICON_MDI_SHAPE_CIRCLE_PLUS "\xf3\xb0\x99\x9d" // U+F065D
+#define ICON_MDI_SHAPE_OUTLINE "\xf3\xb0\xa0\xb2" // U+F0832
+#define ICON_MDI_SHAPE_OVAL_PLUS "\xf3\xb1\x87\xba" // U+F11FA
+#define ICON_MDI_SHAPE_PLUS "\xf3\xb0\x92\x95" // U+F0495
+#define ICON_MDI_SHAPE_PLUS_OUTLINE "\xf3\xb1\xb1\x8f" // U+F1C4F
+#define ICON_MDI_SHAPE_POLYGON_PLUS "\xf3\xb0\x99\x9e" // U+F065E
+#define ICON_MDI_SHAPE_RECTANGLE_PLUS "\xf3\xb0\x99\x9f" // U+F065F
+#define ICON_MDI_SHAPE_SQUARE_PLUS "\xf3\xb0\x99\xa0" // U+F0660
+#define ICON_MDI_SHAPE_SQUARE_ROUNDED_PLUS "\xf3\xb1\x93\xba" // U+F14FA
+#define ICON_MDI_SHARE "\xf3\xb0\x92\x96" // U+F0496
+#define ICON_MDI_SHARE_ALL "\xf3\xb1\x87\xb4" // U+F11F4
+#define ICON_MDI_SHARE_ALL_OUTLINE "\xf3\xb1\x87\xb5" // U+F11F5
+#define ICON_MDI_SHARE_CIRCLE "\xf3\xb1\x86\xad" // U+F11AD
+#define ICON_MDI_SHARE_OFF "\xf3\xb0\xbc\xa3" // U+F0F23
+#define ICON_MDI_SHARE_OFF_OUTLINE "\xf3\xb0\xbc\xa4" // U+F0F24
+#define ICON_MDI_SHARE_OUTLINE "\xf3\xb0\xa4\xb2" // U+F0932
+#define ICON_MDI_SHARE_VARIANT "\xf3\xb0\x92\x97" // U+F0497
+#define ICON_MDI_SHARE_VARIANT_OUTLINE "\xf3\xb1\x94\x94" // U+F1514
+#define ICON_MDI_SHARK "\xf3\xb1\xa2\xba" // U+F18BA
+#define ICON_MDI_SHARK_FIN "\xf3\xb1\x99\xb3" // U+F1673
+#define ICON_MDI_SHARK_FIN_OUTLINE "\xf3\xb1\x99\xb4" // U+F1674
+#define ICON_MDI_SHARK_OFF "\xf3\xb1\xa2\xbb" // U+F18BB
+#define ICON_MDI_SHEEP "\xf3\xb0\xb3\x86" // U+F0CC6
+#define ICON_MDI_SHIELD "\xf3\xb0\x92\x98" // U+F0498
+#define ICON_MDI_SHIELD_ACCOUNT "\xf3\xb0\xa2\x8f" // U+F088F
+#define ICON_MDI_SHIELD_ACCOUNT_OUTLINE "\xf3\xb0\xa8\x92" // U+F0A12
+#define ICON_MDI_SHIELD_ACCOUNT_VARIANT "\xf3\xb1\x96\xa7" // U+F15A7
+#define ICON_MDI_SHIELD_ACCOUNT_VARIANT_OUTLINE "\xf3\xb1\x96\xa8" // U+F15A8
+#define ICON_MDI_SHIELD_AIRPLANE "\xf3\xb0\x9a\xbb" // U+F06BB
+#define ICON_MDI_SHIELD_AIRPLANE_OUTLINE "\xf3\xb0\xb3\x87" // U+F0CC7
+#define ICON_MDI_SHIELD_ALERT "\xf3\xb0\xbb\x8c" // U+F0ECC
+#define ICON_MDI_SHIELD_ALERT_OUTLINE "\xf3\xb0\xbb\x8d" // U+F0ECD
+#define ICON_MDI_SHIELD_BUG "\xf3\xb1\x8f\x9a" // U+F13DA
+#define ICON_MDI_SHIELD_BUG_OUTLINE "\xf3\xb1\x8f\x9b" // U+F13DB
+#define ICON_MDI_SHIELD_CAR "\xf3\xb0\xbe\x83" // U+F0F83
+#define ICON_MDI_SHIELD_CHECK "\xf3\xb0\x95\xa5" // U+F0565
+#define ICON_MDI_SHIELD_CHECK_OUTLINE "\xf3\xb0\xb3\x88" // U+F0CC8
+#define ICON_MDI_SHIELD_CROSS "\xf3\xb0\xb3\x89" // U+F0CC9
+#define ICON_MDI_SHIELD_CROSS_OUTLINE "\xf3\xb0\xb3\x8a" // U+F0CCA
+#define ICON_MDI_SHIELD_CROWN "\xf3\xb1\xa2\xbc" // U+F18BC
+#define ICON_MDI_SHIELD_CROWN_OUTLINE "\xf3\xb1\xa2\xbd" // U+F18BD
+#define ICON_MDI_SHIELD_EDIT "\xf3\xb1\x86\xa0" // U+F11A0
+#define ICON_MDI_SHIELD_EDIT_OUTLINE "\xf3\xb1\x86\xa1" // U+F11A1
+#define ICON_MDI_SHIELD_HALF "\xf3\xb1\x8d\xa0" // U+F1360
+#define ICON_MDI_SHIELD_HALF_FULL "\xf3\xb0\x9e\x80" // U+F0780
+#define ICON_MDI_SHIELD_HOME "\xf3\xb0\x9a\x8a" // U+F068A
+#define ICON_MDI_SHIELD_HOME_OUTLINE "\xf3\xb0\xb3\x8b" // U+F0CCB
+#define ICON_MDI_SHIELD_KEY "\xf3\xb0\xaf\x84" // U+F0BC4
+#define ICON_MDI_SHIELD_KEY_OUTLINE "\xf3\xb0\xaf\x85" // U+F0BC5
+#define ICON_MDI_SHIELD_LINK_VARIANT "\xf3\xb0\xb4\xb3" // U+F0D33
+#define ICON_MDI_SHIELD_LINK_VARIANT_OUTLINE "\xf3\xb0\xb4\xb4" // U+F0D34
+#define ICON_MDI_SHIELD_LOCK "\xf3\xb0\xa6\x9d" // U+F099D
+#define ICON_MDI_SHIELD_LOCK_OPEN "\xf3\xb1\xa6\x9a" // U+F199A
+#define ICON_MDI_SHIELD_LOCK_OPEN_OUTLINE "\xf3\xb1\xa6\x9b" // U+F199B
+#define ICON_MDI_SHIELD_LOCK_OUTLINE "\xf3\xb0\xb3\x8c" // U+F0CCC
+#define ICON_MDI_SHIELD_MOON "\xf3\xb1\xa0\xa8" // U+F1828
+#define ICON_MDI_SHIELD_MOON_OUTLINE "\xf3\xb1\xa0\xa9" // U+F1829
+#define ICON_MDI_SHIELD_OFF "\xf3\xb0\xa6\x9e" // U+F099E
+#define ICON_MDI_SHIELD_OFF_OUTLINE "\xf3\xb0\xa6\x9c" // U+F099C
+#define ICON_MDI_SHIELD_OUTLINE "\xf3\xb0\x92\x99" // U+F0499
+#define ICON_MDI_SHIELD_PLUS "\xf3\xb0\xab\x9a" // U+F0ADA
+#define ICON_MDI_SHIELD_PLUS_OUTLINE "\xf3\xb0\xab\x9b" // U+F0ADB
+#define ICON_MDI_SHIELD_REFRESH "\xf3\xb0\x82\xaa" // U+F00AA
+#define ICON_MDI_SHIELD_REFRESH_OUTLINE "\xf3\xb0\x87\xa0" // U+F01E0
+#define ICON_MDI_SHIELD_REMOVE "\xf3\xb0\xab\x9c" // U+F0ADC
+#define ICON_MDI_SHIELD_REMOVE_OUTLINE "\xf3\xb0\xab\x9d" // U+F0ADD
+#define ICON_MDI_SHIELD_SEARCH "\xf3\xb0\xb6\x9a" // U+F0D9A
+#define ICON_MDI_SHIELD_STAR "\xf3\xb1\x84\xbb" // U+F113B
+#define ICON_MDI_SHIELD_STAR_OUTLINE "\xf3\xb1\x84\xbc" // U+F113C
+#define ICON_MDI_SHIELD_SUN "\xf3\xb1\x81\x9d" // U+F105D
+#define ICON_MDI_SHIELD_SUN_OUTLINE "\xf3\xb1\x81\x9e" // U+F105E
+#define ICON_MDI_SHIELD_SWORD "\xf3\xb1\xa2\xbe" // U+F18BE
+#define ICON_MDI_SHIELD_SWORD_OUTLINE "\xf3\xb1\xa2\xbf" // U+F18BF
+#define ICON_MDI_SHIELD_SYNC "\xf3\xb1\x86\xa2" // U+F11A2
+#define ICON_MDI_SHIELD_SYNC_OUTLINE "\xf3\xb1\x86\xa3" // U+F11A3
+#define ICON_MDI_SHIMMER "\xf3\xb1\x95\x85" // U+F1545
+#define ICON_MDI_SHIP_WHEEL "\xf3\xb0\xa0\xb3" // U+F0833
+#define ICON_MDI_SHIPPING_PALLET "\xf3\xb1\xa1\x8e" // U+F184E
+#define ICON_MDI_SHOE_BALLET "\xf3\xb1\x97\x8a" // U+F15CA
+#define ICON_MDI_SHOE_CLEAT "\xf3\xb1\x97\x87" // U+F15C7
+#define ICON_MDI_SHOE_FORMAL "\xf3\xb0\xad\x87" // U+F0B47
+#define ICON_MDI_SHOE_HEEL "\xf3\xb0\xad\x88" // U+F0B48
+#define ICON_MDI_SHOE_PRINT "\xf3\xb0\xb7\xba" // U+F0DFA
+#define ICON_MDI_SHOE_SNEAKER "\xf3\xb1\x97\x88" // U+F15C8
+#define ICON_MDI_SHOPPING "\xf3\xb0\x92\x9a" // U+F049A
+#define ICON_MDI_SHOPPING_MUSIC "\xf3\xb0\x92\x9b" // U+F049B
+#define ICON_MDI_SHOPPING_OUTLINE "\xf3\xb1\x87\x95" // U+F11D5
+#define ICON_MDI_SHOPPING_SEARCH "\xf3\xb0\xbe\x84" // U+F0F84
+#define ICON_MDI_SHOPPING_SEARCH_OUTLINE "\xf3\xb1\xa9\xaf" // U+F1A6F
+#define ICON_MDI_SHORE "\xf3\xb1\x93\xb9" // U+F14F9
+#define ICON_MDI_SHOVEL "\xf3\xb0\x9c\x90" // U+F0710
+#define ICON_MDI_SHOVEL_OFF "\xf3\xb0\x9c\x91" // U+F0711
+#define ICON_MDI_SHOWER "\xf3\xb0\xa6\xa0" // U+F09A0
+#define ICON_MDI_SHOWER_HEAD "\xf3\xb0\xa6\xa1" // U+F09A1
+#define ICON_MDI_SHREDDER "\xf3\xb0\x92\x9c" // U+F049C
+#define ICON_MDI_SHUFFLE "\xf3\xb0\x92\x9d" // U+F049D
+#define ICON_MDI_SHUFFLE_DISABLED "\xf3\xb0\x92\x9e" // U+F049E
+#define ICON_MDI_SHUFFLE_VARIANT "\xf3\xb0\x92\x9f" // U+F049F
+#define ICON_MDI_SHURIKEN "\xf3\xb1\x8d\xbf" // U+F137F
+#define ICON_MDI_SICKLE "\xf3\xb1\xa3\x80" // U+F18C0
+#define ICON_MDI_SIGMA "\xf3\xb0\x92\xa0" // U+F04A0
+#define ICON_MDI_SIGMA_LOWER "\xf3\xb0\x98\xab" // U+F062B
+#define ICON_MDI_SIGN_CAUTION "\xf3\xb0\x92\xa1" // U+F04A1
+#define ICON_MDI_SIGN_DIRECTION "\xf3\xb0\x9e\x81" // U+F0781
+#define ICON_MDI_SIGN_DIRECTION_MINUS "\xf3\xb1\x80\x80" // U+F1000
+#define ICON_MDI_SIGN_DIRECTION_PLUS "\xf3\xb0\xbf\x9c" // U+F0FDC
+#define ICON_MDI_SIGN_DIRECTION_REMOVE "\xf3\xb0\xbf\x9d" // U+F0FDD
+#define ICON_MDI_SIGN_LANGUAGE "\xf3\xb1\xad\x8d" // U+F1B4D
+#define ICON_MDI_SIGN_LANGUAGE_OUTLINE "\xf3\xb1\xad\x8e" // U+F1B4E
+#define ICON_MDI_SIGN_POLE "\xf3\xb1\x93\xb8" // U+F14F8
+#define ICON_MDI_SIGN_REAL_ESTATE "\xf3\xb1\x84\x98" // U+F1118
+#define ICON_MDI_SIGN_TEXT "\xf3\xb0\x9e\x82" // U+F0782
+#define ICON_MDI_SIGN_YIELD "\xf3\xb1\xae\xaf" // U+F1BAF
+#define ICON_MDI_SIGNAL "\xf3\xb0\x92\xa2" // U+F04A2
+#define ICON_MDI_SIGNAL_2G "\xf3\xb0\x9c\x92" // U+F0712
+#define ICON_MDI_SIGNAL_3G "\xf3\xb0\x9c\x93" // U+F0713
+#define ICON_MDI_SIGNAL_4G "\xf3\xb0\x9c\x94" // U+F0714
+#define ICON_MDI_SIGNAL_5G "\xf3\xb0\xa9\xaf" // U+F0A6F
+#define ICON_MDI_SIGNAL_CELLULAR_1 "\xf3\xb0\xa2\xbc" // U+F08BC
+#define ICON_MDI_SIGNAL_CELLULAR_2 "\xf3\xb0\xa2\xbd" // U+F08BD
+#define ICON_MDI_SIGNAL_CELLULAR_3 "\xf3\xb0\xa2\xbe" // U+F08BE
+#define ICON_MDI_SIGNAL_CELLULAR_OUTLINE "\xf3\xb0\xa2\xbf" // U+F08BF
+#define ICON_MDI_SIGNAL_DISTANCE_VARIANT "\xf3\xb0\xb9\xa4" // U+F0E64
+#define ICON_MDI_SIGNAL_HSPA "\xf3\xb0\x9c\x95" // U+F0715
+#define ICON_MDI_SIGNAL_HSPA_PLUS "\xf3\xb0\x9c\x96" // U+F0716
+#define ICON_MDI_SIGNAL_OFF "\xf3\xb0\x9e\x83" // U+F0783
+#define ICON_MDI_SIGNAL_VARIANT "\xf3\xb0\x98\x8a" // U+F060A
+#define ICON_MDI_SIGNATURE "\xf3\xb0\xb7\xbb" // U+F0DFB
+#define ICON_MDI_SIGNATURE_FREEHAND "\xf3\xb0\xb7\xbc" // U+F0DFC
+#define ICON_MDI_SIGNATURE_IMAGE "\xf3\xb0\xb7\xbd" // U+F0DFD
+#define ICON_MDI_SIGNATURE_TEXT "\xf3\xb0\xb7\xbe" // U+F0DFE
+#define ICON_MDI_SILO "\xf3\xb1\xae\x9f" // U+F1B9F
+#define ICON_MDI_SILO_OUTLINE "\xf3\xb0\xad\x89" // U+F0B49
+#define ICON_MDI_SILVERWARE "\xf3\xb0\x92\xa3" // U+F04A3
+#define ICON_MDI_SILVERWARE_CLEAN "\xf3\xb0\xbf\x9e" // U+F0FDE
+#define ICON_MDI_SILVERWARE_FORK "\xf3\xb0\x92\xa4" // U+F04A4
+#define ICON_MDI_SILVERWARE_FORK_KNIFE "\xf3\xb0\xa9\xb0" // U+F0A70
+#define ICON_MDI_SILVERWARE_SPOON "\xf3\xb0\x92\xa5" // U+F04A5
+#define ICON_MDI_SILVERWARE_VARIANT "\xf3\xb0\x92\xa6" // U+F04A6
+#define ICON_MDI_SIM "\xf3\xb0\x92\xa7" // U+F04A7
+#define ICON_MDI_SIM_ALERT "\xf3\xb0\x92\xa8" // U+F04A8
+#define ICON_MDI_SIM_ALERT_OUTLINE "\xf3\xb1\x97\x93" // U+F15D3
+#define ICON_MDI_SIM_OFF "\xf3\xb0\x92\xa9" // U+F04A9
+#define ICON_MDI_SIM_OFF_OUTLINE "\xf3\xb1\x97\x94" // U+F15D4
+#define ICON_MDI_SIM_OUTLINE "\xf3\xb1\x97\x95" // U+F15D5
+#define ICON_MDI_SIMPLE_ICONS "\xf3\xb1\x8c\x9d" // U+F131D
+#define ICON_MDI_SINA_WEIBO "\xf3\xb0\xab\x9f" // U+F0ADF
+#define ICON_MDI_SINE_WAVE "\xf3\xb0\xa5\x9b" // U+F095B
+#define ICON_MDI_SITEMAP "\xf3\xb0\x92\xaa" // U+F04AA
+#define ICON_MDI_SITEMAP_OUTLINE "\xf3\xb1\xa6\x9c" // U+F199C
+#define ICON_MDI_SIZE_L "\xf3\xb1\x8e\xa6" // U+F13A6
+#define ICON_MDI_SIZE_M "\xf3\xb1\x8e\xa5" // U+F13A5
+#define ICON_MDI_SIZE_S "\xf3\xb1\x8e\xa4" // U+F13A4
+#define ICON_MDI_SIZE_XL "\xf3\xb1\x8e\xa7" // U+F13A7
+#define ICON_MDI_SIZE_XS "\xf3\xb1\x8e\xa3" // U+F13A3
+#define ICON_MDI_SIZE_XXL "\xf3\xb1\x8e\xa8" // U+F13A8
+#define ICON_MDI_SIZE_XXS "\xf3\xb1\x8e\xa2" // U+F13A2
+#define ICON_MDI_SIZE_XXXL "\xf3\xb1\x8e\xa9" // U+F13A9
+#define ICON_MDI_SKATE "\xf3\xb0\xb4\xb5" // U+F0D35
+#define ICON_MDI_SKATE_OFF "\xf3\xb0\x9a\x99" // U+F0699
+#define ICON_MDI_SKATEBOARD "\xf3\xb1\x93\x82" // U+F14C2
+#define ICON_MDI_SKATEBOARDING "\xf3\xb0\x94\x81" // U+F0501
+#define ICON_MDI_SKEW_LESS "\xf3\xb0\xb4\xb6" // U+F0D36
+#define ICON_MDI_SKEW_MORE "\xf3\xb0\xb4\xb7" // U+F0D37
+#define ICON_MDI_SKI "\xf3\xb1\x8c\x84" // U+F1304
+#define ICON_MDI_SKI_CROSS_COUNTRY "\xf3\xb1\x8c\x85" // U+F1305
+#define ICON_MDI_SKI_WATER "\xf3\xb1\x8c\x86" // U+F1306
+#define ICON_MDI_SKIP_BACKWARD "\xf3\xb0\x92\xab" // U+F04AB
+#define ICON_MDI_SKIP_BACKWARD_OUTLINE "\xf3\xb0\xbc\xa5" // U+F0F25
+#define ICON_MDI_SKIP_FORWARD "\xf3\xb0\x92\xac" // U+F04AC
+#define ICON_MDI_SKIP_FORWARD_OUTLINE "\xf3\xb0\xbc\xa6" // U+F0F26
+#define ICON_MDI_SKIP_NEXT "\xf3\xb0\x92\xad" // U+F04AD
+#define ICON_MDI_SKIP_NEXT_CIRCLE "\xf3\xb0\x99\xa1" // U+F0661
+#define ICON_MDI_SKIP_NEXT_CIRCLE_OUTLINE "\xf3\xb0\x99\xa2" // U+F0662
+#define ICON_MDI_SKIP_NEXT_OUTLINE "\xf3\xb0\xbc\xa7" // U+F0F27
+#define ICON_MDI_SKIP_PREVIOUS "\xf3\xb0\x92\xae" // U+F04AE
+#define ICON_MDI_SKIP_PREVIOUS_CIRCLE "\xf3\xb0\x99\xa3" // U+F0663
+#define ICON_MDI_SKIP_PREVIOUS_CIRCLE_OUTLINE "\xf3\xb0\x99\xa4" // U+F0664
+#define ICON_MDI_SKIP_PREVIOUS_OUTLINE "\xf3\xb0\xbc\xa8" // U+F0F28
+#define ICON_MDI_SKULL "\xf3\xb0\x9a\x8c" // U+F068C
+#define ICON_MDI_SKULL_CROSSBONES "\xf3\xb0\xaf\x86" // U+F0BC6
+#define ICON_MDI_SKULL_CROSSBONES_OUTLINE "\xf3\xb0\xaf\x87" // U+F0BC7
+#define ICON_MDI_SKULL_OUTLINE "\xf3\xb0\xaf\x88" // U+F0BC8
+#define ICON_MDI_SKULL_SCAN "\xf3\xb1\x93\x87" // U+F14C7
+#define ICON_MDI_SKULL_SCAN_OUTLINE "\xf3\xb1\x93\x88" // U+F14C8
+#define ICON_MDI_SKYPE "\xf3\xb0\x92\xaf" // U+F04AF
+#define ICON_MDI_SKYPE_BUSINESS "\xf3\xb0\x92\xb0" // U+F04B0
+#define ICON_MDI_SLACK "\xf3\xb0\x92\xb1" // U+F04B1
+#define ICON_MDI_SLASH_FORWARD "\xf3\xb0\xbf\x9f" // U+F0FDF
+#define ICON_MDI_SLASH_FORWARD_BOX "\xf3\xb0\xbf\xa0" // U+F0FE0
+#define ICON_MDI_SLEDDING "\xf3\xb0\x90\x9b" // U+F041B
+#define ICON_MDI_SLEEP "\xf3\xb0\x92\xb2" // U+F04B2
+#define ICON_MDI_SLEEP_OFF "\xf3\xb0\x92\xb3" // U+F04B3
+#define ICON_MDI_SLIDE "\xf3\xb1\x96\xa5" // U+F15A5
+#define ICON_MDI_SLOPE_DOWNHILL "\xf3\xb0\xb7\xbf" // U+F0DFF
+#define ICON_MDI_SLOPE_UPHILL "\xf3\xb0\xb8\x80" // U+F0E00
+#define ICON_MDI_SLOT_MACHINE "\xf3\xb1\x84\x94" // U+F1114
+#define ICON_MDI_SLOT_MACHINE_OUTLINE "\xf3\xb1\x84\x95" // U+F1115
+#define ICON_MDI_SMART_CARD "\xf3\xb1\x82\xbd" // U+F10BD
+#define ICON_MDI_SMART_CARD_OFF "\xf3\xb1\xa3\xb7" // U+F18F7
+#define ICON_MDI_SMART_CARD_OFF_OUTLINE "\xf3\xb1\xa3\xb8" // U+F18F8
+#define ICON_MDI_SMART_CARD_OUTLINE "\xf3\xb1\x82\xbe" // U+F10BE
+#define ICON_MDI_SMART_CARD_READER "\xf3\xb1\x82\xbf" // U+F10BF
+#define ICON_MDI_SMART_CARD_READER_OUTLINE "\xf3\xb1\x83\x80" // U+F10C0
+#define ICON_MDI_SMOG "\xf3\xb0\xa9\xb1" // U+F0A71
+#define ICON_MDI_SMOKE "\xf3\xb1\x9e\x99" // U+F1799
+#define ICON_MDI_SMOKE_DETECTOR "\xf3\xb0\x8e\x92" // U+F0392
+#define ICON_MDI_SMOKE_DETECTOR_ALERT "\xf3\xb1\xa4\xae" // U+F192E
+#define ICON_MDI_SMOKE_DETECTOR_ALERT_OUTLINE "\xf3\xb1\xa4\xaf" // U+F192F
+#define ICON_MDI_SMOKE_DETECTOR_OFF "\xf3\xb1\xa0\x89" // U+F1809
+#define ICON_MDI_SMOKE_DETECTOR_OFF_OUTLINE "\xf3\xb1\xa0\x8a" // U+F180A
+#define ICON_MDI_SMOKE_DETECTOR_OUTLINE "\xf3\xb1\xa0\x88" // U+F1808
+#define ICON_MDI_SMOKE_DETECTOR_VARIANT "\xf3\xb1\xa0\x8b" // U+F180B
+#define ICON_MDI_SMOKE_DETECTOR_VARIANT_ALERT "\xf3\xb1\xa4\xb0" // U+F1930
+#define ICON_MDI_SMOKE_DETECTOR_VARIANT_OFF "\xf3\xb1\xa0\x8c" // U+F180C
+#define ICON_MDI_SMOKING "\xf3\xb0\x92\xb4" // U+F04B4
+#define ICON_MDI_SMOKING_OFF "\xf3\xb0\x92\xb5" // U+F04B5
+#define ICON_MDI_SMOKING_PIPE "\xf3\xb1\x90\x8d" // U+F140D
+#define ICON_MDI_SMOKING_PIPE_OFF "\xf3\xb1\x90\xa8" // U+F1428
+#define ICON_MDI_SNAIL "\xf3\xb1\x99\xb7" // U+F1677
+#define ICON_MDI_SNAKE "\xf3\xb1\x94\x8e" // U+F150E
+#define ICON_MDI_SNAPCHAT "\xf3\xb0\x92\xb6" // U+F04B6
+#define ICON_MDI_SNOWBOARD "\xf3\xb1\x8c\x87" // U+F1307
+#define ICON_MDI_SNOWFLAKE "\xf3\xb0\x9c\x97" // U+F0717
+#define ICON_MDI_SNOWFLAKE_ALERT "\xf3\xb0\xbc\xa9" // U+F0F29
+#define ICON_MDI_SNOWFLAKE_CHECK "\xf3\xb1\xa9\xb0" // U+F1A70
+#define ICON_MDI_SNOWFLAKE_MELT "\xf3\xb1\x8b\x8b" // U+F12CB
+#define ICON_MDI_SNOWFLAKE_OFF "\xf3\xb1\x93\xa3" // U+F14E3
+#define ICON_MDI_SNOWFLAKE_THERMOMETER "\xf3\xb1\xa9\xb1" // U+F1A71
+#define ICON_MDI_SNOWFLAKE_VARIANT "\xf3\xb0\xbc\xaa" // U+F0F2A
+#define ICON_MDI_SNOWMAN "\xf3\xb0\x92\xb7" // U+F04B7
+#define ICON_MDI_SNOWMOBILE "\xf3\xb0\x9b\x9d" // U+F06DD
+#define ICON_MDI_SNOWSHOEING "\xf3\xb1\xa9\xb2" // U+F1A72
+#define ICON_MDI_SOCCER "\xf3\xb0\x92\xb8" // U+F04B8
+#define ICON_MDI_SOCCER_FIELD "\xf3\xb0\xa0\xb4" // U+F0834
+#define ICON_MDI_SOCIAL_DISTANCE_2_METERS "\xf3\xb1\x95\xb9" // U+F1579
+#define ICON_MDI_SOCIAL_DISTANCE_6_FEET "\xf3\xb1\x95\xba" // U+F157A
+#define ICON_MDI_SOFA "\xf3\xb0\x92\xb9" // U+F04B9
+#define ICON_MDI_SOFA_OUTLINE "\xf3\xb1\x95\xad" // U+F156D
+#define ICON_MDI_SOFA_SINGLE "\xf3\xb1\x95\xae" // U+F156E
+#define ICON_MDI_SOFA_SINGLE_OUTLINE "\xf3\xb1\x95\xaf" // U+F156F
+#define ICON_MDI_SOLAR_PANEL "\xf3\xb0\xb6\x9b" // U+F0D9B
+#define ICON_MDI_SOLAR_PANEL_LARGE "\xf3\xb0\xb6\x9c" // U+F0D9C
+#define ICON_MDI_SOLAR_POWER "\xf3\xb0\xa9\xb2" // U+F0A72
+#define ICON_MDI_SOLAR_POWER_VARIANT "\xf3\xb1\xa9\xb3" // U+F1A73
+#define ICON_MDI_SOLAR_POWER_VARIANT_OUTLINE "\xf3\xb1\xa9\xb4" // U+F1A74
+#define ICON_MDI_SOLDERING_IRON "\xf3\xb1\x82\x92" // U+F1092
+#define ICON_MDI_SOLID "\xf3\xb0\x9a\x8d" // U+F068D
+#define ICON_MDI_SONY_PLAYSTATION "\xf3\xb0\x90\x94" // U+F0414
+#define ICON_MDI_SORT "\xf3\xb0\x92\xba" // U+F04BA
+#define ICON_MDI_SORT_ALPHABETICAL_ASCENDING "\xf3\xb0\x96\xbd" // U+F05BD
+#define ICON_MDI_SORT_ALPHABETICAL_ASCENDING_VARIANT "\xf3\xb1\x85\x88" // U+F1148
+#define ICON_MDI_SORT_ALPHABETICAL_DESCENDING "\xf3\xb0\x96\xbf" // U+F05BF
+#define ICON_MDI_SORT_ALPHABETICAL_DESCENDING_VARIANT "\xf3\xb1\x85\x89" // U+F1149
+#define ICON_MDI_SORT_ALPHABETICAL_VARIANT "\xf3\xb0\x92\xbb" // U+F04BB
+#define ICON_MDI_SORT_ASCENDING "\xf3\xb0\x92\xbc" // U+F04BC
+#define ICON_MDI_SORT_BOOL_ASCENDING "\xf3\xb1\x8e\x85" // U+F1385
+#define ICON_MDI_SORT_BOOL_ASCENDING_VARIANT "\xf3\xb1\x8e\x86" // U+F1386
+#define ICON_MDI_SORT_BOOL_DESCENDING "\xf3\xb1\x8e\x87" // U+F1387
+#define ICON_MDI_SORT_BOOL_DESCENDING_VARIANT "\xf3\xb1\x8e\x88" // U+F1388
+#define ICON_MDI_SORT_CALENDAR_ASCENDING "\xf3\xb1\x95\x87" // U+F1547
+#define ICON_MDI_SORT_CALENDAR_DESCENDING "\xf3\xb1\x95\x88" // U+F1548
+#define ICON_MDI_SORT_CLOCK_ASCENDING "\xf3\xb1\x95\x89" // U+F1549
+#define ICON_MDI_SORT_CLOCK_ASCENDING_OUTLINE "\xf3\xb1\x95\x8a" // U+F154A
+#define ICON_MDI_SORT_CLOCK_DESCENDING "\xf3\xb1\x95\x8b" // U+F154B
+#define ICON_MDI_SORT_CLOCK_DESCENDING_OUTLINE "\xf3\xb1\x95\x8c" // U+F154C
+#define ICON_MDI_SORT_DESCENDING "\xf3\xb0\x92\xbd" // U+F04BD
+#define ICON_MDI_SORT_NUMERIC_ASCENDING "\xf3\xb1\x8e\x89" // U+F1389
+#define ICON_MDI_SORT_NUMERIC_ASCENDING_VARIANT "\xf3\xb0\xa4\x8d" // U+F090D
+#define ICON_MDI_SORT_NUMERIC_DESCENDING "\xf3\xb1\x8e\x8a" // U+F138A
+#define ICON_MDI_SORT_NUMERIC_DESCENDING_VARIANT "\xf3\xb0\xab\x92" // U+F0AD2
+#define ICON_MDI_SORT_NUMERIC_VARIANT "\xf3\xb0\x92\xbe" // U+F04BE
+#define ICON_MDI_SORT_REVERSE_VARIANT "\xf3\xb0\x8c\xbc" // U+F033C
+#define ICON_MDI_SORT_VARIANT "\xf3\xb0\x92\xbf" // U+F04BF
+#define ICON_MDI_SORT_VARIANT_LOCK "\xf3\xb0\xb3\x8d" // U+F0CCD
+#define ICON_MDI_SORT_VARIANT_LOCK_OPEN "\xf3\xb0\xb3\x8e" // U+F0CCE
+#define ICON_MDI_SORT_VARIANT_OFF "\xf3\xb1\xaa\xbb" // U+F1ABB
+#define ICON_MDI_SORT_VARIANT_REMOVE "\xf3\xb1\x85\x87" // U+F1147
+#define ICON_MDI_SOUNDBAR "\xf3\xb1\x9f\x9b" // U+F17DB
+#define ICON_MDI_SOUNDCLOUD "\xf3\xb0\x93\x80" // U+F04C0
+#define ICON_MDI_SOURCE_BRANCH "\xf3\xb0\x98\xac" // U+F062C
+#define ICON_MDI_SOURCE_BRANCH_CHECK "\xf3\xb1\x93\x8f" // U+F14CF
+#define ICON_MDI_SOURCE_BRANCH_MINUS "\xf3\xb1\x93\x8b" // U+F14CB
+#define ICON_MDI_SOURCE_BRANCH_PLUS "\xf3\xb1\x93\x8a" // U+F14CA
+#define ICON_MDI_SOURCE_BRANCH_REFRESH "\xf3\xb1\x93\x8d" // U+F14CD
+#define ICON_MDI_SOURCE_BRANCH_REMOVE "\xf3\xb1\x93\x8c" // U+F14CC
+#define ICON_MDI_SOURCE_BRANCH_SYNC "\xf3\xb1\x93\x8e" // U+F14CE
+#define ICON_MDI_SOURCE_COMMIT "\xf3\xb0\x9c\x98" // U+F0718
+#define ICON_MDI_SOURCE_COMMIT_END "\xf3\xb0\x9c\x99" // U+F0719
+#define ICON_MDI_SOURCE_COMMIT_END_LOCAL "\xf3\xb0\x9c\x9a" // U+F071A
+#define ICON_MDI_SOURCE_COMMIT_LOCAL "\xf3\xb0\x9c\x9b" // U+F071B
+#define ICON_MDI_SOURCE_COMMIT_NEXT_LOCAL "\xf3\xb0\x9c\x9c" // U+F071C
+#define ICON_MDI_SOURCE_COMMIT_START "\xf3\xb0\x9c\x9d" // U+F071D
+#define ICON_MDI_SOURCE_COMMIT_START_NEXT_LOCAL "\xf3\xb0\x9c\x9e" // U+F071E
+#define ICON_MDI_SOURCE_FORK "\xf3\xb0\x93\x81" // U+F04C1
+#define ICON_MDI_SOURCE_MERGE "\xf3\xb0\x98\xad" // U+F062D
+#define ICON_MDI_SOURCE_PULL "\xf3\xb0\x93\x82" // U+F04C2
+#define ICON_MDI_SOURCE_REPOSITORY "\xf3\xb0\xb3\x8f" // U+F0CCF
+#define ICON_MDI_SOURCE_REPOSITORY_MULTIPLE "\xf3\xb0\xb3\x90" // U+F0CD0
+#define ICON_MDI_SOY_SAUCE "\xf3\xb0\x9f\xae" // U+F07EE
+#define ICON_MDI_SOY_SAUCE_OFF "\xf3\xb1\x8f\xbc" // U+F13FC
+#define ICON_MDI_SPA "\xf3\xb0\xb3\x91" // U+F0CD1
+#define ICON_MDI_SPA_OUTLINE "\xf3\xb0\xb3\x92" // U+F0CD2
+#define ICON_MDI_SPACE_INVADERS "\xf3\xb0\xaf\x89" // U+F0BC9
+#define ICON_MDI_SPACE_STATION "\xf3\xb1\x8e\x83" // U+F1383
+#define ICON_MDI_SPADE "\xf3\xb0\xb9\xa5" // U+F0E65
+#define ICON_MDI_SPEAKER "\xf3\xb0\x93\x83" // U+F04C3
+#define ICON_MDI_SPEAKER_BLUETOOTH "\xf3\xb0\xa6\xa2" // U+F09A2
+#define ICON_MDI_SPEAKER_MESSAGE "\xf3\xb1\xac\x91" // U+F1B11
+#define ICON_MDI_SPEAKER_MULTIPLE "\xf3\xb0\xb4\xb8" // U+F0D38
+#define ICON_MDI_SPEAKER_OFF "\xf3\xb0\x93\x84" // U+F04C4
+#define ICON_MDI_SPEAKER_PAUSE "\xf3\xb1\xad\xb3" // U+F1B73
+#define ICON_MDI_SPEAKER_PLAY "\xf3\xb1\xad\xb2" // U+F1B72
+#define ICON_MDI_SPEAKER_STOP "\xf3\xb1\xad\xb4" // U+F1B74
+#define ICON_MDI_SPEAKER_WIRELESS "\xf3\xb0\x9c\x9f" // U+F071F
+#define ICON_MDI_SPEAR "\xf3\xb1\xa1\x85" // U+F1845
+#define ICON_MDI_SPEEDOMETER "\xf3\xb0\x93\x85" // U+F04C5
+#define ICON_MDI_SPEEDOMETER_MEDIUM "\xf3\xb0\xbe\x85" // U+F0F85
+#define ICON_MDI_SPEEDOMETER_SLOW "\xf3\xb0\xbe\x86" // U+F0F86
+#define ICON_MDI_SPELLCHECK "\xf3\xb0\x93\x86" // U+F04C6
+#define ICON_MDI_SPHERE "\xf3\xb1\xa5\x94" // U+F1954
+#define ICON_MDI_SPHERE_OFF "\xf3\xb1\xa5\x95" // U+F1955
+#define ICON_MDI_SPIDER "\xf3\xb1\x87\xaa" // U+F11EA
+#define ICON_MDI_SPIDER_OUTLINE "\xf3\xb1\xb1\xb5" // U+F1C75
+#define ICON_MDI_SPIDER_THREAD "\xf3\xb1\x87\xab" // U+F11EB
+#define ICON_MDI_SPIDER_WEB "\xf3\xb0\xaf\x8a" // U+F0BCA
+#define ICON_MDI_SPIRIT_LEVEL "\xf3\xb1\x93\xb1" // U+F14F1
+#define ICON_MDI_SPOON_SUGAR "\xf3\xb1\x90\xa9" // U+F1429
+#define ICON_MDI_SPOTIFY "\xf3\xb0\x93\x87" // U+F04C7
+#define ICON_MDI_SPOTLIGHT "\xf3\xb0\x93\x88" // U+F04C8
+#define ICON_MDI_SPOTLIGHT_BEAM "\xf3\xb0\x93\x89" // U+F04C9
+#define ICON_MDI_SPRAY "\xf3\xb0\x99\xa5" // U+F0665
+#define ICON_MDI_SPRAY_BOTTLE "\xf3\xb0\xab\xa0" // U+F0AE0
+#define ICON_MDI_SPRINKLER "\xf3\xb1\x81\x9f" // U+F105F
+#define ICON_MDI_SPRINKLER_FIRE "\xf3\xb1\xa6\x9d" // U+F199D
+#define ICON_MDI_SPRINKLER_VARIANT "\xf3\xb1\x81\xa0" // U+F1060
+#define ICON_MDI_SPROUT "\xf3\xb0\xb9\xa6" // U+F0E66
+#define ICON_MDI_SPROUT_OUTLINE "\xf3\xb0\xb9\xa7" // U+F0E67
+#define ICON_MDI_SQUARE "\xf3\xb0\x9d\xa4" // U+F0764
+#define ICON_MDI_SQUARE_CIRCLE "\xf3\xb1\x94\x80" // U+F1500
+#define ICON_MDI_SQUARE_CIRCLE_OUTLINE "\xf3\xb1\xb1\x90" // U+F1C50
+#define ICON_MDI_SQUARE_EDIT_OUTLINE "\xf3\xb0\xa4\x8c" // U+F090C
+#define ICON_MDI_SQUARE_MEDIUM "\xf3\xb0\xa8\x93" // U+F0A13
+#define ICON_MDI_SQUARE_MEDIUM_OUTLINE "\xf3\xb0\xa8\x94" // U+F0A14
+#define ICON_MDI_SQUARE_OFF "\xf3\xb1\x8b\xae" // U+F12EE
+#define ICON_MDI_SQUARE_OFF_OUTLINE "\xf3\xb1\x8b\xaf" // U+F12EF
+#define ICON_MDI_SQUARE_OPACITY "\xf3\xb1\xa1\x94" // U+F1854
+#define ICON_MDI_SQUARE_OUTLINE "\xf3\xb0\x9d\xa3" // U+F0763
+#define ICON_MDI_SQUARE_ROOT "\xf3\xb0\x9e\x84" // U+F0784
+#define ICON_MDI_SQUARE_ROOT_BOX "\xf3\xb0\xa6\xa3" // U+F09A3
+#define ICON_MDI_SQUARE_ROUNDED "\xf3\xb1\x93\xbb" // U+F14FB
+#define ICON_MDI_SQUARE_ROUNDED_BADGE "\xf3\xb1\xa8\x87" // U+F1A07
+#define ICON_MDI_SQUARE_ROUNDED_BADGE_OUTLINE "\xf3\xb1\xa8\x88" // U+F1A08
+#define ICON_MDI_SQUARE_ROUNDED_OUTLINE "\xf3\xb1\x93\xbc" // U+F14FC
+#define ICON_MDI_SQUARE_SMALL "\xf3\xb0\xa8\x95" // U+F0A15
+#define ICON_MDI_SQUARE_WAVE "\xf3\xb1\x91\xbb" // U+F147B
+#define ICON_MDI_SQUEEGEE "\xf3\xb0\xab\xa1" // U+F0AE1
+#define ICON_MDI_SSH "\xf3\xb0\xa3\x80" // U+F08C0
+#define ICON_MDI_STACK_EXCHANGE "\xf3\xb0\x98\x8b" // U+F060B
+#define ICON_MDI_STACK_OVERFLOW "\xf3\xb0\x93\x8c" // U+F04CC
+#define ICON_MDI_STACKPATH "\xf3\xb0\x8d\x99" // U+F0359
+#define ICON_MDI_STADIUM "\xf3\xb0\xbf\xb9" // U+F0FF9
+#define ICON_MDI_STADIUM_OUTLINE "\xf3\xb1\xac\x83" // U+F1B03
+#define ICON_MDI_STADIUM_VARIANT "\xf3\xb0\x9c\xa0" // U+F0720
+#define ICON_MDI_STAIRS "\xf3\xb0\x93\x8d" // U+F04CD
+#define ICON_MDI_STAIRS_BOX "\xf3\xb1\x8e\x9e" // U+F139E
+#define ICON_MDI_STAIRS_DOWN "\xf3\xb1\x8a\xbe" // U+F12BE
+#define ICON_MDI_STAIRS_UP "\xf3\xb1\x8a\xbd" // U+F12BD
+#define ICON_MDI_STAMPER "\xf3\xb0\xb4\xb9" // U+F0D39
+#define ICON_MDI_STANDARD_DEFINITION "\xf3\xb0\x9f\xaf" // U+F07EF
+#define ICON_MDI_STAR "\xf3\xb0\x93\x8e" // U+F04CE
+#define ICON_MDI_STAR_BOX "\xf3\xb0\xa9\xb3" // U+F0A73
+#define ICON_MDI_STAR_BOX_MULTIPLE "\xf3\xb1\x8a\x86" // U+F1286
+#define ICON_MDI_STAR_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x8a\x87" // U+F1287
+#define ICON_MDI_STAR_BOX_OUTLINE "\xf3\xb0\xa9\xb4" // U+F0A74
+#define ICON_MDI_STAR_CHECK "\xf3\xb1\x95\xa6" // U+F1566
+#define ICON_MDI_STAR_CHECK_OUTLINE "\xf3\xb1\x95\xaa" // U+F156A
+#define ICON_MDI_STAR_CIRCLE "\xf3\xb0\x93\x8f" // U+F04CF
+#define ICON_MDI_STAR_CIRCLE_OUTLINE "\xf3\xb0\xa6\xa4" // U+F09A4
+#define ICON_MDI_STAR_COG "\xf3\xb1\x99\xa8" // U+F1668
+#define ICON_MDI_STAR_COG_OUTLINE "\xf3\xb1\x99\xa9" // U+F1669
+#define ICON_MDI_STAR_CRESCENT "\xf3\xb0\xa5\xb9" // U+F0979
+#define ICON_MDI_STAR_DAVID "\xf3\xb0\xa5\xba" // U+F097A
+#define ICON_MDI_STAR_FACE "\xf3\xb0\xa6\xa5" // U+F09A5
+#define ICON_MDI_STAR_FOUR_POINTS "\xf3\xb0\xab\xa2" // U+F0AE2
+#define ICON_MDI_STAR_FOUR_POINTS_BOX "\xf3\xb1\xb1\x91" // U+F1C51
+#define ICON_MDI_STAR_FOUR_POINTS_BOX_OUTLINE "\xf3\xb1\xb1\x92" // U+F1C52
+#define ICON_MDI_STAR_FOUR_POINTS_CIRCLE "\xf3\xb1\xb1\x93" // U+F1C53
+#define ICON_MDI_STAR_FOUR_POINTS_CIRCLE_OUTLINE "\xf3\xb1\xb1\x94" // U+F1C54
+#define ICON_MDI_STAR_FOUR_POINTS_OUTLINE "\xf3\xb0\xab\xa3" // U+F0AE3
+#define ICON_MDI_STAR_FOUR_POINTS_SMALL "\xf3\xb1\xb1\x95" // U+F1C55
+#define ICON_MDI_STAR_HALF "\xf3\xb0\x89\x86" // U+F0246
+#define ICON_MDI_STAR_HALF_FULL "\xf3\xb0\x93\x90" // U+F04D0
+#define ICON_MDI_STAR_MINUS "\xf3\xb1\x95\xa4" // U+F1564
+#define ICON_MDI_STAR_MINUS_OUTLINE "\xf3\xb1\x95\xa8" // U+F1568
+#define ICON_MDI_STAR_OFF "\xf3\xb0\x93\x91" // U+F04D1
+#define ICON_MDI_STAR_OFF_OUTLINE "\xf3\xb1\x95\x9b" // U+F155B
+#define ICON_MDI_STAR_OUTLINE "\xf3\xb0\x93\x92" // U+F04D2
+#define ICON_MDI_STAR_PLUS "\xf3\xb1\x95\xa3" // U+F1563
+#define ICON_MDI_STAR_PLUS_OUTLINE "\xf3\xb1\x95\xa7" // U+F1567
+#define ICON_MDI_STAR_REMOVE "\xf3\xb1\x95\xa5" // U+F1565
+#define ICON_MDI_STAR_REMOVE_OUTLINE "\xf3\xb1\x95\xa9" // U+F1569
+#define ICON_MDI_STAR_SETTINGS "\xf3\xb1\x99\xaa" // U+F166A
+#define ICON_MDI_STAR_SETTINGS_OUTLINE "\xf3\xb1\x99\xab" // U+F166B
+#define ICON_MDI_STAR_SHOOTING "\xf3\xb1\x9d\x81" // U+F1741
+#define ICON_MDI_STAR_SHOOTING_OUTLINE "\xf3\xb1\x9d\x82" // U+F1742
+#define ICON_MDI_STAR_THREE_POINTS "\xf3\xb0\xab\xa4" // U+F0AE4
+#define ICON_MDI_STAR_THREE_POINTS_OUTLINE "\xf3\xb0\xab\xa5" // U+F0AE5
+#define ICON_MDI_STATE_MACHINE "\xf3\xb1\x87\xaf" // U+F11EF
+#define ICON_MDI_STEAM "\xf3\xb0\x93\x93" // U+F04D3
+#define ICON_MDI_STEERING "\xf3\xb0\x93\x94" // U+F04D4
+#define ICON_MDI_STEERING_OFF "\xf3\xb0\xa4\x8e" // U+F090E
+#define ICON_MDI_STEP_BACKWARD "\xf3\xb0\x93\x95" // U+F04D5
+#define ICON_MDI_STEP_BACKWARD_2 "\xf3\xb0\x93\x96" // U+F04D6
+#define ICON_MDI_STEP_FORWARD "\xf3\xb0\x93\x97" // U+F04D7
+#define ICON_MDI_STEP_FORWARD_2 "\xf3\xb0\x93\x98" // U+F04D8
+#define ICON_MDI_STETHOSCOPE "\xf3\xb0\x93\x99" // U+F04D9
+#define ICON_MDI_STICKER "\xf3\xb1\x8d\xa4" // U+F1364
+#define ICON_MDI_STICKER_ALERT "\xf3\xb1\x8d\xa5" // U+F1365
+#define ICON_MDI_STICKER_ALERT_OUTLINE "\xf3\xb1\x8d\xa6" // U+F1366
+#define ICON_MDI_STICKER_CHECK "\xf3\xb1\x8d\xa7" // U+F1367
+#define ICON_MDI_STICKER_CHECK_OUTLINE "\xf3\xb1\x8d\xa8" // U+F1368
+#define ICON_MDI_STICKER_CIRCLE_OUTLINE "\xf3\xb0\x97\x90" // U+F05D0
+#define ICON_MDI_STICKER_EMOJI "\xf3\xb0\x9e\x85" // U+F0785
+#define ICON_MDI_STICKER_MINUS "\xf3\xb1\x8d\xa9" // U+F1369
+#define ICON_MDI_STICKER_MINUS_OUTLINE "\xf3\xb1\x8d\xaa" // U+F136A
+#define ICON_MDI_STICKER_OUTLINE "\xf3\xb1\x8d\xab" // U+F136B
+#define ICON_MDI_STICKER_PLUS "\xf3\xb1\x8d\xac" // U+F136C
+#define ICON_MDI_STICKER_PLUS_OUTLINE "\xf3\xb1\x8d\xad" // U+F136D
+#define ICON_MDI_STICKER_REMOVE "\xf3\xb1\x8d\xae" // U+F136E
+#define ICON_MDI_STICKER_REMOVE_OUTLINE "\xf3\xb1\x8d\xaf" // U+F136F
+#define ICON_MDI_STICKER_TEXT "\xf3\xb1\x9e\x8e" // U+F178E
+#define ICON_MDI_STICKER_TEXT_OUTLINE "\xf3\xb1\x9e\x8f" // U+F178F
+#define ICON_MDI_STOCKING "\xf3\xb0\x93\x9a" // U+F04DA
+#define ICON_MDI_STOMACH "\xf3\xb1\x82\x93" // U+F1093
+#define ICON_MDI_STOOL "\xf3\xb1\xa5\x9d" // U+F195D
+#define ICON_MDI_STOOL_OUTLINE "\xf3\xb1\xa5\x9e" // U+F195E
+#define ICON_MDI_STOP "\xf3\xb0\x93\x9b" // U+F04DB
+#define ICON_MDI_STOP_CIRCLE "\xf3\xb0\x99\xa6" // U+F0666
+#define ICON_MDI_STOP_CIRCLE_OUTLINE "\xf3\xb0\x99\xa7" // U+F0667
+#define ICON_MDI_STORAGE_TANK "\xf3\xb1\xa9\xb5" // U+F1A75
+#define ICON_MDI_STORAGE_TANK_OUTLINE "\xf3\xb1\xa9\xb6" // U+F1A76
+#define ICON_MDI_STORE "\xf3\xb0\x93\x9c" // U+F04DC
+#define ICON_MDI_STORE_24_HOUR "\xf3\xb0\x93\x9d" // U+F04DD
+#define ICON_MDI_STORE_ALERT "\xf3\xb1\xa3\x81" // U+F18C1
+#define ICON_MDI_STORE_ALERT_OUTLINE "\xf3\xb1\xa3\x82" // U+F18C2
+#define ICON_MDI_STORE_CHECK "\xf3\xb1\xa3\x83" // U+F18C3
+#define ICON_MDI_STORE_CHECK_OUTLINE "\xf3\xb1\xa3\x84" // U+F18C4
+#define ICON_MDI_STORE_CLOCK "\xf3\xb1\xa3\x85" // U+F18C5
+#define ICON_MDI_STORE_CLOCK_OUTLINE "\xf3\xb1\xa3\x86" // U+F18C6
+#define ICON_MDI_STORE_COG "\xf3\xb1\xa3\x87" // U+F18C7
+#define ICON_MDI_STORE_COG_OUTLINE "\xf3\xb1\xa3\x88" // U+F18C8
+#define ICON_MDI_STORE_EDIT "\xf3\xb1\xa3\x89" // U+F18C9
+#define ICON_MDI_STORE_EDIT_OUTLINE "\xf3\xb1\xa3\x8a" // U+F18CA
+#define ICON_MDI_STORE_MARKER "\xf3\xb1\xa3\x8b" // U+F18CB
+#define ICON_MDI_STORE_MARKER_OUTLINE "\xf3\xb1\xa3\x8c" // U+F18CC
+#define ICON_MDI_STORE_MINUS "\xf3\xb1\x99\x9e" // U+F165E
+#define ICON_MDI_STORE_MINUS_OUTLINE "\xf3\xb1\xa3\x8d" // U+F18CD
+#define ICON_MDI_STORE_OFF "\xf3\xb1\xa3\x8e" // U+F18CE
+#define ICON_MDI_STORE_OFF_OUTLINE "\xf3\xb1\xa3\x8f" // U+F18CF
+#define ICON_MDI_STORE_OUTLINE "\xf3\xb1\x8d\xa1" // U+F1361
+#define ICON_MDI_STORE_PLUS "\xf3\xb1\x99\x9f" // U+F165F
+#define ICON_MDI_STORE_PLUS_OUTLINE "\xf3\xb1\xa3\x90" // U+F18D0
+#define ICON_MDI_STORE_REMOVE "\xf3\xb1\x99\xa0" // U+F1660
+#define ICON_MDI_STORE_REMOVE_OUTLINE "\xf3\xb1\xa3\x91" // U+F18D1
+#define ICON_MDI_STORE_SEARCH "\xf3\xb1\xa3\x92" // U+F18D2
+#define ICON_MDI_STORE_SEARCH_OUTLINE "\xf3\xb1\xa3\x93" // U+F18D3
+#define ICON_MDI_STORE_SETTINGS "\xf3\xb1\xa3\x94" // U+F18D4
+#define ICON_MDI_STORE_SETTINGS_OUTLINE "\xf3\xb1\xa3\x95" // U+F18D5
+#define ICON_MDI_STOREFRONT "\xf3\xb0\x9f\x87" // U+F07C7
+#define ICON_MDI_STOREFRONT_CHECK "\xf3\xb1\xad\xbd" // U+F1B7D
+#define ICON_MDI_STOREFRONT_CHECK_OUTLINE "\xf3\xb1\xad\xbe" // U+F1B7E
+#define ICON_MDI_STOREFRONT_EDIT "\xf3\xb1\xad\xbf" // U+F1B7F
+#define ICON_MDI_STOREFRONT_EDIT_OUTLINE "\xf3\xb1\xae\x80" // U+F1B80
+#define ICON_MDI_STOREFRONT_MINUS "\xf3\xb1\xae\x83" // U+F1B83
+#define ICON_MDI_STOREFRONT_MINUS_OUTLINE "\xf3\xb1\xae\x84" // U+F1B84
+#define ICON_MDI_STOREFRONT_OUTLINE "\xf3\xb1\x83\x81" // U+F10C1
+#define ICON_MDI_STOREFRONT_PLUS "\xf3\xb1\xae\x81" // U+F1B81
+#define ICON_MDI_STOREFRONT_PLUS_OUTLINE "\xf3\xb1\xae\x82" // U+F1B82
+#define ICON_MDI_STOREFRONT_REMOVE "\xf3\xb1\xae\x85" // U+F1B85
+#define ICON_MDI_STOREFRONT_REMOVE_OUTLINE "\xf3\xb1\xae\x86" // U+F1B86
+#define ICON_MDI_STOVE "\xf3\xb0\x93\x9e" // U+F04DE
+#define ICON_MDI_STRATEGY "\xf3\xb1\x87\x96" // U+F11D6
+#define ICON_MDI_STRETCH_TO_PAGE "\xf3\xb0\xbc\xab" // U+F0F2B
+#define ICON_MDI_STRETCH_TO_PAGE_OUTLINE "\xf3\xb0\xbc\xac" // U+F0F2C
+#define ICON_MDI_STRING_LIGHTS "\xf3\xb1\x8a\xba" // U+F12BA
+#define ICON_MDI_STRING_LIGHTS_OFF "\xf3\xb1\x8a\xbb" // U+F12BB
+#define ICON_MDI_SUBDIRECTORY_ARROW_LEFT "\xf3\xb0\x98\x8c" // U+F060C
+#define ICON_MDI_SUBDIRECTORY_ARROW_RIGHT "\xf3\xb0\x98\x8d" // U+F060D
+#define ICON_MDI_SUBMARINE "\xf3\xb1\x95\xac" // U+F156C
+#define ICON_MDI_SUBTITLES "\xf3\xb0\xa8\x96" // U+F0A16
+#define ICON_MDI_SUBTITLES_OUTLINE "\xf3\xb0\xa8\x97" // U+F0A17
+#define ICON_MDI_SUBWAY "\xf3\xb0\x9a\xac" // U+F06AC
+#define ICON_MDI_SUBWAY_ALERT_VARIANT "\xf3\xb0\xb6\x9d" // U+F0D9D
+#define ICON_MDI_SUBWAY_VARIANT "\xf3\xb0\x93\x9f" // U+F04DF
+#define ICON_MDI_SUMMIT "\xf3\xb0\x9e\x86" // U+F0786
+#define ICON_MDI_SUN_ANGLE "\xf3\xb1\xac\xa7" // U+F1B27
+#define ICON_MDI_SUN_ANGLE_OUTLINE "\xf3\xb1\xac\xa8" // U+F1B28
+#define ICON_MDI_SUN_CLOCK "\xf3\xb1\xa9\xb7" // U+F1A77
+#define ICON_MDI_SUN_CLOCK_OUTLINE "\xf3\xb1\xa9\xb8" // U+F1A78
+#define ICON_MDI_SUN_COMPASS "\xf3\xb1\xa6\xa5" // U+F19A5
+#define ICON_MDI_SUN_SNOWFLAKE "\xf3\xb1\x9e\x96" // U+F1796
+#define ICON_MDI_SUN_SNOWFLAKE_VARIANT "\xf3\xb1\xa9\xb9" // U+F1A79
+#define ICON_MDI_SUN_THERMOMETER "\xf3\xb1\xa3\x96" // U+F18D6
+#define ICON_MDI_SUN_THERMOMETER_OUTLINE "\xf3\xb1\xa3\x97" // U+F18D7
+#define ICON_MDI_SUN_WIRELESS "\xf3\xb1\x9f\xbe" // U+F17FE
+#define ICON_MDI_SUN_WIRELESS_OUTLINE "\xf3\xb1\x9f\xbf" // U+F17FF
+#define ICON_MDI_SUNGLASSES "\xf3\xb0\x93\xa0" // U+F04E0
+#define ICON_MDI_SURFING "\xf3\xb1\x9d\x86" // U+F1746
+#define ICON_MDI_SURROUND_SOUND "\xf3\xb0\x97\x85" // U+F05C5
+#define ICON_MDI_SURROUND_SOUND_2_0 "\xf3\xb0\x9f\xb0" // U+F07F0
+#define ICON_MDI_SURROUND_SOUND_2_1 "\xf3\xb1\x9c\xa9" // U+F1729
+#define ICON_MDI_SURROUND_SOUND_3_1 "\xf3\xb0\x9f\xb1" // U+F07F1
+#define ICON_MDI_SURROUND_SOUND_5_1 "\xf3\xb0\x9f\xb2" // U+F07F2
+#define ICON_MDI_SURROUND_SOUND_5_1_2 "\xf3\xb1\x9c\xaa" // U+F172A
+#define ICON_MDI_SURROUND_SOUND_7_1 "\xf3\xb0\x9f\xb3" // U+F07F3
+#define ICON_MDI_SVG "\xf3\xb0\x9c\xa1" // U+F0721
+#define ICON_MDI_SWAP_HORIZONTAL "\xf3\xb0\x93\xa1" // U+F04E1
+#define ICON_MDI_SWAP_HORIZONTAL_BOLD "\xf3\xb0\xaf\x8d" // U+F0BCD
+#define ICON_MDI_SWAP_HORIZONTAL_CIRCLE "\xf3\xb0\xbf\xa1" // U+F0FE1
+#define ICON_MDI_SWAP_HORIZONTAL_CIRCLE_OUTLINE "\xf3\xb0\xbf\xa2" // U+F0FE2
+#define ICON_MDI_SWAP_HORIZONTAL_VARIANT "\xf3\xb0\xa3\x81" // U+F08C1
+#define ICON_MDI_SWAP_VERTICAL "\xf3\xb0\x93\xa2" // U+F04E2
+#define ICON_MDI_SWAP_VERTICAL_BOLD "\xf3\xb0\xaf\x8e" // U+F0BCE
+#define ICON_MDI_SWAP_VERTICAL_CIRCLE "\xf3\xb0\xbf\xa3" // U+F0FE3
+#define ICON_MDI_SWAP_VERTICAL_CIRCLE_OUTLINE "\xf3\xb0\xbf\xa4" // U+F0FE4
+#define ICON_MDI_SWAP_VERTICAL_VARIANT "\xf3\xb0\xa3\x82" // U+F08C2
+#define ICON_MDI_SWIM "\xf3\xb0\x93\xa3" // U+F04E3
+#define ICON_MDI_SWITCH "\xf3\xb0\x93\xa4" // U+F04E4
+#define ICON_MDI_SWORD "\xf3\xb0\x93\xa5" // U+F04E5
+#define ICON_MDI_SWORD_CROSS "\xf3\xb0\x9e\x87" // U+F0787
+#define ICON_MDI_SYLLABARY_HANGUL "\xf3\xb1\x8c\xb3" // U+F1333
+#define ICON_MDI_SYLLABARY_HIRAGANA "\xf3\xb1\x8c\xb4" // U+F1334
+#define ICON_MDI_SYLLABARY_KATAKANA "\xf3\xb1\x8c\xb5" // U+F1335
+#define ICON_MDI_SYLLABARY_KATAKANA_HALFWIDTH "\xf3\xb1\x8c\xb6" // U+F1336
+#define ICON_MDI_SYMBOL "\xf3\xb1\x94\x81" // U+F1501
+#define ICON_MDI_SYMFONY "\xf3\xb0\xab\xa6" // U+F0AE6
+#define ICON_MDI_SYNAGOGUE "\xf3\xb1\xac\x84" // U+F1B04
+#define ICON_MDI_SYNAGOGUE_OUTLINE "\xf3\xb1\xac\x85" // U+F1B05
+#define ICON_MDI_SYNC "\xf3\xb0\x93\xa6" // U+F04E6
+#define ICON_MDI_SYNC_ALERT "\xf3\xb0\x93\xa7" // U+F04E7
+#define ICON_MDI_SYNC_CIRCLE "\xf3\xb1\x8d\xb8" // U+F1378
+#define ICON_MDI_SYNC_OFF "\xf3\xb0\x93\xa8" // U+F04E8
+#define ICON_MDI_TAB "\xf3\xb0\x93\xa9" // U+F04E9
+#define ICON_MDI_TAB_MINUS "\xf3\xb0\xad\x8b" // U+F0B4B
+#define ICON_MDI_TAB_PLUS "\xf3\xb0\x9d\x9c" // U+F075C
+#define ICON_MDI_TAB_REMOVE "\xf3\xb0\xad\x8c" // U+F0B4C
+#define ICON_MDI_TAB_SEARCH "\xf3\xb1\xa6\x9e" // U+F199E
+#define ICON_MDI_TAB_UNSELECTED "\xf3\xb0\x93\xaa" // U+F04EA
+#define ICON_MDI_TABLE "\xf3\xb0\x93\xab" // U+F04EB
+#define ICON_MDI_TABLE_ACCOUNT "\xf3\xb1\x8e\xb9" // U+F13B9
+#define ICON_MDI_TABLE_ALERT "\xf3\xb1\x8e\xba" // U+F13BA
+#define ICON_MDI_TABLE_ARROW_DOWN "\xf3\xb1\x8e\xbb" // U+F13BB
+#define ICON_MDI_TABLE_ARROW_LEFT "\xf3\xb1\x8e\xbc" // U+F13BC
+#define ICON_MDI_TABLE_ARROW_RIGHT "\xf3\xb1\x8e\xbd" // U+F13BD
+#define ICON_MDI_TABLE_ARROW_UP "\xf3\xb1\x8e\xbe" // U+F13BE
+#define ICON_MDI_TABLE_BORDER "\xf3\xb0\xa8\x98" // U+F0A18
+#define ICON_MDI_TABLE_CANCEL "\xf3\xb1\x8e\xbf" // U+F13BF
+#define ICON_MDI_TABLE_CHAIR "\xf3\xb1\x81\xa1" // U+F1061
+#define ICON_MDI_TABLE_CHECK "\xf3\xb1\x8f\x80" // U+F13C0
+#define ICON_MDI_TABLE_CLOCK "\xf3\xb1\x8f\x81" // U+F13C1
+#define ICON_MDI_TABLE_COG "\xf3\xb1\x8f\x82" // U+F13C2
+#define ICON_MDI_TABLE_COLUMN "\xf3\xb0\xa0\xb5" // U+F0835
+#define ICON_MDI_TABLE_COLUMN_PLUS_AFTER "\xf3\xb0\x93\xac" // U+F04EC
+#define ICON_MDI_TABLE_COLUMN_PLUS_BEFORE "\xf3\xb0\x93\xad" // U+F04ED
+#define ICON_MDI_TABLE_COLUMN_REMOVE "\xf3\xb0\x93\xae" // U+F04EE
+#define ICON_MDI_TABLE_COLUMN_WIDTH "\xf3\xb0\x93\xaf" // U+F04EF
+#define ICON_MDI_TABLE_EDIT "\xf3\xb0\x93\xb0" // U+F04F0
+#define ICON_MDI_TABLE_EYE "\xf3\xb1\x82\x94" // U+F1094
+#define ICON_MDI_TABLE_EYE_OFF "\xf3\xb1\x8f\x83" // U+F13C3
+#define ICON_MDI_TABLE_FILTER "\xf3\xb1\xae\x8c" // U+F1B8C
+#define ICON_MDI_TABLE_FURNITURE "\xf3\xb0\x96\xbc" // U+F05BC
+#define ICON_MDI_TABLE_HEADERS_EYE "\xf3\xb1\x88\x9d" // U+F121D
+#define ICON_MDI_TABLE_HEADERS_EYE_OFF "\xf3\xb1\x88\x9e" // U+F121E
+#define ICON_MDI_TABLE_HEART "\xf3\xb1\x8f\x84" // U+F13C4
+#define ICON_MDI_TABLE_KEY "\xf3\xb1\x8f\x85" // U+F13C5
+#define ICON_MDI_TABLE_LARGE "\xf3\xb0\x93\xb1" // U+F04F1
+#define ICON_MDI_TABLE_LARGE_PLUS "\xf3\xb0\xbe\x87" // U+F0F87
+#define ICON_MDI_TABLE_LARGE_REMOVE "\xf3\xb0\xbe\x88" // U+F0F88
+#define ICON_MDI_TABLE_LOCK "\xf3\xb1\x8f\x86" // U+F13C6
+#define ICON_MDI_TABLE_MERGE_CELLS "\xf3\xb0\xa6\xa6" // U+F09A6
+#define ICON_MDI_TABLE_MINUS "\xf3\xb1\x8f\x87" // U+F13C7
+#define ICON_MDI_TABLE_MULTIPLE "\xf3\xb1\x8f\x88" // U+F13C8
+#define ICON_MDI_TABLE_NETWORK "\xf3\xb1\x8f\x89" // U+F13C9
+#define ICON_MDI_TABLE_OF_CONTENTS "\xf3\xb0\xa0\xb6" // U+F0836
+#define ICON_MDI_TABLE_OFF "\xf3\xb1\x8f\x8a" // U+F13CA
+#define ICON_MDI_TABLE_PICNIC "\xf3\xb1\x9d\x83" // U+F1743
+#define ICON_MDI_TABLE_PIVOT "\xf3\xb1\xa0\xbc" // U+F183C
+#define ICON_MDI_TABLE_PLUS "\xf3\xb0\xa9\xb5" // U+F0A75
+#define ICON_MDI_TABLE_QUESTION "\xf3\xb1\xac\xa1" // U+F1B21
+#define ICON_MDI_TABLE_REFRESH "\xf3\xb1\x8e\xa0" // U+F13A0
+#define ICON_MDI_TABLE_REMOVE "\xf3\xb0\xa9\xb6" // U+F0A76
+#define ICON_MDI_TABLE_ROW "\xf3\xb0\xa0\xb7" // U+F0837
+#define ICON_MDI_TABLE_ROW_HEIGHT "\xf3\xb0\x93\xb2" // U+F04F2
+#define ICON_MDI_TABLE_ROW_PLUS_AFTER "\xf3\xb0\x93\xb3" // U+F04F3
+#define ICON_MDI_TABLE_ROW_PLUS_BEFORE "\xf3\xb0\x93\xb4" // U+F04F4
+#define ICON_MDI_TABLE_ROW_REMOVE "\xf3\xb0\x93\xb5" // U+F04F5
+#define ICON_MDI_TABLE_SEARCH "\xf3\xb0\xa4\x8f" // U+F090F
+#define ICON_MDI_TABLE_SETTINGS "\xf3\xb0\xa0\xb8" // U+F0838
+#define ICON_MDI_TABLE_SPLIT_CELL "\xf3\xb1\x90\xaa" // U+F142A
+#define ICON_MDI_TABLE_STAR "\xf3\xb1\x8f\x8b" // U+F13CB
+#define ICON_MDI_TABLE_SYNC "\xf3\xb1\x8e\xa1" // U+F13A1
+#define ICON_MDI_TABLE_TENNIS "\xf3\xb0\xb9\xa8" // U+F0E68
+#define ICON_MDI_TABLET "\xf3\xb0\x93\xb6" // U+F04F6
+#define ICON_MDI_TABLET_CELLPHONE "\xf3\xb0\xa6\xa7" // U+F09A7
+#define ICON_MDI_TABLET_DASHBOARD "\xf3\xb0\xbb\x8e" // U+F0ECE
+#define ICON_MDI_TACO "\xf3\xb0\x9d\xa2" // U+F0762
+#define ICON_MDI_TAG "\xf3\xb0\x93\xb9" // U+F04F9
+#define ICON_MDI_TAG_ARROW_DOWN "\xf3\xb1\x9c\xab" // U+F172B
+#define ICON_MDI_TAG_ARROW_DOWN_OUTLINE "\xf3\xb1\x9c\xac" // U+F172C
+#define ICON_MDI_TAG_ARROW_LEFT "\xf3\xb1\x9c\xad" // U+F172D
+#define ICON_MDI_TAG_ARROW_LEFT_OUTLINE "\xf3\xb1\x9c\xae" // U+F172E
+#define ICON_MDI_TAG_ARROW_RIGHT "\xf3\xb1\x9c\xaf" // U+F172F
+#define ICON_MDI_TAG_ARROW_RIGHT_OUTLINE "\xf3\xb1\x9c\xb0" // U+F1730
+#define ICON_MDI_TAG_ARROW_UP "\xf3\xb1\x9c\xb1" // U+F1731
+#define ICON_MDI_TAG_ARROW_UP_OUTLINE "\xf3\xb1\x9c\xb2" // U+F1732
+#define ICON_MDI_TAG_CHECK "\xf3\xb1\xa9\xba" // U+F1A7A
+#define ICON_MDI_TAG_CHECK_OUTLINE "\xf3\xb1\xa9\xbb" // U+F1A7B
+#define ICON_MDI_TAG_EDIT "\xf3\xb1\xb2\x9c" // U+F1C9C
+#define ICON_MDI_TAG_EDIT_OUTLINE "\xf3\xb1\xb2\x9d" // U+F1C9D
+#define ICON_MDI_TAG_FACES "\xf3\xb0\x93\xba" // U+F04FA
+#define ICON_MDI_TAG_HEART "\xf3\xb0\x9a\x8b" // U+F068B
+#define ICON_MDI_TAG_HEART_OUTLINE "\xf3\xb0\xaf\x8f" // U+F0BCF
+#define ICON_MDI_TAG_HIDDEN "\xf3\xb1\xb1\xb6" // U+F1C76
+#define ICON_MDI_TAG_MINUS "\xf3\xb0\xa4\x90" // U+F0910
+#define ICON_MDI_TAG_MINUS_OUTLINE "\xf3\xb1\x88\x9f" // U+F121F
+#define ICON_MDI_TAG_MULTIPLE "\xf3\xb0\x93\xbb" // U+F04FB
+#define ICON_MDI_TAG_MULTIPLE_OUTLINE "\xf3\xb1\x8b\xb7" // U+F12F7
+#define ICON_MDI_TAG_OFF "\xf3\xb1\x88\xa0" // U+F1220
+#define ICON_MDI_TAG_OFF_OUTLINE "\xf3\xb1\x88\xa1" // U+F1221
+#define ICON_MDI_TAG_OUTLINE "\xf3\xb0\x93\xbc" // U+F04FC
+#define ICON_MDI_TAG_PLUS "\xf3\xb0\x9c\xa2" // U+F0722
+#define ICON_MDI_TAG_PLUS_OUTLINE "\xf3\xb1\x88\xa2" // U+F1222
+#define ICON_MDI_TAG_REMOVE "\xf3\xb0\x9c\xa3" // U+F0723
+#define ICON_MDI_TAG_REMOVE_OUTLINE "\xf3\xb1\x88\xa3" // U+F1223
+#define ICON_MDI_TAG_SEARCH "\xf3\xb1\xa4\x87" // U+F1907
+#define ICON_MDI_TAG_SEARCH_OUTLINE "\xf3\xb1\xa4\x88" // U+F1908
+#define ICON_MDI_TAG_TEXT "\xf3\xb1\x88\xa4" // U+F1224
+#define ICON_MDI_TAG_TEXT_OUTLINE "\xf3\xb0\x93\xbd" // U+F04FD
+#define ICON_MDI_TAILWIND "\xf3\xb1\x8f\xbf" // U+F13FF
+#define ICON_MDI_TALLY_MARK_1 "\xf3\xb1\xaa\xbc" // U+F1ABC
+#define ICON_MDI_TALLY_MARK_2 "\xf3\xb1\xaa\xbd" // U+F1ABD
+#define ICON_MDI_TALLY_MARK_3 "\xf3\xb1\xaa\xbe" // U+F1ABE
+#define ICON_MDI_TALLY_MARK_4 "\xf3\xb1\xaa\xbf" // U+F1ABF
+#define ICON_MDI_TALLY_MARK_5 "\xf3\xb1\xab\x80" // U+F1AC0
+#define ICON_MDI_TANGRAM "\xf3\xb0\x93\xb8" // U+F04F8
+#define ICON_MDI_TANK "\xf3\xb0\xb4\xba" // U+F0D3A
+#define ICON_MDI_TANKER_TRUCK "\xf3\xb0\xbf\xa5" // U+F0FE5
+#define ICON_MDI_TAPE_DRIVE "\xf3\xb1\x9b\x9f" // U+F16DF
+#define ICON_MDI_TAPE_MEASURE "\xf3\xb0\xad\x8d" // U+F0B4D
+#define ICON_MDI_TARGET "\xf3\xb0\x93\xbe" // U+F04FE
+#define ICON_MDI_TARGET_ACCOUNT "\xf3\xb0\xaf\x90" // U+F0BD0
+#define ICON_MDI_TARGET_VARIANT "\xf3\xb0\xa9\xb7" // U+F0A77
+#define ICON_MDI_TAXI "\xf3\xb0\x93\xbf" // U+F04FF
+#define ICON_MDI_TEA "\xf3\xb0\xb6\x9e" // U+F0D9E
+#define ICON_MDI_TEA_OUTLINE "\xf3\xb0\xb6\x9f" // U+F0D9F
+#define ICON_MDI_TEAMVIEWER "\xf3\xb0\x94\x80" // U+F0500
+#define ICON_MDI_TEDDY_BEAR "\xf3\xb1\xa3\xbb" // U+F18FB
+#define ICON_MDI_TELESCOPE "\xf3\xb0\xad\x8e" // U+F0B4E
+#define ICON_MDI_TELEVISION "\xf3\xb0\x94\x82" // U+F0502
+#define ICON_MDI_TELEVISION_AMBIENT_LIGHT "\xf3\xb1\x8d\x96" // U+F1356
+#define ICON_MDI_TELEVISION_BOX "\xf3\xb0\xa0\xb9" // U+F0839
+#define ICON_MDI_TELEVISION_CLASSIC "\xf3\xb0\x9f\xb4" // U+F07F4
+#define ICON_MDI_TELEVISION_CLASSIC_OFF "\xf3\xb0\xa0\xba" // U+F083A
+#define ICON_MDI_TELEVISION_GUIDE "\xf3\xb0\x94\x83" // U+F0503
+#define ICON_MDI_TELEVISION_OFF "\xf3\xb0\xa0\xbb" // U+F083B
+#define ICON_MDI_TELEVISION_PAUSE "\xf3\xb0\xbe\x89" // U+F0F89
+#define ICON_MDI_TELEVISION_PLAY "\xf3\xb0\xbb\x8f" // U+F0ECF
+#define ICON_MDI_TELEVISION_SHIMMER "\xf3\xb1\x84\x90" // U+F1110
+#define ICON_MDI_TELEVISION_SPEAKER "\xf3\xb1\xac\x9b" // U+F1B1B
+#define ICON_MDI_TELEVISION_SPEAKER_OFF "\xf3\xb1\xac\x9c" // U+F1B1C
+#define ICON_MDI_TELEVISION_STOP "\xf3\xb0\xbe\x8a" // U+F0F8A
+#define ICON_MDI_TEMPERATURE_CELSIUS "\xf3\xb0\x94\x84" // U+F0504
+#define ICON_MDI_TEMPERATURE_FAHRENHEIT "\xf3\xb0\x94\x85" // U+F0505
+#define ICON_MDI_TEMPERATURE_KELVIN "\xf3\xb0\x94\x86" // U+F0506
+#define ICON_MDI_TEMPLE_BUDDHIST "\xf3\xb1\xac\x86" // U+F1B06
+#define ICON_MDI_TEMPLE_BUDDHIST_OUTLINE "\xf3\xb1\xac\x87" // U+F1B07
+#define ICON_MDI_TEMPLE_HINDU "\xf3\xb1\xac\x88" // U+F1B08
+#define ICON_MDI_TEMPLE_HINDU_OUTLINE "\xf3\xb1\xac\x89" // U+F1B09
+#define ICON_MDI_TENNIS "\xf3\xb0\xb6\xa0" // U+F0DA0
+#define ICON_MDI_TENNIS_BALL "\xf3\xb0\x94\x87" // U+F0507
+#define ICON_MDI_TENNIS_BALL_OUTLINE "\xf3\xb1\xb1\x9f" // U+F1C5F
+#define ICON_MDI_TENT "\xf3\xb0\x94\x88" // U+F0508
+#define ICON_MDI_TERRAFORM "\xf3\xb1\x81\xa2" // U+F1062
+#define ICON_MDI_TERRAIN "\xf3\xb0\x94\x89" // U+F0509
+#define ICON_MDI_TEST_TUBE "\xf3\xb0\x99\xa8" // U+F0668
+#define ICON_MDI_TEST_TUBE_EMPTY "\xf3\xb0\xa4\x91" // U+F0911
+#define ICON_MDI_TEST_TUBE_OFF "\xf3\xb0\xa4\x92" // U+F0912
+#define ICON_MDI_TEXT "\xf3\xb0\xa6\xa8" // U+F09A8
+#define ICON_MDI_TEXT_ACCOUNT "\xf3\xb1\x95\xb0" // U+F1570
+#define ICON_MDI_TEXT_BOX "\xf3\xb0\x88\x9a" // U+F021A
+#define ICON_MDI_TEXT_BOX_CHECK "\xf3\xb0\xba\xa6" // U+F0EA6
+#define ICON_MDI_TEXT_BOX_CHECK_OUTLINE "\xf3\xb0\xba\xa7" // U+F0EA7
+#define ICON_MDI_TEXT_BOX_EDIT "\xf3\xb1\xa9\xbc" // U+F1A7C
+#define ICON_MDI_TEXT_BOX_EDIT_OUTLINE "\xf3\xb1\xa9\xbd" // U+F1A7D
+#define ICON_MDI_TEXT_BOX_MINUS "\xf3\xb0\xba\xa8" // U+F0EA8
+#define ICON_MDI_TEXT_BOX_MINUS_OUTLINE "\xf3\xb0\xba\xa9" // U+F0EA9
+#define ICON_MDI_TEXT_BOX_MULTIPLE "\xf3\xb0\xaa\xb7" // U+F0AB7
+#define ICON_MDI_TEXT_BOX_MULTIPLE_OUTLINE "\xf3\xb0\xaa\xb8" // U+F0AB8
+#define ICON_MDI_TEXT_BOX_OUTLINE "\xf3\xb0\xa7\xad" // U+F09ED
+#define ICON_MDI_TEXT_BOX_PLUS "\xf3\xb0\xba\xaa" // U+F0EAA
+#define ICON_MDI_TEXT_BOX_PLUS_OUTLINE "\xf3\xb0\xba\xab" // U+F0EAB
+#define ICON_MDI_TEXT_BOX_REMOVE "\xf3\xb0\xba\xac" // U+F0EAC
+#define ICON_MDI_TEXT_BOX_REMOVE_OUTLINE "\xf3\xb0\xba\xad" // U+F0EAD
+#define ICON_MDI_TEXT_BOX_SEARCH "\xf3\xb0\xba\xae" // U+F0EAE
+#define ICON_MDI_TEXT_BOX_SEARCH_OUTLINE "\xf3\xb0\xba\xaf" // U+F0EAF
+#define ICON_MDI_TEXT_LONG "\xf3\xb0\xa6\xaa" // U+F09AA
+#define ICON_MDI_TEXT_RECOGNITION "\xf3\xb1\x84\xbd" // U+F113D
+#define ICON_MDI_TEXT_SEARCH "\xf3\xb1\x8e\xb8" // U+F13B8
+#define ICON_MDI_TEXT_SEARCH_VARIANT "\xf3\xb1\xa9\xbe" // U+F1A7E
+#define ICON_MDI_TEXT_SHADOW "\xf3\xb0\x99\xa9" // U+F0669
+#define ICON_MDI_TEXT_SHORT "\xf3\xb0\xa6\xa9" // U+F09A9
+#define ICON_MDI_TEXTURE "\xf3\xb0\x94\x8c" // U+F050C
+#define ICON_MDI_TEXTURE_BOX "\xf3\xb0\xbf\xa6" // U+F0FE6
+#define ICON_MDI_THEATER "\xf3\xb0\x94\x8d" // U+F050D
+#define ICON_MDI_THEME_LIGHT_DARK "\xf3\xb0\x94\x8e" // U+F050E
+#define ICON_MDI_THERMOMETER "\xf3\xb0\x94\x8f" // U+F050F
+#define ICON_MDI_THERMOMETER_ALERT "\xf3\xb0\xb8\x81" // U+F0E01
+#define ICON_MDI_THERMOMETER_AUTO "\xf3\xb1\xac\x8f" // U+F1B0F
+#define ICON_MDI_THERMOMETER_BLUETOOTH "\xf3\xb1\xa2\x95" // U+F1895
+#define ICON_MDI_THERMOMETER_CHECK "\xf3\xb1\xa9\xbf" // U+F1A7F
+#define ICON_MDI_THERMOMETER_CHEVRON_DOWN "\xf3\xb0\xb8\x82" // U+F0E02
+#define ICON_MDI_THERMOMETER_CHEVRON_UP "\xf3\xb0\xb8\x83" // U+F0E03
+#define ICON_MDI_THERMOMETER_HIGH "\xf3\xb1\x83\x82" // U+F10C2
+#define ICON_MDI_THERMOMETER_LINES "\xf3\xb0\x94\x90" // U+F0510
+#define ICON_MDI_THERMOMETER_LOW "\xf3\xb1\x83\x83" // U+F10C3
+#define ICON_MDI_THERMOMETER_MINUS "\xf3\xb0\xb8\x84" // U+F0E04
+#define ICON_MDI_THERMOMETER_OFF "\xf3\xb1\x94\xb1" // U+F1531
+#define ICON_MDI_THERMOMETER_PLUS "\xf3\xb0\xb8\x85" // U+F0E05
+#define ICON_MDI_THERMOMETER_PROBE "\xf3\xb1\xac\xab" // U+F1B2B
+#define ICON_MDI_THERMOMETER_PROBE_OFF "\xf3\xb1\xac\xac" // U+F1B2C
+#define ICON_MDI_THERMOMETER_WATER "\xf3\xb1\xaa\x80" // U+F1A80
+#define ICON_MDI_THERMOSTAT "\xf3\xb0\x8e\x93" // U+F0393
+#define ICON_MDI_THERMOSTAT_AUTO "\xf3\xb1\xac\x97" // U+F1B17
+#define ICON_MDI_THERMOSTAT_BOX "\xf3\xb0\xa2\x91" // U+F0891
+#define ICON_MDI_THERMOSTAT_BOX_AUTO "\xf3\xb1\xac\x98" // U+F1B18
+#define ICON_MDI_THERMOSTAT_COG "\xf3\xb1\xb2\x80" // U+F1C80
+#define ICON_MDI_THOUGHT_BUBBLE "\xf3\xb0\x9f\xb6" // U+F07F6
+#define ICON_MDI_THOUGHT_BUBBLE_OUTLINE "\xf3\xb0\x9f\xb7" // U+F07F7
+#define ICON_MDI_THUMB_DOWN "\xf3\xb0\x94\x91" // U+F0511
+#define ICON_MDI_THUMB_DOWN_OUTLINE "\xf3\xb0\x94\x92" // U+F0512
+#define ICON_MDI_THUMB_UP "\xf3\xb0\x94\x93" // U+F0513
+#define ICON_MDI_THUMB_UP_OUTLINE "\xf3\xb0\x94\x94" // U+F0514
+#define ICON_MDI_THUMBS_UP_DOWN "\xf3\xb0\x94\x95" // U+F0515
+#define ICON_MDI_THUMBS_UP_DOWN_OUTLINE "\xf3\xb1\xa4\x94" // U+F1914
+#define ICON_MDI_TICKET "\xf3\xb0\x94\x96" // U+F0516
+#define ICON_MDI_TICKET_ACCOUNT "\xf3\xb0\x94\x97" // U+F0517
+#define ICON_MDI_TICKET_CONFIRMATION "\xf3\xb0\x94\x98" // U+F0518
+#define ICON_MDI_TICKET_CONFIRMATION_OUTLINE "\xf3\xb1\x8e\xaa" // U+F13AA
+#define ICON_MDI_TICKET_OUTLINE "\xf3\xb0\xa4\x93" // U+F0913
+#define ICON_MDI_TICKET_PERCENT "\xf3\xb0\x9c\xa4" // U+F0724
+#define ICON_MDI_TICKET_PERCENT_OUTLINE "\xf3\xb1\x90\xab" // U+F142B
+#define ICON_MDI_TIE "\xf3\xb0\x94\x99" // U+F0519
+#define ICON_MDI_TILDE "\xf3\xb0\x9c\xa5" // U+F0725
+#define ICON_MDI_TILDE_OFF "\xf3\xb1\xa3\xb3" // U+F18F3
+#define ICON_MDI_TIMELAPSE "\xf3\xb0\x94\x9a" // U+F051A
+#define ICON_MDI_TIMELINE "\xf3\xb0\xaf\x91" // U+F0BD1
+#define ICON_MDI_TIMELINE_ALERT "\xf3\xb0\xbe\x95" // U+F0F95
+#define ICON_MDI_TIMELINE_ALERT_OUTLINE "\xf3\xb0\xbe\x98" // U+F0F98
+#define ICON_MDI_TIMELINE_CHECK "\xf3\xb1\x94\xb2" // U+F1532
+#define ICON_MDI_TIMELINE_CHECK_OUTLINE "\xf3\xb1\x94\xb3" // U+F1533
+#define ICON_MDI_TIMELINE_CLOCK "\xf3\xb1\x87\xbb" // U+F11FB
+#define ICON_MDI_TIMELINE_CLOCK_OUTLINE "\xf3\xb1\x87\xbc" // U+F11FC
+#define ICON_MDI_TIMELINE_MINUS "\xf3\xb1\x94\xb4" // U+F1534
+#define ICON_MDI_TIMELINE_MINUS_OUTLINE "\xf3\xb1\x94\xb5" // U+F1535
+#define ICON_MDI_TIMELINE_OUTLINE "\xf3\xb0\xaf\x92" // U+F0BD2
+#define ICON_MDI_TIMELINE_PLUS "\xf3\xb0\xbe\x96" // U+F0F96
+#define ICON_MDI_TIMELINE_PLUS_OUTLINE "\xf3\xb0\xbe\x97" // U+F0F97
+#define ICON_MDI_TIMELINE_QUESTION "\xf3\xb0\xbe\x99" // U+F0F99
+#define ICON_MDI_TIMELINE_QUESTION_OUTLINE "\xf3\xb0\xbe\x9a" // U+F0F9A
+#define ICON_MDI_TIMELINE_REMOVE "\xf3\xb1\x94\xb6" // U+F1536
+#define ICON_MDI_TIMELINE_REMOVE_OUTLINE "\xf3\xb1\x94\xb7" // U+F1537
+#define ICON_MDI_TIMELINE_TEXT "\xf3\xb0\xaf\x93" // U+F0BD3
+#define ICON_MDI_TIMELINE_TEXT_OUTLINE "\xf3\xb0\xaf\x94" // U+F0BD4
+#define ICON_MDI_TIMER "\xf3\xb1\x8e\xab" // U+F13AB
+#define ICON_MDI_TIMER_10 "\xf3\xb0\x94\x9c" // U+F051C
+#define ICON_MDI_TIMER_3 "\xf3\xb0\x94\x9d" // U+F051D
+#define ICON_MDI_TIMER_ALERT "\xf3\xb1\xab\x8c" // U+F1ACC
+#define ICON_MDI_TIMER_ALERT_OUTLINE "\xf3\xb1\xab\x8d" // U+F1ACD
+#define ICON_MDI_TIMER_CANCEL "\xf3\xb1\xab\x8e" // U+F1ACE
+#define ICON_MDI_TIMER_CANCEL_OUTLINE "\xf3\xb1\xab\x8f" // U+F1ACF
+#define ICON_MDI_TIMER_CHECK "\xf3\xb1\xab\x90" // U+F1AD0
+#define ICON_MDI_TIMER_CHECK_OUTLINE "\xf3\xb1\xab\x91" // U+F1AD1
+#define ICON_MDI_TIMER_COG "\xf3\xb1\xa4\xa5" // U+F1925
+#define ICON_MDI_TIMER_COG_OUTLINE "\xf3\xb1\xa4\xa6" // U+F1926
+#define ICON_MDI_TIMER_EDIT "\xf3\xb1\xab\x92" // U+F1AD2
+#define ICON_MDI_TIMER_EDIT_OUTLINE "\xf3\xb1\xab\x93" // U+F1AD3
+#define ICON_MDI_TIMER_LOCK "\xf3\xb1\xab\x94" // U+F1AD4
+#define ICON_MDI_TIMER_LOCK_OPEN "\xf3\xb1\xab\x95" // U+F1AD5
+#define ICON_MDI_TIMER_LOCK_OPEN_OUTLINE "\xf3\xb1\xab\x96" // U+F1AD6
+#define ICON_MDI_TIMER_LOCK_OUTLINE "\xf3\xb1\xab\x97" // U+F1AD7
+#define ICON_MDI_TIMER_MARKER "\xf3\xb1\xab\x98" // U+F1AD8
+#define ICON_MDI_TIMER_MARKER_OUTLINE "\xf3\xb1\xab\x99" // U+F1AD9
+#define ICON_MDI_TIMER_MINUS "\xf3\xb1\xab\x9a" // U+F1ADA
+#define ICON_MDI_TIMER_MINUS_OUTLINE "\xf3\xb1\xab\x9b" // U+F1ADB
+#define ICON_MDI_TIMER_MUSIC "\xf3\xb1\xab\x9c" // U+F1ADC
+#define ICON_MDI_TIMER_MUSIC_OUTLINE "\xf3\xb1\xab\x9d" // U+F1ADD
+#define ICON_MDI_TIMER_OFF "\xf3\xb1\x8e\xac" // U+F13AC
+#define ICON_MDI_TIMER_OFF_OUTLINE "\xf3\xb0\x94\x9e" // U+F051E
+#define ICON_MDI_TIMER_OUTLINE "\xf3\xb0\x94\x9b" // U+F051B
+#define ICON_MDI_TIMER_PAUSE "\xf3\xb1\xab\x9e" // U+F1ADE
+#define ICON_MDI_TIMER_PAUSE_OUTLINE "\xf3\xb1\xab\x9f" // U+F1ADF
+#define ICON_MDI_TIMER_PLAY "\xf3\xb1\xab\xa0" // U+F1AE0
+#define ICON_MDI_TIMER_PLAY_OUTLINE "\xf3\xb1\xab\xa1" // U+F1AE1
+#define ICON_MDI_TIMER_PLUS "\xf3\xb1\xab\xa2" // U+F1AE2
+#define ICON_MDI_TIMER_PLUS_OUTLINE "\xf3\xb1\xab\xa3" // U+F1AE3
+#define ICON_MDI_TIMER_REFRESH "\xf3\xb1\xab\xa4" // U+F1AE4
+#define ICON_MDI_TIMER_REFRESH_OUTLINE "\xf3\xb1\xab\xa5" // U+F1AE5
+#define ICON_MDI_TIMER_REMOVE "\xf3\xb1\xab\xa6" // U+F1AE6
+#define ICON_MDI_TIMER_REMOVE_OUTLINE "\xf3\xb1\xab\xa7" // U+F1AE7
+#define ICON_MDI_TIMER_SAND "\xf3\xb0\x94\x9f" // U+F051F
+#define ICON_MDI_TIMER_SAND_COMPLETE "\xf3\xb1\xa6\x9f" // U+F199F
+#define ICON_MDI_TIMER_SAND_EMPTY "\xf3\xb0\x9a\xad" // U+F06AD
+#define ICON_MDI_TIMER_SAND_FULL "\xf3\xb0\x9e\x8c" // U+F078C
+#define ICON_MDI_TIMER_SAND_PAUSED "\xf3\xb1\xa6\xa0" // U+F19A0
+#define ICON_MDI_TIMER_SETTINGS "\xf3\xb1\xa4\xa3" // U+F1923
+#define ICON_MDI_TIMER_SETTINGS_OUTLINE "\xf3\xb1\xa4\xa4" // U+F1924
+#define ICON_MDI_TIMER_STAR "\xf3\xb1\xab\xa8" // U+F1AE8
+#define ICON_MDI_TIMER_STAR_OUTLINE "\xf3\xb1\xab\xa9" // U+F1AE9
+#define ICON_MDI_TIMER_STOP "\xf3\xb1\xab\xaa" // U+F1AEA
+#define ICON_MDI_TIMER_STOP_OUTLINE "\xf3\xb1\xab\xab" // U+F1AEB
+#define ICON_MDI_TIMER_SYNC "\xf3\xb1\xab\xac" // U+F1AEC
+#define ICON_MDI_TIMER_SYNC_OUTLINE "\xf3\xb1\xab\xad" // U+F1AED
+#define ICON_MDI_TIMETABLE "\xf3\xb0\x94\xa0" // U+F0520
+#define ICON_MDI_TIRE "\xf3\xb1\xa2\x96" // U+F1896
+#define ICON_MDI_TOASTER "\xf3\xb1\x81\xa3" // U+F1063
+#define ICON_MDI_TOASTER_OFF "\xf3\xb1\x86\xb7" // U+F11B7
+#define ICON_MDI_TOASTER_OVEN "\xf3\xb0\xb3\x93" // U+F0CD3
+#define ICON_MDI_TOGGLE_SWITCH "\xf3\xb0\x94\xa1" // U+F0521
+#define ICON_MDI_TOGGLE_SWITCH_OFF "\xf3\xb0\x94\xa2" // U+F0522
+#define ICON_MDI_TOGGLE_SWITCH_OFF_OUTLINE "\xf3\xb0\xa8\x99" // U+F0A19
+#define ICON_MDI_TOGGLE_SWITCH_OUTLINE "\xf3\xb0\xa8\x9a" // U+F0A1A
+#define ICON_MDI_TOGGLE_SWITCH_VARIANT "\xf3\xb1\xa8\xa5" // U+F1A25
+#define ICON_MDI_TOGGLE_SWITCH_VARIANT_OFF "\xf3\xb1\xa8\xa6" // U+F1A26
+#define ICON_MDI_TOILET "\xf3\xb0\xa6\xab" // U+F09AB
+#define ICON_MDI_TOOLBOX "\xf3\xb0\xa6\xac" // U+F09AC
+#define ICON_MDI_TOOLBOX_OUTLINE "\xf3\xb0\xa6\xad" // U+F09AD
+#define ICON_MDI_TOOLS "\xf3\xb1\x81\xa4" // U+F1064
+#define ICON_MDI_TOOLTIP "\xf3\xb0\x94\xa3" // U+F0523
+#define ICON_MDI_TOOLTIP_ACCOUNT "\xf3\xb0\x80\x8c" // U+F000C
+#define ICON_MDI_TOOLTIP_CELLPHONE "\xf3\xb1\xa0\xbb" // U+F183B
+#define ICON_MDI_TOOLTIP_CHECK "\xf3\xb1\x95\x9c" // U+F155C
+#define ICON_MDI_TOOLTIP_CHECK_OUTLINE "\xf3\xb1\x95\x9d" // U+F155D
+#define ICON_MDI_TOOLTIP_EDIT "\xf3\xb0\x94\xa4" // U+F0524
+#define ICON_MDI_TOOLTIP_EDIT_OUTLINE "\xf3\xb1\x8b\x85" // U+F12C5
+#define ICON_MDI_TOOLTIP_IMAGE "\xf3\xb0\x94\xa5" // U+F0525
+#define ICON_MDI_TOOLTIP_IMAGE_OUTLINE "\xf3\xb0\xaf\x95" // U+F0BD5
+#define ICON_MDI_TOOLTIP_MINUS "\xf3\xb1\x95\x9e" // U+F155E
+#define ICON_MDI_TOOLTIP_MINUS_OUTLINE "\xf3\xb1\x95\x9f" // U+F155F
+#define ICON_MDI_TOOLTIP_OUTLINE "\xf3\xb0\x94\xa6" // U+F0526
+#define ICON_MDI_TOOLTIP_PLUS "\xf3\xb0\xaf\x96" // U+F0BD6
+#define ICON_MDI_TOOLTIP_PLUS_OUTLINE "\xf3\xb0\x94\xa7" // U+F0527
+#define ICON_MDI_TOOLTIP_QUESTION "\xf3\xb1\xae\xba" // U+F1BBA
+#define ICON_MDI_TOOLTIP_QUESTION_OUTLINE "\xf3\xb1\xae\xbb" // U+F1BBB
+#define ICON_MDI_TOOLTIP_REMOVE "\xf3\xb1\x95\xa0" // U+F1560
+#define ICON_MDI_TOOLTIP_REMOVE_OUTLINE "\xf3\xb1\x95\xa1" // U+F1561
+#define ICON_MDI_TOOLTIP_TEXT "\xf3\xb0\x94\xa8" // U+F0528
+#define ICON_MDI_TOOLTIP_TEXT_OUTLINE "\xf3\xb0\xaf\x97" // U+F0BD7
+#define ICON_MDI_TOOTH "\xf3\xb0\xa3\x83" // U+F08C3
+#define ICON_MDI_TOOTH_OUTLINE "\xf3\xb0\x94\xa9" // U+F0529
+#define ICON_MDI_TOOTHBRUSH "\xf3\xb1\x84\xa9" // U+F1129
+#define ICON_MDI_TOOTHBRUSH_ELECTRIC "\xf3\xb1\x84\xac" // U+F112C
+#define ICON_MDI_TOOTHBRUSH_PASTE "\xf3\xb1\x84\xaa" // U+F112A
+#define ICON_MDI_TORCH "\xf3\xb1\x98\x86" // U+F1606
+#define ICON_MDI_TORTOISE "\xf3\xb0\xb4\xbb" // U+F0D3B
+#define ICON_MDI_TOSLINK "\xf3\xb1\x8a\xb8" // U+F12B8
+#define ICON_MDI_TOUCH_TEXT_OUTLINE "\xf3\xb1\xb1\xa0" // U+F1C60
+#define ICON_MDI_TOURNAMENT "\xf3\xb0\xa6\xae" // U+F09AE
+#define ICON_MDI_TOW_TRUCK "\xf3\xb0\xa0\xbc" // U+F083C
+#define ICON_MDI_TOWER_BEACH "\xf3\xb0\x9a\x81" // U+F0681
+#define ICON_MDI_TOWER_FIRE "\xf3\xb0\x9a\x82" // U+F0682
+#define ICON_MDI_TOWN_HALL "\xf3\xb1\xa1\xb5" // U+F1875
+#define ICON_MDI_TOY_BRICK "\xf3\xb1\x8a\x88" // U+F1288
+#define ICON_MDI_TOY_BRICK_MARKER "\xf3\xb1\x8a\x89" // U+F1289
+#define ICON_MDI_TOY_BRICK_MARKER_OUTLINE "\xf3\xb1\x8a\x8a" // U+F128A
+#define ICON_MDI_TOY_BRICK_MINUS "\xf3\xb1\x8a\x8b" // U+F128B
+#define ICON_MDI_TOY_BRICK_MINUS_OUTLINE "\xf3\xb1\x8a\x8c" // U+F128C
+#define ICON_MDI_TOY_BRICK_OUTLINE "\xf3\xb1\x8a\x8d" // U+F128D
+#define ICON_MDI_TOY_BRICK_PLUS "\xf3\xb1\x8a\x8e" // U+F128E
+#define ICON_MDI_TOY_BRICK_PLUS_OUTLINE "\xf3\xb1\x8a\x8f" // U+F128F
+#define ICON_MDI_TOY_BRICK_REMOVE "\xf3\xb1\x8a\x90" // U+F1290
+#define ICON_MDI_TOY_BRICK_REMOVE_OUTLINE "\xf3\xb1\x8a\x91" // U+F1291
+#define ICON_MDI_TOY_BRICK_SEARCH "\xf3\xb1\x8a\x92" // U+F1292
+#define ICON_MDI_TOY_BRICK_SEARCH_OUTLINE "\xf3\xb1\x8a\x93" // U+F1293
+#define ICON_MDI_TRACK_LIGHT "\xf3\xb0\xa4\x94" // U+F0914
+#define ICON_MDI_TRACK_LIGHT_OFF "\xf3\xb1\xac\x81" // U+F1B01
+#define ICON_MDI_TRACKPAD "\xf3\xb0\x9f\xb8" // U+F07F8
+#define ICON_MDI_TRACKPAD_LOCK "\xf3\xb0\xa4\xb3" // U+F0933
+#define ICON_MDI_TRACTOR "\xf3\xb0\xa2\x92" // U+F0892
+#define ICON_MDI_TRACTOR_VARIANT "\xf3\xb1\x93\x84" // U+F14C4
+#define ICON_MDI_TRADEMARK "\xf3\xb0\xa9\xb8" // U+F0A78
+#define ICON_MDI_TRAFFIC_CONE "\xf3\xb1\x8d\xbc" // U+F137C
+#define ICON_MDI_TRAFFIC_LIGHT "\xf3\xb0\x94\xab" // U+F052B
+#define ICON_MDI_TRAFFIC_LIGHT_OUTLINE "\xf3\xb1\xa0\xaa" // U+F182A
+#define ICON_MDI_TRAIN "\xf3\xb0\x94\xac" // U+F052C
+#define ICON_MDI_TRAIN_BUS "\xf3\xb1\xb3\x87" // U+F1CC7
+#define ICON_MDI_TRAIN_CAR "\xf3\xb0\xaf\x98" // U+F0BD8
+#define ICON_MDI_TRAIN_CAR_AUTORACK "\xf3\xb1\xac\xad" // U+F1B2D
+#define ICON_MDI_TRAIN_CAR_BOX "\xf3\xb1\xac\xae" // U+F1B2E
+#define ICON_MDI_TRAIN_CAR_BOX_FULL "\xf3\xb1\xac\xaf" // U+F1B2F
+#define ICON_MDI_TRAIN_CAR_BOX_OPEN "\xf3\xb1\xac\xb0" // U+F1B30
+#define ICON_MDI_TRAIN_CAR_CABOOSE "\xf3\xb1\xac\xb1" // U+F1B31
+#define ICON_MDI_TRAIN_CAR_CENTERBEAM "\xf3\xb1\xac\xb2" // U+F1B32
+#define ICON_MDI_TRAIN_CAR_CENTERBEAM_FULL "\xf3\xb1\xac\xb3" // U+F1B33
+#define ICON_MDI_TRAIN_CAR_CONTAINER "\xf3\xb1\xac\xb4" // U+F1B34
+#define ICON_MDI_TRAIN_CAR_FLATBED "\xf3\xb1\xac\xb5" // U+F1B35
+#define ICON_MDI_TRAIN_CAR_FLATBED_CAR "\xf3\xb1\xac\xb6" // U+F1B36
+#define ICON_MDI_TRAIN_CAR_FLATBED_TANK "\xf3\xb1\xac\xb7" // U+F1B37
+#define ICON_MDI_TRAIN_CAR_GONDOLA "\xf3\xb1\xac\xb8" // U+F1B38
+#define ICON_MDI_TRAIN_CAR_GONDOLA_FULL "\xf3\xb1\xac\xb9" // U+F1B39
+#define ICON_MDI_TRAIN_CAR_HOPPER "\xf3\xb1\xac\xba" // U+F1B3A
+#define ICON_MDI_TRAIN_CAR_HOPPER_COVERED "\xf3\xb1\xac\xbb" // U+F1B3B
+#define ICON_MDI_TRAIN_CAR_HOPPER_FULL "\xf3\xb1\xac\xbc" // U+F1B3C
+#define ICON_MDI_TRAIN_CAR_INTERMODAL "\xf3\xb1\xac\xbd" // U+F1B3D
+#define ICON_MDI_TRAIN_CAR_PASSENGER "\xf3\xb1\x9c\xb3" // U+F1733
+#define ICON_MDI_TRAIN_CAR_PASSENGER_DOOR "\xf3\xb1\x9c\xb4" // U+F1734
+#define ICON_MDI_TRAIN_CAR_PASSENGER_DOOR_OPEN "\xf3\xb1\x9c\xb5" // U+F1735
+#define ICON_MDI_TRAIN_CAR_PASSENGER_VARIANT "\xf3\xb1\x9c\xb6" // U+F1736
+#define ICON_MDI_TRAIN_CAR_TANK "\xf3\xb1\xac\xbe" // U+F1B3E
+#define ICON_MDI_TRAIN_VARIANT "\xf3\xb0\xa3\x84" // U+F08C4
+#define ICON_MDI_TRAM "\xf3\xb0\x94\xad" // U+F052D
+#define ICON_MDI_TRAM_SIDE "\xf3\xb0\xbf\xa7" // U+F0FE7
+#define ICON_MDI_TRANSCRIBE "\xf3\xb0\x94\xae" // U+F052E
+#define ICON_MDI_TRANSCRIBE_CLOSE "\xf3\xb0\x94\xaf" // U+F052F
+#define ICON_MDI_TRANSFER "\xf3\xb1\x81\xa5" // U+F1065
+#define ICON_MDI_TRANSFER_DOWN "\xf3\xb0\xb6\xa1" // U+F0DA1
+#define ICON_MDI_TRANSFER_LEFT "\xf3\xb0\xb6\xa2" // U+F0DA2
+#define ICON_MDI_TRANSFER_RIGHT "\xf3\xb0\x94\xb0" // U+F0530
+#define ICON_MDI_TRANSFER_UP "\xf3\xb0\xb6\xa3" // U+F0DA3
+#define ICON_MDI_TRANSIT_CONNECTION "\xf3\xb0\xb4\xbc" // U+F0D3C
+#define ICON_MDI_TRANSIT_CONNECTION_HORIZONTAL "\xf3\xb1\x95\x86" // U+F1546
+#define ICON_MDI_TRANSIT_CONNECTION_VARIANT "\xf3\xb0\xb4\xbd" // U+F0D3D
+#define ICON_MDI_TRANSIT_DETOUR "\xf3\xb0\xbe\x8b" // U+F0F8B
+#define ICON_MDI_TRANSIT_SKIP "\xf3\xb1\x94\x95" // U+F1515
+#define ICON_MDI_TRANSIT_TRANSFER "\xf3\xb0\x9a\xae" // U+F06AE
+#define ICON_MDI_TRANSITION "\xf3\xb0\xa4\x95" // U+F0915
+#define ICON_MDI_TRANSITION_MASKED "\xf3\xb0\xa4\x96" // U+F0916
+#define ICON_MDI_TRANSLATE "\xf3\xb0\x97\x8a" // U+F05CA
+#define ICON_MDI_TRANSLATE_OFF "\xf3\xb0\xb8\x86" // U+F0E06
+#define ICON_MDI_TRANSLATE_VARIANT "\xf3\xb1\xae\x99" // U+F1B99
+#define ICON_MDI_TRANSMISSION_TOWER "\xf3\xb0\xb4\xbe" // U+F0D3E
+#define ICON_MDI_TRANSMISSION_TOWER_EXPORT "\xf3\xb1\xa4\xac" // U+F192C
+#define ICON_MDI_TRANSMISSION_TOWER_IMPORT "\xf3\xb1\xa4\xad" // U+F192D
+#define ICON_MDI_TRANSMISSION_TOWER_OFF "\xf3\xb1\xa7\x9d" // U+F19DD
+#define ICON_MDI_TRASH_CAN "\xf3\xb0\xa9\xb9" // U+F0A79
+#define ICON_MDI_TRASH_CAN_OUTLINE "\xf3\xb0\xa9\xba" // U+F0A7A
+#define ICON_MDI_TRAY "\xf3\xb1\x8a\x94" // U+F1294
+#define ICON_MDI_TRAY_ALERT "\xf3\xb1\x8a\x95" // U+F1295
+#define ICON_MDI_TRAY_ARROW_DOWN "\xf3\xb0\x84\xa0" // U+F0120
+#define ICON_MDI_TRAY_ARROW_UP "\xf3\xb0\x84\x9d" // U+F011D
+#define ICON_MDI_TRAY_FULL "\xf3\xb1\x8a\x96" // U+F1296
+#define ICON_MDI_TRAY_MINUS "\xf3\xb1\x8a\x97" // U+F1297
+#define ICON_MDI_TRAY_PLUS "\xf3\xb1\x8a\x98" // U+F1298
+#define ICON_MDI_TRAY_REMOVE "\xf3\xb1\x8a\x99" // U+F1299
+#define ICON_MDI_TREASURE_CHEST "\xf3\xb0\x9c\xa6" // U+F0726
+#define ICON_MDI_TREASURE_CHEST_OUTLINE "\xf3\xb1\xb1\xb7" // U+F1C77
+#define ICON_MDI_TREE "\xf3\xb0\x94\xb1" // U+F0531
+#define ICON_MDI_TREE_OUTLINE "\xf3\xb0\xb9\xa9" // U+F0E69
+#define ICON_MDI_TRELLO "\xf3\xb0\x94\xb2" // U+F0532
+#define ICON_MDI_TRENDING_DOWN "\xf3\xb0\x94\xb3" // U+F0533
+#define ICON_MDI_TRENDING_NEUTRAL "\xf3\xb0\x94\xb4" // U+F0534
+#define ICON_MDI_TRENDING_UP "\xf3\xb0\x94\xb5" // U+F0535
+#define ICON_MDI_TRIANGLE "\xf3\xb0\x94\xb6" // U+F0536
+#define ICON_MDI_TRIANGLE_DOWN "\xf3\xb1\xb1\x96" // U+F1C56
+#define ICON_MDI_TRIANGLE_DOWN_OUTLINE "\xf3\xb1\xb1\x97" // U+F1C57
+#define ICON_MDI_TRIANGLE_OUTLINE "\xf3\xb0\x94\xb7" // U+F0537
+#define ICON_MDI_TRIANGLE_SMALL_DOWN "\xf3\xb1\xa8\x89" // U+F1A09
+#define ICON_MDI_TRIANGLE_SMALL_UP "\xf3\xb1\xa8\x8a" // U+F1A0A
+#define ICON_MDI_TRIANGLE_WAVE "\xf3\xb1\x91\xbc" // U+F147C
+#define ICON_MDI_TRIFORCE "\xf3\xb0\xaf\x99" // U+F0BD9
+#define ICON_MDI_TROPHY "\xf3\xb0\x94\xb8" // U+F0538
+#define ICON_MDI_TROPHY_AWARD "\xf3\xb0\x94\xb9" // U+F0539
+#define ICON_MDI_TROPHY_BROKEN "\xf3\xb0\xb6\xa4" // U+F0DA4
+#define ICON_MDI_TROPHY_OUTLINE "\xf3\xb0\x94\xba" // U+F053A
+#define ICON_MDI_TROPHY_VARIANT "\xf3\xb0\x94\xbb" // U+F053B
+#define ICON_MDI_TROPHY_VARIANT_OUTLINE "\xf3\xb0\x94\xbc" // U+F053C
+#define ICON_MDI_TRUCK "\xf3\xb0\x94\xbd" // U+F053D
+#define ICON_MDI_TRUCK_ALERT "\xf3\xb1\xa7\x9e" // U+F19DE
+#define ICON_MDI_TRUCK_ALERT_OUTLINE "\xf3\xb1\xa7\x9f" // U+F19DF
+#define ICON_MDI_TRUCK_CARGO_CONTAINER "\xf3\xb1\xa3\x98" // U+F18D8
+#define ICON_MDI_TRUCK_CHECK "\xf3\xb0\xb3\x94" // U+F0CD4
+#define ICON_MDI_TRUCK_CHECK_OUTLINE "\xf3\xb1\x8a\x9a" // U+F129A
+#define ICON_MDI_TRUCK_DELIVERY "\xf3\xb0\x94\xbe" // U+F053E
+#define ICON_MDI_TRUCK_DELIVERY_OUTLINE "\xf3\xb1\x8a\x9b" // U+F129B
+#define ICON_MDI_TRUCK_FAST "\xf3\xb0\x9e\x88" // U+F0788
+#define ICON_MDI_TRUCK_FAST_OUTLINE "\xf3\xb1\x8a\x9c" // U+F129C
+#define ICON_MDI_TRUCK_FLATBED "\xf3\xb1\xa2\x91" // U+F1891
+#define ICON_MDI_TRUCK_MINUS "\xf3\xb1\xa6\xae" // U+F19AE
+#define ICON_MDI_TRUCK_MINUS_OUTLINE "\xf3\xb1\xa6\xbd" // U+F19BD
+#define ICON_MDI_TRUCK_OFF_ROAD "\xf3\xb1\xb2\x9e" // U+F1C9E
+#define ICON_MDI_TRUCK_OFF_ROAD_OFF "\xf3\xb1\xb2\x9f" // U+F1C9F
+#define ICON_MDI_TRUCK_OUTLINE "\xf3\xb1\x8a\x9d" // U+F129D
+#define ICON_MDI_TRUCK_PLUS "\xf3\xb1\xa6\xad" // U+F19AD
+#define ICON_MDI_TRUCK_PLUS_OUTLINE "\xf3\xb1\xa6\xbc" // U+F19BC
+#define ICON_MDI_TRUCK_REMOVE "\xf3\xb1\xa6\xaf" // U+F19AF
+#define ICON_MDI_TRUCK_REMOVE_OUTLINE "\xf3\xb1\xa6\xbe" // U+F19BE
+#define ICON_MDI_TRUCK_SNOWFLAKE "\xf3\xb1\xa6\xa6" // U+F19A6
+#define ICON_MDI_TRUCK_TRAILER "\xf3\xb0\x9c\xa7" // U+F0727
+#define ICON_MDI_TRUMPET "\xf3\xb1\x82\x96" // U+F1096
+#define ICON_MDI_TSHIRT_CREW "\xf3\xb0\xa9\xbb" // U+F0A7B
+#define ICON_MDI_TSHIRT_CREW_OUTLINE "\xf3\xb0\x94\xbf" // U+F053F
+#define ICON_MDI_TSHIRT_V "\xf3\xb0\xa9\xbc" // U+F0A7C
+#define ICON_MDI_TSHIRT_V_OUTLINE "\xf3\xb0\x95\x80" // U+F0540
+#define ICON_MDI_TSUNAMI "\xf3\xb1\xaa\x81" // U+F1A81
+#define ICON_MDI_TUMBLE_DRYER "\xf3\xb0\xa4\x97" // U+F0917
+#define ICON_MDI_TUMBLE_DRYER_ALERT "\xf3\xb1\x86\xba" // U+F11BA
+#define ICON_MDI_TUMBLE_DRYER_OFF "\xf3\xb1\x86\xbb" // U+F11BB
+#define ICON_MDI_TUNE "\xf3\xb0\x98\xae" // U+F062E
+#define ICON_MDI_TUNE_VARIANT "\xf3\xb1\x95\x82" // U+F1542
+#define ICON_MDI_TUNE_VERTICAL "\xf3\xb0\x99\xaa" // U+F066A
+#define ICON_MDI_TUNE_VERTICAL_VARIANT "\xf3\xb1\x95\x83" // U+F1543
+#define ICON_MDI_TUNNEL "\xf3\xb1\xa0\xbd" // U+F183D
+#define ICON_MDI_TUNNEL_OUTLINE "\xf3\xb1\xa0\xbe" // U+F183E
+#define ICON_MDI_TURBINE "\xf3\xb1\xaa\x82" // U+F1A82
+#define ICON_MDI_TURKEY "\xf3\xb1\x9c\x9b" // U+F171B
+#define ICON_MDI_TURNSTILE "\xf3\xb0\xb3\x95" // U+F0CD5
+#define ICON_MDI_TURNSTILE_OUTLINE "\xf3\xb0\xb3\x96" // U+F0CD6
+#define ICON_MDI_TURTLE "\xf3\xb0\xb3\x97" // U+F0CD7
+#define ICON_MDI_TWITCH "\xf3\xb0\x95\x83" // U+F0543
+#define ICON_MDI_TWITTER "\xf3\xb0\x95\x84" // U+F0544
+#define ICON_MDI_TWO_FACTOR_AUTHENTICATION "\xf3\xb0\xa6\xaf" // U+F09AF
+#define ICON_MDI_TYPEWRITER "\xf3\xb0\xbc\xad" // U+F0F2D
+#define ICON_MDI_UBISOFT "\xf3\xb0\xaf\x9a" // U+F0BDA
+#define ICON_MDI_UBUNTU "\xf3\xb0\x95\x88" // U+F0548
+#define ICON_MDI_UFO "\xf3\xb1\x83\x84" // U+F10C4
+#define ICON_MDI_UFO_OUTLINE "\xf3\xb1\x83\x85" // U+F10C5
+#define ICON_MDI_ULTRA_HIGH_DEFINITION "\xf3\xb0\x9f\xb9" // U+F07F9
+#define ICON_MDI_UMBRACO "\xf3\xb0\x95\x89" // U+F0549
+#define ICON_MDI_UMBRELLA "\xf3\xb0\x95\x8a" // U+F054A
+#define ICON_MDI_UMBRELLA_BEACH "\xf3\xb1\xa2\x8a" // U+F188A
+#define ICON_MDI_UMBRELLA_BEACH_OUTLINE "\xf3\xb1\xa2\x8b" // U+F188B
+#define ICON_MDI_UMBRELLA_CLOSED "\xf3\xb0\xa6\xb0" // U+F09B0
+#define ICON_MDI_UMBRELLA_CLOSED_OUTLINE "\xf3\xb1\x8f\xa2" // U+F13E2
+#define ICON_MDI_UMBRELLA_CLOSED_VARIANT "\xf3\xb1\x8f\xa1" // U+F13E1
+#define ICON_MDI_UMBRELLA_OUTLINE "\xf3\xb0\x95\x8b" // U+F054B
+#define ICON_MDI_UNDO "\xf3\xb0\x95\x8c" // U+F054C
+#define ICON_MDI_UNDO_VARIANT "\xf3\xb0\x95\x8d" // U+F054D
+#define ICON_MDI_UNFOLD_LESS_HORIZONTAL "\xf3\xb0\x95\x8e" // U+F054E
+#define ICON_MDI_UNFOLD_LESS_VERTICAL "\xf3\xb0\x9d\xa0" // U+F0760
+#define ICON_MDI_UNFOLD_MORE_HORIZONTAL "\xf3\xb0\x95\x8f" // U+F054F
+#define ICON_MDI_UNFOLD_MORE_VERTICAL "\xf3\xb0\x9d\xa1" // U+F0761
+#define ICON_MDI_UNGROUP "\xf3\xb0\x95\x90" // U+F0550
+#define ICON_MDI_UNICODE "\xf3\xb0\xbb\x90" // U+F0ED0
+#define ICON_MDI_UNICORN "\xf3\xb1\x97\x82" // U+F15C2
+#define ICON_MDI_UNICORN_VARIANT "\xf3\xb1\x97\x83" // U+F15C3
+#define ICON_MDI_UNICYCLE "\xf3\xb1\x97\xa5" // U+F15E5
+#define ICON_MDI_UNITY "\xf3\xb0\x9a\xaf" // U+F06AF
+#define ICON_MDI_UNREAL "\xf3\xb0\xa6\xb1" // U+F09B1
+#define ICON_MDI_UPDATE "\xf3\xb0\x9a\xb0" // U+F06B0
+#define ICON_MDI_UPLOAD "\xf3\xb0\x95\x92" // U+F0552
+#define ICON_MDI_UPLOAD_LOCK "\xf3\xb1\x8d\xb3" // U+F1373
+#define ICON_MDI_UPLOAD_LOCK_OUTLINE "\xf3\xb1\x8d\xb4" // U+F1374
+#define ICON_MDI_UPLOAD_MULTIPLE "\xf3\xb0\xa0\xbd" // U+F083D
+#define ICON_MDI_UPLOAD_NETWORK "\xf3\xb0\x9b\xb6" // U+F06F6
+#define ICON_MDI_UPLOAD_NETWORK_OUTLINE "\xf3\xb0\xb3\x98" // U+F0CD8
+#define ICON_MDI_UPLOAD_OFF "\xf3\xb1\x83\x86" // U+F10C6
+#define ICON_MDI_UPLOAD_OFF_OUTLINE "\xf3\xb1\x83\x87" // U+F10C7
+#define ICON_MDI_UPLOAD_OUTLINE "\xf3\xb0\xb8\x87" // U+F0E07
+#define ICON_MDI_USB "\xf3\xb0\x95\x93" // U+F0553
+#define ICON_MDI_USB_C_PORT "\xf3\xb1\xb2\xbf" // U+F1CBF
+#define ICON_MDI_USB_FLASH_DRIVE "\xf3\xb1\x8a\x9e" // U+F129E
+#define ICON_MDI_USB_FLASH_DRIVE_OUTLINE "\xf3\xb1\x8a\x9f" // U+F129F
+#define ICON_MDI_USB_PORT "\xf3\xb1\x87\xb0" // U+F11F0
+#define ICON_MDI_VACUUM "\xf3\xb1\xa6\xa1" // U+F19A1
+#define ICON_MDI_VACUUM_OUTLINE "\xf3\xb1\xa6\xa2" // U+F19A2
+#define ICON_MDI_VALVE "\xf3\xb1\x81\xa6" // U+F1066
+#define ICON_MDI_VALVE_CLOSED "\xf3\xb1\x81\xa7" // U+F1067
+#define ICON_MDI_VALVE_OPEN "\xf3\xb1\x81\xa8" // U+F1068
+#define ICON_MDI_VAN_PASSENGER "\xf3\xb0\x9f\xba" // U+F07FA
+#define ICON_MDI_VAN_UTILITY "\xf3\xb0\x9f\xbb" // U+F07FB
+#define ICON_MDI_VANISH "\xf3\xb0\x9f\xbc" // U+F07FC
+#define ICON_MDI_VANISH_QUARTER "\xf3\xb1\x95\x94" // U+F1554
+#define ICON_MDI_VANITY_LIGHT "\xf3\xb1\x87\xa1" // U+F11E1
+#define ICON_MDI_VARIABLE "\xf3\xb0\xab\xa7" // U+F0AE7
+#define ICON_MDI_VARIABLE_BOX "\xf3\xb1\x84\x91" // U+F1111
+#define ICON_MDI_VECTOR_ARRANGE_ABOVE "\xf3\xb0\x95\x94" // U+F0554
+#define ICON_MDI_VECTOR_ARRANGE_BELOW "\xf3\xb0\x95\x95" // U+F0555
+#define ICON_MDI_VECTOR_BEZIER "\xf3\xb0\xab\xa8" // U+F0AE8
+#define ICON_MDI_VECTOR_CIRCLE "\xf3\xb0\x95\x96" // U+F0556
+#define ICON_MDI_VECTOR_CIRCLE_VARIANT "\xf3\xb0\x95\x97" // U+F0557
+#define ICON_MDI_VECTOR_COMBINE "\xf3\xb0\x95\x98" // U+F0558
+#define ICON_MDI_VECTOR_CURVE "\xf3\xb0\x95\x99" // U+F0559
+#define ICON_MDI_VECTOR_DIFFERENCE "\xf3\xb0\x95\x9a" // U+F055A
+#define ICON_MDI_VECTOR_DIFFERENCE_AB "\xf3\xb0\x95\x9b" // U+F055B
+#define ICON_MDI_VECTOR_DIFFERENCE_BA "\xf3\xb0\x95\x9c" // U+F055C
+#define ICON_MDI_VECTOR_ELLIPSE "\xf3\xb0\xa2\x93" // U+F0893
+#define ICON_MDI_VECTOR_INTERSECTION "\xf3\xb0\x95\x9d" // U+F055D
+#define ICON_MDI_VECTOR_LINE "\xf3\xb0\x95\x9e" // U+F055E
+#define ICON_MDI_VECTOR_LINK "\xf3\xb0\xbf\xa8" // U+F0FE8
+#define ICON_MDI_VECTOR_POINT "\xf3\xb0\x87\x84" // U+F01C4
+#define ICON_MDI_VECTOR_POINT_EDIT "\xf3\xb0\xa7\xa8" // U+F09E8
+#define ICON_MDI_VECTOR_POINT_MINUS "\xf3\xb1\xad\xb8" // U+F1B78
+#define ICON_MDI_VECTOR_POINT_PLUS "\xf3\xb1\xad\xb9" // U+F1B79
+#define ICON_MDI_VECTOR_POINT_SELECT "\xf3\xb0\x95\x9f" // U+F055F
+#define ICON_MDI_VECTOR_POLYGON "\xf3\xb0\x95\xa0" // U+F0560
+#define ICON_MDI_VECTOR_POLYGON_VARIANT "\xf3\xb1\xa1\x96" // U+F1856
+#define ICON_MDI_VECTOR_POLYLINE "\xf3\xb0\x95\xa1" // U+F0561
+#define ICON_MDI_VECTOR_POLYLINE_EDIT "\xf3\xb1\x88\xa5" // U+F1225
+#define ICON_MDI_VECTOR_POLYLINE_MINUS "\xf3\xb1\x88\xa6" // U+F1226
+#define ICON_MDI_VECTOR_POLYLINE_PLUS "\xf3\xb1\x88\xa7" // U+F1227
+#define ICON_MDI_VECTOR_POLYLINE_REMOVE "\xf3\xb1\x88\xa8" // U+F1228
+#define ICON_MDI_VECTOR_RADIUS "\xf3\xb0\x9d\x8a" // U+F074A
+#define ICON_MDI_VECTOR_RECTANGLE "\xf3\xb0\x97\x86" // U+F05C6
+#define ICON_MDI_VECTOR_SELECTION "\xf3\xb0\x95\xa2" // U+F0562
+#define ICON_MDI_VECTOR_SQUARE "\xf3\xb0\x80\x81" // U+F0001
+#define ICON_MDI_VECTOR_SQUARE_CLOSE "\xf3\xb1\xa1\x97" // U+F1857
+#define ICON_MDI_VECTOR_SQUARE_EDIT "\xf3\xb1\xa3\x99" // U+F18D9
+#define ICON_MDI_VECTOR_SQUARE_MINUS "\xf3\xb1\xa3\x9a" // U+F18DA
+#define ICON_MDI_VECTOR_SQUARE_OPEN "\xf3\xb1\xa1\x98" // U+F1858
+#define ICON_MDI_VECTOR_SQUARE_PLUS "\xf3\xb1\xa3\x9b" // U+F18DB
+#define ICON_MDI_VECTOR_SQUARE_REMOVE "\xf3\xb1\xa3\x9c" // U+F18DC
+#define ICON_MDI_VECTOR_TRIANGLE "\xf3\xb0\x95\xa3" // U+F0563
+#define ICON_MDI_VECTOR_UNION "\xf3\xb0\x95\xa4" // U+F0564
+#define ICON_MDI_VHS "\xf3\xb0\xa8\x9b" // U+F0A1B
+#define ICON_MDI_VIBRATE "\xf3\xb0\x95\xa6" // U+F0566
+#define ICON_MDI_VIBRATE_OFF "\xf3\xb0\xb3\x99" // U+F0CD9
+#define ICON_MDI_VIDEO "\xf3\xb0\x95\xa7" // U+F0567
+#define ICON_MDI_VIDEO_2D "\xf3\xb1\xa8\x9c" // U+F1A1C
+#define ICON_MDI_VIDEO_3D "\xf3\xb0\x9f\xbd" // U+F07FD
+#define ICON_MDI_VIDEO_3D_OFF "\xf3\xb1\x8f\x99" // U+F13D9
+#define ICON_MDI_VIDEO_3D_VARIANT "\xf3\xb0\xbb\x91" // U+F0ED1
+#define ICON_MDI_VIDEO_4K_BOX "\xf3\xb0\xa0\xbe" // U+F083E
+#define ICON_MDI_VIDEO_ACCOUNT "\xf3\xb0\xa4\x99" // U+F0919
+#define ICON_MDI_VIDEO_BOX "\xf3\xb0\x83\xbd" // U+F00FD
+#define ICON_MDI_VIDEO_BOX_OFF "\xf3\xb0\x83\xbe" // U+F00FE
+#define ICON_MDI_VIDEO_CHECK "\xf3\xb1\x81\xa9" // U+F1069
+#define ICON_MDI_VIDEO_CHECK_OUTLINE "\xf3\xb1\x81\xaa" // U+F106A
+#define ICON_MDI_VIDEO_HIGH_DEFINITION "\xf3\xb1\x94\xae" // U+F152E
+#define ICON_MDI_VIDEO_IMAGE "\xf3\xb0\xa4\x9a" // U+F091A
+#define ICON_MDI_VIDEO_INPUT_ANTENNA "\xf3\xb0\xa0\xbf" // U+F083F
+#define ICON_MDI_VIDEO_INPUT_COMPONENT "\xf3\xb0\xa1\x80" // U+F0840
+#define ICON_MDI_VIDEO_INPUT_HDMI "\xf3\xb0\xa1\x81" // U+F0841
+#define ICON_MDI_VIDEO_INPUT_SCART "\xf3\xb0\xbe\x8c" // U+F0F8C
+#define ICON_MDI_VIDEO_INPUT_SVIDEO "\xf3\xb0\xa1\x82" // U+F0842
+#define ICON_MDI_VIDEO_MARKER "\xf3\xb1\xa6\xa9" // U+F19A9
+#define ICON_MDI_VIDEO_MARKER_OUTLINE "\xf3\xb1\xa6\xaa" // U+F19AA
+#define ICON_MDI_VIDEO_MINUS "\xf3\xb0\xa6\xb2" // U+F09B2
+#define ICON_MDI_VIDEO_MINUS_OUTLINE "\xf3\xb0\x8a\xba" // U+F02BA
+#define ICON_MDI_VIDEO_OFF "\xf3\xb0\x95\xa8" // U+F0568
+#define ICON_MDI_VIDEO_OFF_OUTLINE "\xf3\xb0\xaf\x9b" // U+F0BDB
+#define ICON_MDI_VIDEO_OUTLINE "\xf3\xb0\xaf\x9c" // U+F0BDC
+#define ICON_MDI_VIDEO_PLUS "\xf3\xb0\xa6\xb3" // U+F09B3
+#define ICON_MDI_VIDEO_PLUS_OUTLINE "\xf3\xb0\x87\x93" // U+F01D3
+#define ICON_MDI_VIDEO_STABILIZATION "\xf3\xb0\xa4\x9b" // U+F091B
+#define ICON_MDI_VIDEO_STANDARD_DEFINITION "\xf3\xb1\xb2\xa0" // U+F1CA0
+#define ICON_MDI_VIDEO_SWITCH "\xf3\xb0\x95\xa9" // U+F0569
+#define ICON_MDI_VIDEO_SWITCH_OUTLINE "\xf3\xb0\x9e\x90" // U+F0790
+#define ICON_MDI_VIDEO_VINTAGE "\xf3\xb0\xa8\x9c" // U+F0A1C
+#define ICON_MDI_VIDEO_WIRELESS "\xf3\xb0\xbb\x92" // U+F0ED2
+#define ICON_MDI_VIDEO_WIRELESS_OUTLINE "\xf3\xb0\xbb\x93" // U+F0ED3
+#define ICON_MDI_VIEW_AGENDA "\xf3\xb0\x95\xaa" // U+F056A
+#define ICON_MDI_VIEW_AGENDA_OUTLINE "\xf3\xb1\x87\x98" // U+F11D8
+#define ICON_MDI_VIEW_ARRAY "\xf3\xb0\x95\xab" // U+F056B
+#define ICON_MDI_VIEW_ARRAY_OUTLINE "\xf3\xb1\x92\x85" // U+F1485
+#define ICON_MDI_VIEW_CAROUSEL "\xf3\xb0\x95\xac" // U+F056C
+#define ICON_MDI_VIEW_CAROUSEL_OUTLINE "\xf3\xb1\x92\x86" // U+F1486
+#define ICON_MDI_VIEW_COLUMN "\xf3\xb0\x95\xad" // U+F056D
+#define ICON_MDI_VIEW_COLUMN_OUTLINE "\xf3\xb1\x92\x87" // U+F1487
+#define ICON_MDI_VIEW_COMFY "\xf3\xb0\xb9\xaa" // U+F0E6A
+#define ICON_MDI_VIEW_COMFY_OUTLINE "\xf3\xb1\x92\x88" // U+F1488
+#define ICON_MDI_VIEW_COMPACT "\xf3\xb0\xb9\xab" // U+F0E6B
+#define ICON_MDI_VIEW_COMPACT_OUTLINE "\xf3\xb0\xb9\xac" // U+F0E6C
+#define ICON_MDI_VIEW_DASHBOARD "\xf3\xb0\x95\xae" // U+F056E
+#define ICON_MDI_VIEW_DASHBOARD_EDIT "\xf3\xb1\xa5\x87" // U+F1947
+#define ICON_MDI_VIEW_DASHBOARD_EDIT_OUTLINE "\xf3\xb1\xa5\x88" // U+F1948
+#define ICON_MDI_VIEW_DASHBOARD_OUTLINE "\xf3\xb0\xa8\x9d" // U+F0A1D
+#define ICON_MDI_VIEW_DASHBOARD_VARIANT "\xf3\xb0\xa1\x83" // U+F0843
+#define ICON_MDI_VIEW_DASHBOARD_VARIANT_OUTLINE "\xf3\xb1\x92\x89" // U+F1489
+#define ICON_MDI_VIEW_DAY "\xf3\xb0\x95\xaf" // U+F056F
+#define ICON_MDI_VIEW_DAY_OUTLINE "\xf3\xb1\x92\x8a" // U+F148A
+#define ICON_MDI_VIEW_GALLERY "\xf3\xb1\xa2\x88" // U+F1888
+#define ICON_MDI_VIEW_GALLERY_OUTLINE "\xf3\xb1\xa2\x89" // U+F1889
+#define ICON_MDI_VIEW_GRID "\xf3\xb0\x95\xb0" // U+F0570
+#define ICON_MDI_VIEW_GRID_COMPACT "\xf3\xb1\xb1\xa1" // U+F1C61
+#define ICON_MDI_VIEW_GRID_OUTLINE "\xf3\xb1\x87\x99" // U+F11D9
+#define ICON_MDI_VIEW_GRID_PLUS "\xf3\xb0\xbe\x8d" // U+F0F8D
+#define ICON_MDI_VIEW_GRID_PLUS_OUTLINE "\xf3\xb1\x87\x9a" // U+F11DA
+#define ICON_MDI_VIEW_HEADLINE "\xf3\xb0\x95\xb1" // U+F0571
+#define ICON_MDI_VIEW_LIST "\xf3\xb0\x95\xb2" // U+F0572
+#define ICON_MDI_VIEW_LIST_OUTLINE "\xf3\xb1\x92\x8b" // U+F148B
+#define ICON_MDI_VIEW_MODULE "\xf3\xb0\x95\xb3" // U+F0573
+#define ICON_MDI_VIEW_MODULE_OUTLINE "\xf3\xb1\x92\x8c" // U+F148C
+#define ICON_MDI_VIEW_PARALLEL "\xf3\xb0\x9c\xa8" // U+F0728
+#define ICON_MDI_VIEW_PARALLEL_OUTLINE "\xf3\xb1\x92\x8d" // U+F148D
+#define ICON_MDI_VIEW_QUILT "\xf3\xb0\x95\xb4" // U+F0574
+#define ICON_MDI_VIEW_QUILT_OUTLINE "\xf3\xb1\x92\x8e" // U+F148E
+#define ICON_MDI_VIEW_SEQUENTIAL "\xf3\xb0\x9c\xa9" // U+F0729
+#define ICON_MDI_VIEW_SEQUENTIAL_OUTLINE "\xf3\xb1\x92\x8f" // U+F148F
+#define ICON_MDI_VIEW_SPLIT_HORIZONTAL "\xf3\xb0\xaf\x8b" // U+F0BCB
+#define ICON_MDI_VIEW_SPLIT_VERTICAL "\xf3\xb0\xaf\x8c" // U+F0BCC
+#define ICON_MDI_VIEW_STREAM "\xf3\xb0\x95\xb5" // U+F0575
+#define ICON_MDI_VIEW_STREAM_OUTLINE "\xf3\xb1\x92\x90" // U+F1490
+#define ICON_MDI_VIEW_WEEK "\xf3\xb0\x95\xb6" // U+F0576
+#define ICON_MDI_VIEW_WEEK_OUTLINE "\xf3\xb1\x92\x91" // U+F1491
+#define ICON_MDI_VIMEO "\xf3\xb0\x95\xb7" // U+F0577
+#define ICON_MDI_VIOLIN "\xf3\xb0\x98\x8f" // U+F060F
+#define ICON_MDI_VIRTUAL_REALITY "\xf3\xb0\xa2\x94" // U+F0894
+#define ICON_MDI_VIRUS "\xf3\xb1\x8e\xb6" // U+F13B6
+#define ICON_MDI_VIRUS_OFF "\xf3\xb1\xa3\xa1" // U+F18E1
+#define ICON_MDI_VIRUS_OFF_OUTLINE "\xf3\xb1\xa3\xa2" // U+F18E2
+#define ICON_MDI_VIRUS_OUTLINE "\xf3\xb1\x8e\xb7" // U+F13B7
+#define ICON_MDI_VLC "\xf3\xb0\x95\xbc" // U+F057C
+#define ICON_MDI_VOICEMAIL "\xf3\xb0\x95\xbd" // U+F057D
+#define ICON_MDI_VOLCANO "\xf3\xb1\xaa\x83" // U+F1A83
+#define ICON_MDI_VOLCANO_OUTLINE "\xf3\xb1\xaa\x84" // U+F1A84
+#define ICON_MDI_VOLLEYBALL "\xf3\xb0\xa6\xb4" // U+F09B4
+#define ICON_MDI_VOLUME_EQUAL "\xf3\xb1\xac\x90" // U+F1B10
+#define ICON_MDI_VOLUME_HIGH "\xf3\xb0\x95\xbe" // U+F057E
+#define ICON_MDI_VOLUME_LOW "\xf3\xb0\x95\xbf" // U+F057F
+#define ICON_MDI_VOLUME_MEDIUM "\xf3\xb0\x96\x80" // U+F0580
+#define ICON_MDI_VOLUME_MINUS "\xf3\xb0\x9d\x9e" // U+F075E
+#define ICON_MDI_VOLUME_MUTE "\xf3\xb0\x9d\x9f" // U+F075F
+#define ICON_MDI_VOLUME_OFF "\xf3\xb0\x96\x81" // U+F0581
+#define ICON_MDI_VOLUME_PLUS "\xf3\xb0\x9d\x9d" // U+F075D
+#define ICON_MDI_VOLUME_SOURCE "\xf3\xb1\x84\xa0" // U+F1120
+#define ICON_MDI_VOLUME_VARIANT_OFF "\xf3\xb0\xb8\x88" // U+F0E08
+#define ICON_MDI_VOLUME_VIBRATE "\xf3\xb1\x84\xa1" // U+F1121
+#define ICON_MDI_VOTE "\xf3\xb0\xa8\x9f" // U+F0A1F
+#define ICON_MDI_VOTE_OUTLINE "\xf3\xb0\xa8\xa0" // U+F0A20
+#define ICON_MDI_VPN "\xf3\xb0\x96\x82" // U+F0582
+#define ICON_MDI_VUEJS "\xf3\xb0\xa1\x84" // U+F0844
+#define ICON_MDI_VUETIFY "\xf3\xb0\xb9\xad" // U+F0E6D
+#define ICON_MDI_WALK "\xf3\xb0\x96\x83" // U+F0583
+#define ICON_MDI_WALL "\xf3\xb0\x9f\xbe" // U+F07FE
+#define ICON_MDI_WALL_FIRE "\xf3\xb1\xa8\x91" // U+F1A11
+#define ICON_MDI_WALL_SCONCE "\xf3\xb0\xa4\x9c" // U+F091C
+#define ICON_MDI_WALL_SCONCE_FLAT "\xf3\xb0\xa4\x9d" // U+F091D
+#define ICON_MDI_WALL_SCONCE_FLAT_OUTLINE "\xf3\xb1\x9f\x89" // U+F17C9
+#define ICON_MDI_WALL_SCONCE_FLAT_VARIANT "\xf3\xb0\x90\x9c" // U+F041C
+#define ICON_MDI_WALL_SCONCE_FLAT_VARIANT_OUTLINE "\xf3\xb1\x9f\x8a" // U+F17CA
+#define ICON_MDI_WALL_SCONCE_OUTLINE "\xf3\xb1\x9f\x8b" // U+F17CB
+#define ICON_MDI_WALL_SCONCE_ROUND "\xf3\xb0\x9d\x88" // U+F0748
+#define ICON_MDI_WALL_SCONCE_ROUND_OUTLINE "\xf3\xb1\x9f\x8c" // U+F17CC
+#define ICON_MDI_WALL_SCONCE_ROUND_VARIANT "\xf3\xb0\xa4\x9e" // U+F091E
+#define ICON_MDI_WALL_SCONCE_ROUND_VARIANT_OUTLINE "\xf3\xb1\x9f\x8d" // U+F17CD
+#define ICON_MDI_WALLET "\xf3\xb0\x96\x84" // U+F0584
+#define ICON_MDI_WALLET_BIFOLD "\xf3\xb1\xb1\x98" // U+F1C58
+#define ICON_MDI_WALLET_BIFOLD_OUTLINE "\xf3\xb1\xb1\x99" // U+F1C59
+#define ICON_MDI_WALLET_GIFTCARD "\xf3\xb0\x96\x85" // U+F0585
+#define ICON_MDI_WALLET_MEMBERSHIP "\xf3\xb0\x96\x86" // U+F0586
+#define ICON_MDI_WALLET_OUTLINE "\xf3\xb0\xaf\x9d" // U+F0BDD
+#define ICON_MDI_WALLET_PLUS "\xf3\xb0\xbe\x8e" // U+F0F8E
+#define ICON_MDI_WALLET_PLUS_OUTLINE "\xf3\xb0\xbe\x8f" // U+F0F8F
+#define ICON_MDI_WALLET_TRAVEL "\xf3\xb0\x96\x87" // U+F0587
+#define ICON_MDI_WALLPAPER "\xf3\xb0\xb8\x89" // U+F0E09
+#define ICON_MDI_WAN "\xf3\xb0\x96\x88" // U+F0588
+#define ICON_MDI_WARDROBE "\xf3\xb0\xbe\x90" // U+F0F90
+#define ICON_MDI_WARDROBE_OUTLINE "\xf3\xb0\xbe\x91" // U+F0F91
+#define ICON_MDI_WAREHOUSE "\xf3\xb0\xbe\x81" // U+F0F81
+#define ICON_MDI_WASHING_MACHINE "\xf3\xb0\x9c\xaa" // U+F072A
+#define ICON_MDI_WASHING_MACHINE_ALERT "\xf3\xb1\x86\xbc" // U+F11BC
+#define ICON_MDI_WASHING_MACHINE_OFF "\xf3\xb1\x86\xbd" // U+F11BD
+#define ICON_MDI_WATCH "\xf3\xb0\x96\x89" // U+F0589
+#define ICON_MDI_WATCH_EXPORT "\xf3\xb0\x96\x8a" // U+F058A
+#define ICON_MDI_WATCH_EXPORT_VARIANT "\xf3\xb0\xa2\x95" // U+F0895
+#define ICON_MDI_WATCH_IMPORT "\xf3\xb0\x96\x8b" // U+F058B
+#define ICON_MDI_WATCH_IMPORT_VARIANT "\xf3\xb0\xa2\x96" // U+F0896
+#define ICON_MDI_WATCH_VARIANT "\xf3\xb0\xa2\x97" // U+F0897
+#define ICON_MDI_WATCH_VIBRATE "\xf3\xb0\x9a\xb1" // U+F06B1
+#define ICON_MDI_WATCH_VIBRATE_OFF "\xf3\xb0\xb3\x9a" // U+F0CDA
+#define ICON_MDI_WATER "\xf3\xb0\x96\x8c" // U+F058C
+#define ICON_MDI_WATER_ALERT "\xf3\xb1\x94\x82" // U+F1502
+#define ICON_MDI_WATER_ALERT_OUTLINE "\xf3\xb1\x94\x83" // U+F1503
+#define ICON_MDI_WATER_BOILER "\xf3\xb0\xbe\x92" // U+F0F92
+#define ICON_MDI_WATER_BOILER_ALERT "\xf3\xb1\x86\xb3" // U+F11B3
+#define ICON_MDI_WATER_BOILER_AUTO "\xf3\xb1\xae\x98" // U+F1B98
+#define ICON_MDI_WATER_BOILER_OFF "\xf3\xb1\x86\xb4" // U+F11B4
+#define ICON_MDI_WATER_CHECK "\xf3\xb1\x94\x84" // U+F1504
+#define ICON_MDI_WATER_CHECK_OUTLINE "\xf3\xb1\x94\x85" // U+F1505
+#define ICON_MDI_WATER_CIRCLE "\xf3\xb1\xa0\x86" // U+F1806
+#define ICON_MDI_WATER_MINUS "\xf3\xb1\x94\x86" // U+F1506
+#define ICON_MDI_WATER_MINUS_OUTLINE "\xf3\xb1\x94\x87" // U+F1507
+#define ICON_MDI_WATER_OFF "\xf3\xb0\x96\x8d" // U+F058D
+#define ICON_MDI_WATER_OFF_OUTLINE "\xf3\xb1\x94\x88" // U+F1508
+#define ICON_MDI_WATER_OPACITY "\xf3\xb1\xa1\x95" // U+F1855
+#define ICON_MDI_WATER_OUTLINE "\xf3\xb0\xb8\x8a" // U+F0E0A
+#define ICON_MDI_WATER_PERCENT "\xf3\xb0\x96\x8e" // U+F058E
+#define ICON_MDI_WATER_PERCENT_ALERT "\xf3\xb1\x94\x89" // U+F1509
+#define ICON_MDI_WATER_PLUS "\xf3\xb1\x94\x8a" // U+F150A
+#define ICON_MDI_WATER_PLUS_OUTLINE "\xf3\xb1\x94\x8b" // U+F150B
+#define ICON_MDI_WATER_POLO "\xf3\xb1\x8a\xa0" // U+F12A0
+#define ICON_MDI_WATER_PUMP "\xf3\xb0\x96\x8f" // U+F058F
+#define ICON_MDI_WATER_PUMP_OFF "\xf3\xb0\xbe\x93" // U+F0F93
+#define ICON_MDI_WATER_REMOVE "\xf3\xb1\x94\x8c" // U+F150C
+#define ICON_MDI_WATER_REMOVE_OUTLINE "\xf3\xb1\x94\x8d" // U+F150D
+#define ICON_MDI_WATER_SYNC "\xf3\xb1\x9f\x86" // U+F17C6
+#define ICON_MDI_WATER_THERMOMETER "\xf3\xb1\xaa\x85" // U+F1A85
+#define ICON_MDI_WATER_THERMOMETER_OUTLINE "\xf3\xb1\xaa\x86" // U+F1A86
+#define ICON_MDI_WATER_WELL "\xf3\xb1\x81\xab" // U+F106B
+#define ICON_MDI_WATER_WELL_OUTLINE "\xf3\xb1\x81\xac" // U+F106C
+#define ICON_MDI_WATERFALL "\xf3\xb1\xa1\x89" // U+F1849
+#define ICON_MDI_WATERING_CAN "\xf3\xb1\x92\x81" // U+F1481
+#define ICON_MDI_WATERING_CAN_OUTLINE "\xf3\xb1\x92\x82" // U+F1482
+#define ICON_MDI_WATERMARK "\xf3\xb0\x98\x92" // U+F0612
+#define ICON_MDI_WAVE "\xf3\xb0\xbc\xae" // U+F0F2E
+#define ICON_MDI_WAVE_ARROW_DOWN "\xf3\xb1\xb2\xb0" // U+F1CB0
+#define ICON_MDI_WAVE_ARROW_UP "\xf3\xb1\xb2\xb1" // U+F1CB1
+#define ICON_MDI_WAVE_UNDERCURRENT "\xf3\xb1\xb3\x80" // U+F1CC0
+#define ICON_MDI_WAVEFORM "\xf3\xb1\x91\xbd" // U+F147D
+#define ICON_MDI_WAVES "\xf3\xb0\x9e\x8d" // U+F078D
+#define ICON_MDI_WAVES_ARROW_LEFT "\xf3\xb1\xa1\x99" // U+F1859
+#define ICON_MDI_WAVES_ARROW_RIGHT "\xf3\xb1\xa1\x9a" // U+F185A
+#define ICON_MDI_WAVES_ARROW_UP "\xf3\xb1\xa1\x9b" // U+F185B
+#define ICON_MDI_WAZE "\xf3\xb0\xaf\x9e" // U+F0BDE
+#define ICON_MDI_WEATHER_CLOUDY "\xf3\xb0\x96\x90" // U+F0590
+#define ICON_MDI_WEATHER_CLOUDY_ALERT "\xf3\xb0\xbc\xaf" // U+F0F2F
+#define ICON_MDI_WEATHER_CLOUDY_ARROW_RIGHT "\xf3\xb0\xb9\xae" // U+F0E6E
+#define ICON_MDI_WEATHER_CLOUDY_CLOCK "\xf3\xb1\xa3\xb6" // U+F18F6
+#define ICON_MDI_WEATHER_DUST "\xf3\xb1\xad\x9a" // U+F1B5A
+#define ICON_MDI_WEATHER_FOG "\xf3\xb0\x96\x91" // U+F0591
+#define ICON_MDI_WEATHER_HAIL "\xf3\xb0\x96\x92" // U+F0592
+#define ICON_MDI_WEATHER_HAZY "\xf3\xb0\xbc\xb0" // U+F0F30
+#define ICON_MDI_WEATHER_HURRICANE "\xf3\xb0\xa2\x98" // U+F0898
+#define ICON_MDI_WEATHER_HURRICANE_OUTLINE "\xf3\xb1\xb1\xb8" // U+F1C78
+#define ICON_MDI_WEATHER_LIGHTNING "\xf3\xb0\x96\x93" // U+F0593
+#define ICON_MDI_WEATHER_LIGHTNING_RAINY "\xf3\xb0\x99\xbe" // U+F067E
+#define ICON_MDI_WEATHER_NIGHT "\xf3\xb0\x96\x94" // U+F0594
+#define ICON_MDI_WEATHER_NIGHT_PARTLY_CLOUDY "\xf3\xb0\xbc\xb1" // U+F0F31
+#define ICON_MDI_WEATHER_PARTLY_CLOUDY "\xf3\xb0\x96\x95" // U+F0595
+#define ICON_MDI_WEATHER_PARTLY_LIGHTNING "\xf3\xb0\xbc\xb2" // U+F0F32
+#define ICON_MDI_WEATHER_PARTLY_RAINY "\xf3\xb0\xbc\xb3" // U+F0F33
+#define ICON_MDI_WEATHER_PARTLY_SNOWY "\xf3\xb0\xbc\xb4" // U+F0F34
+#define ICON_MDI_WEATHER_PARTLY_SNOWY_RAINY "\xf3\xb0\xbc\xb5" // U+F0F35
+#define ICON_MDI_WEATHER_POURING "\xf3\xb0\x96\x96" // U+F0596
+#define ICON_MDI_WEATHER_RAINY "\xf3\xb0\x96\x97" // U+F0597
+#define ICON_MDI_WEATHER_SNOWY "\xf3\xb0\x96\x98" // U+F0598
+#define ICON_MDI_WEATHER_SNOWY_HEAVY "\xf3\xb0\xbc\xb6" // U+F0F36
+#define ICON_MDI_WEATHER_SNOWY_RAINY "\xf3\xb0\x99\xbf" // U+F067F
+#define ICON_MDI_WEATHER_SUNNY "\xf3\xb0\x96\x99" // U+F0599
+#define ICON_MDI_WEATHER_SUNNY_ALERT "\xf3\xb0\xbc\xb7" // U+F0F37
+#define ICON_MDI_WEATHER_SUNNY_OFF "\xf3\xb1\x93\xa4" // U+F14E4
+#define ICON_MDI_WEATHER_SUNSET "\xf3\xb0\x96\x9a" // U+F059A
+#define ICON_MDI_WEATHER_SUNSET_DOWN "\xf3\xb0\x96\x9b" // U+F059B
+#define ICON_MDI_WEATHER_SUNSET_UP "\xf3\xb0\x96\x9c" // U+F059C
+#define ICON_MDI_WEATHER_TORNADO "\xf3\xb0\xbc\xb8" // U+F0F38
+#define ICON_MDI_WEATHER_WINDY "\xf3\xb0\x96\x9d" // U+F059D
+#define ICON_MDI_WEATHER_WINDY_VARIANT "\xf3\xb0\x96\x9e" // U+F059E
+#define ICON_MDI_WEB "\xf3\xb0\x96\x9f" // U+F059F
+#define ICON_MDI_WEB_BOX "\xf3\xb0\xbe\x94" // U+F0F94
+#define ICON_MDI_WEB_CANCEL "\xf3\xb1\x9e\x90" // U+F1790
+#define ICON_MDI_WEB_CHECK "\xf3\xb0\x9e\x89" // U+F0789
+#define ICON_MDI_WEB_CLOCK "\xf3\xb1\x89\x8a" // U+F124A
+#define ICON_MDI_WEB_MINUS "\xf3\xb1\x82\xa0" // U+F10A0
+#define ICON_MDI_WEB_OFF "\xf3\xb0\xaa\x8e" // U+F0A8E
+#define ICON_MDI_WEB_PLUS "\xf3\xb0\x80\xb3" // U+F0033
+#define ICON_MDI_WEB_REFRESH "\xf3\xb1\x9e\x91" // U+F1791
+#define ICON_MDI_WEB_REMOVE "\xf3\xb0\x95\x91" // U+F0551
+#define ICON_MDI_WEB_SYNC "\xf3\xb1\x9e\x92" // U+F1792
+#define ICON_MDI_WEBCAM "\xf3\xb0\x96\xa0" // U+F05A0
+#define ICON_MDI_WEBCAM_OFF "\xf3\xb1\x9c\xb7" // U+F1737
+#define ICON_MDI_WEBHOOK "\xf3\xb0\x98\xaf" // U+F062F
+#define ICON_MDI_WEBPACK "\xf3\xb0\x9c\xab" // U+F072B
+#define ICON_MDI_WEBRTC "\xf3\xb1\x89\x88" // U+F1248
+#define ICON_MDI_WECHAT "\xf3\xb0\x98\x91" // U+F0611
+#define ICON_MDI_WEIGHT "\xf3\xb0\x96\xa1" // U+F05A1
+#define ICON_MDI_WEIGHT_GRAM "\xf3\xb0\xb4\xbf" // U+F0D3F
+#define ICON_MDI_WEIGHT_KILOGRAM "\xf3\xb0\x96\xa2" // U+F05A2
+#define ICON_MDI_WEIGHT_LIFTER "\xf3\xb1\x85\x9d" // U+F115D
+#define ICON_MDI_WEIGHT_POUND "\xf3\xb0\xa6\xb5" // U+F09B5
+#define ICON_MDI_WHATSAPP "\xf3\xb0\x96\xa3" // U+F05A3
+#define ICON_MDI_WHEEL_BARROW "\xf3\xb1\x93\xb2" // U+F14F2
+#define ICON_MDI_WHEELCHAIR "\xf3\xb1\xaa\x87" // U+F1A87
+#define ICON_MDI_WHEELCHAIR_ACCESSIBILITY "\xf3\xb0\x96\xa4" // U+F05A4
+#define ICON_MDI_WHISTLE "\xf3\xb0\xa6\xb6" // U+F09B6
+#define ICON_MDI_WHISTLE_OUTLINE "\xf3\xb1\x8a\xbc" // U+F12BC
+#define ICON_MDI_WHITE_BALANCE_AUTO "\xf3\xb0\x96\xa5" // U+F05A5
+#define ICON_MDI_WHITE_BALANCE_INCANDESCENT "\xf3\xb0\x96\xa6" // U+F05A6
+#define ICON_MDI_WHITE_BALANCE_IRIDESCENT "\xf3\xb0\x96\xa7" // U+F05A7
+#define ICON_MDI_WHITE_BALANCE_SUNNY "\xf3\xb0\x96\xa8" // U+F05A8
+#define ICON_MDI_WIDGETS "\xf3\xb0\x9c\xac" // U+F072C
+#define ICON_MDI_WIDGETS_OUTLINE "\xf3\xb1\x8d\x95" // U+F1355
+#define ICON_MDI_WIFI "\xf3\xb0\x96\xa9" // U+F05A9
+#define ICON_MDI_WIFI_ALERT "\xf3\xb1\x9a\xb5" // U+F16B5
+#define ICON_MDI_WIFI_ARROW_DOWN "\xf3\xb1\x9a\xb6" // U+F16B6
+#define ICON_MDI_WIFI_ARROW_LEFT "\xf3\xb1\x9a\xb7" // U+F16B7
+#define ICON_MDI_WIFI_ARROW_LEFT_RIGHT "\xf3\xb1\x9a\xb8" // U+F16B8
+#define ICON_MDI_WIFI_ARROW_RIGHT "\xf3\xb1\x9a\xb9" // U+F16B9
+#define ICON_MDI_WIFI_ARROW_UP "\xf3\xb1\x9a\xba" // U+F16BA
+#define ICON_MDI_WIFI_ARROW_UP_DOWN "\xf3\xb1\x9a\xbb" // U+F16BB
+#define ICON_MDI_WIFI_CANCEL "\xf3\xb1\x9a\xbc" // U+F16BC
+#define ICON_MDI_WIFI_CHECK "\xf3\xb1\x9a\xbd" // U+F16BD
+#define ICON_MDI_WIFI_COG "\xf3\xb1\x9a\xbe" // U+F16BE
+#define ICON_MDI_WIFI_LOCK "\xf3\xb1\x9a\xbf" // U+F16BF
+#define ICON_MDI_WIFI_LOCK_OPEN "\xf3\xb1\x9b\x80" // U+F16C0
+#define ICON_MDI_WIFI_MARKER "\xf3\xb1\x9b\x81" // U+F16C1
+#define ICON_MDI_WIFI_MINUS "\xf3\xb1\x9b\x82" // U+F16C2
+#define ICON_MDI_WIFI_OFF "\xf3\xb0\x96\xaa" // U+F05AA
+#define ICON_MDI_WIFI_PLUS "\xf3\xb1\x9b\x83" // U+F16C3
+#define ICON_MDI_WIFI_REFRESH "\xf3\xb1\x9b\x84" // U+F16C4
+#define ICON_MDI_WIFI_REMOVE "\xf3\xb1\x9b\x85" // U+F16C5
+#define ICON_MDI_WIFI_SETTINGS "\xf3\xb1\x9b\x86" // U+F16C6
+#define ICON_MDI_WIFI_STAR "\xf3\xb0\xb8\x8b" // U+F0E0B
+#define ICON_MDI_WIFI_STRENGTH_1 "\xf3\xb0\xa4\x9f" // U+F091F
+#define ICON_MDI_WIFI_STRENGTH_1_ALERT "\xf3\xb0\xa4\xa0" // U+F0920
+#define ICON_MDI_WIFI_STRENGTH_1_LOCK "\xf3\xb0\xa4\xa1" // U+F0921
+#define ICON_MDI_WIFI_STRENGTH_1_LOCK_OPEN "\xf3\xb1\x9b\x8b" // U+F16CB
+#define ICON_MDI_WIFI_STRENGTH_2 "\xf3\xb0\xa4\xa2" // U+F0922
+#define ICON_MDI_WIFI_STRENGTH_2_ALERT "\xf3\xb0\xa4\xa3" // U+F0923
+#define ICON_MDI_WIFI_STRENGTH_2_LOCK "\xf3\xb0\xa4\xa4" // U+F0924
+#define ICON_MDI_WIFI_STRENGTH_2_LOCK_OPEN "\xf3\xb1\x9b\x8c" // U+F16CC
+#define ICON_MDI_WIFI_STRENGTH_3 "\xf3\xb0\xa4\xa5" // U+F0925
+#define ICON_MDI_WIFI_STRENGTH_3_ALERT "\xf3\xb0\xa4\xa6" // U+F0926
+#define ICON_MDI_WIFI_STRENGTH_3_LOCK "\xf3\xb0\xa4\xa7" // U+F0927
+#define ICON_MDI_WIFI_STRENGTH_3_LOCK_OPEN "\xf3\xb1\x9b\x8d" // U+F16CD
+#define ICON_MDI_WIFI_STRENGTH_4 "\xf3\xb0\xa4\xa8" // U+F0928
+#define ICON_MDI_WIFI_STRENGTH_4_ALERT "\xf3\xb0\xa4\xa9" // U+F0929
+#define ICON_MDI_WIFI_STRENGTH_4_LOCK "\xf3\xb0\xa4\xaa" // U+F092A
+#define ICON_MDI_WIFI_STRENGTH_4_LOCK_OPEN "\xf3\xb1\x9b\x8e" // U+F16CE
+#define ICON_MDI_WIFI_STRENGTH_ALERT_OUTLINE "\xf3\xb0\xa4\xab" // U+F092B
+#define ICON_MDI_WIFI_STRENGTH_LOCK_OPEN_OUTLINE "\xf3\xb1\x9b\x8f" // U+F16CF
+#define ICON_MDI_WIFI_STRENGTH_LOCK_OUTLINE "\xf3\xb0\xa4\xac" // U+F092C
+#define ICON_MDI_WIFI_STRENGTH_OFF "\xf3\xb0\xa4\xad" // U+F092D
+#define ICON_MDI_WIFI_STRENGTH_OFF_OUTLINE "\xf3\xb0\xa4\xae" // U+F092E
+#define ICON_MDI_WIFI_STRENGTH_OUTLINE "\xf3\xb0\xa4\xaf" // U+F092F
+#define ICON_MDI_WIFI_SYNC "\xf3\xb1\x9b\x87" // U+F16C7
+#define ICON_MDI_WIKIPEDIA "\xf3\xb0\x96\xac" // U+F05AC
+#define ICON_MDI_WIND_POWER "\xf3\xb1\xaa\x88" // U+F1A88
+#define ICON_MDI_WIND_POWER_OUTLINE "\xf3\xb1\xaa\x89" // U+F1A89
+#define ICON_MDI_WIND_TURBINE "\xf3\xb0\xb6\xa5" // U+F0DA5
+#define ICON_MDI_WIND_TURBINE_ALERT "\xf3\xb1\xa6\xab" // U+F19AB
+#define ICON_MDI_WIND_TURBINE_CHECK "\xf3\xb1\xa6\xac" // U+F19AC
+#define ICON_MDI_WINDOW_CLOSE "\xf3\xb0\x96\xad" // U+F05AD
+#define ICON_MDI_WINDOW_CLOSED "\xf3\xb0\x96\xae" // U+F05AE
+#define ICON_MDI_WINDOW_CLOSED_VARIANT "\xf3\xb1\x87\x9b" // U+F11DB
+#define ICON_MDI_WINDOW_MAXIMIZE "\xf3\xb0\x96\xaf" // U+F05AF
+#define ICON_MDI_WINDOW_MINIMIZE "\xf3\xb0\x96\xb0" // U+F05B0
+#define ICON_MDI_WINDOW_OPEN "\xf3\xb0\x96\xb1" // U+F05B1
+#define ICON_MDI_WINDOW_OPEN_VARIANT "\xf3\xb1\x87\x9c" // U+F11DC
+#define ICON_MDI_WINDOW_RESTORE "\xf3\xb0\x96\xb2" // U+F05B2
+#define ICON_MDI_WINDOW_SHUTTER "\xf3\xb1\x84\x9c" // U+F111C
+#define ICON_MDI_WINDOW_SHUTTER_ALERT "\xf3\xb1\x84\x9d" // U+F111D
+#define ICON_MDI_WINDOW_SHUTTER_AUTO "\xf3\xb1\xae\xa3" // U+F1BA3
+#define ICON_MDI_WINDOW_SHUTTER_COG "\xf3\xb1\xaa\x8a" // U+F1A8A
+#define ICON_MDI_WINDOW_SHUTTER_OPEN "\xf3\xb1\x84\x9e" // U+F111E
+#define ICON_MDI_WINDOW_SHUTTER_SETTINGS "\xf3\xb1\xaa\x8b" // U+F1A8B
+#define ICON_MDI_WINDSOCK "\xf3\xb1\x97\xba" // U+F15FA
+#define ICON_MDI_WIPER "\xf3\xb0\xab\xa9" // U+F0AE9
+#define ICON_MDI_WIPER_WASH "\xf3\xb0\xb6\xa6" // U+F0DA6
+#define ICON_MDI_WIPER_WASH_ALERT "\xf3\xb1\xa3\x9f" // U+F18DF
+#define ICON_MDI_WIZARD_HAT "\xf3\xb1\x91\xb7" // U+F1477
+#define ICON_MDI_WORDPRESS "\xf3\xb0\x96\xb4" // U+F05B4
+#define ICON_MDI_WRAP "\xf3\xb0\x96\xb6" // U+F05B6
+#define ICON_MDI_WRAP_DISABLED "\xf3\xb0\xaf\x9f" // U+F0BDF
+#define ICON_MDI_WRENCH "\xf3\xb0\x96\xb7" // U+F05B7
+#define ICON_MDI_WRENCH_CHECK "\xf3\xb1\xae\x8f" // U+F1B8F
+#define ICON_MDI_WRENCH_CHECK_OUTLINE "\xf3\xb1\xae\x90" // U+F1B90
+#define ICON_MDI_WRENCH_CLOCK "\xf3\xb1\xa6\xa3" // U+F19A3
+#define ICON_MDI_WRENCH_CLOCK_OUTLINE "\xf3\xb1\xae\x93" // U+F1B93
+#define ICON_MDI_WRENCH_COG "\xf3\xb1\xae\x91" // U+F1B91
+#define ICON_MDI_WRENCH_COG_OUTLINE "\xf3\xb1\xae\x92" // U+F1B92
+#define ICON_MDI_WRENCH_OUTLINE "\xf3\xb0\xaf\xa0" // U+F0BE0
+#define ICON_MDI_XAMARIN "\xf3\xb0\xa1\x85" // U+F0845
+#define ICON_MDI_XML "\xf3\xb0\x97\x80" // U+F05C0
+#define ICON_MDI_XMPP "\xf3\xb0\x9f\xbf" // U+F07FF
+#define ICON_MDI_YAHOO "\xf3\xb0\xad\x8f" // U+F0B4F
+#define ICON_MDI_YEAST "\xf3\xb0\x97\x81" // U+F05C1
+#define ICON_MDI_YIN_YANG "\xf3\xb0\x9a\x80" // U+F0680
+#define ICON_MDI_YOGA "\xf3\xb1\x85\xbc" // U+F117C
+#define ICON_MDI_YOUTUBE "\xf3\xb0\x97\x83" // U+F05C3
+#define ICON_MDI_YOUTUBE_GAMING "\xf3\xb0\xa1\x88" // U+F0848
+#define ICON_MDI_YOUTUBE_STUDIO "\xf3\xb0\xa1\x87" // U+F0847
+#define ICON_MDI_YOUTUBE_SUBSCRIPTION "\xf3\xb0\xb5\x80" // U+F0D40
+#define ICON_MDI_YOUTUBE_TV "\xf3\xb0\x91\x88" // U+F0448
+#define ICON_MDI_YURT "\xf3\xb1\x94\x96" // U+F1516
+#define ICON_MDI_Z_WAVE "\xf3\xb0\xab\xaa" // U+F0AEA
+#define ICON_MDI_ZEND "\xf3\xb0\xab\xab" // U+F0AEB
+#define ICON_MDI_ZIGBEE "\xf3\xb0\xb5\x81" // U+F0D41
+#define ICON_MDI_ZIP_BOX "\xf3\xb0\x97\x84" // U+F05C4
+#define ICON_MDI_ZIP_BOX_OUTLINE "\xf3\xb0\xbf\xba" // U+F0FFA
+#define ICON_MDI_ZIP_DISK "\xf3\xb0\xa8\xa3" // U+F0A23
+#define ICON_MDI_ZODIAC_AQUARIUS "\xf3\xb0\xa9\xbd" // U+F0A7D
+#define ICON_MDI_ZODIAC_ARIES "\xf3\xb0\xa9\xbe" // U+F0A7E
+#define ICON_MDI_ZODIAC_CANCER "\xf3\xb0\xa9\xbf" // U+F0A7F
+#define ICON_MDI_ZODIAC_CAPRICORN "\xf3\xb0\xaa\x80" // U+F0A80
+#define ICON_MDI_ZODIAC_GEMINI "\xf3\xb0\xaa\x81" // U+F0A81
+#define ICON_MDI_ZODIAC_LEO "\xf3\xb0\xaa\x82" // U+F0A82
+#define ICON_MDI_ZODIAC_LIBRA "\xf3\xb0\xaa\x83" // U+F0A83
+#define ICON_MDI_ZODIAC_PISCES "\xf3\xb0\xaa\x84" // U+F0A84
+#define ICON_MDI_ZODIAC_SAGITTARIUS "\xf3\xb0\xaa\x85" // U+F0A85
+#define ICON_MDI_ZODIAC_SCORPIO "\xf3\xb0\xaa\x86" // U+F0A86
+#define ICON_MDI_ZODIAC_TAURUS "\xf3\xb0\xaa\x87" // U+F0A87
+#define ICON_MDI_ZODIAC_VIRGO "\xf3\xb0\xaa\x88" // U+F0A88
+#define ICON_MDI_BLANK "\xef\x9a\x8c" // U+F68C
+#line 0
+// editor_script
+#define GLEQ_IMPLEMENTATION
+#line 1 "3rd_lite_sys_gleq.h"
+/*
+ * GLEQ - A basic event queue for GLFW 3
+ * Copyright © Camilla Löwy
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would
+ * be appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ */
+
+#ifndef GLEQ_HEADER_FILE
+#define GLEQ_HEADER_FILE
+
+// #include
+
+#ifdef GLEQ_STATIC
+ #define GLEQDEF static
+#else
+ #define GLEQDEF extern
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum
+{
+ GLEQ_NONE = 0,
+ GLEQ_WINDOW_MOVED = 1<<1,
+ GLEQ_WINDOW_RESIZED = 1<<2,
+ GLEQ_WINDOW_CLOSED = 1<<3,
+ GLEQ_WINDOW_REFRESH = 1<<4,
+ GLEQ_WINDOW_FOCUSED = 1<<5,
+ GLEQ_WINDOW_DEFOCUSED = 1<<6,
+ GLEQ_WINDOW_ICONIFIED = 1<<7,
+ GLEQ_WINDOW_UNICONIFIED = 1<<8,
+ GLEQ_FRAMEBUFFER_RESIZED = 1<<9,
+ GLEQ_BUTTON_PRESSED = 1<<10,
+ GLEQ_BUTTON_RELEASED = 1<<11,
+ GLEQ_CURSOR_MOVED = 1<<12,
+ GLEQ_CURSOR_ENTERED = 1<<13,
+ GLEQ_CURSOR_LEFT = 1<<14,
+ GLEQ_SCROLLED = 1<<15,
+ GLEQ_KEY_PRESSED = 1<<16,
+ GLEQ_KEY_REPEATED = 1<<17,
+ GLEQ_KEY_RELEASED = 1<<18,
+ GLEQ_CODEPOINT_INPUT = 1<<19,
+ GLEQ_MONITOR_CONNECTED = 1<<20,
+ GLEQ_MONITOR_DISCONNECTED = 1<<21,
+#if GLFW_VERSION_MINOR >= 1
+ GLEQ_FILE_DROPPED = 1<<22,
+#endif
+#if GLFW_VERSION_MINOR >= 2
+ GLEQ_JOYSTICK_CONNECTED = 1<<23,
+ GLEQ_JOYSTICK_DISCONNECTED = 1<<24,
+#endif
+#if GLFW_VERSION_MINOR >= 3
+ GLEQ_WINDOW_MAXIMIZED = 1<<25,
+ GLEQ_WINDOW_UNMAXIMIZED = 1<<26,
+ GLEQ_WINDOW_SCALE_CHANGED = 1<<27,
+#endif
+} GLEQtype;
+
+typedef struct GLEQevent
+{
+ unsigned/*GLEQtype*/ type;
+ union {
+ GLFWwindow* window;
+ GLFWmonitor* monitor;
+ int joystick;
+ };
+ union {
+ struct {
+ int x;
+ int y;
+ } pos;
+ struct {
+ int width;
+ int height;
+ } size;
+ struct {
+ double x;
+ double y;
+ } scroll;
+ struct {
+ int key;
+ int scancode;
+ int mods;
+ } keyboard;
+ struct {
+ int button;
+ int mods;
+ } mouse;
+ unsigned int codepoint;
+#if GLFW_VERSION_MINOR >= 1
+ struct {
+ char** paths;
+ int count;
+ } file;
+#endif
+#if GLFW_VERSION_MINOR >= 3
+ struct {
+ float x;
+ float y;
+ } scale;
+#endif
+ };
+} GLEQevent;
+
+GLEQDEF void gleqInit(void);
+GLEQDEF void gleqTrackWindow(GLFWwindow* window);
+
+GLEQDEF int gleqNextEvent(GLEQevent* event);
+GLEQDEF void gleqFreeEvent(GLEQevent* event);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef GLEQ_IMPLEMENTATION
+
+#include
+#include
+#include
+
+#ifndef GLEQ_CAPACITY
+ #define GLEQ_CAPACITY 1024
+#endif
+
+static struct
+{
+ GLEQevent events[GLEQ_CAPACITY];
+ size_t head;
+ size_t tail;
+} gleq_queue = { {0}, 0, 0 };
+
+static char* gleq_strdup(const char* string)
+{
+ const size_t size = strlen(string) + 1;
+ char* result = (char*) malloc(size);
+ memcpy(result, string, size);
+ return result;
+}
+
+static GLEQevent* gleq_new_event(void)
+{
+ GLEQevent* event = gleq_queue.events + gleq_queue.head;
+ gleq_queue.head = (gleq_queue.head + 1) % GLEQ_CAPACITY;
+ assert(gleq_queue.head != gleq_queue.tail);
+ memset(event, 0, sizeof(GLEQevent));
+ return event;
+}
+
+static void gleq_window_pos_callback(GLFWwindow* window, int x, int y)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_WINDOW_MOVED;
+ event->window = window;
+ event->pos.x = x;
+ event->pos.y = y;
+}
+
+static void gleq_window_size_callback(GLFWwindow* window, int width, int height)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_WINDOW_RESIZED;
+ event->window = window;
+ event->size.width = width;
+ event->size.height = height;
+}
+
+static void gleq_window_close_callback(GLFWwindow* window)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_WINDOW_CLOSED;
+ event->window = window;
+}
+
+static void gleq_window_refresh_callback(GLFWwindow* window)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_WINDOW_REFRESH;
+ event->window = window;
+}
+
+static void gleq_window_focus_callback(GLFWwindow* window, int focused)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+
+ if (focused)
+ event->type = GLEQ_WINDOW_FOCUSED;
+ else
+ event->type = GLEQ_WINDOW_DEFOCUSED;
+}
+
+static void gleq_window_iconify_callback(GLFWwindow* window, int iconified)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+
+ if (iconified)
+ event->type = GLEQ_WINDOW_ICONIFIED;
+ else
+ event->type = GLEQ_WINDOW_UNICONIFIED;
+}
+
+static void gleq_framebuffer_size_callback(GLFWwindow* window, int width, int height)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_FRAMEBUFFER_RESIZED;
+ event->window = window;
+ event->size.width = width;
+ event->size.height = height;
+}
+
+static void gleq_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+ event->mouse.button = button;
+ event->mouse.mods = mods;
+
+ if (action == GLFW_PRESS)
+ event->type = GLEQ_BUTTON_PRESSED;
+ else if (action == GLFW_RELEASE)
+ event->type = GLEQ_BUTTON_RELEASED;
+}
+
+static void gleq_cursor_pos_callback(GLFWwindow* window, double x, double y)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_CURSOR_MOVED;
+ event->window = window;
+ event->pos.x = (int) x;
+ event->pos.y = (int) y;
+}
+
+static void gleq_cursor_enter_callback(GLFWwindow* window, int entered)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+
+ if (entered)
+ event->type = GLEQ_CURSOR_ENTERED;
+ else
+ event->type = GLEQ_CURSOR_LEFT;
+}
+
+static void gleq_scroll_callback(GLFWwindow* window, double x, double y)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_SCROLLED;
+ event->window = window;
+ event->scroll.x = x;
+ event->scroll.y = y;
+}
+
+static void gleq_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+ event->keyboard.key = key;
+ event->keyboard.scancode = scancode;
+ event->keyboard.mods = mods;
+
+ if (action == GLFW_PRESS)
+ event->type = GLEQ_KEY_PRESSED;
+ else if (action == GLFW_RELEASE)
+ event->type = GLEQ_KEY_RELEASED;
+ else if (action == GLFW_REPEAT)
+ event->type = GLEQ_KEY_REPEATED;
+}
+
+static void gleq_char_callback(GLFWwindow* window, unsigned int codepoint)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_CODEPOINT_INPUT;
+ event->window = window;
+ event->codepoint = codepoint;
+}
+
+static void gleq_monitor_callback(GLFWmonitor* monitor, int action)
+{
+ GLEQevent* event = gleq_new_event();
+ event->monitor = monitor;
+
+ if (action == GLFW_CONNECTED)
+ event->type = GLEQ_MONITOR_CONNECTED;
+ else if (action == GLFW_DISCONNECTED)
+ event->type = GLEQ_MONITOR_DISCONNECTED;
+}
+
+#if GLFW_VERSION_MINOR >= 1
+static void gleq_file_drop_callback(GLFWwindow* window, int count, const char** paths)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_FILE_DROPPED;
+ event->window = window;
+ event->file.paths = (char**) malloc(count * sizeof(char*));
+ event->file.count = count;
+
+ while (count--)
+ event->file.paths[count] = gleq_strdup(paths[count]);
+}
+#endif
+
+#if GLFW_VERSION_MINOR >= 2
+static void gleq_joystick_callback(int jid, int action)
+{
+ GLEQevent* event = gleq_new_event();
+ event->joystick = jid;
+
+ if (action == GLFW_CONNECTED)
+ event->type = GLEQ_JOYSTICK_CONNECTED;
+ else if (action == GLFW_DISCONNECTED)
+ event->type = GLEQ_JOYSTICK_DISCONNECTED;
+}
+#endif
+
+#if GLFW_VERSION_MINOR >= 3
+static void gleq_window_maximize_callback(GLFWwindow* window, int maximized)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+
+ if (maximized)
+ event->type = GLEQ_WINDOW_MAXIMIZED;
+ else
+ event->type = GLEQ_WINDOW_UNMAXIMIZED;
+}
+
+static void gleq_window_content_scale_callback(GLFWwindow* window, float xscale, float yscale)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+ event->type = GLEQ_WINDOW_SCALE_CHANGED;
+ event->scale.x = xscale;
+ event->scale.y = yscale;
+}
+#endif
+
+GLEQDEF void gleqInit(void)
+{
+ glfwSetMonitorCallback(gleq_monitor_callback);
+#if GLFW_VERSION_MINOR >= 2
+ glfwSetJoystickCallback(gleq_joystick_callback);
+#endif
+}
+
+GLEQDEF void gleqTrackWindow(GLFWwindow* window)
+{
+ glfwSetWindowPosCallback(window, gleq_window_pos_callback);
+ glfwSetWindowSizeCallback(window, gleq_window_size_callback);
+ glfwSetWindowCloseCallback(window, gleq_window_close_callback);
+ glfwSetWindowRefreshCallback(window, gleq_window_refresh_callback);
+ glfwSetWindowFocusCallback(window, gleq_window_focus_callback);
+ glfwSetWindowIconifyCallback(window, gleq_window_iconify_callback);
+ glfwSetFramebufferSizeCallback(window, gleq_framebuffer_size_callback);
+ glfwSetMouseButtonCallback(window, gleq_mouse_button_callback);
+ glfwSetCursorPosCallback(window, gleq_cursor_pos_callback);
+ glfwSetCursorEnterCallback(window, gleq_cursor_enter_callback);
+ glfwSetScrollCallback(window, gleq_scroll_callback);
+ glfwSetKeyCallback(window, gleq_key_callback);
+ glfwSetCharCallback(window, gleq_char_callback);
+#if GLFW_VERSION_MINOR >= 1
+ glfwSetDropCallback(window, gleq_file_drop_callback);
+#endif
+#if GLFW_VERSION_MINOR >= 3
+ glfwSetWindowMaximizeCallback(window, gleq_window_maximize_callback);
+ glfwSetWindowContentScaleCallback(window, gleq_window_content_scale_callback);
+#endif
+}
+
+GLEQDEF int gleqNextEvent(GLEQevent* event)
+{
+ memset(event, 0, sizeof(GLEQevent));
+
+ if (gleq_queue.head != gleq_queue.tail)
+ {
+ *event = gleq_queue.events[gleq_queue.tail];
+ gleq_queue.tail = (gleq_queue.tail + 1) % GLEQ_CAPACITY;
+ }
+
+ return event->type != GLEQ_NONE;
+}
+
+GLEQDEF void gleqFreeEvent(GLEQevent* event)
+{
+#if GLFW_VERSION_MINOR >= 1
+ if (event->type == GLEQ_FILE_DROPPED)
+ {
+ while (event->file.count--)
+ free(event->file.paths[event->file.count]);
+
+ free(event->file.paths);
+ }
+#endif
+
+ memset(event, 0, sizeof(GLEQevent));
+}
+
+#endif /* GLEQ_IMPLEMENTATION */
+
+#endif /* GLEQ_HEADER_FILE */
+#line 0
+#line 1 "3rd_lite_sys.h"
+// lite editor, platform details
+// - rlyeh, public domain
+
+#define LT_DATAPATH "/lite"
+
+#define lt_assert(x) ASSERT(x)
+
+#define lt_realpath(p, q) file_pathabs(p)
+#define lt_realpath_free(p)
+
+#define lt_malloc(n) MALLOC(n)
+#define lt_calloc(n,m) CALLOC(n,m)
+#define lt_free(p) FREE(p)
+#define lt_memcpy(d,s,c) memcpy(d,s,c)
+#define lt_memset(p,ch,c) memset(p,ch,c)
+
+#define lt_time_ms() time_ms()
+#define lt_sleep_ms(ms) sleep_ms(ms)
+
+#define lt_getclipboard(w) window_clipboard()
+#define lt_setclipboard(w,s) window_setclipboard(s)
+
+#define lt_window() window_handle()
+#define lt_setwindowmode(m) window_fullscreen(m == 2), (m < 2 && (window_maximize(m),1)) // 0:normal,1:maximized,2:fullscreen
+#define lt_setwindowtitle(t) //window_title(t)
+#define lt_haswindowfocus() window_has_focus()
+#define lt_setcursor(shape) window_cursor_shape(lt_events & (1<<31) ? CURSOR_SW_AUTO : shape+1) // 0:arrow,1:ibeam,2:sizeh,3:sizev,4:hand
+
+#define lt_prompt(msg,title) ifndef(win32, 0, (MessageBoxA(0, msg, title, MB_YESNO | MB_ICONWARNING) == IDYES))
+
+unsigned lt_events = ~0u;
+int lt_mx = 0, lt_my = 0, lt_wx = 0, lt_wy = 0, lt_ww = 0, lt_wh = 0;
+
+typedef struct lt_surface {
+ unsigned w, h;
+ void *pixels;
+ texture_t t;
+} lt_surface;
+
+typedef struct lt_rect {
+ int x, y, width, height;
+} lt_rect;
+
+lt_surface *lt_getsurface(void *window) {
+ static lt_surface s = {0};
+ return &s;
+}
+void lt_updatesurfacerects(lt_surface *s, lt_rect* rects, unsigned count) {
+ if(0)
+ for( int i = 0; i < count; ++i ) {
+ memset( (unsigned*)s->pixels + (rects[i].x + rects[i].y * s->w), 0xFF, rects[i].width*4 );
+ memset( (unsigned*)s->pixels + (rects[i].x + (rects[i].y + (rects[i].height-1)) * s->w), 0xFF, rects[i].width*4 );
+ for( int y = 1; y < (rects[i].height-1); ++y ) {
+ ((unsigned*)s->pixels)[ rects[i].x + y * s->w ] =
+ ((unsigned*)s->pixels)[ rects[i].x + (rects[i].width-1) + y * s->w ] = 0xFFFFFFFF;
+ }
+ }
+
+ // update contents
+ texture_update(&s->t, s->w, s->h, 4, s->pixels, TEXTURE_LINEAR|TEXTURE_BGRA);
+}
+
+void ren_set_clip_rect(struct lt_rect rect);
+void rencache_invalidate(void);
+int lt_resizesurface(lt_surface *s, int ww, int wh) {
+ s->w = ww, s->h = wh;
+ if( s->t.id == 0 || s->w != s->t.w || s->h != s->t.h ) {
+ // invalidate tiles
+ ren_set_clip_rect( (lt_rect) { 0, 0, s->w, s->h } );
+ rencache_invalidate();
+
+ // texture clear
+ if( !s->t.id ) s->t = texture_create(1, 1, 4, " ", TEXTURE_LINEAR|TEXTURE_RGBA|TEXTURE_BYTE );
+ s->pixels = REALLOC(s->pixels, s->w * s->h * 4);
+ memset(s->pixels, 0, s->w * s->h * 4);
+
+ // texture update
+ lt_updatesurfacerects(s,0,0);
+ return 1; // resized
+ }
+ return 0; // unchanged
+}
+
+void *lt_load_file(const char *filename, int *size) {
+ int datalen; char *data = file_load(filename, &datalen);
+ if( !data || !datalen ) {
+ filename = (const char *)file_normalize(filename);
+ if( strbegi(filename, app_path()) ) filename += strlen(app_path());
+ data = vfs_load(filename, &datalen);
+ }
+ if (size) *size = 0;
+ if (!data) { return NULL; }
+ if (size) *size = datalen;
+ // return permanent buffers here, as file_load() and vfs_load() do return temporaries
+ data = memcpy(MALLOC(datalen+1), data, datalen);
+ data[datalen] = 0;
+ return data;
+}
+
+const char* lt_button_name(int button) {
+ if(button == GLFW_MOUSE_BUTTON_LEFT) return "left";
+ if(button == GLFW_MOUSE_BUTTON_RIGHT) return "right";
+ if(button == GLFW_MOUSE_BUTTON_MIDDLE) return "middle";
+ return "?";
+}
+
+char* lt_key_name(char *dst, int key, int vk, int mods) {
+ // @todo: "altgr" -> left ctrl + right alt
+
+ if( key == GLFW_KEY_UP ) return "up";
+ if( key == GLFW_KEY_DOWN ) return "down";
+ if( key == GLFW_KEY_LEFT ) return "left";
+ if( key == GLFW_KEY_RIGHT ) return "right";
+ if( key == GLFW_KEY_LEFT_ALT ) return "left alt";
+ if( key == GLFW_KEY_RIGHT_ALT ) return "right alt";
+ if( key == GLFW_KEY_LEFT_SHIFT ) return "left shift";
+ if( key == GLFW_KEY_RIGHT_SHIFT ) return "right shift";
+ if( key == GLFW_KEY_LEFT_CONTROL ) return "left ctrl";
+ if( key == GLFW_KEY_RIGHT_CONTROL ) return "right ctrl";
+ if( key == GLFW_KEY_LEFT_SUPER ) return "left windows";
+ if( key == GLFW_KEY_RIGHT_SUPER ) return "left windows";
+ if( key == GLFW_KEY_MENU ) return "menu";
+
+ if( key == GLFW_KEY_ESCAPE ) return "escape";
+ if( key == GLFW_KEY_BACKSPACE ) return "backspace";
+ if( key == GLFW_KEY_ENTER ) return "return";
+ if( key == GLFW_KEY_KP_ENTER ) return "keypad enter";
+ if( key == GLFW_KEY_TAB ) return "tab";
+ if( key == GLFW_KEY_CAPS_LOCK ) return "capslock";
+
+ if( key == GLFW_KEY_HOME ) return "home";
+ if( key == GLFW_KEY_END ) return "end";
+ if( key == GLFW_KEY_INSERT ) return "insert";
+ if( key == GLFW_KEY_DELETE ) return "delete";
+ if( key == GLFW_KEY_PAGE_UP ) return "pageup";
+ if( key == GLFW_KEY_PAGE_DOWN ) return "pagedown";
+
+ if( key == GLFW_KEY_F1 ) return "f1";
+ if( key == GLFW_KEY_F2 ) return "f2";
+ if( key == GLFW_KEY_F3 ) return "f3";
+ if( key == GLFW_KEY_F4 ) return "f4";
+ if( key == GLFW_KEY_F5 ) return "f5";
+ if( key == GLFW_KEY_F6 ) return "f6";
+ if( key == GLFW_KEY_F7 ) return "f7";
+ if( key == GLFW_KEY_F8 ) return "f8";
+ if( key == GLFW_KEY_F9 ) return "f9";
+ if( key == GLFW_KEY_F10 ) return "f10";
+ if( key == GLFW_KEY_F11 ) return "f11";
+ if( key == GLFW_KEY_F12 ) return "f12";
+
+ const char *name = glfwGetKeyName(key, vk);
+ strcpy(dst, name ? name : "");
+ char *p = dst;
+ while (*p) {
+ *p = tolower(*p);
+ p++;
+ }
+ return dst;
+}
+
+void lt_globpath(struct lua_State*L, const char *path) {
+ unsigned j = 0;
+
+ if(!strend(path, "/")) path = (const char *)va("%s/", path);
+ for( dir *d = dir_open(path, ""); d; dir_close(d), d = 0 ) {
+ for( unsigned i = 0, end = dir_count(d); i < end; ++i ) {
+ char *name = dir_name(d,i);
+ char *last = name + strlen(name) - 1;
+ if( *last == '/' ) *last = '\0';
+ name = file_name(name);
+ lua_pushstring(L, name);
+ lua_rawseti(L, -2, ++j);
+ }
+ }
+
+ for( const char *section = strstri(path, LT_DATAPATH); section && section[sizeof(LT_DATAPATH)-1] == '/'; section = 0) {
+ array(char*) list = vfs_list("**");
+ for( unsigned i = 0, end = array_count(list); i < end; ++i ) {
+ char *name = list[i];
+ if( !strstri(name, section+1) ) continue;
+ lua_pushstring(L, file_name(name));
+ lua_rawseti(L, -2, ++j);
+ }
+ if( array_count(list) ) return;
+ }
+}
+
+int lt_emit_event(lua_State *L, const char *event_name, const char *event_fmt, ...) {
+ int count = 0;
+ lua_pushstring(L, event_name);
+ if( event_fmt ) {
+ va_list va;
+ va_start(va, event_fmt);
+ for( ; event_fmt[count]; ++count ) {
+ /**/ if( event_fmt[count] == 'd' ) { int d = va_arg(va, int); lua_pushnumber(L, d); }
+ else if( event_fmt[count] == 'f' ) { double f = va_arg(va, double); lua_pushnumber(L, f); }
+ else if( event_fmt[count] == 's' ) { const char *s = va_arg(va, const char *); lua_pushstring(L, s); }
+ }
+ va_end(va);
+ }
+ return 1+count;
+}
+
+int printi(int i) {
+ // printf("clicks: %d\n", i);
+ return i;
+}
+
+static const char* codepoint_to_utf8(unsigned c);
+int lt_poll_event(lua_State *L) { // init.lua > core.step() wakes on mousemoved || inputtext
+ int rc = 0;
+ char buf[16];
+ static int prevx = 0, prevy = 0;
+
+ static unsigned clicks_time = 0, clicks = 0;
+ if( (lt_time_ms() - clicks_time) > 400 ) clicks = 0;
+
+ //
+
+ for( GLEQevent e; gleqNextEvent(&e); gleqFreeEvent(&e) )
+ if( lt_events & e.type )
+ switch (e.type) {
+ default:
+ break; case GLEQ_WINDOW_CLOSED: // it used to be ok. depends on window_swap() flow
+ rc += lt_emit_event(L, "quit", NULL);
+ return rc;
+
+ break; case GLEQ_WINDOW_MOVED:
+ lt_wx = e.pos.x;
+ lt_wy = e.pos.y;
+
+ break; case GLEQ_WINDOW_RESIZED:
+ rc += lt_emit_event(L, "resized", "dd", lt_ww = e.size.width, lt_wh = e.size.height);
+ lt_resizesurface(lt_getsurface(lt_window()), lt_ww, lt_wh);
+
+ break; case GLEQ_WINDOW_REFRESH:
+ rc += lt_emit_event(L, "exposed", NULL);
+ rencache_invalidate();
+
+ break; case GLEQ_FILE_DROPPED:
+ rc += lt_emit_event(L, "filedropped", "sdd", e.file.paths[0], lt_mx, lt_my);
+
+ break; case GLEQ_KEY_PRESSED:
+ case GLEQ_KEY_REPEATED:
+ rc += lt_emit_event(L, "keypressed", "s", lt_key_name(buf, e.keyboard.key, e.keyboard.scancode, e.keyboard.mods));
+ goto bottom;
+
+ break; case GLEQ_KEY_RELEASED:
+ rc += lt_emit_event(L, "keyreleased", "s", lt_key_name(buf, e.keyboard.key, e.keyboard.scancode, e.keyboard.mods));
+ goto bottom;
+
+ break; case GLEQ_CODEPOINT_INPUT:
+ rc += lt_emit_event(L, "textinput", "s", codepoint_to_utf8(e.codepoint));
+
+ break; case GLEQ_BUTTON_PRESSED:
+ rc += lt_emit_event(L, "mousepressed", "sddd", lt_button_name(e.mouse.button), lt_mx, lt_my, printi(1 + clicks));
+
+ break; case GLEQ_BUTTON_RELEASED:
+ clicks += e.mouse.button == GLFW_MOUSE_BUTTON_1;
+ clicks_time = lt_time_ms();
+ rc += lt_emit_event(L, "mousereleased", "sdd", lt_button_name(e.mouse.button), lt_mx, lt_my);
+
+ break; case GLEQ_CURSOR_MOVED:
+ lt_mx = e.pos.x - lt_wx, lt_my = e.pos.y - lt_wy;
+ rc += lt_emit_event(L, "mousemoved", "dddd", lt_mx, lt_my, lt_mx - prevx, lt_my - prevy);
+ prevx = lt_mx, prevy = lt_my;
+
+ break; case GLEQ_SCROLLED:
+ rc += lt_emit_event(L, "mousewheel", "f", e.scroll.y);
+ }
+
+bottom:;
+
+ return rc;
+}
+#line 0
+#line 1 "3rd_lite.h"
+// Copyright (c) 2020 rxi
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+// [doc] https://rxi.github.io/lite_an_implementation_overview.html
+// [chg] differences from https://github.com/rxi/lite listed below:
+//
+// a) amalgamated as single-file source.
+// b) platform agnostic now (no more specific SDL calls; tested with GLFW backend).
+// c) specific `lt_` platform bits have been moved out to an external file (lite_sys.h)
+// d) lua, stb-truetype and lite_sys headers *must be included* beforehand.
+// e) embeddable: reverted loop handler from framework to library mode. see: lt_init/lt_tick
+// f) data folders reorganized as data/themes, data/languages/ and data/plugins/.
+// g) DATADIR path can be specified now and no longer forced to be EXEDIR/data/.
+// h) packaged with a bunch of handy plugins from https://github.com/rxi/lite-plugins
+// i) packaged with all color themes from https://github.com/rxi/lite-colors
+// j) merged a few pending PRs and pending fixes from original repo.
+// k) Lua sources fixed for Lua >= 5.2
+//
+// All contributions released under same MIT licensing terms than original code.
+// - rlyeh.
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef S_ISDIR
+#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+
+#ifndef S_ISREG
+#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+
+// ----------------------------------------------------------------------------
+// lite/api.h
+
+#define API_TYPE_FONT "Font"
+
+// ----------------------------------------------------------------------------
+// lite/renderer.h
+
+typedef struct RenImage RenImage;
+typedef struct RenFont RenFont;
+
+typedef struct { uint8_t b, g, r, a; } RenColor;
+//typedef struct { int x, y, width, height; } RenRect;
+typedef lt_rect RenRect;
+
+
+void ren_init(void *win);
+void ren_update_rects(RenRect *rects, int count);
+void ren_set_clip_rect(RenRect rect);
+void ren_get_size(int *x, int *y);
+
+RenImage* ren_new_image(int width, int height);
+void ren_free_image(RenImage *image);
+
+RenFont* ren_load_font(const char *filename, float size);
+void ren_free_font(RenFont *font);
+void ren_set_font_tab_width(RenFont *font, int n);
+int ren_get_font_tab_width(RenFont *font);
+int ren_get_font_width(RenFont *font, const char *text);
+int ren_get_font_height(RenFont *font);
+
+void ren_draw_rect(RenRect rect, RenColor color);
+void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color);
+int ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color);
+
+// ----------------------------------------------------------------------------
+// lite/rencache.h
+
+void rencache_show_debug(bool enable);
+void rencache_free_font(RenFont *font);
+void rencache_set_clip_rect(RenRect rect);
+void rencache_draw_rect(RenRect rect, RenColor color);
+int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor color);
+void rencache_invalidate(void);
+void rencache_begin_frame(void);
+void rencache_end_frame(void);
+
+// ----------------------------------------------------------------------------
+// lite/renderer.c
+
+#define MAX_GLYPHSET 256
+
+struct RenImage {
+ RenColor *pixels;
+ int width, height;
+};
+
+typedef struct {
+ RenImage *image;
+ stbtt_bakedchar glyphs[256];
+} GlyphSet;
+
+struct RenFont {
+ void *data;
+ stbtt_fontinfo stbfont;
+ GlyphSet *sets[MAX_GLYPHSET];
+ float size;
+ int height;
+};
+
+static struct { int left, top, right, bottom; } lt_clip;
+
+static const char* codepoint_to_utf8(unsigned c) { //< @r-lyeh
+ static char s[4+1];
+ lt_memset(s, 0, 5);
+ /**/ if (c < 0x80) s[0] = c, s[1] = 0;
+ else if (c < 0x800) s[0] = 0xC0 | ((c >> 6) & 0x1F), s[1] = 0x80 | ( c & 0x3F), s[2] = 0;
+ else if (c < 0x10000) s[0] = 0xE0 | ((c >> 12) & 0x0F), s[1] = 0x80 | ((c >> 6) & 0x3F), s[2] = 0x80 | ( c & 0x3F), s[3] = 0;
+ else if (c < 0x110000) s[0] = 0xF0 | ((c >> 18) & 0x07), s[1] = 0x80 | ((c >> 12) & 0x3F), s[2] = 0x80 | ((c >> 6) & 0x3F), s[3] = 0x80 | (c & 0x3F), s[4] = 0;
+ return s;
+}
+static const char* utf8_to_codepoint(const char *p, unsigned *dst) {
+ unsigned res, n;
+ switch (*p & 0xf0) {
+ case 0xf0 : res = *p & 0x07; n = 3; break;
+ case 0xe0 : res = *p & 0x0f; n = 2; break;
+ case 0xd0 :
+ case 0xc0 : res = *p & 0x1f; n = 1; break;
+ default : res = *p; n = 0; break;
+ }
+ while (n-- && *p++) { //< https://github.com/rxi/lite/issues/262
+ res = (res << 6) | (*p & 0x3f); //< https://github.com/rxi/lite/issues/262
+ }
+ *dst = res;
+ return p + 1;
+}
+
+void ren_init(void *win) {
+ lt_surface *surf = lt_getsurface(lt_window());
+ ren_set_clip_rect( (RenRect) { 0, 0, surf->w, surf->h } );
+}
+
+
+void ren_update_rects(RenRect *rects, int count) {
+ lt_updatesurfacerects(lt_getsurface(lt_window()), (lt_rect*) rects, count);
+}
+
+
+void ren_set_clip_rect(RenRect rect) {
+ lt_clip.left = rect.x;
+ lt_clip.top = rect.y;
+ lt_clip.right = rect.x + rect.width;
+ lt_clip.bottom = rect.y + rect.height;
+}
+
+
+void ren_get_size(int *x, int *y) {
+ lt_surface *surf = lt_getsurface(lt_window());
+ *x = surf->w;
+ *y = surf->h;
+}
+
+
+RenImage* ren_new_image(int width, int height) {
+ lt_assert(width > 0 && height > 0);
+ RenImage *image = lt_malloc(sizeof(RenImage) + width * height * sizeof(RenColor));
+ image->pixels = (void*) (image + 1);
+ image->width = width;
+ image->height = height;
+ return image;
+}
+
+
+void ren_free_image(RenImage *image) {
+ lt_free(image);
+}
+
+
+static GlyphSet* load_glyphset(RenFont *font, int idx) {
+ GlyphSet *set = lt_calloc(1, sizeof(GlyphSet));
+
+ /* init image */
+ int width = 128;
+ int height = 128;
+retry:
+ set->image = ren_new_image(width, height);
+
+ /* load glyphs */
+ float s =
+ stbtt_ScaleForMappingEmToPixels(&font->stbfont, 1) /
+ stbtt_ScaleForPixelHeight(&font->stbfont, 1);
+ int res = stbtt_BakeFontBitmap(
+ font->data, 0, font->size * s, (void*) set->image->pixels,
+ width, height, idx * 256, 256, set->glyphs);
+
+ /* retry with a larger image buffer if the buffer wasn't large enough */
+ if (res < 0) {
+ width *= 2;
+ height *= 2;
+ ren_free_image(set->image);
+ goto retry;
+ }
+
+ /* adjust glyph yoffsets and xadvance */
+ int ascent, descent, linegap;
+ stbtt_GetFontVMetrics(&font->stbfont, &ascent, &descent, &linegap);
+ float scale = stbtt_ScaleForMappingEmToPixels(&font->stbfont, font->size);
+ int scaled_ascent = ascent * scale + 0.5;
+ for (int i = 0; i < 256; i++) {
+ set->glyphs[i].yoff += scaled_ascent;
+ set->glyphs[i].xadvance = floor(set->glyphs[i].xadvance);
+ }
+
+ /* convert 8bit data to 32bit */
+ for (int i = width * height - 1; i >= 0; i--) {
+ uint8_t n = *((uint8_t*) set->image->pixels + i);
+ set->image->pixels[i] = (RenColor) { .r = 255, .g = 255, .b = 255, .a = n };
+ }
+
+ return set;
+}
+
+
+static GlyphSet* get_glyphset(RenFont *font, int codepoint) {
+ int idx = (codepoint >> 8) % MAX_GLYPHSET;
+ if (!font->sets[idx]) {
+ font->sets[idx] = load_glyphset(font, idx);
+ }
+ return font->sets[idx];
+}
+
+
+RenFont* ren_load_font(const char *filename, float size) {
+ /* load font into buffer */ //< @r-lyeh: load font file before allocating `font`
+ char *fontdata = lt_load_file(filename, NULL);
+ if( !fontdata ) return NULL;
+
+ RenFont *font = NULL;
+
+ /* init font */
+ font = lt_calloc(1, sizeof(RenFont));
+ font->size = size;
+ font->data = fontdata;
+
+ /* init stbfont */
+ int ok = stbtt_InitFont(&font->stbfont, font->data, 0);
+ if (!ok) {
+ if (font) { lt_free(font->data); }
+ lt_free(font);
+ return NULL;
+ }
+
+ /* get height and scale */
+ int ascent, descent, linegap;
+ stbtt_GetFontVMetrics(&font->stbfont, &ascent, &descent, &linegap);
+ float scale = stbtt_ScaleForMappingEmToPixels(&font->stbfont, size);
+ font->height = (ascent - descent + linegap) * scale + 0.5;
+
+ /* make tab and newline glyphs invisible */
+ stbtt_bakedchar *g = get_glyphset(font, '\n')->glyphs;
+ g['\t'].x1 = g['\t'].x0;
+ g['\n'].x1 = g['\n'].x0;
+
+ return font;
+}
+
+
+void ren_free_font(RenFont *font) {
+ for (int i = 0; i < MAX_GLYPHSET; i++) {
+ GlyphSet *set = font->sets[i];
+ if (set) {
+ ren_free_image(set->image);
+ lt_free(set);
+ }
+ }
+ lt_free(font->data);
+ lt_free(font);
+}
+
+
+void ren_set_font_tab_width(RenFont *font, int n) {
+ GlyphSet *set = get_glyphset(font, '\t');
+ set->glyphs['\t'].xadvance = n;
+}
+
+
+int ren_get_font_tab_width(RenFont *font) {
+ GlyphSet *set = get_glyphset(font, '\t');
+ return set->glyphs['\t'].xadvance;
+}
+
+
+int ren_get_font_width(RenFont *font, const char *text) {
+ int x = 0;
+ const char *p = text;
+ unsigned codepoint;
+ while (*p) {
+ p = utf8_to_codepoint(p, &codepoint);
+ GlyphSet *set = get_glyphset(font, codepoint);
+ stbtt_bakedchar *g = &set->glyphs[codepoint & 0xff];
+ x += g->xadvance;
+ }
+ return x;
+}
+
+
+int ren_get_font_height(RenFont *font) {
+ return font->height;
+}
+
+
+static inline RenColor blend_pixel(RenColor dst, RenColor src) {
+ int ia = 0xff - src.a;
+ dst.r = ((src.r * src.a) + (dst.r * ia)) >> 8;
+ dst.g = ((src.g * src.a) + (dst.g * ia)) >> 8;
+ dst.b = ((src.b * src.a) + (dst.b * ia)) >> 8;
+ return dst;
+}
+
+
+static inline RenColor blend_pixel2(RenColor dst, RenColor src, RenColor color) {
+ src.a = (src.a * color.a) >> 8;
+ int ia = 0xff - src.a;
+ dst.r = ((src.r * color.r * src.a) >> 16) + ((dst.r * ia) >> 8);
+ dst.g = ((src.g * color.g * src.a) >> 16) + ((dst.g * ia) >> 8);
+ dst.b = ((src.b * color.b * src.a) >> 16) + ((dst.b * ia) >> 8);
+ return dst;
+}
+
+
+#define rect_draw_loop(expr) \
+ for (int j = y1; j < y2; j++) { \
+ for (int i = x1; i < x2; i++) { \
+ *d = expr; \
+ d++; \
+ } \
+ d += dr; \
+ }
+
+void ren_draw_rect(RenRect rect, RenColor color) {
+ if (color.a == 0) { return; }
+
+ int x1 = rect.x < lt_clip.left ? lt_clip.left : rect.x;
+ int y1 = rect.y < lt_clip.top ? lt_clip.top : rect.y;
+ int x2 = rect.x + rect.width;
+ int y2 = rect.y + rect.height;
+ x2 = x2 > lt_clip.right ? lt_clip.right : x2;
+ y2 = y2 > lt_clip.bottom ? lt_clip.bottom : y2;
+
+ lt_surface *surf = lt_getsurface(lt_window());
+ RenColor *d = (RenColor*) surf->pixels;
+ d += x1 + y1 * surf->w;
+ int dr = surf->w - (x2 - x1);
+
+ if (color.a == 0xff) {
+ rect_draw_loop(color);
+ } else {
+ rect_draw_loop(blend_pixel(*d, color));
+ }
+}
+
+
+void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color) {
+ if (color.a == 0) { return; }
+
+ /* clip */
+ int n;
+ if ((n = lt_clip.left - x) > 0) { sub->width -= n; sub->x += n; x += n; }
+ if ((n = lt_clip.top - y) > 0) { sub->height -= n; sub->y += n; y += n; }
+ if ((n = x + sub->width - lt_clip.right ) > 0) { sub->width -= n; }
+ if ((n = y + sub->height - lt_clip.bottom) > 0) { sub->height -= n; }
+
+ if (sub->width <= 0 || sub->height <= 0) {
+ return;
+ }
+
+ /* draw */
+ lt_surface *surf = lt_getsurface(lt_window());
+ RenColor *s = image->pixels;
+ RenColor *d = (RenColor*) surf->pixels;
+ s += sub->x + sub->y * image->width;
+ d += x + y * surf->w;
+ int sr = image->width - sub->width;
+ int dr = surf->w - sub->width;
+
+ for (int j = 0; j < sub->height; j++) {
+ for (int i = 0; i < sub->width; i++) {
+ *d = blend_pixel2(*d, *s, color);
+ d++;
+ s++;
+ }
+ d += dr;
+ s += sr;
+ }
+}
+
+
+int ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) {
+ RenRect rect;
+ const char *p = text;
+ unsigned codepoint;
+ while (*p) {
+ p = utf8_to_codepoint(p, &codepoint);
+ GlyphSet *set = get_glyphset(font, codepoint);
+ stbtt_bakedchar *g = &set->glyphs[codepoint & 0xff];
+ rect.x = g->x0;
+ rect.y = g->y0;
+ rect.width = g->x1 - g->x0;
+ rect.height = g->y1 - g->y0;
+ ren_draw_image(set->image, &rect, x + g->xoff, y + g->yoff, color);
+ x += g->xadvance;
+ }
+ return x;
+}
+
+// ----------------------------------------------------------------------------
+// lite/renderer_font.c
+
+static int f_load(lua_State *L) {
+ const char *filename = luaL_checkstring(L, 1);
+ float size = luaL_checknumber(L, 2);
+ RenFont **self = lua_newuserdata(L, sizeof(*self));
+ luaL_setmetatable(L, API_TYPE_FONT);
+ *self = ren_load_font(filename, size);
+ if (!*self) { luaL_error(L, "failed to load font"); }
+ return 1;
+}
+
+
+static int f_set_tab_width(lua_State *L) {
+ RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT);
+ int n = luaL_checknumber(L, 2);
+ ren_set_font_tab_width(*self, n);
+ return 0;
+}
+
+
+static int f_GC(lua_State *L) {
+ RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT);
+ if (*self) { rencache_free_font(*self); }
+ return 0;
+}
+
+
+static int f_get_width(lua_State *L) {
+ RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT);
+ const char *text = luaL_checkstring(L, 2);
+ lua_pushnumber(L, ren_get_font_width(*self, text) );
+ return 1;
+}
+
+
+static int f_get_height(lua_State *L) {
+ RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT);
+ lua_pushnumber(L, ren_get_font_height(*self) );
+ return 1;
+}
+
+
+int luaopen_renderer_font(lua_State *L) {
+ static const luaL_Reg lib[] = {
+ { "__gc", f_GC },
+ { "load", f_load },
+ { "set_tab_width", f_set_tab_width },
+ { "get_width", f_get_width },
+ { "get_height", f_get_height },
+ { NULL, NULL }
+ };
+ luaL_newmetatable(L, API_TYPE_FONT);
+ luaL_setfuncs(L, lib, 0);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ return 1;
+}
+
+// ----------------------------------------------------------------------------
+// lite/renderer_api.c
+
+static RenColor checkcolor(lua_State *L, int idx, int def) {
+ RenColor color;
+ if (lua_isnoneornil(L, idx)) {
+ return (RenColor) { def, def, def, 255 };
+ }
+ lua_rawgeti(L, idx, 1);
+ lua_rawgeti(L, idx, 2);
+ lua_rawgeti(L, idx, 3);
+ lua_rawgeti(L, idx, 4);
+ color.r = luaL_checknumber(L, -4);
+ color.g = luaL_checknumber(L, -3);
+ color.b = luaL_checknumber(L, -2);
+ color.a = luaL_optnumber(L, -1, 255);
+ lua_pop(L, 4);
+ return color;
+}
+
+
+static int f_show_debug(lua_State *L) {
+ luaL_checkany(L, 1);
+ rencache_show_debug(lua_toboolean(L, 1));
+ return 0;
+}
+
+
+static int f_get_size(lua_State *L) {
+ int w, h;
+ ren_get_size(&w, &h);
+ lua_pushnumber(L, w);
+ lua_pushnumber(L, h);
+ return 2;
+}
+
+
+static int f_begin_frame(lua_State *L) {
+ rencache_begin_frame();
+ return 0;
+}
+
+
+static int f_end_frame(lua_State *L) {
+ rencache_end_frame();
+ return 0;
+}
+
+
+static int f_set_clip_rect(lua_State *L) {
+ RenRect rect;
+ rect.x = luaL_checknumber(L, 1);
+ rect.y = luaL_checknumber(L, 2);
+ rect.width = luaL_checknumber(L, 3);
+ rect.height = luaL_checknumber(L, 4);
+ rencache_set_clip_rect(rect);
+ return 0;
+}
+
+
+static int f_draw_rect(lua_State *L) {
+ RenRect rect;
+ rect.x = luaL_checknumber(L, 1);
+ rect.y = luaL_checknumber(L, 2);
+ rect.width = luaL_checknumber(L, 3);
+ rect.height = luaL_checknumber(L, 4);
+ RenColor color = checkcolor(L, 5, 255);
+ rencache_draw_rect(rect, color);
+ return 0;
+}
+
+
+static int f_draw_text(lua_State *L) {
+ RenFont **font = luaL_checkudata(L, 1, API_TYPE_FONT);
+ const char *text = luaL_checkstring(L, 2);
+ int x = luaL_checknumber(L, 3);
+ int y = luaL_checknumber(L, 4);
+ RenColor color = checkcolor(L, 5, 255);
+ x = rencache_draw_text(*font, text, x, y, color);
+ lua_pushnumber(L, x);
+ return 1;
+}
+
+int luaopen_renderer(lua_State *L) {
+ static const luaL_Reg lib[] = {
+ { "show_debug", f_show_debug },
+ { "get_size", f_get_size },
+ { "begin_frame", f_begin_frame },
+ { "end_frame", f_end_frame },
+ { "set_clip_rect", f_set_clip_rect },
+ { "draw_rect", f_draw_rect },
+ { "draw_text", f_draw_text },
+ { NULL, NULL }
+ };
+ luaL_newlib(L, lib);
+ luaopen_renderer_font(L);
+ lua_setfield(L, -2, "font");
+ return 1;
+}
+
+// ----------------------------------------------------------------------------
+// lite/rencache.c
+
+/* a cache over the software renderer -- all drawing operations are stored as
+** commands when issued. At the end of the frame we write the commands to a grid
+** of hash values, take the cells that have changed since the previous frame,
+** merge them into dirty rectangles and redraw only those regions */
+
+#define CELLS_X 80
+#define CELLS_Y 50
+#define CELL_SIZE 96
+#define COMMAND_BUF_SIZE (1024 * 512)
+
+enum { FREE_FONT, SET_CLIP, DRAW_TEXT, DRAW_RECT };
+
+typedef struct {
+ int type, size;
+ RenRect rect;
+ RenColor color;
+ RenFont *font;
+ int tab_width;
+ char text[0];
+} Command;
+
+
+static unsigned cells_buf1[CELLS_X * CELLS_Y];
+static unsigned cells_buf2[CELLS_X * CELLS_Y];
+static unsigned *cells_prev = cells_buf1;
+static unsigned *cells = cells_buf2;
+static RenRect rect_buf[CELLS_X * CELLS_Y / 2];
+static char command_buf[COMMAND_BUF_SIZE];
+static int command_buf_idx;
+static RenRect screen_rect;
+static bool show_debug;
+
+
+/* 32bit fnv-1a hash */
+#define HASH_INITIAL 2166136261
+
+static void hash(unsigned *h, const void *data, int size) {
+ const unsigned char *p = data;
+ while (size--) {
+ *h = (*h ^ *p++) * 16777619;
+ }
+}
+
+
+static inline int cell_idx(int x, int y) {
+ return x + y * CELLS_X;
+}
+
+
+static inline bool rects_overlap(RenRect a, RenRect b) {
+ return b.x + b.width >= a.x && b.x <= a.x + a.width
+ && b.y + b.height >= a.y && b.y <= a.y + a.height;
+}
+
+
+static RenRect intersect_rects(RenRect a, RenRect b) {
+ int x1 = maxi(a.x, b.x);
+ int y1 = maxi(a.y, b.y);
+ int x2 = mini(a.x + a.width, b.x + b.width);
+ int y2 = mini(a.y + a.height, b.y + b.height);
+ return (RenRect) { x1, y1, max(0, x2 - x1), max(0, y2 - y1) };
+}
+
+
+static RenRect merge_rects(RenRect a, RenRect b) {
+ int x1 = mini(a.x, b.x);
+ int y1 = mini(a.y, b.y);
+ int x2 = maxi(a.x + a.width, b.x + b.width);
+ int y2 = maxi(a.y + a.height, b.y + b.height);
+ return (RenRect) { x1, y1, x2 - x1, y2 - y1 };
+}
+
+
+static Command* push_command(int type, int size) {
+ size_t alignment = 7; // alignof(max_align_t) - 1; //< C11 https://github.com/rxi/lite/pull/292/commits/ad1bdf56e3f212446e1c61fd45de8b94de5e2bc3
+ size = (size + alignment) & ~alignment; //< https://github.com/rxi/lite/pull/292/commits/ad1bdf56e3f212446e1c61fd45de8b94de5e2bc3
+ Command *cmd = (Command*) (command_buf + command_buf_idx);
+ int n = command_buf_idx + size;
+ if (n > COMMAND_BUF_SIZE) {
+ fprintf(stderr, "Warning: (" __FILE__ "): exhausted command buffer\n");
+ return NULL;
+ }
+ command_buf_idx = n;
+ lt_memset(cmd, 0, sizeof(Command));
+ cmd->type = type;
+ cmd->size = size;
+ return cmd;
+}
+
+
+static bool next_command(Command **prev) {
+ if (*prev == NULL) {
+ *prev = (Command*) command_buf;
+ } else {
+ *prev = (Command*) (((char*) *prev) + (*prev)->size);
+ }
+ return *prev != ((Command*) (command_buf + command_buf_idx));
+}
+
+
+void rencache_show_debug(bool enable) {
+ show_debug = enable;
+}
+
+
+void rencache_free_font(RenFont *font) {
+ Command *cmd = push_command(FREE_FONT, sizeof(Command));
+ if (cmd) { cmd->font = font; }
+}
+
+
+void rencache_set_clip_rect(RenRect rect) {
+ Command *cmd = push_command(SET_CLIP, sizeof(Command));
+ if (cmd) { cmd->rect = intersect_rects(rect, screen_rect); }
+}
+
+
+void rencache_draw_rect(RenRect rect, RenColor color) {
+ if (!rects_overlap(screen_rect, rect)) { return; }
+ Command *cmd = push_command(DRAW_RECT, sizeof(Command));
+ if (cmd) {
+ cmd->rect = rect;
+ cmd->color = color;
+ }
+}
+
+
+int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) {
+ RenRect rect;
+ rect.x = x;
+ rect.y = y;
+ rect.width = ren_get_font_width(font, text);
+ rect.height = ren_get_font_height(font);
+
+ if (rects_overlap(screen_rect, rect)) {
+ int sz = strlen(text) + 1;
+ Command *cmd = push_command(DRAW_TEXT, sizeof(Command) + sz);
+ if (cmd) {
+ memcpy(cmd->text, text, sz);
+ cmd->color = color;
+ cmd->font = font;
+ cmd->rect = rect;
+ cmd->tab_width = ren_get_font_tab_width(font);
+ }
+ }
+
+ return x + rect.width;
+}
+
+
+void rencache_invalidate(void) {
+ lt_memset(cells_prev, 0xff, sizeof(cells_buf1));
+}
+
+
+void rencache_begin_frame(void) {
+ /* reset all cells if the screen width/height has changed */
+ int w, h;
+ ren_get_size(&w, &h);
+ if (screen_rect.width != w || h != screen_rect.height) {
+ screen_rect.width = w;
+ screen_rect.height = h;
+ rencache_invalidate();
+ }
+}
+
+
+static void update_overlapping_cells(RenRect r, unsigned h) {
+ int x1 = r.x / CELL_SIZE;
+ int y1 = r.y / CELL_SIZE;
+ int x2 = (r.x + r.width) / CELL_SIZE;
+ int y2 = (r.y + r.height) / CELL_SIZE;
+
+ for (int y = y1; y <= y2; y++) {
+ for (int x = x1; x <= x2; x++) {
+ int idx = cell_idx(x, y);
+ hash(&cells[idx], &h, sizeof(h));
+ }
+ }
+}
+
+
+static void push_rect(RenRect r, int *count) {
+ /* try to merge with existing rectangle */
+ for (int i = *count - 1; i >= 0; i--) {
+ RenRect *rp = &rect_buf[i];
+ if (rects_overlap(*rp, r)) {
+ *rp = merge_rects(*rp, r);
+ return;
+ }
+ }
+ /* couldn't merge with previous rectangle: push */
+ rect_buf[(*count)++] = r;
+}
+
+
+void rencache_end_frame(void) {
+ /* update cells from commands */
+ Command *cmd = NULL;
+ RenRect cr = screen_rect;
+ while (next_command(&cmd)) {
+ if (cmd->type == SET_CLIP) { cr = cmd->rect; }
+ RenRect r = intersect_rects(cmd->rect, cr);
+ if (r.width == 0 || r.height == 0) { continue; }
+ unsigned h = HASH_INITIAL;
+ hash(&h, cmd, cmd->size);
+ update_overlapping_cells(r, h);
+ }
+
+ /* push rects for all cells changed from last frame, reset cells */
+ int rect_count = 0;
+ int max_x = screen_rect.width / CELL_SIZE + 1;
+ int max_y = screen_rect.height / CELL_SIZE + 1;
+ for (int y = 0; y < max_y; y++) {
+ for (int x = 0; x < max_x; x++) {
+ /* compare previous and current cell for change */
+ int idx = cell_idx(x, y);
+ if (cells[idx] != cells_prev[idx]) {
+ push_rect((RenRect) { x, y, 1, 1 }, &rect_count);
+ }
+ cells_prev[idx] = HASH_INITIAL;
+ }
+ }
+
+ /* expand rects from cells to pixels */
+ for (int i = 0; i < rect_count; i++) {
+ RenRect *r = &rect_buf[i];
+ r->x *= CELL_SIZE;
+ r->y *= CELL_SIZE;
+ r->width *= CELL_SIZE;
+ r->height *= CELL_SIZE;
+ *r = intersect_rects(*r, screen_rect);
+ }
+
+ /* redraw updated regions */
+ bool has_free_commands = false;
+ for (int i = 0; i < rect_count; i++) {
+ /* draw */
+ RenRect r = rect_buf[i];
+ ren_set_clip_rect(r);
+
+ cmd = NULL;
+ while (next_command(&cmd)) {
+ switch (cmd->type) {
+ case FREE_FONT:
+ has_free_commands = true;
+ break;
+ case SET_CLIP:
+ ren_set_clip_rect(intersect_rects(cmd->rect, r));
+ break;
+ case DRAW_RECT:
+ ren_draw_rect(cmd->rect, cmd->color);
+ break;
+ case DRAW_TEXT:
+ ren_set_font_tab_width(cmd->font, cmd->tab_width);
+ ren_draw_text(cmd->font, cmd->text, cmd->rect.x, cmd->rect.y, cmd->color);
+ break;
+ }
+ }
+
+ if (show_debug) {
+ RenColor color = { rand(), rand(), rand(), 50 };
+ ren_draw_rect(r, color);
+ }
+ }
+
+ /* update dirty rects */
+ if (rect_count > 0) {
+ ren_update_rects(rect_buf, rect_count);
+ }
+
+ /* free fonts */
+ if (has_free_commands) {
+ cmd = NULL;
+ while (next_command(&cmd)) {
+ if (cmd->type == FREE_FONT) {
+ ren_free_font(cmd->font);
+ }
+ }
+ }
+
+ /* swap cell buffer and reset */
+ unsigned *tmp = cells;
+ cells = cells_prev;
+ cells_prev = tmp;
+ command_buf_idx = 0;
+}
+
+// ----------------------------------------------------------------------------
+// lite/system.c
+
+static int f_set_cursor(lua_State *L) {
+ static const char *cursor_opts[] = {
+ "arrow",
+ "ibeam",
+ "sizeh",
+ "sizev",
+ "hand",
+ NULL
+ };
+ int n = luaL_checkoption(L, 1, "arrow", cursor_opts);
+ lt_setcursor(n);
+ return 0;
+}
+
+static int f_set_window_title(lua_State *L) {
+ const char *title = luaL_checkstring(L, 1);
+ lt_setwindowtitle(title);
+ return 0;
+}
+static int f_set_window_mode(lua_State *L) {
+ static const char *window_opts[] = { "normal", "maximized", "fullscreen", 0 };
+ enum { WIN_NORMAL, WIN_MAXIMIZED, WIN_FULLSCREEN };
+ int n = luaL_checkoption(L, 1, "normal", window_opts);
+ lt_setwindowmode(n);
+ return 0;
+}
+static int f_window_has_focus(lua_State *L) {
+ unsigned flags = lt_haswindowfocus();
+ lua_pushboolean(L, flags);
+ return 1;
+}
+
+static int f_show_confirm_dialog(lua_State *L) {
+ const char *title = luaL_checkstring(L, 1);
+ const char *msg = luaL_checkstring(L, 2);
+ int id = lt_prompt(msg, title); // 0:no, 1:yes
+ lua_pushboolean(L, !!id);
+ return 1;
+}
+
+static int f_chdir(lua_State *L) {
+ const char *path = luaL_checkstring(L, 1);
+ int err = chdir(path);
+ if (err) { luaL_error(L, "chdir() failed"); }
+ return 0;
+}
+static int f_list_dir(lua_State *L) {
+ const char *path = luaL_checkstring(L, 1);
+ lua_newtable(L);
+ lt_globpath(L, path);
+ return 1;
+}
+static int f_absolute_path(lua_State *L) {
+ const char *path = luaL_checkstring(L, 1);
+ char *res = lt_realpath(path, NULL);
+ if (!res) { return 0; }
+ lua_pushstring(L, res);
+ lt_realpath_free(res);
+ return 1;
+}
+static int f_get_file_info(lua_State *L) {
+ const char *path = luaL_checkstring(L, 1);
+
+ struct stat s;
+ int err = stat(path, &s);
+ if (err < 0) {
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(errno));
+ return 2;
+ }
+
+ lua_newtable(L);
+ lua_pushnumber(L, s.st_mtime);
+ lua_setfield(L, -2, "modified");
+
+ lua_pushnumber(L, s.st_size);
+ lua_setfield(L, -2, "size");
+
+ if (S_ISREG(s.st_mode)) {
+ lua_pushstring(L, "file");
+ } else if (S_ISDIR(s.st_mode)) {
+ lua_pushstring(L, "dir");
+ } else {
+ lua_pushnil(L);
+ }
+ lua_setfield(L, -2, "type");
+
+ return 1;
+}
+
+
+static int f_get_clipboard(lua_State *L) {
+ const char *text = lt_getclipboard(lt_window());
+ if (!text) { return 0; }
+ lua_pushstring(L, text);
+ return 1;
+}
+static int f_set_clipboard(lua_State *L) {
+ const char *text = luaL_checkstring(L, 1);
+ lt_setclipboard(lt_window(), text);
+ return 0;
+}
+
+
+static int f_get_time(lua_State *L) {
+ double ss = lt_time_ms() / 1000.0;
+ lua_pushnumber(L, ss);
+ return 1;
+}
+static int f_sleep(lua_State *L) {
+ double ss = luaL_checknumber(L, 1);
+ lt_sleep_ms(ss * 1000);
+ return 0;
+}
+
+
+static int f_exec(lua_State *L) {
+ size_t len;
+ const char *cmd = luaL_checklstring(L, 1, &len);
+ char *buf = lt_malloc(len + 32);
+ if (!buf) { luaL_error(L, "buffer allocation failed"); }
+#if _WIN32
+ sprintf(buf, "cmd /c \"%s\"", cmd);
+ WinExec(buf, SW_HIDE);
+#else
+ sprintf(buf, "%s &", cmd);
+ int res = system(buf);
+#endif
+ lt_free(buf);
+ return 0;
+}
+
+
+static int f_fuzzy_match(lua_State *L) {
+ const char *str = luaL_checkstring(L, 1);
+ const char *ptn = luaL_checkstring(L, 2);
+ int score = 0;
+ int run = 0;
+
+ while (*str && *ptn) {
+ while (*str == ' ') { str++; }
+ while (*ptn == ' ') { ptn++; }
+ if (tolower(*str) == tolower(*ptn)) {
+ score += run * 10 - (*str != *ptn);
+ run++;
+ ptn++;
+ } else {
+ score -= 10;
+ run = 0;
+ }
+ str++;
+ }
+ if (*ptn) { return 0; }
+
+ lua_pushnumber(L, score - (int) strlen(str));
+ return 1;
+}
+
+static int f_poll_event(lua_State *L) { // init.lua > core.step() wakes on mousemoved || inputtext
+ int rc = lt_poll_event(L);
+ return rc;
+}
+
+int luaopen_system(lua_State *L) {
+ static const luaL_Reg lib[] = {
+ { "poll_event", f_poll_event },
+ { "set_cursor", f_set_cursor },
+ { "set_window_title", f_set_window_title },
+ { "set_window_mode", f_set_window_mode },
+ { "window_has_focus", f_window_has_focus },
+ { "show_confirm_dialog", f_show_confirm_dialog },
+ { "chdir", f_chdir },
+ { "list_dir", f_list_dir },
+ { "absolute_path", f_absolute_path },
+ { "get_file_info", f_get_file_info },
+ { "get_clipboard", f_get_clipboard },
+ { "set_clipboard", f_set_clipboard },
+ { "get_time", f_get_time },
+ { "sleep", f_sleep },
+ { "exec", f_exec },
+ { "fuzzy_match", f_fuzzy_match },
+ { NULL, NULL }
+ };
+ luaL_newlib(L, lib);
+ return 1;
+}
+
+// ----------------------------------------------------------------------------
+// lite/api/api.c
+
+void api_load_libs(lua_State *L) {
+ static const luaL_Reg libs[] = {
+ { "system", luaopen_system },
+ { "renderer", luaopen_renderer },
+ { NULL, NULL }
+ };
+ for (int i = 0; libs[i].name; i++) {
+ luaL_requiref(L, libs[i].name, libs[i].func, 1);
+ }
+}
+
+// ----------------------------------------------------------------------------
+// lite/main.c
+
+void lt_init(lua_State *L, void *handle, const char *pathdata, int argc, char **argv, float scale, const char *platform, const char *pathexe) {
+ // setup renderer
+ ren_init(handle);
+
+ // setup lua context
+ api_load_libs(L);
+
+ lua_newtable(L);
+ for (int i = 0; i < argc; i++) {
+ lua_pushstring(L, argv[i]);
+ lua_rawseti(L, -2, i + 1);
+ }
+ lua_setglobal(L, "ARGS");
+
+ lua_pushstring(L, "1.11");
+ lua_setglobal(L, "VERSION");
+
+ lua_pushstring(L, platform);
+ lua_setglobal(L, "PLATFORM");
+
+ lua_pushnumber(L, scale);
+ lua_setglobal(L, "SCALE");
+
+ lua_pushstring(L, pathdata);
+ lua_setglobal(L, "DATADIR");
+
+ lua_pushstring(L, pathexe);
+ lua_setglobal(L, "EXEFILE");
+
+ // init lite
+ luaL_dostring(L, "core = {}");
+ luaL_dostring(L,
+ "xpcall(function()\n"
+ " SCALE = tonumber(os.getenv(\"LITE_SCALE\")) or SCALE\n"
+ " PATHSEP = package.config:sub(1, 1)\n"
+ " EXEDIR = EXEFILE:match(\"^(.+)[/\\\\].*$\")\n"
+ " USERDIR = EXEDIR .. 'data/user/'\n"
+ " package.path = EXEDIR .. '/data/?.lua;' .. package.path\n"
+ " package.path = EXEDIR .. '/data/?/init.lua;' .. package.path\n"
+ " core = require('core')\n"
+ " core.init()\n"
+ "end, function(err)\n"
+ " print('Error: ' .. tostring(err))\n"
+ " print(debug.traceback(nil, 2))\n"
+ " if core and core.on_error then\n"
+ " pcall(core.on_error, err)\n"
+ " end\n"
+ " os.exit(1)\n"
+ "end)"
+ );
+}
+void lt_tick(struct lua_State *L) {
+ luaL_dostring(L,
+ "xpcall(function()\n"
+ " core.run1()\n"
+ "end, function(err)\n"
+ " print('Error: ' .. tostring(err))\n"
+ " print(debug.traceback(nil, 2))\n"
+ " if core and core.on_error then\n"
+ " pcall(core.on_error, err)\n"
+ " end\n"
+ " os.exit(1)\n"
+ "end)"
+ );
+}
+#line 0
+
#endif // V4K_3RD
/* game framework.
* - rlyeh, public domain
@@ -334170,7 +347747,7 @@ array(char) base64_decode(const char *inp, unsigned inlen) { // array_free() aft
//-----------------------------------------------------------------------------
// C files
-#line 1 "engine/split/v4k_begin.c"
+#line 1 "v4k_begin.c"
#define do_threadlock(mutexptr) \
for( int init_ = !!(mutexptr) || (thread_mutex_init( (mutexptr) = CALLOC(1, sizeof(thread_mutex_t)) ), 1); init_; init_ = 0) \
for( int lock_ = (thread_mutex_lock( mutexptr ), 1); lock_; lock_ = (thread_mutex_unlock( mutexptr ), 0) )
@@ -334179,7 +347756,7 @@ array(char) base64_decode(const char *inp, unsigned inlen) { // array_free() aft
((struct nk_color){ ((color>>0))&255,((color>>8))&255,((color>>16))&255,((color>>24))&255 })
#line 0
-#line 1 "engine/split/v4k_ds.c"
+#line 1 "v4k_ds.c"
// -----------------------------------------------------------------------------
// sort/less
@@ -334569,7 +348146,7 @@ void (set_free)(set* m) {
}
#line 0
-#line 1 "engine/split/v4k_string.c"
+#line 1 "v4k_string.c"
#include
char* tempvl(const char *fmt, va_list vl) {
@@ -334990,9 +348567,158 @@ AUTORUN {
test( !strcmp("Hello happy world.", buf) );
}
#endif
+
+// ----------------------------------------------------------------------------
+// localization kit
+
+static const char *kit_lang = "enUS", *kit_langs =
+ "enUS,enGB,"
+ "frFR,"
+ "esES,esAR,esMX,"
+ "deDE,deCH,deAT,"
+ "itIT,itCH,"
+ "ptBR,ptPT,"
+ "zhCN,zhSG,zhTW,zhHK,zhMO,"
+ "ruRU,elGR,trTR,daDK,noNB,svSE,nlNL,plPL,fiFI,jaJP,"
+ "koKR,csCZ,huHU,roRO,thTH,bgBG,heIL"
+;
+
+static map(char*,char*) kit_ids;
+static map(char*,char*) kit_vars;
+
+#ifndef KIT_FMT_ID2
+#define KIT_FMT_ID2 "%s.%s"
+#endif
+
+void kit_init() {
+ do_once map_init(kit_ids, less_str, hash_str);
+ do_once map_init(kit_vars, less_str, hash_str);
+}
+
+void kit_insert( const char *id, const char *translation) {
+ char *id2 = va(KIT_FMT_ID2, kit_lang, id);
+
+ char **found = map_find_or_add_allocated_key(kit_ids, STRDUP(id2), NULL);
+ if(*found) FREE(*found);
+ *found = STRDUP(translation);
+}
+
+bool kit_merge( const char *filename ) {
+ // @todo: xlsx2ini
+ return false;
+}
+
+void kit_clear() {
+ map_clear(kit_ids);
+}
+
+bool kit_load( const char *filename ) {
+ return kit_clear(), kit_merge( filename );
+}
+
+void kit_set( const char *key, const char *value ) {
+ value = value && value[0] ? value : "";
+
+ char **found = map_find_or_add_allocated_key(kit_vars, STRDUP(key), NULL );
+ if(*found) FREE(*found);
+ *found = STRDUP(value);
+}
+
+void kit_reset() {
+ map_clear(kit_vars);
+}
+
+char *kit_translate2( const char *id, const char *lang ) {
+ char *id2 = va(KIT_FMT_ID2, lang, id);
+
+ char **found = map_find(kit_ids, id2);
+
+ // return original [[ID]] if no translation is found
+ if( !found ) return va("[[%s]]", id);
+
+ // return translation if no {{moustaches}} are found
+ if( !strstr(*found, "{{") ) return *found;
+
+ // else replace all found {{moustaches}} with context vars
+ {
+ // make room
+ static __thread char *results[16] = {0};
+ static __thread unsigned counter = 0; counter = (counter+1) % 16;
+
+ char *buffer = results[ counter ];
+ if( buffer ) FREE(buffer), buffer = 0;
+
+ // iterate moustaches
+ const char *begin, *end, *text = *found;
+ while( NULL != (begin = strstr(text, "{{")) ) {
+ end = strstr(begin+2, "}}");
+ if( end ) {
+ char *var = va("%.*s", (int)(end - (begin+2)), begin+2);
+ char **found_var = map_find(kit_vars, var);
+
+ if( found_var && 0[*found_var] ) {
+ strcatf(&buffer, "%.*s%s", (int)(begin - text), text, *found_var);
+ } else {
+ strcatf(&buffer, "%.*s{{%s}}", (int)(begin - text), text, var);
+ }
+
+ text = end+2;
+ } else {
+ strcatf(&buffer, "%.*s", (int)(begin - text), text);
+
+ text = begin+2;
+ }
+ }
+
+ strcatf(&buffer, "%s", text);
+ return buffer;
+ }
+}
+
+char *kit_translate( const char *id ) {
+ return kit_translate2( id, kit_lang );
+}
+
+void kit_locale( const char *lang ) {
+ kit_lang = STRDUP(lang); // @leak
+}
+
+void kit_dump_state( FILE *fp ) {
+ for each_map(kit_ids, char *, k, char *, v) {
+ fprintf(fp, "[ID ] %s=%s\n", k, v);
+ }
+ for each_map(kit_vars, char *, k, char *, v) {
+ fprintf(fp, "[VAR] %s=%s\n", k, v);
+ }
+}
+
+/*
+int main() {
+ kit_init();
+
+ kit_locale("enUS");
+ kit_insert("HELLO_PLAYERS", "Hi {{PLAYER1}} and {{PLAYER2}}!");
+ kit_insert("GREET_PLAYERS", "Nice to meet you.");
+
+ kit_locale("esES");
+ kit_insert("HELLO_PLAYERS", "Hola {{PLAYER1}} y {{PLAYER2}}!");
+ kit_insert("GREET_PLAYERS", "Un placer conoceros.");
+
+ kit_locale("enUS");
+ printf("%s %s\n", kit_translate("HELLO_PLAYERS"), kit_translate("GREET_PLAYERS")); // Hi {{PLAYER1}} and {{PLAYER2}}! Nice to meet you.
+
+ kit_locale("esES");
+ kit_set("PLAYER1", "John");
+ kit_set("PLAYER2", "Karl");
+ printf("%s %s\n", kit_translate("HELLO_PLAYERS"), kit_translate("GREET_PLAYERS")); // Hola John y Karl! Un placer conoceros.
+
+ assert( 0 == strcmp(kit_translate("NON_EXISTING"), "[[NON_EXISTING]]")); // [[NON_EXISTING]]
+ assert(~puts("Ok"));
+}
+*/
#line 0
-#line 1 "engine/split/v4k_compat.c"
+#line 1 "v4k_compat.c"
//-----------------------------------------------------------------------------
// compat (unix & stdio.h)
@@ -335111,7 +348837,7 @@ static void v4k_pre_init();
static void v4k_post_init(float);
#line 0
-#line 1 "engine/split/v4k_ui.c"
+#line 1 "v4k_ui.c"
// ----------------------------------------------------------------------------------------
// ui extensions first
@@ -337015,8 +350741,8 @@ int ui_color4f(const char *label, float *color) {
nk_layout_row_dynamic(ui_ctx, 0, 2);
ui_label_(label, NK_TEXT_LEFT);
- struct nk_colorf after = { color[0]*ui_alpha, color[1]*ui_alpha, color[2]*ui_alpha, color[3] }, before = after;
- struct nk_colorf clamped = { clampf(color[0],0,1), clampf(color[1],0,1), clampf(color[2],0,1), clampf(color[3],0,1) };
+ struct nk_colorf after = { color[0]*ui_alpha, color[1]*ui_alpha, color[2]*ui_alpha, color[3]*ui_alpha }, before = after;
+ struct nk_colorf clamped = { clampf(after.r,0,1), clampf(after.g,0,1), clampf(after.b,0,1), clampf(after.a,0,1) };
if (nk_combo_begin_color(ui_ctx, nk_rgb_cf(clamped), nk_vec2(200,400))) {
nk_layout_row_dynamic(ui_ctx, 120, 1);
after = nk_color_picker(ui_ctx, after, NK_RGB);
@@ -337103,8 +350829,8 @@ int ui_color3f(const char *label, float *color) {
nk_layout_row_dynamic(ui_ctx, 0, 2);
ui_label_(label, NK_TEXT_LEFT);
- struct nk_colorf after = { color[0]*ui_alpha, color[1]*ui_alpha, color[2]*ui_alpha, ui_alpha }, before = after;
- struct nk_colorf clamped = { clampf(color[0],0,1), clampf(color[1],0,1), clampf(color[2],0,1), 1 };
+ struct nk_colorf after = { color[0]*ui_alpha, color[1]*ui_alpha, color[2]*ui_alpha, color[3]*ui_alpha }, before = after;
+ struct nk_colorf clamped = { clampf(after.r,0,1), clampf(after.g,0,1), clampf(after.b,0,1), ui_alpha };
if (nk_combo_begin_color(ui_ctx, nk_rgb_cf(clamped), nk_vec2(200,400))) {
nk_layout_row_dynamic(ui_ctx, 120, 1);
after = nk_color_picker(ui_ctx, after, NK_RGB);
@@ -337147,7 +350873,7 @@ int ui_color3(const char *label, unsigned *color) {
nk_layout_row_dynamic(ui_ctx, 0, 2);
ui_label_(label, NK_TEXT_LEFT);
- struct nk_colorf after = { r*ui_alpha, g*ui_alpha, b*ui_alpha, 1 }, before = after;
+ struct nk_colorf after = { r*ui_alpha/255, g*ui_alpha/255, b*ui_alpha/255, ui_alpha }, before = after;
if (nk_combo_begin_color(ui_ctx, nk_rgb_cf(after), nk_vec2(200,400))) {
nk_layout_row_dynamic(ui_ctx, 120, 1);
after = nk_color_picker(ui_ctx, after, NK_RGB);
@@ -337809,8 +351535,10 @@ int ui_demo(int do_windows) {
static float float2[2] = {1,2};
static float float3[3] = {1,2,3};
static float float4[4] = {1,2,3,4};
- static float rgb[3] = {0.84,0.67,0.17};
- static float rgba[4] = {0.67,0.90,0.12,1};
+ static float rgbf[3] = {0.84,0.67,0.17};
+ static float rgbaf[4] = {0.67,0.90,0.12,1};
+ static unsigned rgb = CYAN;
+ static unsigned rgba = PINK;
static float slider = 0.5f;
static float slider2 = 0.5f;
static char string[64] = "hello world 123";
@@ -337854,8 +351582,10 @@ int ui_demo(int do_windows) {
if( ui_list("my list", list, 3, &item ) ) puts("list changed");
if( ui_section("Colors")) {}
- if( ui_color3f("my color3", rgb) ) puts("color3 changed");
- if( ui_color4f("my color4@this is a tooltip", rgba) ) puts("color4 changed");
+ if( ui_color3("my color3", &rgb) ) puts("color3 changed");
+ if( ui_color4("my color4@this is a tooltip", &rgba) ) puts("color4 changed");
+ if( ui_color3f("my color3f", rgbf) ) puts("color3f changed");
+ if( ui_color4f("my color4f@this is a tooltip", rgbaf) ) puts("color4f changed");
if( ui_section("Sliders")) {}
if( ui_slider("my slider", &slider)) puts("slider changed");
@@ -337968,7 +351698,7 @@ int ui_demo(int do_windows) {
#line 0
-#line 1 "engine/split/v4k_audio.c"
+#line 1 "v4k_audio.c"
// @fixme: really shutdown audio & related threads before quitting. ma_dr_wav crashes.
@@ -338561,7 +352291,7 @@ int ui_audio() {
}
#line 0
-#line 1 "engine/split/v4k_collide.c"
+#line 1 "v4k_collide.c"
/* poly */
poly poly_alloc(int cnt) {
poly p = {0};
@@ -339989,7 +353719,7 @@ void collide_demo() { // debug draw collisions // @fixme: fix leaks: poly_free()
}
#line 0
-#line 1 "engine/split/v4k_cook.c"
+#line 1 "v4k_cook.c"
// data pipeline
// - rlyeh, public domain.
// ----------------------------------------------------------------------------
@@ -340003,7 +353733,7 @@ void collide_demo() { // debug draw collisions // @fixme: fix leaks: poly_free()
const char *ART = "art/";
const char *TOOLS = "tools/bin/";
-const char *EDITOR = "tools/editor/";
+const char *EDITOR = "tools/";
const char *COOK_INI = "tools/cook.ini";
static unsigned ART_SKIP_ROOT; // number of chars to skip the base root in ART folder
@@ -340500,11 +354230,14 @@ int cook(void *userdata) {
fclose(in);
}
+// if(array_count(uncooked))
+// PRINTF("cook_jobs[%d]=%d\n", job->threadid, array_count(uncooked));
+
// generate cook metrics. you usually do `game.exe --cook-stats && (type *.csv | sort /R > cook.csv)`
static __thread FILE *statsfile = 0;
if(flag("--cook-stats"))
fseek(statsfile = fopen(va("cook%d.csv",job->threadid), "a+t"), 0L, SEEK_END);
- if(statsfile && ftell(statsfile) == 0) fprintf(statsfile,"%10s,%10s,%10s,%10s,%10s, %s\n","+total_ms","gen_ms","exe_ms","zip_ms","pass","file");
+ if(statsfile && !job->threadid && ftell(statsfile) == 0) fprintf(statsfile,"%10s,%10s,%10s,%10s,%10s, %s\n","+total_ms","gen_ms","exe_ms","zip_ms","pass","file");
// added or changed files
for( int i = 0, end = array_count(uncooked); i < end && !cook_cancelling; ++i ) {
@@ -340817,10 +354550,8 @@ void cook_stop() {
int cook_progress() {
int count = 0, sum = 0;
for( int i = 0, end = cook_jobs(); i < end; ++i ) {
-// if( jobs[i].progress >= 0 ) {
sum += jobs[i].progress;
++count;
-// }
}
return cook_jobs() ? sum / (count+!count) : 100;
}
@@ -340848,7 +354579,7 @@ bool have_tools() {
}
#line 0
-#line 1 "engine/split/v4k_data.c"
+#line 1 "v4k_data.c"
static array(json5) roots;
static array(char*) sources;
@@ -341078,7 +354809,7 @@ bool data_tests() {
}
#line 0
-#line 1 "engine/split/v4k_extend.c"
+#line 1 "v4k_extend.c"
// dll ------------------------------------------------------------------------
/* deprecated
@@ -341369,7 +355100,7 @@ void *script_init_env(unsigned flags) {
}
#line 0
-#line 1 "engine/split/v4k_file.c"
+#line 1 "v4k_file.c"
// -----------------------------------------------------------------------------
// file
@@ -342256,7 +355987,7 @@ if( found && *found == 0 ) {
char *cmd = va("%scook" ifdef(osx,".osx",ifdef(linux,".linux",".exe"))" %s %s --cook-ini=%s --cook-additive --cook-jobs=1 --quiet", TOOLS, group1, group2, COOK_INI);
// cook groups
- int rc = atoi(app_exec(cmd));
+ int rc = system(cmd); // atoi(app_exec(cmd));
if(rc < 0) PANIC("cannot invoke `%scook` (return code %d)", TOOLS, rc);
vfs_reload(); // @todo: optimize me. it is waaay inefficent to reload the whole VFS layout after cooking a single asset
@@ -342522,7 +356253,7 @@ bool ini_write(const char *filename, const char *section, const char *key, const
#line 0
-#line 1 "engine/split/v4k_font.c"
+#line 1 "v4k_font.c"
// font framework. original code by Vassvik (UNLICENSED)
// - rlyeh, public domain.
//
@@ -344876,7 +358607,7 @@ vec2 font_rect(const char *str) {
}
#line 0
-#line 1 "engine/split/v4k_input.c"
+#line 1 "v4k_input.c"
// input framework
// - rlyeh, public domain
//
@@ -345641,7 +359372,7 @@ int ui_gamepads() {
}
#line 0
-#line 1 "engine/split/v4k_math.c"
+#line 1 "v4k_math.c"
// -----------------------------------------------------------------------------
// math framework: rand, ease, vec2, vec3, vec4, quat, mat2, mat33, mat34, mat4
// - rlyeh, public domain
@@ -346521,7 +360252,7 @@ AUTORUN {
}
#line 0
-#line 1 "engine/split/v4k_memory.c"
+#line 1 "v4k_memory.c"
size_t dlmalloc_usable_size(void*); // __ANDROID_API__
#if is(bsd) || is(osx) // bsd or osx
@@ -346530,9 +360261,10 @@ size_t dlmalloc_usable_size(void*); // __ANDROID_API__
# include
#endif
-#ifndef SYS_REALLOC
-#define SYS_REALLOC realloc
-#define SYS_MSIZE /* bsd/osx, then win32, then ems/__GLIBC__, then __ANDROID_API__ */ \
+#ifndef SYS_MEM_INIT
+#define SYS_MEM_INIT()
+#define SYS_MEM_REALLOC realloc
+#define SYS_MEM_SIZE /* bsd/osx, then win32, then ems/__GLIBC__, then __ANDROID_API__ */ \
ifdef(osx, malloc_size, ifdef(bsd, malloc_size, \
ifdef(win32, _msize, malloc_usable_size)))
#endif
@@ -346542,10 +360274,12 @@ size_t dlmalloc_usable_size(void*); // __ANDROID_API__
static __thread uint64_t xstats_current = 0, xstats_total = 0, xstats_allocs = 0;
void* xrealloc(void* oldptr, size_t size) {
+ static __thread int once = 0; for(;!once;once = 1) SYS_MEM_INIT();
+
// for stats
size_t oldsize = xsize(oldptr);
- void *ptr = SYS_REALLOC(oldptr, size);
+ void *ptr = SYS_MEM_REALLOC(oldptr, size);
if( !ptr && size ) {
PANIC("Not memory enough (trying to allocate %u bytes)", (unsigned)size);
}
@@ -346570,7 +360304,7 @@ void* xrealloc(void* oldptr, size_t size) {
return ptr;
}
size_t xsize(void* p) {
- if( p ) return SYS_MSIZE(p);
+ if( p ) return SYS_MEM_SIZE(p);
return 0;
}
char *xstats(void) {
@@ -346622,7 +360356,7 @@ void* forget( void *ptr ) {
}
#line 0
-#line 1 "engine/split/v4k_network.c"
+#line 1 "v4k_network.c"
#if is(tcc) && is(win32) // @fixme: https lib is broken with tcc. replaced with InternetReadFile() api for now
@@ -346919,7 +360653,7 @@ static void network_init() {
}
#line 0
-#line 1 "engine/split/v4k_track.c"
+#line 1 "v4k_track.c"
static __thread int track__sock = -1;
//~ Lifecycle methods
@@ -347056,7 +360790,7 @@ int track_event_props(char const *event_id, char const *user_id, const track_pro
#undef TRACK__APPEND_SAFE_EX
#line 0
-#line 1 "engine/split/v4k_netsync.c"
+#line 1 "v4k_netsync.c"
typedef void* (*rpc_function)();
typedef struct rpc_call {
@@ -347742,7 +361476,7 @@ void network_rpc_send(unsigned id, const char *cmdline) {
}
#line 0
-#line 1 "engine/split/v4k_pack.c"
+#line 1 "v4k_pack.c"
// -----------------------------------------------------------------------------
// semantic versioning in a single byte (octal)
// - rlyeh, public domain.
@@ -350115,7 +363849,7 @@ AUTORUN {
#endif
#line 0
-#line 1 "engine/split/v4k_reflect.c"
+#line 1 "v4k_reflect.c"
// C reflection: enums, functions, structs, members and anotations.
// - rlyeh, public domain
//
@@ -350309,7 +364043,7 @@ AUTOTEST {
}
#line 0
-#line 1 "engine/split/v4k_render.c"
+#line 1 "v4k_render.c"
// -----------------------------------------------------------------------------
// opengl
@@ -351741,1110 +365475,6 @@ void fullscreen_quad_ycbcr_flipped( texture_t textureYCbCr[3], float gamma ) {
// glDisable( GL_BLEND );
}
-// ----------------------------------------------------------------------------
-// sprites
-
-typedef struct sprite_t {
- float px, py, pz; // origin x, y, depth
- float ox, oy, cos, sin; // offset x, offset y, cos/sin of rotation degree
- float sx, sy; // scale x,y
- uint32_t rgba; // vertex color
- float cellw, cellh; // dimensions of any cell in spritesheet
-
- union {
- struct {
- int frame, ncx, ncy; // frame in a (num cellx, num celly) spritesheet
- };
- struct {
- float x, y, w, h; // normalized[0..1] within texture bounds
- };
- };
-} sprite_t;
-
-// sprite batching
-typedef struct batch_t { array(sprite_t) sprites; mesh_t mesh; int dirty; } batch_t;
-typedef map(int, batch_t) batch_group_t; // mapkey is anything that forces a flush. texture_id for now, might be texture_id+program_id soon
-
-// sprite stream
-typedef struct sprite_vertex { vec3 pos; vec2 uv; uint32_t rgba; } sprite_vertex;
-typedef struct sprite_index { GLuint triangle[3]; } sprite_index;
-
-#define sprite_vertex(...) C_CAST(sprite_vertex, __VA_ARGS__)
-#define sprite_index(...) C_CAST(sprite_index, __VA_ARGS__)
-
-// sprite impl
-static int sprite_count = 0;
-static int sprite_program = -1;
-static array(sprite_index) sprite_indices = 0;
-static array(sprite_vertex) sprite_vertices = 0;
-static batch_group_t sprite_additive_group = {0}; // (w/2,h/2) centered
-static batch_group_t sprite_translucent_group = {0}; // (w/2,h/2) centered
-static batch_group_t sprite_00_translucent_group = {0}; // (0,0) centered
-
-void sprite( texture_t texture, float position[3], float rotation, uint32_t color ) {
- float offset[2] = {0,0}, scale[2] = {1,1}, spritesheet[3] = {0,0,0};
- sprite_sheet( texture, spritesheet, position, rotation, offset, scale, 0, color, false );
-}
-
-// rect(x,y,w,h) is [0..1] normalized, z-index, pos(x,y,scalex,scaley), rotation (degrees), color (rgba)
-void sprite_rect( texture_t t, vec4 rect, float zindex, vec4 pos, float tilt_deg, unsigned tint_rgba) {
- // do not queue if either alpha or scale is zero
- if( 0 == (pos.z * pos.w * ((tint_rgba>>24) & 255)) ) return;
-
- sprite_t s = {0};
-
- s.px = pos.x, s.py = pos.y, s.pz = zindex;
- s.sx = pos.z, s.sy = pos.w;
-
- s.x = rect.x, s.y = rect.y, s.w = rect.z, s.h = rect.w;
- s.cellw = s.w * s.sx * t.w, s.cellh = s.h * s.sy * t.h;
-
- s.rgba = tint_rgba;
- s.ox = 0/*ox*/ * s.sx;
- s.oy = 0/*oy*/ * s.sy;
- if( tilt_deg ) {
- tilt_deg = (tilt_deg + 0) * ((float)C_PI / 180);
- s.cos = cosf(tilt_deg);
- s.sin = sinf(tilt_deg);
- } else {
- s.cos = 1;
- s.sin = 0;
- }
-
- batch_group_t *batches = &sprite_00_translucent_group;
- batch_t *found = map_find_or_add(*batches, t.id, (batch_t){0});
-
- array_push(found->sprites, s);
-}
-
-void sprite_sheet( texture_t texture, float spritesheet[3], float position[3], float rotation, float offset[2], float scale[2], int is_additive, uint32_t rgba, int resolution_independant) {
- const float px = position[0], py = position[1], pz = position[2];
- const float ox = offset[0], oy = offset[1], sx = scale[0], sy = scale[1];
- const float frame = spritesheet[0], xcells = spritesheet[1], ycells = spritesheet[2];
-
- if (frame < 0) return;
- if (frame > 0 && frame >= (xcells * ycells)) return;
-
- // no need to queue if alpha or scale are zero
- if( sx && sy && alpha(rgba) ) {
- vec3 bak = camera_get_active()->position;
- if( resolution_independant ) { // @todo: optimize me
- sprite_flush();
- camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
- }
-
- sprite_t s;
- s.px = px;
- s.py = py;
- s.pz = pz;
- s.frame = frame;
- s.ncx = xcells ? xcells : 1;
- s.ncy = ycells ? ycells : 1;
- s.sx = sx;
- s.sy = sy;
- s.ox = ox * sx;
- s.oy = oy * sy;
- s.cellw = (texture.x * sx / s.ncx);
- s.cellh = (texture.y * sy / s.ncy);
- s.rgba = rgba;
- s.cos = 1;
- s.sin = 0;
- if(rotation) {
- rotation = (rotation + 0) * ((float)C_PI / 180);
- s.cos = cosf(rotation);
- s.sin = sinf(rotation);
- }
-
- batch_group_t *batches = is_additive ? &sprite_additive_group : &sprite_translucent_group;
-#if 0
- batch_t *found = map_find(*batches, texture.id);
- if( !found ) found = map_insert(*batches, texture.id, (batch_t){0});
-#else
- batch_t *found = map_find_or_add(*batches, texture.id, (batch_t){0});
-#endif
-
- array_push(found->sprites, s);
-
- if( resolution_independant ) { // @todo: optimize me
- sprite_flush();
- camera_get_active()->position = bak;
- }
- }
-}
-
-static void sprite_rebuild_meshes() {
- sprite_count = 0;
-
- batch_group_t* list[] = { &sprite_additive_group, &sprite_translucent_group };
- for( int l = 0; l < countof(list); ++l) {
- for each_map_ptr(*list[l], int,_, batch_t,bt) {
-
- bt->dirty = array_count(bt->sprites) ? 1 : 0;
- if( !bt->dirty ) continue;
-
- int index = 0;
- array_clear(sprite_indices);
- array_clear(sprite_vertices);
-
- array_foreach_ptr(bt->sprites, sprite_t,it ) {
- float x0 = it->ox - it->cellw/2, x3 = x0 + it->cellw;
- float y0 = it->oy - it->cellh/2, y3 = y0;
- float x1 = x0, x2 = x3;
- float y1 = y0 + it->cellh, y2 = y1;
-
- // @todo: move this affine transform into glsl shader
- vec3 v0 = { it->px + ( x0 * it->cos - y0 * it->sin ), it->py + ( x0 * it->sin + y0 * it->cos ), it->pz };
- vec3 v1 = { it->px + ( x1 * it->cos - y1 * it->sin ), it->py + ( x1 * it->sin + y1 * it->cos ), it->pz };
- vec3 v2 = { it->px + ( x2 * it->cos - y2 * it->sin ), it->py + ( x2 * it->sin + y2 * it->cos ), it->pz };
- vec3 v3 = { it->px + ( x3 * it->cos - y3 * it->sin ), it->py + ( x3 * it->sin + y3 * it->cos ), it->pz };
-
- float cx = (1.0f / it->ncx) - 1e-9f;
- float cy = (1.0f / it->ncy) - 1e-9f;
- int idx = (int)it->frame;
- int px = idx % it->ncx;
- int py = idx / it->ncx;
-
- float ux = px * cx, uy = py * cy;
- float vx = ux + cx, vy = uy + cy;
-
- vec2 uv0 = vec2(ux, uy);
- vec2 uv1 = vec2(ux, vy);
- vec2 uv2 = vec2(vx, vy);
- vec2 uv3 = vec2(vx, uy);
-
- array_push( sprite_vertices, sprite_vertex(v0, uv0, it->rgba) ); // Vertex 0 (A)
- array_push( sprite_vertices, sprite_vertex(v1, uv1, it->rgba) ); // Vertex 1 (B)
- array_push( sprite_vertices, sprite_vertex(v2, uv2, it->rgba) ); // Vertex 2 (C)
- array_push( sprite_vertices, sprite_vertex(v3, uv3, it->rgba) ); // Vertex 3 (D)
-
- // A--B A A-B
- // quad | | becomes triangle |\ and triangle \|
- // D--C D-C C
- GLuint A = (index+0), B = (index+1), C = (index+2), D = (index+3); index += 4;
-
- array_push( sprite_indices, sprite_index(C, D, A) ); // Triangle 1
- array_push( sprite_indices, sprite_index(C, A, B) ); // Triangle 2
- }
-
- mesh_update(&bt->mesh, "p3 t2 c4B", 0,array_count(sprite_vertices),sprite_vertices, 3*array_count(sprite_indices),sprite_indices, MESH_STATIC);
-
- // clear elements from queue
- sprite_count += array_count(bt->sprites);
- array_clear(bt->sprites);
- }
- }
-
- batch_group_t* list2[] = { &sprite_00_translucent_group };
- for( int l = 0; l < countof(list2); ++l) {
- for each_map_ptr(*list2[l], int,_, batch_t,bt) {
-
- bt->dirty = array_count(bt->sprites) ? 1 : 0;
- if( !bt->dirty ) continue;
-
- int index = 0;
- array_clear(sprite_indices);
- array_clear(sprite_vertices);
-
- array_foreach_ptr(bt->sprites, sprite_t,it ) {
- float x0 = it->ox - it->cellw/2, x3 = x0 + it->cellw;
- float y0 = it->oy - it->cellh/2, y3 = y0;
- float x1 = x0, x2 = x3;
- float y1 = y0 + it->cellh, y2 = y1;
-
- // @todo: move this affine transform into glsl shader
- vec3 v0 = { it->px + ( x0 * it->cos - y0 * it->sin ), it->py + ( x0 * it->sin + y0 * it->cos ), it->pz };
- vec3 v1 = { it->px + ( x1 * it->cos - y1 * it->sin ), it->py + ( x1 * it->sin + y1 * it->cos ), it->pz };
- vec3 v2 = { it->px + ( x2 * it->cos - y2 * it->sin ), it->py + ( x2 * it->sin + y2 * it->cos ), it->pz };
- vec3 v3 = { it->px + ( x3 * it->cos - y3 * it->sin ), it->py + ( x3 * it->sin + y3 * it->cos ), it->pz };
-
- float ux = it->x, vx = ux + it->w;
- float uy = it->y, vy = uy + it->h;
-
- vec2 uv0 = vec2(ux, uy);
- vec2 uv1 = vec2(ux, vy);
- vec2 uv2 = vec2(vx, vy);
- vec2 uv3 = vec2(vx, uy);
-
- array_push( sprite_vertices, sprite_vertex(v0, uv0, it->rgba) ); // Vertex 0 (A)
- array_push( sprite_vertices, sprite_vertex(v1, uv1, it->rgba) ); // Vertex 1 (B)
- array_push( sprite_vertices, sprite_vertex(v2, uv2, it->rgba) ); // Vertex 2 (C)
- array_push( sprite_vertices, sprite_vertex(v3, uv3, it->rgba) ); // Vertex 3 (D)
-
- // A--B A A-B
- // quad | | becomes triangle |\ and triangle \|
- // D--C D-C C
- GLuint A = (index+0), B = (index+1), C = (index+2), D = (index+3); index += 4;
-
- array_push( sprite_indices, sprite_index(C, D, A) ); // Triangle 1
- array_push( sprite_indices, sprite_index(C, A, B) ); // Triangle 2
- }
-
- mesh_update(&bt->mesh, "p3 t2 c4B", 0,array_count(sprite_vertices),sprite_vertices, 3*array_count(sprite_indices),sprite_indices, MESH_STATIC);
-
- // clear elements from queue
- sprite_count += array_count(bt->sprites);
- array_clear(bt->sprites);
- }
- }
-}
-
-static void sprite_render_meshes() {
- if( map_count(sprite_additive_group) <= 0 )
- if( map_count(sprite_translucent_group) <= 0 )
- if( map_count(sprite_00_translucent_group) <= 0 )
- return;
-
- if( sprite_program < 0 ) {
- sprite_program = shader( vfs_read("shaders/vs_324_24_sprite.glsl"), vfs_read("shaders/fs_24_4_sprite.glsl"),
- "att_Position,att_TexCoord,att_Color",
- "fragColor", NULL
- );
- }
-
- // use the shader and bind the texture @ unit 0
- shader_bind(sprite_program);
- glActiveTexture(GL_TEXTURE0);
-
- // setup rendering state
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_BLEND);
- glDepthFunc(GL_LEQUAL); // try to help with zfighting
-
- // update camera
- // camera_fps(camera_get_active(), 0,0);
- vec3 pos = camera_get_active()->position;
- float zoom = absf(pos.z); if(zoom < 0.1f) zoom = 0.1f; zoom = 1.f / (zoom + !zoom);
- float width = window_width();
- float height = window_height();
-
- // set mvp in the uniform. (0,0) is center of screen.
- mat44 mvp2d;
- float zdepth_max = window_height(); // 1;
- float l = pos.x - width * zoom / 2;
- float r = pos.x + width * zoom / 2;
- float b = pos.y + height * zoom / 2;
- float t = pos.y - height * zoom / 2;
- ortho44(mvp2d, l,r,b,t, -zdepth_max, +zdepth_max);
-
- shader_mat44("u_mvp", mvp2d);
-
- // set (unit 0) in the uniform texture sampler, and render batch
- // for all additive then translucent groups
-
- if( map_count(sprite_additive_group) > 0 ) {
- glBlendFunc( GL_SRC_ALPHA, GL_ONE );
- for each_map_ptr(sprite_additive_group, int,texture_id, batch_t,bt) {
- if( bt->dirty ) {
- shader_texture_unit("u_texture", *texture_id, 0);
- mesh_render(&bt->mesh);
- }
- }
-// map_clear(sprite_additive_group);
- }
-
- if( map_count(sprite_translucent_group) > 0 ) {
- glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
- for each_map_ptr(sprite_translucent_group, int,texture_id, batch_t,bt) {
- if( bt->dirty ) {
- shader_texture_unit("u_texture", *texture_id, 0);
- mesh_render(&bt->mesh);
- }
- }
-// map_clear(sprite_translucent_group);
- }
-
- if( map_count(sprite_00_translucent_group) > 0 ) {
- glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
- for each_map_ptr(sprite_00_translucent_group, int,texture_id, batch_t,bt) {
- if( bt->dirty ) {
- shader_texture_unit("u_texture", *texture_id, 0);
- mesh_render(&bt->mesh);
- }
- }
-// map_clear(sprite_00_translucent_group);
- }
-
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_BLEND);
- glDepthFunc(GL_LESS);
- glUseProgram(0);
-}
-
-static void sprite_init() {
- do_once {
- map_init(sprite_00_translucent_group, less_int, hash_int);
- map_init(sprite_translucent_group, less_int, hash_int);
- map_init(sprite_additive_group, less_int, hash_int);
- }
-}
-
-void sprite_flush() {
- profile("Sprite.rebuild_time") {
- sprite_rebuild_meshes();
- }
- profile("Sprite.render_time") {
- sprite_render_meshes();
- }
-}
-
-// -----------------------------------------------------------------------------
-// tilemaps
-
-tilemap_t tilemap(const char *map, int blank_chr, int linefeed_chr) {
- tilemap_t t = {0};
- t.tint = ~0u; // WHITE
- t.blank_chr = blank_chr;
- for( ; *map ; ++map ) {
- if( map[0] == linefeed_chr ) ++t.rows;
- else {
- array_push(t.map, map[0]);
- ++t.cols;
- }
- }
- return t;
-}
-
-void tilemap_render_ext( tilemap_t m, tileset_t t, float zindex, float xy_zoom[3], float tilt, unsigned tint, bool is_additive ) {
- vec3 old_pos = camera_get_active()->position;
- sprite_flush();
- camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
-
- float scale[2] = {xy_zoom[2], xy_zoom[2]};
- xy_zoom[2] = zindex;
-
- float offset[2] = {0,0};
- float spritesheet[3] = {0,t.cols,t.rows}; // selected tile index and spritesheet dimensions (cols,rows)
-
- for( unsigned y = 0, c = 0; y < m.rows; ++y ) {
- for( unsigned x = 0; x < m.cols; ++x, ++c ) {
- if( m.map[c] != m.blank_chr ) {
- spritesheet[0] = m.map[c];
- sprite_sheet(t.tex, spritesheet, xy_zoom, tilt, offset, scale, is_additive, tint, false);
- }
- offset[0] += t.tile_w;
- }
- offset[0] = 0, offset[1] += t.tile_h;
- }
-
- sprite_flush();
- camera_get_active()->position = old_pos;
-}
-
-void tilemap_render( tilemap_t map, tileset_t set ) {
- map.position.x += set.tile_w;
- map.position.y += set.tile_h;
- tilemap_render_ext( map, set, map.zindex, &map.position.x, map.tilt, map.tint, map.is_additive );
-}
-
-tileset_t tileset(texture_t tex, unsigned tile_w, unsigned tile_h, unsigned cols, unsigned rows) {
- tileset_t t = {0};
- t.tex = tex;
- t.cols = cols, t.rows = rows;
- t.tile_w = tile_w, t.tile_h = tile_h;
- return t;
-}
-
-int ui_tileset( tileset_t t ) {
- ui_subimage(va("Selection #%d (%d,%d)", t.selected, t.selected % t.cols, t.selected / t.cols), t.tex.id, t.tex.w, t.tex.h, (t.selected % t.cols) * t.tile_w, (t.selected / t.cols) * t.tile_h, t.tile_w, t.tile_h);
- int choice;
- if( (choice = ui_image(0, t.tex.id, t.tex.w,t.tex.h)) ) {
- int px = ((choice / 100) / 100.f) * t.tex.w / t.tile_w;
- int py = ((choice % 100) / 100.f) * t.tex.h / t.tile_h;
- t.selected = px + py * t.cols;
- }
- // if( (choice = ui_buttons(3, "load", "save", "clear")) ) {}
- return t.selected;
-}
-
-// -----------------------------------------------------------------------------
-// tiled
-
-tiled_t tiled(const char *file_tmx) {
- tiled_t zero = {0}, ti = zero;
-
- // read file and parse json
- if( !xml_push(file_tmx) ) return zero;
-
- // sanity checks
- bool supported = !strcmp(xml_string("/map/@orientation"), "orthogonal") && !strcmp(xml_string("/map/@renderorder"), "right-down");
- if( !supported ) return xml_pop(), zero;
-
- // tileset
- const char *file_tsx = xml_string("/map/tileset/@source");
- if( !xml_push(vfs_read(file_tsx)) ) return zero;
- const char *set_src = xml_string("/tileset/image/@source");
- int set_w = xml_int("/tileset/@tilewidth");
- int set_h = xml_int("/tileset/@tileheight");
- int set_c = xml_int("/tileset/@columns");
- int set_r = xml_int("/tileset/@tilecount") / set_c;
- tileset_t set = tileset(texture(set_src,0), set_w, set_h, set_c, set_r );
- xml_pop();
-
- // actual parsing
- ti.w = xml_int("/map/@width");
- ti.h = xml_int("/map/@height");
- ti.tilew = xml_int("/map/@tilewidth");
- ti.tileh = xml_int("/map/@tileheight");
- ti.first_gid = xml_int("/map/tileset/@firstgid");
- ti.map_name = STRDUP( xml_string("/map/tileset/@source") ); // @leak
-
- for(int l = 0, layers = xml_count("/map/layer"); l < layers; ++l ) {
- if( strcmp(xml_string("/map/layer[%d]/data/@encoding",l), "base64") || strcmp(xml_string("/map/layer[%d]/data/@compression",l), "zlib") ) {
- PRINTF("Warning: layer encoding not supported: '%s' -> layer '%s'\n", file_tmx, *array_back(ti.names));
- continue;
- }
-
- int cols = xml_int("/map/layer[%d]/@width",l);
- int rows = xml_int("/map/layer[%d]/@height",l);
-
- tilemap_t tm = tilemap("", ' ', '\n');
- tm.blank_chr = ~0u; //ti.first_gid - 1;
- tm.cols = cols;
- tm.rows = rows;
- array_resize(tm.map, tm.cols * tm.rows);
- memset(tm.map, 0xFF, tm.cols * tm.rows * sizeof(int));
-
- for( int c = 0, chunks = xml_count("/map/layer[%d]/data/chunk", l); c <= chunks; ++c ) {
- int cw, ch;
- int cx, cy;
- array(char) b64 = 0;
-
- if( !chunks ) { // non-infinite mode
- b64 = xml_blob("/map/layer[%d]/data/$",l);
- cw = tm.cols, ch = tm.rows;
- cx = 0, cy = 0;
- } else { // infinite mode
- b64 = xml_blob("/map/layer[%d]/data/chunk[%d]/$",l,c);
- cw = xml_int("/map/layer[%d]/data/chunk[%d]/@width",l,c), ch = xml_int("/map/layer[%d]/data/chunk[%d]/@height",l,c); // 20x20
- cx = xml_int("/map/layer[%d]/data/chunk[%d]/@x",l,c), cy = xml_int("/map/layer[%d]/data/chunk[%d]/@y",l,c); // (-16,-32)
- cx = abs(cx), cy = abs(cy);
- }
-
- int outlen = cw * ch * 4;
- static __thread int *out = 0; out = (int *)REALLOC( 0, outlen + zexcess(COMPRESS_ZLIB) ); // @leak
- if( zdecode( out, outlen, b64, array_count(b64), COMPRESS_ZLIB ) > 0 ) {
- for( int y = 0, p = 0; y < ch; ++y ) {
- for( int x = 0; x < cw; ++x, ++p ) {
- if( out[p] >= ti.first_gid ) {
- int offset = (x + cx) + (y + cy) * tm.cols;
- if( offset >= 0 && offset < (cw * ch) )
- tm.map[ offset ] = out[ p ] - ti.first_gid;
- }
- }
- }
- }
- else {
- PRINTF("Warning: bad zlib stream: '%s' -> layer #%d -> chunk #%d\n", file_tmx, l, c);
- }
-
- array_free(b64);
- }
-
- array_push(ti.layers, tm);
- array_push(ti.names, STRDUP(xml_string("/map/layer[%d]/@name",l)));
- array_push(ti.visible, true);
- array_push(ti.sets, set);
- }
-
- xml_pop();
- return ti;
-}
-
-void tiled_render(tiled_t tmx, vec3 pos) {
- for( unsigned i = 0, end = array_count(tmx.layers); i < end; ++i ) {
- tmx.layers[i].position = pos; // add3(camera_get_active()->position, pos);
- if( tmx.parallax ) tmx.layers[i].position.x /= (3+i), tmx.layers[i].position.y /= (5+i);
- if( tmx.visible[i] ) tilemap_render(tmx.layers[i], tmx.sets[i]);
- }
-}
-
-void ui_tiled(tiled_t *t) {
- ui_label2("Loaded map", t->map_name ? t->map_name : "(none)");
- ui_label2("Map dimensions", va("%dx%d", t->w, t->h));
- ui_label2("Tile dimensions", va("%dx%d", t->tilew, t->tileh));
- ui_separator();
- ui_bool("Parallax", &t->parallax);
- ui_separator();
- ui_label2("Layers", va("%d", array_count(t->layers)));
- for( int i = 0; i < array_count(t->layers); ++i ) {
- if( ui_label2_toolbar(va("- %s (%dx%d)", t->names[i], t->layers[i].cols, t->layers[i].rows ), t->visible[i] ? "\xee\xa3\xb4" : "\xee\xa3\xb5") > 0 ) { // ICON_MD_VISIBILITY / ICON_MD_VISIBILITY_OFF
- t->visible[i] ^= true;
- }
- }
- ui_separator();
- if( ui_collapse(va("Sets: %d", array_count(t->layers)), va("%p",t))) {
- for( int i = 0; i < array_count(t->layers); ++i ) {
- if( ui_collapse(va("%d", i+1), va("%p%d",t,i)) ) {
- t->sets[i].selected = ui_tileset( t->sets[i] );
- ui_collapse_end();
- }
- }
- ui_collapse_end();
- }
-}
-
-// -----------------------------------------------------------------------------
-// spine json loader (wip)
-// - rlyeh, public domain
-//
-// [ref] http://es.esotericsoftware.com/spine-json-format
-//
-// notable misses:
-// - mesh deforms
-// - cubic beziers
-// - shears
-// - bounding boxes
-
-enum { SPINE_MAX_BONES = 64 }; // max bones
-
-typedef struct spine_bone_t {
- char *name, *parent;
- struct spine_bone_t *parent_bone;
-
- float z; // draw order usually matches bone-id. ie, zindex == bone_id .. root(0) < chest (mid) < finger(top)
-
- float len;
- float x, y, deg; // base
- float x2, y2, deg2; // accum / temporaries during bone transform time
- float x3, y3, deg3; // values from timeline
-
- unsigned rect_id;
- unsigned atlas_id;
-} spine_bone_t;
-
-typedef struct spine_slot_t {
- char *name, *bone, *attach;
-} spine_slot_t;
-
-typedef struct spine_rect_t {
- char *name;
- float x,y,w,h,sx,sy,deg;
-} spine_rect_t;
-
-typedef struct spine_skin_t {
- char *name;
- array(spine_rect_t) rects;
-} spine_skin_t;
-
-typedef struct spine_animkey_t { // offline; only during loading
- float time, curve[4]; // time is mandatory, curve is optional
- union {
- char *name; // type: attachment (mode-1)
- struct { float deg; }; // type: rotate (mode-2)
- struct { float x,y; }; // type: translate (mode-3)
- };
-} spine_animkey_t;
-
-#if 0
-typedef struct spine_pose_t { // runtime; only during playing
- unsigned frame;
- array(vec4) xform; // entry per bone. translation(x,y),rotation(z),attachment-id(w)
-} spine_pose_t;
-#endif
-
-typedef struct spine_anim_t {
- char *name;
- union {
-#if 0
- struct {
- unsigned frames;
- array(spine_pose_t) poses;
- };
-#endif
- struct {
- array(spine_animkey_t) attach_keys[SPINE_MAX_BONES];
- array(spine_animkey_t) rotate_keys[SPINE_MAX_BONES];
- array(spine_animkey_t) translate_keys[SPINE_MAX_BONES];
- };
- };
-} spine_anim_t;
-
-typedef struct spine_atlas_t {
- char *name;
- float x,y,w,h,deg;
-} spine_atlas_t;
-
-typedef struct spine_t {
- char *name;
- texture_t texture;
- unsigned skin;
- array(spine_bone_t) bones;
- array(spine_slot_t) slots;
- array(spine_skin_t) skins;
- array(spine_anim_t) anims;
- array(spine_atlas_t) atlas;
- // anim controller
- unsigned inuse;
- float time, maxtime;
- unsigned debug_atlas_id;
-} spine_t;
-
-// ---
-
-static
-void spine_convert_animkeys_to_animpose(spine_anim_t *input) {
- spine_anim_t copy = *input; // @todo
- // @leak: attach/rot/tra keys
-}
-
-static
-int find_bone_id(spine_t *s, const char *bone_name) {
- for( unsigned i = 0, end = array_count(s->bones); i < end; ++i )
- if( !strcmp(s->bones[i].name, bone_name)) return i;
- return -1;
-}
-static
-spine_bone_t *find_bone(spine_t *s, const char *bone_name) {
- int bone_id = find_bone_id(s, bone_name);
- return bone_id >= 0 ? &s->bones[bone_id] : NULL;
-}
-
-void spine_skin(spine_t *p, unsigned skin) {
- if( !p->texture.id ) return;
- if( skin >= array_count(p->skins) ) return;
-
- p->skin = skin;
-
- char *skin_name = va("%s/", p->skins[skin].name);
- int header = strlen(skin_name);
-
- for( int i = 0; i < array_count(p->atlas); ++i) {
- if(!strbeg(p->atlas[i].name, skin_name)) continue;
-
- int bone_id = find_bone_id(p, p->atlas[i].name+header );
- if( bone_id < 0 ) continue;
-
- p->bones[bone_id].atlas_id = i;
- }
-
- for( int i = 0; i < array_count(p->skins[p->skin].rects); ++i) {
- int bone_id = find_bone_id(p, p->skins[p->skin].rects[i].name );
- if( bone_id < 0 ) continue;
-
- p->bones[bone_id].rect_id = i;
- }
-}
-
-static
-bool spine_(spine_t *t, const char *file_json, const char *file_atlas, unsigned flags) {
- char *atlas = vfs_read(file_atlas);
- if(!atlas || !atlas[0]) return false;
-
- memset(t, 0, sizeof(spine_t));
-
- // goblins.png
- // size: 1024, 128
- // filter: Linear, Linear
- // pma: true
- // dagger
- // bounds: 2, 18, 26, 108
- // goblin/eyes-closed
- // bounds: 2, 4, 34, 12
- spine_atlas_t *sa = 0;
- const char *last_id = 0;
- const char *texture_name = 0;
- const char *texture_filter = 0;
- const char *texture_format = 0;
- const char *texture_repeat = 0;
- float texture_width = 0, texture_height = 0, temp;
- for each_substring(atlas, "\r\n", it) {
- it += strspn(it, " \t\f\v");
- /**/ if( strbeg(it, "pma:" ) || strbeg(it, "index:") ) {} // ignored
- else if( strbeg(it, "size:" ) ) sscanf(it+5, "%f,%f", &texture_width, &texture_height);
- else if( strbeg(it, "rotate:" ) ) { float tmp; tmp=sa->w,sa->w=sa->h,sa->h=tmp; sa->deg = 90; } // assert(val==90)
- else if( strbeg(it, "repeat:" ) ) texture_repeat = it+7; // temp string
- else if( strbeg(it, "filter:" ) ) texture_filter = it+7; // temp string
- else if( strbeg(it, "format:" ) ) texture_format = it+7; // temp string
- else if( strbeg(it, "bounds:" ) ) {
- sscanf(it+7, "%f,%f,%f,%f", &sa->x, &sa->y, &sa->w, &sa->h);
- }
- else if( !texture_name ) texture_name = va("%s", it);
- else {
- array_push(t->atlas, ((spine_atlas_t){0}) );
- sa = &t->atlas[array_count(t->atlas) - 1];
- sa->name = STRDUP(it);
- }
- }
- for( int i = 0; i < array_count(t->atlas); ++i ) {
- sa = &t->atlas[i];
- sa->x /= texture_width, sa->y /= texture_height;
- sa->w /= texture_width, sa->h /= texture_height;
- }
-
- if(!texture_name) return false;
-
- t->texture = texture(texture_name, TEXTURE_LINEAR);
-
- json_push(vfs_read(file_json)); // @fixme: json_push_from_file() ?
-
- array_resize(t->bones, json_count("/bones"));
- array_reserve(t->slots, json_count("/slots"));
- array_resize(t->skins, json_count("/skins"));
- array_resize(t->anims, json_count("/animations"));
-
- for( int i = 0, end = json_count("/bones"); i < end; ++i ) {
- spine_bone_t v = {0};
- v.name = STRDUP(json_string("/bones[%d]/name", i));
- v.parent = STRDUP(json_string("/bones[%d]/parent", i));
- v.x = json_float("/bones[%d]/x", i);
- v.y = json_float("/bones[%d]/y", i);
- v.z = i;
- v.len = json_float("/bones[%d]/length", i);
- v.deg = json_float("/bones[%d]/rotation", i);
- t->bones[i] = v;
-
- for( int j = i-1; j > 0; --j ) {
- if( strcmp(t->bones[j].name,v.parent) ) continue;
- t->bones[i].parent_bone = &t->bones[j];
- break;
- }
- }
-
- for( int i = 0, end = json_count("/slots"); i < end; ++i ) {
- spine_slot_t v = {0};
- v.name = STRDUP(json_string("/slots[%d]/name", i));
- v.bone = STRDUP(json_string("/slots[%d]/bone", i));
- v.attach = STRDUP(json_string("/slots[%d]/attachment", i));
-
- array_push(t->slots, v);
-
- // slots define draw-order. so, update draw-order/zindex in bone
- spine_bone_t *b = find_bone(t, v.name);
- if( b ) b->z = i;
- }
-
- for( int i = 0, end = json_count("/skins"); i < end; ++i ) {
- spine_skin_t v = {0};
- v.name = STRDUP(json_string("/skins[%d]/name", i));
-
- for( int j = 0, jend = json_count("/skins[%d]/attachments",i); j < jend; ++j ) // /skins/default/
- for( int k = 0, kend = json_count("/skins[%d]/attachments[%d]",i,j); k < kend; ++k ) { // /skins/default/left hand item/
- spine_rect_t r = {0};
- r.name = STRDUP(json_key("/skins[%d]/attachments[%d][%d]",i,j,k)); // stringf("%s-%s-%s", json_key("/skins[%d]",i), json_key("/skins[%d][%d]",i,j), json_key("/skins[%d][%d][%d]",i,j,k));
- r.x = json_float("/skins[%d]/attachments[%d][%d]/x",i,j,k);
- r.y = json_float("/skins[%d]/attachments[%d][%d]/y",i,j,k);
- r.sx= json_float("/skins[%d]/attachments[%d][%d]/scaleX",i,j,k); r.sx += !r.sx;
- r.sy= json_float("/skins[%d]/attachments[%d][%d]/scaleY",i,j,k); r.sy += !r.sy;
- r.w = json_float("/skins[%d]/attachments[%d][%d]/width",i,j,k);
- r.h = json_float("/skins[%d]/attachments[%d][%d]/height",i,j,k);
- r.deg = json_float("/skins[%d]/attachments[%d][%d]/rotation",i,j,k);
- array_push(v.rects, r);
- }
-
- t->skins[i] = v;
- }
-
-#if 1
- // simplify:
- // merge /skins/default into existing /skins/*, then delete /skins/default
- if( array_count(t->skins) > 1 ) {
- for( int i = 1; i < array_count(t->skins); ++i ) {
- for( int j = 0; j < array_count(t->skins[0].rects); ++j ) {
- array_push(t->skins[i].rects, t->skins[0].rects[j]);
- }
- }
- // @leak @fixme: FREE(t->skins[0])
- for( int i = 0; i < array_count(t->skins)-1; ++i ) {
- t->skins[i] = t->skins[i+1];
- }
- array_pop(t->skins);
- }
-#endif
-
- for( int i = 0, end = json_count("/animations"); i < end; ++i ) {
- int id;
- const char *name;
-
- spine_anim_t v = {0};
- v.name = STRDUP(json_key("/animations[%d]", i));
-
- // slots / attachments
-
- for( int j = 0, jend = json_count("/animations[%d]/slots",i); j < jend; ++j )
- for( int k = 0, kend = json_count("/animations[%d]/slots[%d]",i,j); k < kend; ++k ) // ids
- {
- int bone_id = find_bone_id(t, json_key("/animations[%d]/bones[%d]",i,j));
- if( bone_id < 0 ) continue;
-
- for( int l = 0, lend = json_count("/animations[%d]/slots[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
- spine_animkey_t key = {0};
-
- key.name = STRDUP(json_string("/animations[%d]/slots[%d][%d][%d]/name",i,j,k,l));
- key.time = json_float("/animations[%d]/slots[%d][%d][%d]/time",i,j,k,l);
- if( json_count("/animations[%d]/slots[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
- key.curve[0] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[0]",i,j,k,l);
- key.curve[1] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[1]",i,j,k,l);
- key.curve[2] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[2]",i,j,k,l);
- key.curve[3] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[3]",i,j,k,l);
- }
-
- // @todo: convert name to id
- // for(id = 0; t->bones[id].name && strcmp(t->bones[id].name,key.name); ++id)
- // printf("%s vs %s\n", key.name, t->bones[id].name);
-
- array_push(v.attach_keys[bone_id], key);
- }
- }
-
- // bones
-
- for( int j = 0, jend = json_count("/animations[%d]/bones",i); j < jend; ++j ) // slots or bones
- for( int k = 0, kend = json_count("/animations[%d]/bones[%d]",i,j); k < kend; ++k ) { // bone ids
- int bone_id = find_bone_id(t, json_key("/animations[%d]/bones[%d]",i,j));
- if( bone_id < 0 ) continue;
-
- // parse bones
- for( int l = 0, lend = json_count("/animations[%d]/bones[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
- const char *channel = json_key("/animations[%d]/bones[%d][%d]",i,j,k);
- int track = !strcmp(channel, "rotate") ? 1 : !strcmp(channel, "translate") ? 2 : 0;
- if( !track ) continue;
-
- spine_animkey_t key = {0};
-
- key.time = json_float("/animations[%d]/bones[%d][%d][%d]/time",i,j,k,l);
- if( json_count("/animations[%d]/bones[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
- key.curve[0] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[0]",i,j,k,l);
- key.curve[1] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[1]",i,j,k,l);
- key.curve[2] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[2]",i,j,k,l);
- key.curve[3] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[3]",i,j,k,l);
- }
-
- if( track == 1 )
- key.deg = json_float("/animations[%d]/bones[%d][%d][%d]/value",i,j,k,l), // "/angle"
- array_push(v.rotate_keys[bone_id], key);
- else
- key.x = json_float("/animations[%d]/bones[%d][%d][%d]/x",i,j,k,l),
- key.y = json_float("/animations[%d]/bones[%d][%d][%d]/y",i,j,k,l),
- array_push(v.translate_keys[bone_id], key);
- }
- }
-
- t->anims[i] = v;
- }
-
- json_pop();
-
- spine_skin(t, 0);
-
- return true;
-}
-
-spine_t* spine(const char *file_json, const char *file_atlas, unsigned flags) {
- spine_t *t = MALLOC(sizeof(spine_t));
- if( !spine_(t, file_json, file_atlas, flags) ) return FREE(t), NULL;
- return t;
-}
-
-void spine_render(spine_t *p, vec3 offset, unsigned flags) {
- if( !p->texture.id ) return;
- if( !flags ) return;
-
- ddraw_push_2d();
- // if( flags & 2 ) ddraw_line(vec3(0,0,0), vec3(window_width(),window_height(),0));
- // if( flags & 2 ) ddraw_line(vec3(window_width(),0,0), vec3(0,window_height(),0));
-
- // int already_computed[SPINE_MAX_BONES] = {0}; // @fixme: optimize: update longest chains first, then remnant branches
-
- for( int i = 1; i < array_count(p->bones); ++i ) {
- spine_bone_t *self = &p->bones[i];
- if( !self->rect_id ) continue;
-
- int num_bones = 0;
- static array(spine_bone_t*) chain = 0; array_resize(chain, 0);
- for( spine_bone_t *next = self; next ; next = next->parent_bone, ++num_bones ) {
- array_push(chain, next);
- }
-
- vec3 target = {0}, prev = {0};
- for( int j = 0, end = array_count(chain); j < end; ++j ) { // traverse from root(skipped) -> `i` bone direction
- int j_opposite = end - 1 - j;
-
- spine_bone_t *b = chain[j_opposite]; // bone
- spine_bone_t *pb = b->parent_bone; // parent bone
-
- float pb_x2 = 0, pb_y2 = 0, pb_deg2 = 0;
- if( pb ) pb_x2 = pb->x2, pb_y2 = pb->y2, pb_deg2 = pb->deg2;
-
- const float deg2rad = C_PI / 180;
- b->x2 = b->x3 + pb_x2 + b->x * cos( -pb_deg2 * deg2rad ) - b->y * sin( -pb_deg2 * deg2rad );
- b->y2 = -b->y3 + pb_y2 - b->y * cos( pb_deg2 * deg2rad ) + b->x * sin( pb_deg2 * deg2rad );
- b->deg2 = -b->deg3 + pb_deg2 - b->deg;
-
- prev = target;
- target = vec3(b->x2,b->y2,b->deg2);
- }
-
- target.z = 0;
- target = add3(target, offset);
- prev.z = 0;
- prev = add3(prev, offset);
-
- if( flags & 2 ) {
- ddraw_point( target );
- ddraw_text( target, -0.25f, self->name );
- ddraw_bone( prev, target ); // from parent to bone
- }
- if( flags & 1 ) {
- spine_atlas_t *a = &p->atlas[self->atlas_id];
- spine_rect_t *r = &p->skins[p->skin].rects[self->rect_id];
-
- vec4 rect = ptr4(&a->x);
- float zindex = self->z;
- float offsx = 0;
- float offsy = 0;
- float tilt = self->deg2 + (a->deg - r->deg);
- unsigned tint = self->atlas_id == p->debug_atlas_id ? 0xFF<<24 | 0xFF : ~0u;
-
- if( 1 ) {
- vec3 dir = vec3(r->x,r->y,0);
- dir = rotatez3(dir, self->deg2);
- offsx = dir.x * r->sx;
- offsy = dir.y * r->sy;
- }
-
- sprite_rect(p->texture, rect, zindex, add4(vec4(target.x,target.y,1,1),vec4(offsx,offsy,0,0)), tilt, tint);
- }
- }
-
- ddraw_pop_2d();
- ddraw_flush();
-}
-
-static
-void spine_animate_(spine_t *p, float *time, float *maxtime, float delta) {
- if( !p->texture.id ) return;
-
- if( delta > 1/120.f ) delta = 1/120.f;
- if( *time >= *maxtime ) *time = 0; else *time += delta;
-
- // reset root // needed?
- p->bones[0].x2 = 0;
- p->bones[0].y2 = 0;
- p->bones[0].deg2 = 0;
- p->bones[0].x3 = 0;
- p->bones[0].y3 = 0;
- p->bones[0].deg3 = 0;
-
- for( int i = 0, end = array_count(p->bones); i < end; ++i) {
- // @todo: attach channel
- // @todo: per channel: if curve == linear || curve == stepped || array_count(curve) == 4 {...}
- for each_array_ptr(p->anims[p->inuse].rotate_keys[i], spine_animkey_t, r) {
- double r0 = r->time;
- *maxtime = maxf( *maxtime, r0 );
- if( absf(*time - r0) < delta ) {
- p->bones[i].deg3 = r->deg;
- }
- }
- for each_array_ptr(p->anims[p->inuse].translate_keys[i], spine_animkey_t, r) {
- double r0 = r->time;
- *maxtime = maxf( *maxtime, r0 );
- if( absf(*time - r0) < delta ) {
- p->bones[i].x3 = r->x;
- p->bones[i].y3 = r->y;
- }
- }
- }
-}
-
-void spine_animate(spine_t *p, float delta) {
- spine_animate_(p, &p->time, &p->maxtime, delta);
-}
-
-void ui_spine(spine_t *p) {
- if( ui_collapse(va("Anims: %d", array_count(p->anims)), va("%p-a", p))) {
- for each_array_ptr(p->anims, spine_anim_t, q) {
- if(ui_slider2("", &p->time, va("%.2f/%.0f %.2f%%", p->time, p->maxtime, p->time * 100.f))) {
- spine_animate(p, 0);
- }
-
- int choice = ui_label2_toolbar(q->name, ICON_MD_PAUSE_CIRCLE " " ICON_MD_PLAY_CIRCLE);
- if( choice == 1 ) window_pause( 0 ); // play
- if( choice == 2 ) window_pause( 1 ); // pause
-
- for( int i = 0; i < SPINE_MAX_BONES; ++i ) {
- ui_separator();
- ui_label(va("Bone %d: Attachment keys", i));
- for each_array_ptr(q->attach_keys[i], spine_animkey_t, r) {
- ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %s", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->name));
- }
- ui_label(va("Bone %d: Rotate keys", i));
- for each_array_ptr(q->rotate_keys[i], spine_animkey_t, r) {
- ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %.2f deg", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->deg));
- }
- ui_label(va("Bone %d: Translate keys", i));
- for each_array_ptr(q->translate_keys[i], spine_animkey_t, r) {
- ui_label(va("%.2f [%.2f %.2f %.2f %.2f] (%.2f,%.2f)", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->x, r->y));
- }
- }
- }
- ui_collapse_end();
- }
- if( ui_collapse(va("Bones: %d", array_count(p->bones)), va("%p-b", p))) {
- for each_array_ptr(p->bones, spine_bone_t, q)
- if( ui_collapse(q->name, va("%p-b2", q)) ) {
- ui_label2("Parent:", q->parent);
- ui_label2("X:", va("%.2f", q->x));
- ui_label2("Y:", va("%.2f", q->y));
- ui_label2("Length:", va("%.2f", q->len));
- ui_label2("Rotation:", va("%.2f", q->deg));
- ui_collapse_end();
- }
- ui_collapse_end();
- }
- if( ui_collapse(va("Slots: %d", array_count(p->slots)), va("%p-s", p))) {
- for each_array_ptr(p->slots, spine_slot_t, q)
- if( ui_collapse(q->name, va("%p-s2", q)) ) {
- ui_label2("Bone:", q->bone);
- ui_label2("Attachment:", q->attach);
- ui_collapse_end();
- }
- ui_collapse_end();
- }
- if( ui_collapse(va("Skins: %d", array_count(p->skins)), va("%p-k", p))) {
- for each_array_ptr(p->skins, spine_skin_t, q)
- if( ui_collapse(q->name, va("%p-k2", q)) ) {
- for each_array_ptr(q->rects, spine_rect_t, r)
- if( ui_collapse(r->name, va("%p-k3", r)) ) {
- ui_label2("X:", va("%.2f", r->x));
- ui_label2("Y:", va("%.2f", r->y));
- ui_label2("Scale X:", va("%.2f", r->sx));
- ui_label2("Scale Y:", va("%.2f", r->sy));
- ui_label2("Width:", va("%.2f", r->w));
- ui_label2("Height:", va("%.2f", r->h));
- ui_label2("Rotation:", va("%.2f", r->deg));
- ui_collapse_end();
-
- spine_bone_t *b = find_bone(p, r->name);
- if( b ) {
- p->debug_atlas_id = b->atlas_id;
-
- static float tilt = 0;
- if( input(KEY_LCTRL) ) tilt += 60*1/60.f; else tilt = 0;
- spine_atlas_t *r = p->atlas + b->atlas_id;
- sprite_flush();
- camera_get_active()->position = vec3(0,0,2);
- vec4 rect = ptr4(&r->x); float zindex = 0; vec3 xy_zoom = vec3(0,0,0); unsigned tint = ~0u;
- sprite_rect(p->texture,
- // rect: vec4(r->x*1.0/p->texture.w,r->y*1.0/p->texture.h,(r->x+r->w)*1.0/p->texture.w,(r->y+r->h)*1.0/p->texture.h),
- ptr4(&r->x), // atlas
- 0, vec4(0,0,1,1), r->deg + tilt, tint);
- sprite_flush();
- camera_get_active()->position = vec3(+window_width()/3,window_height()/2.25,2);
- }
- }
- ui_collapse_end();
- }
- ui_collapse_end();
- }
-
- if( ui_int("Use skin", &p->skin) ) {
- p->skin = clampf(p->skin, 0, array_count(p->skins) - 1);
- spine_skin(p, p->skin);
- }
-
- if( p->texture.id ) ui_texture(0, p->texture);
-}
-
// -----------------------------------------------------------------------------
// cubemaps
@@ -355123,7 +367753,7 @@ anims_t animations(const char *pathfile, int flags) {
}
#line 0
-#line 1 "engine/split/v4k_renderdd.c"
+#line 1 "v4k_renderdd.c"
static const char *dd_vs = "//" FILELINE "\n"
"in vec3 att_position;\n"
"uniform mat4 u_MVP;\n"
@@ -355971,7 +368601,7 @@ void ddraw_demo() {
}
#line 0
-#line 1 "engine/split/v4k_scene.c"
+#line 1 "v4k_scene.c"
//
// @todo: remove explicit GL code from here
@@ -356543,7 +369173,1476 @@ void scene_render(int flags) {
}
#line 0
-#line 1 "engine/split/v4k_system.c"
+#line 1 "v4k_sprite.c"
+// ----------------------------------------------------------------------------
+// sprites
+
+typedef struct sprite_static_t {
+ float px, py, pz; // origin x, y, depth
+ float ox, oy, cos, sin; // offset x, offset y, cos/sin of rotation degree
+ float sx, sy; // scale x,y
+ float cellw, cellh; // dimensions of any cell in spritesheet
+
+ union {
+ struct {
+ int frame, ncx, ncy; // frame in a (num cellx, num celly) spritesheet
+ };
+ struct {
+ float x, y, w, h; // normalized[0..1] within texture bounds
+ };
+ };
+
+ uint32_t rgba, flags; // vertex color and flags
+} sprite_static_t;
+
+// sprite batching
+typedef struct batch_t { array(sprite_static_t) sprites; mesh_t mesh; int dirty; } batch_t;
+typedef map(int, batch_t) batch_group_t; // mapkey is anything that forces a flush. texture_id for now, might be texture_id+program_id soon
+
+// sprite stream
+typedef struct sprite_vertex { vec3 pos; vec2 uv; uint32_t rgba; } sprite_vertex;
+typedef struct sprite_index { GLuint triangle[3]; } sprite_index;
+
+#define sprite_vertex(...) C_CAST(sprite_vertex, __VA_ARGS__)
+#define sprite_index(...) C_CAST(sprite_index, __VA_ARGS__)
+
+// sprite impl
+static int sprite_count = 0;
+static int sprite_program = -1;
+static array(sprite_index) sprite_indices = 0;
+static array(sprite_vertex) sprite_vertices = 0;
+
+// center_wh << 2 | additive << 1 | projected << 0
+static batch_group_t sprite_group[8] = {0};
+
+// rect(x,y,w,h) is [0..1] normalized, pos(xyz,z-index), scale_offset(sx,sy,offx,offy), rotation (degrees), color (rgba)
+void sprite_rect( texture_t t, vec4 rect, vec4 pos, vec4 scale_offset, float tilt_deg, unsigned tint_rgba, unsigned flags) {
+ float zindex = pos.w;
+ float scalex = scale_offset.x;
+ float scaley = scale_offset.y;
+ float offsetx = scale_offset.z;
+ float offsety = scale_offset.w;
+
+ // do not queue if either scales or alpha are zero
+ if( 0 == (scalex * scaley * ((tint_rgba>>24) & 255)) ) return;
+
+ ASSERT( (flags & SPRITE_CENTERED) == 0 );
+ if( flags & SPRITE_PROJECTED ) {
+ tilt_deg += 180, scalex = -scalex; // flip texture Y on mvp3d (same than turn 180º then flip X)
+ }
+
+ sprite_static_t s = {0};
+
+ s.px = pos.x, s.py = pos.y, s.pz = pos.z - zindex;
+ s.sx = scalex, s.sy = scaley;
+
+ s.x = rect.x, s.y = rect.y, s.w = rect.z, s.h = rect.w;
+ s.cellw = s.w * s.sx * t.w, s.cellh = s.h * s.sy * t.h;
+
+ s.rgba = tint_rgba;
+ s.flags = flags;
+
+#if 0
+ s.ox = 0/*ox*/ * s.sx;
+ s.oy = 0/*oy*/ * s.sy;
+#else
+ s.ox += offsetx * scalex;
+ s.oy += offsety * scaley;
+#endif
+
+ if( tilt_deg ) {
+ tilt_deg = (tilt_deg + 0) * ((float)C_PI / 180);
+ s.cos = cosf(tilt_deg);
+ s.sin = sinf(tilt_deg);
+ } else {
+ s.cos = 1;
+ s.sin = 0;
+ }
+
+ batch_group_t *batches = &sprite_group[ flags & 7 ];
+ batch_t *found = map_find_or_add(*batches, t.id, (batch_t){0});
+
+ array_push(found->sprites, s);
+}
+
+void sprite_sheet( texture_t texture, float spritesheet[3], float position[3], float rotation, float offset[2], float scale[2], unsigned rgba, unsigned flags) {
+ flags |= SPRITE_CENTERED;
+ ASSERT( flags & SPRITE_CENTERED );
+
+ const float px = position[0], py = position[1], pz = position[2];
+ const float ox = offset[0], oy = offset[1], sx = scale[0], sy = scale[1];
+ const float frame = spritesheet[0], xcells = spritesheet[1], ycells = spritesheet[2];
+
+ if (frame < 0) return;
+ if (frame > 0 && frame >= (xcells * ycells)) return;
+
+ // no need to queue if alpha or scale are zero
+ if( sx && sy && alpha(rgba) ) {
+ vec3 bak = camera_get_active()->position;
+ if( flags & SPRITE_RESOLUTION_INDEPENDANT ) { // @todo: optimize me
+ sprite_flush();
+ camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
+ }
+
+ sprite_static_t s;
+ s.px = px;
+ s.py = py;
+ s.pz = pz;
+ s.frame = frame;
+ s.ncx = xcells ? xcells : 1;
+ s.ncy = ycells ? ycells : 1;
+ s.sx = sx;
+ s.sy = sy;
+ s.ox = ox * sx;
+ s.oy = oy * sy;
+ s.cellw = (texture.x * sx / s.ncx);
+ s.cellh = (texture.y * sy / s.ncy);
+ s.rgba = rgba;
+ s.flags = flags;
+ s.cos = 1;
+ s.sin = 0;
+ if(rotation) {
+ rotation = (rotation + 0) * ((float)C_PI / 180);
+ s.cos = cosf(rotation);
+ s.sin = sinf(rotation);
+ }
+
+ batch_group_t *batches = &sprite_group[ flags & 7 ];
+#if 0
+ batch_t *found = map_find(*batches, texture.id);
+ if( !found ) found = map_insert(*batches, texture.id, (batch_t){0});
+#else
+ batch_t *found = map_find_or_add(*batches, texture.id, (batch_t){0});
+#endif
+
+ array_push(found->sprites, s);
+
+ if( flags & SPRITE_RESOLUTION_INDEPENDANT ) { // @todo: optimize me
+ sprite_flush();
+ camera_get_active()->position = bak;
+ }
+ }
+}
+
+void sprite( texture_t texture, float position[3], float rotation, unsigned color, unsigned flags) {
+ float offset[2] = {0,0}, scale[2] = {1,1}, spritesheet[3] = {0,0,0};
+ sprite_sheet( texture, spritesheet, position, rotation, offset, scale, color, flags );
+}
+
+static void sprite_rebuild_meshes() {
+ sprite_count = 0;
+
+ // w/2,h/2 centered
+ for( int l = countof(sprite_group) / 2; l < countof(sprite_group); ++l) {
+ for each_map_ptr(sprite_group[l], int,_, batch_t,bt) {
+
+ bt->dirty = array_count(bt->sprites) ? 1 : 0;
+ if( !bt->dirty ) continue;
+
+ int index = 0;
+ array_clear(sprite_indices);
+ array_clear(sprite_vertices);
+
+ array_foreach_ptr(bt->sprites, sprite_static_t,it ) {
+ float x0 = it->ox - it->cellw/2, x3 = x0 + it->cellw;
+ float y0 = it->oy - it->cellh/2, y3 = y0;
+ float x1 = x0, x2 = x3;
+ float y1 = y0 + it->cellh, y2 = y1;
+
+ // @todo: move this affine transform into glsl shader
+ vec3 v0 = { it->px + ( x0 * it->cos - y0 * it->sin ), it->py + ( x0 * it->sin + y0 * it->cos ), it->pz };
+ vec3 v1 = { it->px + ( x1 * it->cos - y1 * it->sin ), it->py + ( x1 * it->sin + y1 * it->cos ), it->pz };
+ vec3 v2 = { it->px + ( x2 * it->cos - y2 * it->sin ), it->py + ( x2 * it->sin + y2 * it->cos ), it->pz };
+ vec3 v3 = { it->px + ( x3 * it->cos - y3 * it->sin ), it->py + ( x3 * it->sin + y3 * it->cos ), it->pz };
+
+ float cx = (1.0f / it->ncx) - 1e-9f;
+ float cy = (1.0f / it->ncy) - 1e-9f;
+ int idx = (int)it->frame;
+ int px = idx % it->ncx;
+ int py = idx / it->ncx;
+
+ float ux = px * cx, uy = py * cy;
+ float vx = ux + cx, vy = uy + cy;
+
+ vec2 uv0 = vec2(ux, uy);
+ vec2 uv1 = vec2(ux, vy);
+ vec2 uv2 = vec2(vx, vy);
+ vec2 uv3 = vec2(vx, uy);
+
+ array_push( sprite_vertices, sprite_vertex(v0, uv0, it->rgba) ); // Vertex 0 (A)
+ array_push( sprite_vertices, sprite_vertex(v1, uv1, it->rgba) ); // Vertex 1 (B)
+ array_push( sprite_vertices, sprite_vertex(v2, uv2, it->rgba) ); // Vertex 2 (C)
+ array_push( sprite_vertices, sprite_vertex(v3, uv3, it->rgba) ); // Vertex 3 (D)
+
+ // A--B A A-B
+ // quad | | becomes triangle |\ and triangle \|
+ // D--C D-C C
+ GLuint A = (index+0), B = (index+1), C = (index+2), D = (index+3); index += 4;
+
+ array_push( sprite_indices, sprite_index(C, D, A) ); // Triangle 1
+ array_push( sprite_indices, sprite_index(C, A, B) ); // Triangle 2
+ }
+
+ mesh_update(&bt->mesh, "p3 t2 c4B", 0,array_count(sprite_vertices),sprite_vertices, 3*array_count(sprite_indices),sprite_indices, MESH_STATIC);
+
+ // clear elements from queue
+ sprite_count += array_count(bt->sprites);
+ array_clear(bt->sprites);
+ }
+ }
+
+ // (0,0) centered
+ for( int l = 0; l < countof(sprite_group) / 2; ++l) {
+ for each_map_ptr(sprite_group[l], int,_, batch_t,bt) {
+
+ bt->dirty = array_count(bt->sprites) ? 1 : 0;
+ if( !bt->dirty ) continue;
+
+ int index = 0;
+ array_clear(sprite_indices);
+ array_clear(sprite_vertices);
+
+ array_foreach_ptr(bt->sprites, sprite_static_t,it ) {
+ float x0 = it->ox - it->cellw/2, x3 = x0 + it->cellw;
+ float y0 = it->oy - it->cellh/2, y3 = y0;
+ float x1 = x0, x2 = x3;
+ float y1 = y0 + it->cellh, y2 = y1;
+
+ // @todo: move this affine transform into glsl shader
+ vec3 v0 = { it->px + ( x0 * it->cos - y0 * it->sin ), it->py + ( x0 * it->sin + y0 * it->cos ), it->pz };
+ vec3 v1 = { it->px + ( x1 * it->cos - y1 * it->sin ), it->py + ( x1 * it->sin + y1 * it->cos ), it->pz };
+ vec3 v2 = { it->px + ( x2 * it->cos - y2 * it->sin ), it->py + ( x2 * it->sin + y2 * it->cos ), it->pz };
+ vec3 v3 = { it->px + ( x3 * it->cos - y3 * it->sin ), it->py + ( x3 * it->sin + y3 * it->cos ), it->pz };
+
+ float ux = it->x, vx = ux + it->w;
+ float uy = it->y, vy = uy + it->h;
+
+ vec2 uv0 = vec2(ux, uy);
+ vec2 uv1 = vec2(ux, vy);
+ vec2 uv2 = vec2(vx, vy);
+ vec2 uv3 = vec2(vx, uy);
+
+ array_push( sprite_vertices, sprite_vertex(v0, uv0, it->rgba) ); // Vertex 0 (A)
+ array_push( sprite_vertices, sprite_vertex(v1, uv1, it->rgba) ); // Vertex 1 (B)
+ array_push( sprite_vertices, sprite_vertex(v2, uv2, it->rgba) ); // Vertex 2 (C)
+ array_push( sprite_vertices, sprite_vertex(v3, uv3, it->rgba) ); // Vertex 3 (D)
+
+ // A--B A A-B
+ // quad | | becomes triangle |\ and triangle \|
+ // D--C D-C C
+ GLuint A = (index+0), B = (index+1), C = (index+2), D = (index+3); index += 4;
+
+ array_push( sprite_indices, sprite_index(C, D, A) ); // Triangle 1
+ array_push( sprite_indices, sprite_index(C, A, B) ); // Triangle 2
+ }
+
+ mesh_update(&bt->mesh, "p3 t2 c4B", 0,array_count(sprite_vertices),sprite_vertices, 3*array_count(sprite_indices),sprite_indices, MESH_STATIC);
+
+ // clear elements from queue
+ sprite_count += array_count(bt->sprites);
+ array_clear(bt->sprites);
+ }
+ }
+}
+
+static void sprite_render_meshes_group(batch_group_t* sprites, int alpha_key, int alpha_value, float mvp[16]) {
+ if( map_count(*sprites) > 0 ) {
+ // setup shader
+ if( sprite_program < 0 ) {
+ sprite_program = shader( vfs_read("shaders/vs_324_24_sprite.glsl"), vfs_read("shaders/fs_24_4_sprite.glsl"),
+ "att_Position,att_TexCoord,att_Color",
+ "fragColor", NULL
+ );
+ }
+ shader_bind(sprite_program);
+ shader_mat44("u_mvp", mvp);
+
+ // set (unit 0) in the uniform texture sampler, and render batch
+ glActiveTexture(GL_TEXTURE0);
+ glBlendFunc( alpha_key, alpha_value );
+
+ for each_map_ptr(*sprites, int,texture_id, batch_t,bt) {
+ if( bt->dirty ) {
+ shader_texture_unit("u_texture", *texture_id, 0);
+ mesh_render(&bt->mesh);
+ }
+ }
+// map_clear(*sprites);
+ }
+}
+
+static void sprite_init() {
+ do_once for(int i = 0; i < countof(sprite_group); ++i) {
+ map_init(sprite_group[i], less_int, hash_int);
+ }
+}
+
+void sprite_flush() {
+ profile("Sprite.rebuild_time") {
+ sprite_rebuild_meshes();
+ }
+ profile("Sprite.render_time") {
+ // setup rendering state
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glDepthFunc(GL_LEQUAL); // try to help with zfighting
+
+ // 3d
+ mat44 mvp3d; multiply44x2(mvp3d, camera_get_active()->proj, camera_get_active()->view);
+ // render all additive then translucent groups
+ sprite_render_meshes_group(&sprite_group[SPRITE_PROJECTED], GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, mvp3d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_PROJECTED|SPRITE_CENTERED], GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, mvp3d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_PROJECTED|SPRITE_CENTERED|SPRITE_ADDITIVE], GL_SRC_ALPHA, GL_ONE, mvp3d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_PROJECTED|SPRITE_ADDITIVE], GL_SRC_ALPHA, GL_ONE, mvp3d );
+
+ // 2d: (0,0) is center of screen
+ mat44 mvp2d;
+ vec3 pos = camera_get_active()->position;
+ float zoom = absf(pos.z); if(zoom < 0.1f) zoom = 0.1f; zoom = 1.f / (zoom + !zoom);
+ float zdepth_max = window_height(); // 1;
+ float l = pos.x - window_width() * zoom / 2;
+ float r = pos.x + window_width() * zoom / 2;
+ float b = pos.y + window_height() * zoom / 2;
+ float t = pos.y - window_height() * zoom / 2;
+ ortho44(mvp2d, l,r,b,t, -zdepth_max, +zdepth_max);
+ // render all additive then translucent groups
+ sprite_render_meshes_group(&sprite_group[0], GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, mvp2d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_CENTERED], GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, mvp2d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_CENTERED|SPRITE_ADDITIVE], GL_SRC_ALPHA, GL_ONE, mvp2d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_ADDITIVE], GL_SRC_ALPHA, GL_ONE, mvp2d );
+
+ // restore rendering state
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDepthFunc(GL_LESS);
+ glUseProgram(0);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// tilemaps
+
+tilemap_t tilemap(const char *map, int blank_chr, int linefeed_chr) {
+ tilemap_t t = {0};
+ t.tint = ~0u; // WHITE
+ t.blank_chr = blank_chr;
+ for( ; *map ; ++map ) {
+ if( map[0] == linefeed_chr ) ++t.rows;
+ else {
+ array_push(t.map, map[0]);
+ ++t.cols;
+ }
+ }
+ return t;
+}
+
+void tilemap_render_ext( tilemap_t m, tileset_t t, float zindex, float xy_zoom[3], float tilt, unsigned tint, bool is_additive ) {
+ vec3 old_pos = camera_get_active()->position;
+ sprite_flush();
+ camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
+
+ float scale[2] = {xy_zoom[2], xy_zoom[2]};
+ xy_zoom[2] = zindex;
+
+ float offset[2] = {0,0};
+ float spritesheet[3] = {0,t.cols,t.rows}; // selected tile index and spritesheet dimensions (cols,rows)
+
+ for( unsigned y = 0, c = 0; y < m.rows; ++y ) {
+ for( unsigned x = 0; x < m.cols; ++x, ++c ) {
+ if( m.map[c] != m.blank_chr ) {
+ spritesheet[0] = m.map[c];
+ sprite_sheet(t.tex, spritesheet, xy_zoom, tilt, offset, scale, tint, is_additive ? SPRITE_ADDITIVE : 0);
+ }
+ offset[0] += t.tile_w;
+ }
+ offset[0] = 0, offset[1] += t.tile_h;
+ }
+
+ sprite_flush();
+ camera_get_active()->position = old_pos;
+}
+
+void tilemap_render( tilemap_t map, tileset_t set ) {
+ map.position.x += set.tile_w;
+ map.position.y += set.tile_h;
+ tilemap_render_ext( map, set, map.zindex, &map.position.x, map.tilt, map.tint, map.is_additive );
+}
+
+tileset_t tileset(texture_t tex, unsigned tile_w, unsigned tile_h, unsigned cols, unsigned rows) {
+ tileset_t t = {0};
+ t.tex = tex;
+ t.cols = cols, t.rows = rows;
+ t.tile_w = tile_w, t.tile_h = tile_h;
+ return t;
+}
+
+int ui_tileset( tileset_t t ) {
+ ui_subimage(va("Selection #%d (%d,%d)", t.selected, t.selected % t.cols, t.selected / t.cols), t.tex.id, t.tex.w, t.tex.h, (t.selected % t.cols) * t.tile_w, (t.selected / t.cols) * t.tile_h, t.tile_w, t.tile_h);
+ int choice;
+ if( (choice = ui_image(0, t.tex.id, t.tex.w,t.tex.h)) ) {
+ int px = ((choice / 100) / 100.f) * t.tex.w / t.tile_w;
+ int py = ((choice % 100) / 100.f) * t.tex.h / t.tile_h;
+ t.selected = px + py * t.cols;
+ }
+ // if( (choice = ui_buttons(3, "load", "save", "clear")) ) {}
+ return t.selected;
+}
+
+// -----------------------------------------------------------------------------
+// tiled
+
+tiled_t tiled(const char *file_tmx) {
+ tiled_t zero = {0}, ti = zero;
+
+ // read file and parse json
+ if( !xml_push(file_tmx) ) return zero;
+
+ // sanity checks
+ bool supported = !strcmp(xml_string("/map/@orientation"), "orthogonal") && !strcmp(xml_string("/map/@renderorder"), "right-down");
+ if( !supported ) return xml_pop(), zero;
+
+ // tileset
+ const char *file_tsx = xml_string("/map/tileset/@source");
+ if( !xml_push(vfs_read(file_tsx)) ) return zero;
+ const char *set_src = xml_string("/tileset/image/@source");
+ int set_w = xml_int("/tileset/@tilewidth");
+ int set_h = xml_int("/tileset/@tileheight");
+ int set_c = xml_int("/tileset/@columns");
+ int set_r = xml_int("/tileset/@tilecount") / set_c;
+ tileset_t set = tileset(texture(set_src,0), set_w, set_h, set_c, set_r );
+ xml_pop();
+
+ // actual parsing
+ ti.w = xml_int("/map/@width");
+ ti.h = xml_int("/map/@height");
+ ti.tilew = xml_int("/map/@tilewidth");
+ ti.tileh = xml_int("/map/@tileheight");
+ ti.first_gid = xml_int("/map/tileset/@firstgid");
+ ti.map_name = STRDUP( xml_string("/map/tileset/@source") ); // @leak
+
+ for(int l = 0, layers = xml_count("/map/layer"); l < layers; ++l ) {
+ if( strcmp(xml_string("/map/layer[%d]/data/@encoding",l), "base64") || strcmp(xml_string("/map/layer[%d]/data/@compression",l), "zlib") ) {
+ PRINTF("Warning: layer encoding not supported: '%s' -> layer '%s'\n", file_tmx, *array_back(ti.names));
+ continue;
+ }
+
+ int cols = xml_int("/map/layer[%d]/@width",l);
+ int rows = xml_int("/map/layer[%d]/@height",l);
+
+ tilemap_t tm = tilemap("", ' ', '\n');
+ tm.blank_chr = ~0u; //ti.first_gid - 1;
+ tm.cols = cols;
+ tm.rows = rows;
+ array_resize(tm.map, tm.cols * tm.rows);
+ memset(tm.map, 0xFF, tm.cols * tm.rows * sizeof(int));
+
+ for( int c = 0, chunks = xml_count("/map/layer[%d]/data/chunk", l); c <= chunks; ++c ) {
+ int cw, ch;
+ int cx, cy;
+ array(char) b64 = 0;
+
+ if( !chunks ) { // non-infinite mode
+ b64 = xml_blob("/map/layer[%d]/data/$",l);
+ cw = tm.cols, ch = tm.rows;
+ cx = 0, cy = 0;
+ } else { // infinite mode
+ b64 = xml_blob("/map/layer[%d]/data/chunk[%d]/$",l,c);
+ cw = xml_int("/map/layer[%d]/data/chunk[%d]/@width",l,c), ch = xml_int("/map/layer[%d]/data/chunk[%d]/@height",l,c); // 20x20
+ cx = xml_int("/map/layer[%d]/data/chunk[%d]/@x",l,c), cy = xml_int("/map/layer[%d]/data/chunk[%d]/@y",l,c); // (-16,-32)
+ cx = abs(cx), cy = abs(cy);
+ }
+
+ int outlen = cw * ch * 4;
+ static __thread int *out = 0; out = (int *)REALLOC( 0, outlen + zexcess(COMPRESS_ZLIB) ); // @leak
+ if( zdecode( out, outlen, b64, array_count(b64), COMPRESS_ZLIB ) > 0 ) {
+ for( int y = 0, p = 0; y < ch; ++y ) {
+ for( int x = 0; x < cw; ++x, ++p ) {
+ if( out[p] >= ti.first_gid ) {
+ int offset = (x + cx) + (y + cy) * tm.cols;
+ if( offset >= 0 && offset < (cw * ch) )
+ tm.map[ offset ] = out[ p ] - ti.first_gid;
+ }
+ }
+ }
+ }
+ else {
+ PRINTF("Warning: bad zlib stream: '%s' -> layer #%d -> chunk #%d\n", file_tmx, l, c);
+ }
+
+ array_free(b64);
+ }
+
+ array_push(ti.layers, tm);
+ array_push(ti.names, STRDUP(xml_string("/map/layer[%d]/@name",l)));
+ array_push(ti.visible, true);
+ array_push(ti.sets, set);
+ }
+
+ xml_pop();
+ return ti;
+}
+
+void tiled_render(tiled_t tmx, vec3 pos) {
+ for( unsigned i = 0, end = array_count(tmx.layers); i < end; ++i ) {
+ tmx.layers[i].position = pos; // add3(camera_get_active()->position, pos);
+ if( tmx.parallax ) tmx.layers[i].position.x /= (3+i), tmx.layers[i].position.y /= (5+i);
+ if( tmx.visible[i] ) tilemap_render(tmx.layers[i], tmx.sets[i]);
+ }
+}
+
+void ui_tiled(tiled_t *t) {
+ ui_label2("Loaded map", t->map_name ? t->map_name : "(none)");
+ ui_label2("Map dimensions", va("%dx%d", t->w, t->h));
+ ui_label2("Tile dimensions", va("%dx%d", t->tilew, t->tileh));
+ ui_separator();
+ ui_bool("Parallax", &t->parallax);
+ ui_separator();
+ ui_label2("Layers", va("%d", array_count(t->layers)));
+ for( int i = 0; i < array_count(t->layers); ++i ) {
+ if( ui_label2_toolbar(va("- %s (%dx%d)", t->names[i], t->layers[i].cols, t->layers[i].rows ), t->visible[i] ? "\xee\xa3\xb4" : "\xee\xa3\xb5") > 0 ) { // ICON_MD_VISIBILITY / ICON_MD_VISIBILITY_OFF
+ t->visible[i] ^= true;
+ }
+ }
+ ui_separator();
+ if( ui_collapse(va("Sets: %d", array_count(t->layers)), va("%p",t))) {
+ for( int i = 0; i < array_count(t->layers); ++i ) {
+ if( ui_collapse(va("%d", i+1), va("%p%d",t,i)) ) {
+ t->sets[i].selected = ui_tileset( t->sets[i] );
+ ui_collapse_end();
+ }
+ }
+ ui_collapse_end();
+ }
+}
+
+// -----------------------------------------------------------------------------
+// spine json loader (wip)
+// - rlyeh, public domain
+//
+// [ref] http://es.esotericsoftware.com/spine-json-format
+//
+// notable misses:
+// - mesh deforms
+// - cubic beziers
+// - shears
+// - bounding boxes
+
+enum { SPINE_MAX_BONES = 64 }; // max bones
+
+typedef struct spine_bone_t {
+ char *name, *parent;
+ struct spine_bone_t *parent_bone;
+
+ float z; // draw order usually matches bone-id. ie, zindex == bone_id .. root(0) < chest (mid) < finger(top)
+
+ float len;
+ float x, y, deg; // base
+ float x2, y2, deg2; // accum / temporaries during bone transform time
+ float x3, y3, deg3; // values from timeline
+
+ unsigned rect_id;
+ unsigned atlas_id;
+} spine_bone_t;
+
+typedef struct spine_slot_t {
+ char *name, *bone, *attach;
+} spine_slot_t;
+
+typedef struct spine_rect_t {
+ char *name;
+ float x,y,w,h,sx,sy,deg;
+} spine_rect_t;
+
+typedef struct spine_skin_t {
+ char *name;
+ array(spine_rect_t) rects;
+} spine_skin_t;
+
+typedef struct spine_animkey_t { // offline; only during loading
+ float time, curve[4]; // time is mandatory, curve is optional
+ union {
+ char *name; // type: attachment (mode-1)
+ struct { float deg; }; // type: rotate (mode-2)
+ struct { float x,y; }; // type: translate (mode-3)
+ };
+} spine_animkey_t;
+
+#if 0
+typedef struct spine_pose_t { // runtime; only during playing
+ unsigned frame;
+ array(vec4) xform; // entry per bone. translation(x,y),rotation(z),attachment-id(w)
+} spine_pose_t;
+#endif
+
+typedef struct spine_anim_t {
+ char *name;
+ union {
+#if 0
+ struct {
+ unsigned frames;
+ array(spine_pose_t) poses;
+ };
+#endif
+ struct {
+ array(spine_animkey_t) attach_keys[SPINE_MAX_BONES];
+ array(spine_animkey_t) rotate_keys[SPINE_MAX_BONES];
+ array(spine_animkey_t) translate_keys[SPINE_MAX_BONES];
+ };
+ };
+} spine_anim_t;
+
+typedef struct spine_atlas_t {
+ char *name;
+ float x,y,w,h,deg;
+} spine_atlas_t;
+
+typedef struct spine_t {
+ char *name;
+ texture_t texture;
+ unsigned skin;
+ array(spine_bone_t) bones;
+ array(spine_slot_t) slots;
+ array(spine_skin_t) skins;
+ array(spine_anim_t) anims;
+ array(spine_atlas_t) atlas;
+ // anim controller
+ unsigned inuse;
+ float time, maxtime;
+ unsigned debug_atlas_id;
+} spine_t;
+
+// ---
+
+static
+void spine_convert_animkeys_to_animpose(spine_anim_t *input) {
+ spine_anim_t copy = *input; // @todo
+ // @leak: attach/rot/tra keys
+}
+
+static
+int find_bone_id(spine_t *s, const char *bone_name) {
+ for( unsigned i = 0, end = array_count(s->bones); i < end; ++i )
+ if( !strcmp(s->bones[i].name, bone_name)) return i;
+ return -1;
+}
+static
+spine_bone_t *find_bone(spine_t *s, const char *bone_name) {
+ int bone_id = find_bone_id(s, bone_name);
+ return bone_id >= 0 ? &s->bones[bone_id] : NULL;
+}
+
+void spine_skin(spine_t *p, unsigned skin) {
+ if( !p->texture.id ) return;
+ if( skin >= array_count(p->skins) ) return;
+
+ p->skin = skin;
+
+ char *skin_name = va("%s/", p->skins[skin].name);
+ int header = strlen(skin_name);
+
+ for( int i = 0; i < array_count(p->atlas); ++i) {
+ if(!strbeg(p->atlas[i].name, skin_name)) continue;
+
+ int bone_id = find_bone_id(p, p->atlas[i].name+header );
+ if( bone_id < 0 ) continue;
+
+ p->bones[bone_id].atlas_id = i;
+ }
+
+ for( int i = 0; i < array_count(p->skins[p->skin].rects); ++i) {
+ int bone_id = find_bone_id(p, p->skins[p->skin].rects[i].name );
+ if( bone_id < 0 ) continue;
+
+ p->bones[bone_id].rect_id = i;
+ }
+}
+
+static
+bool spine_(spine_t *t, const char *file_json, const char *file_atlas, unsigned flags) {
+ char *atlas = vfs_read(file_atlas);
+ if(!atlas || !atlas[0]) return false;
+
+ memset(t, 0, sizeof(spine_t));
+
+ // goblins.png
+ // size: 1024, 128
+ // filter: Linear, Linear
+ // pma: true
+ // dagger
+ // bounds: 2, 18, 26, 108
+ // goblin/eyes-closed
+ // bounds: 2, 4, 34, 12
+ spine_atlas_t *sa = 0;
+ const char *last_id = 0;
+ const char *texture_name = 0;
+ const char *texture_filter = 0;
+ const char *texture_format = 0;
+ const char *texture_repeat = 0;
+ float texture_width = 0, texture_height = 0, temp;
+ for each_substring(atlas, "\r\n", it) {
+ it += strspn(it, " \t\f\v");
+ /**/ if( strbeg(it, "pma:" ) || strbeg(it, "index:") ) {} // ignored
+ else if( strbeg(it, "size:" ) ) sscanf(it+5, "%f,%f", &texture_width, &texture_height);
+ else if( strbeg(it, "rotate:" ) ) { float tmp; tmp=sa->w,sa->w=sa->h,sa->h=tmp; sa->deg = 90; } // assert(val==90)
+ else if( strbeg(it, "repeat:" ) ) texture_repeat = it+7; // temp string
+ else if( strbeg(it, "filter:" ) ) texture_filter = it+7; // temp string
+ else if( strbeg(it, "format:" ) ) texture_format = it+7; // temp string
+ else if( strbeg(it, "bounds:" ) ) {
+ sscanf(it+7, "%f,%f,%f,%f", &sa->x, &sa->y, &sa->w, &sa->h);
+ }
+ else if( !texture_name ) texture_name = va("%s", it);
+ else {
+ array_push(t->atlas, ((spine_atlas_t){0}) );
+ sa = &t->atlas[array_count(t->atlas) - 1];
+ sa->name = STRDUP(it);
+ }
+ }
+ for( int i = 0; i < array_count(t->atlas); ++i ) {
+ sa = &t->atlas[i];
+ sa->x /= texture_width, sa->y /= texture_height;
+ sa->w /= texture_width, sa->h /= texture_height;
+ }
+
+ if(!texture_name) return false;
+
+ t->texture = texture(texture_name, TEXTURE_LINEAR);
+
+ json_push(vfs_read(file_json)); // @fixme: json_push_from_file() ?
+
+ array_resize(t->bones, json_count("/bones"));
+ array_reserve(t->slots, json_count("/slots"));
+ array_resize(t->skins, json_count("/skins"));
+ array_resize(t->anims, json_count("/animations"));
+
+ for( int i = 0, end = json_count("/bones"); i < end; ++i ) {
+ spine_bone_t v = {0};
+ v.name = STRDUP(json_string("/bones[%d]/name", i));
+ v.parent = STRDUP(json_string("/bones[%d]/parent", i));
+ v.x = json_float("/bones[%d]/x", i);
+ v.y = json_float("/bones[%d]/y", i);
+ v.z = i;
+ v.len = json_float("/bones[%d]/length", i);
+ v.deg = json_float("/bones[%d]/rotation", i);
+ t->bones[i] = v;
+
+ for( int j = i-1; j > 0; --j ) {
+ if( strcmp(t->bones[j].name,v.parent) ) continue;
+ t->bones[i].parent_bone = &t->bones[j];
+ break;
+ }
+ }
+
+ for( int i = 0, end = json_count("/slots"); i < end; ++i ) {
+ spine_slot_t v = {0};
+ v.name = STRDUP(json_string("/slots[%d]/name", i));
+ v.bone = STRDUP(json_string("/slots[%d]/bone", i));
+ v.attach = STRDUP(json_string("/slots[%d]/attachment", i));
+
+ array_push(t->slots, v);
+
+ // slots define draw-order. so, update draw-order/zindex in bone
+ spine_bone_t *b = find_bone(t, v.name);
+ if( b ) b->z = i;
+ }
+
+ for( int i = 0, end = json_count("/skins"); i < end; ++i ) {
+ spine_skin_t v = {0};
+ v.name = STRDUP(json_string("/skins[%d]/name", i));
+
+ for( int j = 0, jend = json_count("/skins[%d]/attachments",i); j < jend; ++j ) // /skins/default/
+ for( int k = 0, kend = json_count("/skins[%d]/attachments[%d]",i,j); k < kend; ++k ) { // /skins/default/left hand item/
+ spine_rect_t r = {0};
+ r.name = STRDUP(json_key("/skins[%d]/attachments[%d][%d]",i,j,k)); // stringf("%s-%s-%s", json_key("/skins[%d]",i), json_key("/skins[%d][%d]",i,j), json_key("/skins[%d][%d][%d]",i,j,k));
+ r.x = json_float("/skins[%d]/attachments[%d][%d]/x",i,j,k);
+ r.y = json_float("/skins[%d]/attachments[%d][%d]/y",i,j,k);
+ r.sx= json_float("/skins[%d]/attachments[%d][%d]/scaleX",i,j,k); r.sx += !r.sx;
+ r.sy= json_float("/skins[%d]/attachments[%d][%d]/scaleY",i,j,k); r.sy += !r.sy;
+ r.w = json_float("/skins[%d]/attachments[%d][%d]/width",i,j,k);
+ r.h = json_float("/skins[%d]/attachments[%d][%d]/height",i,j,k);
+ r.deg = json_float("/skins[%d]/attachments[%d][%d]/rotation",i,j,k);
+ array_push(v.rects, r);
+ }
+
+ t->skins[i] = v;
+ }
+
+#if 1
+ // simplify:
+ // merge /skins/default into existing /skins/*, then delete /skins/default
+ if( array_count(t->skins) > 1 ) {
+ for( int i = 1; i < array_count(t->skins); ++i ) {
+ for( int j = 0; j < array_count(t->skins[0].rects); ++j ) {
+ array_push(t->skins[i].rects, t->skins[0].rects[j]);
+ }
+ }
+ // @leak @fixme: FREE(t->skins[0])
+ for( int i = 0; i < array_count(t->skins)-1; ++i ) {
+ t->skins[i] = t->skins[i+1];
+ }
+ array_pop(t->skins);
+ }
+#endif
+
+ for( int i = 0, end = json_count("/animations"); i < end; ++i ) {
+ int id;
+ const char *name;
+
+ spine_anim_t v = {0};
+ v.name = STRDUP(json_key("/animations[%d]", i));
+
+ // slots / attachments
+
+ for( int j = 0, jend = json_count("/animations[%d]/slots",i); j < jend; ++j )
+ for( int k = 0, kend = json_count("/animations[%d]/slots[%d]",i,j); k < kend; ++k ) // ids
+ {
+ int bone_id = find_bone_id(t, json_key("/animations[%d]/bones[%d]",i,j));
+ if( bone_id < 0 ) continue;
+
+ for( int l = 0, lend = json_count("/animations[%d]/slots[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
+ spine_animkey_t key = {0};
+
+ key.name = STRDUP(json_string("/animations[%d]/slots[%d][%d][%d]/name",i,j,k,l));
+ key.time = json_float("/animations[%d]/slots[%d][%d][%d]/time",i,j,k,l);
+ if( json_count("/animations[%d]/slots[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
+ key.curve[0] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[0]",i,j,k,l);
+ key.curve[1] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[1]",i,j,k,l);
+ key.curve[2] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[2]",i,j,k,l);
+ key.curve[3] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[3]",i,j,k,l);
+ }
+
+ // @todo: convert name to id
+ // for(id = 0; t->bones[id].name && strcmp(t->bones[id].name,key.name); ++id)
+ // printf("%s vs %s\n", key.name, t->bones[id].name);
+
+ array_push(v.attach_keys[bone_id], key);
+ }
+ }
+
+ // bones
+
+ for( int j = 0, jend = json_count("/animations[%d]/bones",i); j < jend; ++j ) // slots or bones
+ for( int k = 0, kend = json_count("/animations[%d]/bones[%d]",i,j); k < kend; ++k ) { // bone ids
+ int bone_id = find_bone_id(t, json_key("/animations[%d]/bones[%d]",i,j));
+ if( bone_id < 0 ) continue;
+
+ // parse bones
+ for( int l = 0, lend = json_count("/animations[%d]/bones[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
+ const char *channel = json_key("/animations[%d]/bones[%d][%d]",i,j,k);
+ int track = !strcmp(channel, "rotate") ? 1 : !strcmp(channel, "translate") ? 2 : 0;
+ if( !track ) continue;
+
+ spine_animkey_t key = {0};
+
+ key.time = json_float("/animations[%d]/bones[%d][%d][%d]/time",i,j,k,l);
+ if( json_count("/animations[%d]/bones[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
+ key.curve[0] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[0]",i,j,k,l);
+ key.curve[1] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[1]",i,j,k,l);
+ key.curve[2] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[2]",i,j,k,l);
+ key.curve[3] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[3]",i,j,k,l);
+ }
+
+ if( track == 1 )
+ key.deg = json_float("/animations[%d]/bones[%d][%d][%d]/value",i,j,k,l), // "/angle"
+ array_push(v.rotate_keys[bone_id], key);
+ else
+ key.x = json_float("/animations[%d]/bones[%d][%d][%d]/x",i,j,k,l),
+ key.y = json_float("/animations[%d]/bones[%d][%d][%d]/y",i,j,k,l),
+ array_push(v.translate_keys[bone_id], key);
+ }
+ }
+
+ t->anims[i] = v;
+ }
+
+ json_pop();
+
+ spine_skin(t, 0);
+
+ return true;
+}
+
+spine_t* spine(const char *file_json, const char *file_atlas, unsigned flags) {
+ spine_t *t = MALLOC(sizeof(spine_t));
+ if( !spine_(t, file_json, file_atlas, flags) ) return FREE(t), NULL;
+ return t;
+}
+
+void spine_render(spine_t *p, vec3 offset, unsigned flags) {
+ if( !p->texture.id ) return;
+ if( !flags ) return;
+
+ ddraw_push_2d();
+ // if( flags & 2 ) ddraw_line(vec3(0,0,0), vec3(window_width(),window_height(),0));
+ // if( flags & 2 ) ddraw_line(vec3(window_width(),0,0), vec3(0,window_height(),0));
+
+ // int already_computed[SPINE_MAX_BONES] = {0}; // @fixme: optimize: update longest chains first, then remnant branches
+
+ for( int i = 1; i < array_count(p->bones); ++i ) {
+ spine_bone_t *self = &p->bones[i];
+ if( !self->rect_id ) continue;
+
+ int num_bones = 0;
+ static array(spine_bone_t*) chain = 0; array_resize(chain, 0);
+ for( spine_bone_t *next = self; next ; next = next->parent_bone, ++num_bones ) {
+ array_push(chain, next);
+ }
+
+ vec3 target = {0}, prev = {0};
+ for( int j = 0, end = array_count(chain); j < end; ++j ) { // traverse from root(skipped) -> `i` bone direction
+ int j_opposite = end - 1 - j;
+
+ spine_bone_t *b = chain[j_opposite]; // bone
+ spine_bone_t *pb = b->parent_bone; // parent bone
+
+ float pb_x2 = 0, pb_y2 = 0, pb_deg2 = 0;
+ if( pb ) pb_x2 = pb->x2, pb_y2 = pb->y2, pb_deg2 = pb->deg2;
+
+ const float deg2rad = C_PI / 180;
+ b->x2 = b->x3 + pb_x2 + b->x * cos( -pb_deg2 * deg2rad ) - b->y * sin( -pb_deg2 * deg2rad );
+ b->y2 = -b->y3 + pb_y2 - b->y * cos( pb_deg2 * deg2rad ) + b->x * sin( pb_deg2 * deg2rad );
+ b->deg2 = -b->deg3 + pb_deg2 - b->deg;
+
+ prev = target;
+ target = vec3(b->x2,b->y2,b->deg2);
+ }
+
+ target.z = 0;
+ target = add3(target, offset);
+ prev.z = 0;
+ prev = add3(prev, offset);
+
+ if( flags & 2 ) {
+ ddraw_point( target );
+ ddraw_text( target, -0.25f, self->name );
+ ddraw_bone( prev, target ); // from parent to bone
+ }
+ if( flags & 1 ) {
+ spine_atlas_t *a = &p->atlas[self->atlas_id];
+ spine_rect_t *r = &p->skins[p->skin].rects[self->rect_id];
+
+ vec4 rect = ptr4(&a->x);
+ float zindex = self->z;
+ float offsx = 0;
+ float offsy = 0;
+ float tilt = self->deg2 + (a->deg - r->deg);
+ unsigned tint = self->atlas_id == p->debug_atlas_id ? 0xFF<<24 | 0xFF : ~0u;
+
+ if( 1 ) {
+ vec3 dir = vec3(r->x,r->y,0);
+ dir = rotatez3(dir, self->deg2);
+ offsx = dir.x * r->sx;
+ offsy = dir.y * r->sy;
+ }
+
+ sprite_rect(p->texture, rect, vec4(target.x,target.y,0,zindex), vec4(1,1,offsx,offsy), tilt, tint, 0);
+ }
+ }
+
+ ddraw_pop_2d();
+ ddraw_flush();
+}
+
+static
+void spine_animate_(spine_t *p, float *time, float *maxtime, float delta) {
+ if( !p->texture.id ) return;
+
+ if( delta > 1/120.f ) delta = 1/120.f;
+ if( *time >= *maxtime ) *time = 0; else *time += delta;
+
+ // reset root // needed?
+ p->bones[0].x2 = 0;
+ p->bones[0].y2 = 0;
+ p->bones[0].deg2 = 0;
+ p->bones[0].x3 = 0;
+ p->bones[0].y3 = 0;
+ p->bones[0].deg3 = 0;
+
+ for( int i = 0, end = array_count(p->bones); i < end; ++i) {
+ // @todo: attach channel
+ // @todo: per channel: if curve == linear || curve == stepped || array_count(curve) == 4 {...}
+ for each_array_ptr(p->anims[p->inuse].rotate_keys[i], spine_animkey_t, r) {
+ double r0 = r->time;
+ *maxtime = maxf( *maxtime, r0 );
+ if( absf(*time - r0) < delta ) {
+ p->bones[i].deg3 = r->deg;
+ }
+ }
+ for each_array_ptr(p->anims[p->inuse].translate_keys[i], spine_animkey_t, r) {
+ double r0 = r->time;
+ *maxtime = maxf( *maxtime, r0 );
+ if( absf(*time - r0) < delta ) {
+ p->bones[i].x3 = r->x;
+ p->bones[i].y3 = r->y;
+ }
+ }
+ }
+}
+
+void spine_animate(spine_t *p, float delta) {
+ spine_animate_(p, &p->time, &p->maxtime, delta);
+}
+
+void ui_spine(spine_t *p) {
+ if( ui_collapse(va("Anims: %d", array_count(p->anims)), va("%p-a", p))) {
+ for each_array_ptr(p->anims, spine_anim_t, q) {
+ if(ui_slider2("", &p->time, va("%.2f/%.0f %.2f%%", p->time, p->maxtime, p->time * 100.f))) {
+ spine_animate(p, 0);
+ }
+
+ int choice = ui_label2_toolbar(q->name, ICON_MD_PAUSE_CIRCLE " " ICON_MD_PLAY_CIRCLE);
+ if( choice == 1 ) window_pause( 0 ); // play
+ if( choice == 2 ) window_pause( 1 ); // pause
+
+ for( int i = 0; i < SPINE_MAX_BONES; ++i ) {
+ ui_separator();
+ ui_label(va("Bone %d: Attachment keys", i));
+ for each_array_ptr(q->attach_keys[i], spine_animkey_t, r) {
+ ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %s", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->name));
+ }
+ ui_label(va("Bone %d: Rotate keys", i));
+ for each_array_ptr(q->rotate_keys[i], spine_animkey_t, r) {
+ ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %.2f deg", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->deg));
+ }
+ ui_label(va("Bone %d: Translate keys", i));
+ for each_array_ptr(q->translate_keys[i], spine_animkey_t, r) {
+ ui_label(va("%.2f [%.2f %.2f %.2f %.2f] (%.2f,%.2f)", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->x, r->y));
+ }
+ }
+ }
+ ui_collapse_end();
+ }
+ if( ui_collapse(va("Bones: %d", array_count(p->bones)), va("%p-b", p))) {
+ for each_array_ptr(p->bones, spine_bone_t, q)
+ if( ui_collapse(q->name, va("%p-b2", q)) ) {
+ ui_label2("Parent:", q->parent);
+ ui_label2("X:", va("%.2f", q->x));
+ ui_label2("Y:", va("%.2f", q->y));
+ ui_label2("Length:", va("%.2f", q->len));
+ ui_label2("Rotation:", va("%.2f", q->deg));
+ ui_collapse_end();
+ }
+ ui_collapse_end();
+ }
+ if( ui_collapse(va("Slots: %d", array_count(p->slots)), va("%p-s", p))) {
+ for each_array_ptr(p->slots, spine_slot_t, q)
+ if( ui_collapse(q->name, va("%p-s2", q)) ) {
+ ui_label2("Bone:", q->bone);
+ ui_label2("Attachment:", q->attach);
+ ui_collapse_end();
+ }
+ ui_collapse_end();
+ }
+ if( ui_collapse(va("Skins: %d", array_count(p->skins)), va("%p-k", p))) {
+ for each_array_ptr(p->skins, spine_skin_t, q)
+ if( ui_collapse(q->name, va("%p-k2", q)) ) {
+ for each_array_ptr(q->rects, spine_rect_t, r)
+ if( ui_collapse(r->name, va("%p-k3", r)) ) {
+ ui_label2("X:", va("%.2f", r->x));
+ ui_label2("Y:", va("%.2f", r->y));
+ ui_label2("Scale X:", va("%.2f", r->sx));
+ ui_label2("Scale Y:", va("%.2f", r->sy));
+ ui_label2("Width:", va("%.2f", r->w));
+ ui_label2("Height:", va("%.2f", r->h));
+ ui_label2("Rotation:", va("%.2f", r->deg));
+ ui_collapse_end();
+
+ spine_bone_t *b = find_bone(p, r->name);
+ if( b ) {
+ p->debug_atlas_id = b->atlas_id;
+
+ static float tilt = 0;
+ if( input(KEY_LCTRL) ) tilt += 60*1/60.f; else tilt = 0;
+ spine_atlas_t *r = p->atlas + b->atlas_id;
+ sprite_flush();
+ camera_get_active()->position = vec3(0,0,2);
+ vec4 rect = ptr4(&r->x); float zindex = 0; vec4 scale_offset = vec4(1,1,0,0);
+ sprite_rect(p->texture, ptr4(&r->x), vec4(0,0,0,zindex), scale_offset, r->deg + tilt, ~0u, 0);
+ sprite_flush();
+ camera_get_active()->position = vec3(+window_width()/3,window_height()/2.25,2);
+ }
+ }
+ ui_collapse_end();
+ }
+ ui_collapse_end();
+ }
+
+ if( ui_int("Use skin", &p->skin) ) {
+ p->skin = clampf(p->skin, 0, array_count(p->skins) - 1);
+ spine_skin(p, p->skin);
+ }
+
+ if( p->texture.id ) ui_texture(0, p->texture);
+}
+
+// ----------------------------------------------------------------------------
+
+// texture_t texture_createclip(unsigned cx,unsigned cy,unsigned cw,unsigned ch, unsigned tw,unsigned th,unsigned tn,void *pixels, unsigned flags) {
+// return texture_create(tw,th,tn,pixels,flags);
+// static array(unsigned) clip = 0;
+// array_resize(clip, cw*ch*4);
+// for( unsigned y = 0; y < ch; ++y )
+// memcpy((char *)clip + (0+(0+y)*cw)*tn, (char*)pixels + (cx+(cy+y)*tw)*tn, cw*tn);
+// return texture_create(cw,ch,tn,clip,flags);
+// }
+
+typedef unsigned quark_t;
+
+#define array_reserve_(arr,x) (array_count(arr) > (x) ? (arr) : array_resize(arr, 1+(x)))
+
+#define ui_array(label,type,ptr) do { \
+ int changed = 0; \
+ if( ui_collapse(label, va(#type "%p",ptr)) ) { \
+ char label_ex[8]; \
+ for( int idx = 0, iend = array_count(*(ptr)); idx < iend; ++idx ) { \
+ type* it = *(ptr) + idx; \
+ snprintf(label_ex, sizeof(label_ex), "[%d]", idx); \
+ changed |= ui_##type(label_ex, it); \
+ } \
+ ui_collapse_end(); \
+ } \
+} while(0)
+
+int ui_vec2i(const char *label, vec2i *v) { return ui_unsigned2(label, (unsigned*)v); }
+int ui_vec3i(const char *label, vec3i *v) { return ui_unsigned3(label, (unsigned*)v); }
+int ui_vec2(const char *label, vec2 *v) { return ui_float2(label, (float*)v); }
+int ui_vec3(const char *label, vec3 *v) { return ui_float3(label, (float*)v); }
+int ui_vec4(const char *label, vec4 *v) { return ui_float4(label, (float*)v); }
+
+char *trimspace(char *str) {
+ for( char *s = str; *s; ++s )
+ if(*s <= 32) memmove(s, s+1, strlen(s));
+ return str;
+}
+
+char *file_parent(const char *f) { // folder/folder/abc
+ char *p = file_path(f); // folder/folder/
+ char *last = strrchr(p, '/'); // ^
+ if( !last ) return p; // return parent if no sep
+ *last = '\0'; // folder/folder
+ last = strrchr(p, '/'); // ^
+ return last ? last + 1 : p; // return parent if no sep
+}
+
+int ui_obj(const char *fmt, obj *o) {
+ int changed = 0, item = 1;
+ for each_objmember(o, TYPE,NAME,PTR) {
+ char *label = va(fmt, NAME);
+ /**/ if(!strcmp(TYPE,"float")) { if(ui_float(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"int")) { if(ui_int(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"unsigned")) { if(ui_unsigned(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"vec2")) { if(ui_float2(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"vec3")) { if(ui_float3(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"vec4")) { if(ui_float4(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"rgb")) { if(ui_color3(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"rgba")) { if(ui_color4(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"color")) { if(ui_color4f(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"color3f")) { if(ui_color3f(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"color4f")) { if(ui_color4f(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"char*")) { if(ui_string(label, PTR)) changed = item; }
+ else ui_label2(label, va("(%s)", TYPE)); // INFO instead of (TYPE)?
+ ++item;
+ }
+ return changed;
+}
+
+#define OBJTYPEDEF2(...) OBJTYPEDEF(__VA_ARGS__); AUTORUN
+
+// ----------------------------------------------------------------------------
+// atlas
+
+typedef struct atlas_frame_t {
+ unsigned delay;
+ vec4 sheet;
+ vec2 anchor; // @todo
+ array(vec3i) indices;
+ array(vec2) coords;
+ array(vec2) uvs;
+} atlas_frame_t;
+
+typedef struct atlas_anim_t {
+ quark_t name;
+ array(unsigned) frames;
+} atlas_anim_t;
+
+typedef struct atlas_t {
+ texture_t tex;
+
+ array(atlas_frame_t) frames;
+ array(atlas_anim_t) anims;
+
+ quarks_db db;
+} atlas_t;
+
+int ui_atlas_frame(atlas_frame_t *f) {
+ ui_unsigned("delay", &f->delay);
+ ui_vec4("sheet", &f->sheet);
+ ui_array("indices", vec3i, &f->indices);
+ ui_array("coords", vec2, &f->coords);
+ ui_array("uvs", vec2, &f->uvs);
+ return 0;
+}
+
+int ui_atlas(atlas_t *a) {
+ int changed = 0;
+ ui_texture(NULL, a->tex);
+ for( int i = 0; i < array_count(a->anims); ++i ) {
+ if( ui_collapse(quark_string(&a->db, a->anims[i].name), va("%p%d", a, a->anims[i].name) ) ) {
+ changed = i+1;
+ for( int j = 0; j < array_count(a->anims[i].frames); ++j ) {
+ if( ui_collapse(va("[%d]",j), va("%p%d.%d", a, a->anims[i].name,j) ) ) {
+ ui_unsigned("Frame", &a->anims[i].frames[j]);
+ ui_atlas_frame(a->frames + a->anims[i].frames[j]);
+ ui_collapse_end();
+ }
+ }
+ ui_collapse_end();
+ }
+ }
+ return changed;
+}
+
+void atlas_destroy(atlas_t *a) {
+ if( a ) {
+ texture_destroy(&a->tex);
+ memset(a, 0, sizeof(atlas_t));
+ }
+}
+atlas_t atlas_create(const char *inifile, unsigned flags) {
+ atlas_t a = {0};
+ int padding = 0, border = 0;
+
+ ini_t kv = ini(inifile);
+ for each_map(kv, char*,k, char*,v ) {
+ unsigned index = atoi(k);
+ /**/ if( strend(k, ".name") ) {
+ array_reserve_(a.anims, index);
+
+ a.anims[index].name = quark_intern(&a.db, v);
+ }
+ else if( strend(k, ".frames") ) {
+ array_reserve_(a.anims, index);
+
+ array(char*) pairs = strsplit(v, ",");
+ for( int i = 0, end = array_count(pairs); i < end; i += 2 ) {
+ unsigned frame = atoi(pairs[i]);
+ unsigned delay = atoi(pairs[i+1]);
+
+ array_reserve_(a.frames, frame);
+ a.frames[frame].delay = delay;
+
+ array_push(a.anims[index].frames, frame);
+ }
+ }
+ else if( strend(k, ".sheet") ) {
+ array_reserve_(a.frames, index);
+
+ vec4 sheet = atof4(v); //x,y,x2+2,y2+2 -> x,y,w,h (for 2,2 padding)
+ a.frames[index].sheet = vec4(sheet.x,sheet.y,sheet.z-sheet.x,sheet.w-sheet.y);
+ }
+ else if( strend(k, ".indices") ) {
+ array_reserve_(a.frames, index);
+
+ const char *text = v;
+ array(char*) tuples = strsplit(text, ",");
+ for( int i = 0, end = array_count(tuples); i < end; i += 3 ) {
+ unsigned p1 = atoi(tuples[i]);
+ unsigned p2 = atoi(tuples[i+1]);
+ unsigned p3 = atoi(tuples[i+2]);
+ array_push(a.frames[index].indices, vec3i(p1,p2,p3));
+ }
+ }
+ else if( strend(k, ".coords") ) {
+ array_reserve_(a.frames, index);
+
+ const char *text = v;
+ array(char*) pairs = strsplit(text, ",");
+ for( int i = 0, end = array_count(pairs); i < end; i += 2 ) {
+ unsigned x = atoi(pairs[i]);
+ unsigned y = atoi(pairs[i+1]);
+ array_push(a.frames[index].coords, vec2(x,y));
+ }
+ }
+ else if( strend(k, ".uvs") ) {
+ array_reserve_(a.frames, index);
+
+ const char *text = v;
+ array(char*) pairs = strsplit(text, ",");
+ for( int i = 0, end = array_count(pairs); i < end; i += 2 ) {
+ unsigned u = atoi(pairs[i]);
+ unsigned v = atoi(pairs[i+1]);
+ array_push(a.frames[index].uvs, vec2(u,v));
+ }
+ }
+ else if( strend(k, "padding") ) {
+ padding = atoi(v);
+ }
+ else if( strend(k, "border") ) {
+ border = atoi(v);
+ }
+ else if( strend(k, "file") ) {
+ a.tex = texture(v, 0);
+ }
+ else if( strend(k, "bitmap") ) {
+ const char *text = v;
+ array(char) bin = base64_decode(text, strlen(text));
+ a.tex = texture_from_mem(bin, array_count(bin), 0);
+ array_free(bin);
+ }
+#if 0
+ else if( strend(k, ".frame") ) {
+ array_reserve_(a.frames, index);
+ puts(k), puts(v);
+ }
+#endif
+ }
+
+ // post-process: normalize uvs and coords into [0..1] ranges
+ for each_array_ptr(a.frames, atlas_frame_t, f) {
+ for each_array_ptr(f->uvs, vec2, uv) {
+ uv->x /= a.tex.w;
+ uv->y /= a.tex.h;
+ }
+ for each_array_ptr(f->coords, vec2, xy) {
+ xy->x /= a.tex.w;
+ xy->y /= a.tex.h;
+ }
+ // @todo: adjust padding/border
+ }
+#if 0
+ // post-process: specify an anchor for each anim based on 1st frame dims
+ for each_array_ptr(a.anims, atlas_anim_t, anim) {
+ atlas_frame_t *first = a.frames + *anim->frames;
+ for( int i = 0; i < array_count(anim->frames); i += 2) {
+ atlas_frame_t *ff = a.frames + anim->frames[ i ];
+ ff->anchor.x = (ff->sheet.z - first->sheet.z) / 2;
+ ff->anchor.y = (ff->sheet.w - first->sheet.w) / 2;
+ }
+ }
+#endif
+
+ return a;
+}
+
+// ----------------------------------------------------------------------------
+// sprite v2
+
+void sprite_ctor(sprite_t *s) {
+ s->tint = WHITE;
+ s->timer_ms = 100;
+ s->flipped = 1;
+ s->sca.x += !s->sca.x;
+ s->sca.y += !s->sca.y;
+}
+void sprite_dtor(sprite_t *s) {
+ memset(s, 0, sizeof(*s));
+}
+void sprite_tick(sprite_t *s) {
+ int right = input(s->gamepad.array[3]) - input(s->gamepad.array[2]); // RIGHT - LEFT
+ int forward = input(s->gamepad.array[1]) - input(s->gamepad.array[0]); // DOWN - UP
+ int move = right || forward;
+ int dt = 16; // window_delta() * 1000;
+
+ unsigned over = (s->timer - dt) > s->timer;
+ if(!s->paused) s->timer -= dt;
+ if( over ) {
+ int len = array_count(s->a->anims[s->play].frames);
+ unsigned next = (s->frame + 1) % (len + !len);
+ unsigned eoa = next < s->frame;
+ s->frame = next;
+
+ atlas_frame_t *f = &s->a->frames[ s->a->anims[s->play].frames[s->frame] ];
+ s->timer_ms = f->delay;
+ s->timer += s->timer_ms;
+ }
+
+ if( s->play == 0 && move ) sprite_setanim(s, 1);
+ if( s->play == 1 ) { //<
+ if(right) s->flip_ = right < 0, sprite_setanim(s, 1);
+ if(!right && !forward) sprite_setanim(s, 0);
+
+ float speed = s->sca.x*2;
+ s->pos = add4(s->pos, scale4(norm4(vec4(right,0,forward,0)),speed));
+ }
+}
+void sprite_draw(sprite_t *s) {
+ atlas_frame_t *f = &s->a->frames[ s->a->anims[s->play].frames[s->frame] ];
+
+#if 1
+ // @todo {
+ unsigned sample = s->a->anims[s->play].frames[s->frame];
+ sample = 0;
+ f->anchor.x = (-s->a->frames[sample].sheet.z + f->sheet.z) / 2;
+ f->anchor.y = (+s->a->frames[sample].sheet.w - f->sheet.w) / 2;
+ // }
+#endif
+
+ // rect(x,y,w,h) is [0..1] normalized, z-index, pos(x,y,scale), rotation (degrees), color (rgba)
+ vec4 rect = { f->sheet.x / s->a->tex.w, f->sheet.y / s->a->tex.h, f->sheet.z / s->a->tex.w, f->sheet.w / s->a->tex.h };
+ sprite_rect(s->a->tex, rect, s->pos, vec4(s->flip_ ^ s->flipped?s->sca.x:-s->sca.x,s->sca.y,f->anchor.x,f->anchor.y), s->tilt, s->tint, 0|SPRITE_PROJECTED);
+}
+void sprite_edit(sprite_t *s) {
+ const char *name = obj_name(s);
+ const char *id = vac("%p", s);
+ if( s && ui_collapse(name ? name : id, id) ) {
+ ui_obj("%s", (obj*)s);
+
+ ui_bool("paused", &s->paused);
+ ui_label(va("frame anim [%d]", s->a->anims[s->play].frames[s->frame]));
+
+ int k = s->play;
+ if( ui_int("anim", &k) ) {
+ sprite_setanim(s, k);
+ }
+
+ int selected = ui_atlas(s->a);
+ if( selected ) sprite_setanim(s, selected - 1);
+
+ ui_collapse_end();
+ }
+}
+
+sprite_t* sprite_new(const char *ase, int bindings[6]) {
+ sprite_t *s = obj_new(sprite_t, {bindings[0],bindings[1],bindings[2],bindings[3]}, {bindings[4],bindings[5]});
+ atlas_t own = atlas_create(ase, 0);
+ memcpy(s->a = MALLOC(sizeof(atlas_t)), &own, sizeof(atlas_t)); // s->a = &s->own;
+ return s;
+}
+void sprite_del(sprite_t *s) {
+ if( s ) {
+ if( s->a ) atlas_destroy(s->a), FREE(s->a); // if( s->a == &s->own )
+ obj_free(s);
+ memset(s, 0, sizeof(sprite_t));
+ }
+}
+void sprite_setanim(sprite_t *s, unsigned name) {
+ if( s->play != name ) {
+ s->play = name;
+ s->frame = 0;
+
+ atlas_frame_t *f = &s->a->frames[ s->a->anims[s->play].frames[s->frame] ];
+
+ s->timer_ms = f->delay;
+ s->timer = s->timer_ms;
+ }
+}
+
+AUTORUN {
+ STRUCT(sprite_t, vec4, pos);
+ STRUCT(sprite_t, vec2, sca);
+ STRUCT(sprite_t, float, tilt);
+ STRUCT(sprite_t, vec4, gamepad);
+ STRUCT(sprite_t, vec2, fire);
+ STRUCT(sprite_t, rgba, tint);
+ STRUCT(sprite_t, unsigned, frame);
+ STRUCT(sprite_t, unsigned, timer);
+ STRUCT(sprite_t, unsigned, timer_ms);
+ STRUCT(sprite_t, unsigned, flipped);
+ STRUCT(sprite_t, unsigned, play);
+ EXTEND_T(sprite, ctor,edit,draw,tick);
+}
+#line 0
+
+#line 1 "v4k_system.c"
#if (is(tcc) && is(linux)) || (is(gcc) && !is(mingw)) // || is(clang)
int __argc; char **__argv;
#if !is(ems)
@@ -356746,8 +370845,8 @@ static char **backtrace_symbols(void *const *list,int size) {
static __thread char **symbols = 0; //[32][64] = {0};
if( !symbols ) {
- symbols = SYS_REALLOC(0, 128 * sizeof(char*));
- for( int i = 0; i < 128; ++i) symbols[i] = SYS_REALLOC(0, 128 * sizeof(char));
+ symbols = SYS_MEM_REALLOC(0, 128 * sizeof(char*));
+ for( int i = 0; i < 128; ++i) symbols[i] = SYS_MEM_REALLOC(0, 128 * sizeof(char));
}
if(size > 128) size = 128;
@@ -356780,7 +370879,7 @@ static char **backtrace_symbols(void *const *sym,int num) { return 0; }
char *callstack( int traces ) {
static __thread char *output = 0;
- if(!output ) output = SYS_REALLOC( 0, 128 * (64+2) );
+ if(!output ) output = SYS_MEM_REALLOC( 0, 128 * (64+2) );
if( output ) output[0] = '\0';
char *ptr = output;
@@ -357339,7 +371438,7 @@ int (PRINTF)(const char *text, const char *stack, const char *file, int line, co
static void *panic_oom_reserve; // for out-of-memory recovery
int (PANIC)(const char *error, const char *file, int line) {
- panic_oom_reserve = SYS_REALLOC(panic_oom_reserve, 0);
+ panic_oom_reserve = SYS_MEM_REALLOC(panic_oom_reserve, 0);
tty_color(RED);
@@ -357515,7 +371614,7 @@ int (test)(const char *file, int line, const char *expr, bool result) {
}
#line 0
-#line 1 "engine/split/v4k_time.c"
+#line 1 "v4k_time.c"
// ----------------------------------------------------------------------------
// time
@@ -358155,7 +372254,7 @@ void curve_destroy(curve_t *c) {
}
#line 0
-#line 1 "engine/split/v4k_profile.c"
+#line 1 "v4k_profile.c"
#if ENABLE_PROFILER
profiler_t profiler;
int profiler_enabled = 1;
@@ -358213,7 +372312,7 @@ void (ui_profiler)() {
#endif
#line 0
-#line 1 "engine/split/v4k_video.c"
+#line 1 "v4k_video.c"
// tip: convert video to x265/mp4. note: higher crf to increase compression (default crf is 28)
// ffmpeg -i {{infile}} -c:v libx265 -crf 24 -c:a copy {{outfile}}
@@ -358445,7 +372544,7 @@ void record_frame() {
}
#line 0
-#line 1 "engine/split/v4k_window.c"
+#line 1 "v4k_window.c"
//-----------------------------------------------------------------------------
// fps locking
@@ -358872,7 +372971,7 @@ bool window_create_from_handle(void *handle, float scale, unsigned flags) {
#define ddraw_progress_bar(JOB_ID, JOB_MAX, PERCENT) do { \
/* NDC coordinates (2d): bottom-left(-1,-1), center(0,0), top-right(+1,+1) */ \
float progress = (PERCENT+1) / 100.f; if(progress > 1) progress = 1; \
- float speed = progress < 1 ? 0.2f : 0.5f; \
+ float speed = progress < 1 ? 0.05f : 0.75f; \
float smooth = previous[JOB_ID] = progress * speed + previous[JOB_ID] * (1-speed); \
\
float pixel = 2.f / window_height(), dist = smooth*2-1, y = pixel*3*JOB_ID; \
@@ -359534,7 +373633,7 @@ double window_scale() { // ok? @testme
}
#line 0
-#line 1 "engine/split/v4k_obj.c"
+#line 1 "v4k_obj.c"
// -----------------------------------------------------------------------------
// factory of handle ids, based on code by randy gaul (PD/Zlib licensed)
// - rlyeh, public domain
@@ -360546,7 +374645,7 @@ void *obj_make(const char *str) {
}
#line 0
-#line 1 "engine/split/v4k_ai.c"
+#line 1 "v4k_ai.c"
// AI framework
// - rlyeh, public domain.
//
@@ -361384,7 +375483,7 @@ int ui_bt(bt_t *b) {
}
#line 0
-#line 1 "engine/split/v4k_editor.c"
+#line 1 "v4k_editor0.c"
// editing:
// nope > functions: add/rem property
@@ -361917,158 +376016,9 @@ int gizmo(vec3 *pos, vec3 *rot, vec3 *sca) {
return modified;
}
-// -- localization kit
-
-static const char *kit_lang = "enUS", *kit_langs =
- "enUS,enGB,"
- "frFR,"
- "esES,esAR,esMX,"
- "deDE,deCH,deAT,"
- "itIT,itCH,"
- "ptBR,ptPT,"
- "zhCN,zhSG,zhTW,zhHK,zhMO,"
- "ruRU,elGR,trTR,daDK,noNB,svSE,nlNL,plPL,fiFI,jaJP,"
- "koKR,csCZ,huHU,roRO,thTH,bgBG,heIL"
-;
-
-static map(char*,char*) kit_ids;
-static map(char*,char*) kit_vars;
-
-#ifndef KIT_FMT_ID2
-#define KIT_FMT_ID2 "%s.%s"
-#endif
-
-void kit_init() {
- do_once map_init(kit_ids, less_str, hash_str);
- do_once map_init(kit_vars, less_str, hash_str);
-}
-
-void kit_insert( const char *id, const char *translation) {
- char *id2 = va(KIT_FMT_ID2, kit_lang, id);
-
- char **found = map_find_or_add_allocated_key(kit_ids, STRDUP(id2), NULL);
- if(*found) FREE(*found);
- *found = STRDUP(translation);
-}
-
-bool kit_merge( const char *filename ) {
- // @todo: xlsx2ini
- return false;
-}
-
-void kit_clear() {
- map_clear(kit_ids);
-}
-
-bool kit_load( const char *filename ) {
- return kit_clear(), kit_merge( filename );
-}
-
-void kit_set( const char *key, const char *value ) {
- value = value && value[0] ? value : "";
-
- char **found = map_find_or_add_allocated_key(kit_vars, STRDUP(key), NULL );
- if(*found) FREE(*found);
- *found = STRDUP(value);
-}
-
-void kit_reset() {
- map_clear(kit_vars);
-}
-
-char *kit_translate2( const char *id, const char *lang ) {
- char *id2 = va(KIT_FMT_ID2, lang, id);
-
- char **found = map_find(kit_ids, id2);
-
- // return original [[ID]] if no translation is found
- if( !found ) return va("[[%s]]", id);
-
- // return translation if no {{moustaches}} are found
- if( !strstr(*found, "{{") ) return *found;
-
- // else replace all found {{moustaches}} with context vars
- {
- // make room
- static __thread char *results[16] = {0};
- static __thread unsigned counter = 0; counter = (counter+1) % 16;
-
- char *buffer = results[ counter ];
- if( buffer ) FREE(buffer), buffer = 0;
-
- // iterate moustaches
- const char *begin, *end, *text = *found;
- while( NULL != (begin = strstr(text, "{{")) ) {
- end = strstr(begin+2, "}}");
- if( end ) {
- char *var = va("%.*s", (int)(end - (begin+2)), begin+2);
- char **found_var = map_find(kit_vars, var);
-
- if( found_var && 0[*found_var] ) {
- strcatf(&buffer, "%.*s%s", (int)(begin - text), text, *found_var);
- } else {
- strcatf(&buffer, "%.*s{{%s}}", (int)(begin - text), text, var);
- }
-
- text = end+2;
- } else {
- strcatf(&buffer, "%.*s", (int)(begin - text), text);
-
- text = begin+2;
- }
- }
-
- strcatf(&buffer, "%s", text);
- return buffer;
- }
-}
-
-char *kit_translate( const char *id ) {
- return kit_translate2( id, kit_lang );
-}
-
-void kit_locale( const char *lang ) {
- kit_lang = STRDUP(lang); // @leak
-}
-
-void kit_dump_state( FILE *fp ) {
- for each_map(kit_ids, char *, k, char *, v) {
- fprintf(fp, "[ID ] %s=%s\n", k, v);
- }
- for each_map(kit_vars, char *, k, char *, v) {
- fprintf(fp, "[VAR] %s=%s\n", k, v);
- }
-}
-
-/*
-int main() {
- kit_init();
-
- kit_locale("enUS");
- kit_insert("HELLO_PLAYERS", "Hi {{PLAYER1}} and {{PLAYER2}}!");
- kit_insert("GREET_PLAYERS", "Nice to meet you.");
-
- kit_locale("esES");
- kit_insert("HELLO_PLAYERS", "Hola {{PLAYER1}} y {{PLAYER2}}!");
- kit_insert("GREET_PLAYERS", "Un placer conoceros.");
-
- kit_locale("enUS");
- printf("%s %s\n", kit_translate("HELLO_PLAYERS"), kit_translate("GREET_PLAYERS")); // Hi {{PLAYER1}} and {{PLAYER2}}! Nice to meet you.
-
- kit_locale("esES");
- kit_set("PLAYER1", "John");
- kit_set("PLAYER2", "Karl");
- printf("%s %s\n", kit_translate("HELLO_PLAYERS"), kit_translate("GREET_PLAYERS")); // Hola John y Karl! Un placer conoceros.
-
- assert( 0 == strcmp(kit_translate("NON_EXISTING"), "[[NON_EXISTING]]")); // [[NON_EXISTING]]
- assert(~puts("Ok"));
-}
-*/
#line 0
-// editor is last in place, so it can use all internals from above headers
-
-#line 1 "engine/split/v4k_main.c"
+#line 1 "v4k_main.c"
// ----------------------------------------------------------------------------
static void v4k_pre_init() {
@@ -362135,7 +376085,7 @@ void v4k_init() {
ifdef(debug, trap_install());
// init panic handler
- panic_oom_reserve = SYS_REALLOC(panic_oom_reserve, 1<<20); // 1MiB
+ panic_oom_reserve = SYS_MEM_REALLOC(panic_oom_reserve, 1<<20); // 1MiB
// init glfw
glfw_init();
@@ -362161,7 +376111,2155 @@ void v4k_init() {
}
#line 0
-#line 1 "engine/split/v4k_end.c"
+// editor is last in place, so it can use all internals from above headers
+#line 1 "v4k_editor.c"
+// ## Editor long-term plan
+// - editor = tree of nodes. levels and objects are nodes, and their widgets are also nodes
+// - you can perform actions on nodes, with or without descendants, top-bottom or bottom-top
+// - these operations include load/save, undo/redo, reset, play/render, ddraw, etc
+// - nodes are saved to disk as a filesystem layout: parents are folders, and leafs are files
+// - network replication can be done by external tools by comparing the filesystems and by sending the resulting diff zipped
+//
+// ## Editor roadmap
+// - Gizmos?, scene tree, property editor?, load/save?, undo/redo?, copy/paste, on/off (vis,tick,ddraw,log), vcs.
+// - Scenenode pass: node singleton display, node console, node labels, node outlines?.
+// - Render pass: billboards?, materials, un/lit, cast shadows, wireframe, skybox?/mie?, fog/atmosphere
+// - Level pass: volumes, triggers, platforms, level streaming, collide?, physics
+// - Edit pass: Procedural content, brushes, noise and CSG.
+// - GUI pass: timeline and data tracks, node graphs.
+
+// ## Alt plan
+// editor is a database + window/tile manager + ui toolkit; all network driven.
+// to be precise, editor is a dumb app and ...
+// - does not know a thing about what it stores.
+// - does not know how to render the game graphics.
+// - does not know how to run the game logic.
+//
+// the editor will create a canvas for your game to render.
+// your game will be responsible to tick the logic and render the window inside the editor.
+//
+// that being said, editor...
+// - can store datas hierarchically.
+// - can perform diffs and merges, and version the datas into repositories.
+// - can be instructed to render UI on top of game and window views.
+// - can download new .natvis and plugins quickly.
+// - can dump whole project in a filesystem form (zip).
+
+// - editor reflects database contents up-to-date.
+// - database can be queried and modified via OSC(UDP) commands.
+
+// editor database uses one table, and stores two kind of payload types:
+// - classes: defines typename and dna. class names are prefixed by '@'
+// - instances: defines typename and datas. instance names are as-is, not prefixed.
+//
+// every save contains 5Ws: what, who, when, where, how,
+// every save can be diffed/merged.
+
+// ----------------------------------------------------------------------------
+
+#define EDITOR_VERSION "2023.10"
+
+// ----------------------------------------------------------------------------
+
+typedef struct editor_bind_t {
+ const char *command;
+ const char *bindings;
+ void (*fn)();
+} editor_bind_t;
+
+array(editor_bind_t) editor_binds;
+
+#define EDITOR_BIND(CMD,KEYS,...) void macro(editor_bind_##CMD##_fn_)() { __VA_ARGS__ }; AUTORUN { array_push(editor_binds, ((editor_bind_t){#CMD,KEYS,macro(editor_bind_##CMD##_fn_)}) ); }
+
+// ----------------------------------------------------------------------------
+
+typedef void (*editor_no_property)(void *);
+array(void*) editor_persist_kv;
+array(editor_no_property) editor_no_properties;
+
+#define EDITOR_PROPERTY(property_name,T,defaults) \
+typedef map(void*,T) editor_##property_name##_map_t; \
+editor_##property_name##_map_t *editor_##property_name##_map() { \
+ static editor_##property_name##_map_t map = 0; do_once map_init_ptr(map); \
+ return ↦ \
+} \
+T editor_##property_name(const void *obj) { \
+ return *map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) defaults)); \
+} \
+void editor_set##property_name(const void *obj, T value) { \
+ *map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) value)) = ((T) value); \
+} \
+void editor_alt##property_name(const void *obj) { \
+ T* found = map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) defaults)); \
+ *found = (T)(uintptr_t)!(*found); \
+} \
+void editor_no##property_name(void *obj) { \
+ T* found = map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) defaults)); \
+ map_erase(*editor_##property_name##_map(), (void*)obj); \
+} \
+AUTORUN { array_push(editor_persist_kv, #T); array_push(editor_persist_kv, editor_##property_name##_map()); array_push(editor_no_properties, editor_no##property_name); }
+
+EDITOR_PROPERTY(open, int, 0); // whether object is tree opened in tree editor
+EDITOR_PROPERTY(selected, int, 0); // whether object is displaying a contextual popup or not
+EDITOR_PROPERTY(changed, int, 0); // whether object is displaying a contextual popup or not
+EDITOR_PROPERTY(popup, int, 0); // whether object is displaying a contextual popup or not
+EDITOR_PROPERTY(visible, int, 0);
+EDITOR_PROPERTY(script, int, 0);
+EDITOR_PROPERTY(event, int, 0);
+EDITOR_PROPERTY(iconinstance, char*, 0);
+EDITOR_PROPERTY(iconclass, char*, 0);
+EDITOR_PROPERTY(treeoffsety, int, 0);
+// new prop: breakpoint: request to break on any given node
+// new prop: persist: objects with this property will be saved on disk
+
+void editor_destroy_properties(void *o) {
+ for each_array(editor_no_properties,editor_no_property,fn) {
+ fn(o);
+ }
+}
+
+void editor_load_on_boot(void) {
+}
+void editor_save_on_quit(void) {
+}
+AUTORUN {
+ editor_load_on_boot();
+ (atexit)(editor_save_on_quit);
+}
+
+// ----------------------------------------------------------------------------
+
+typedef int(*subeditor)(int mode);
+
+struct editor_t {
+ // time
+ unsigned frame;
+ double t, dt, slomo;
+ // controls
+ int transparent;
+ int attached;
+ int active; // focus? does_grabinput instead?
+ int key;
+ vec2 mouse; // 2d coord for ray/picking
+ bool gamepad; // mask instead? |1|2|4|8
+ int hz_high, hz_medium, hz_low;
+ int filter;
+ bool battery; // battery mode: low fps
+ bool unlit;
+ bool ddraw;
+ // event root nodes
+ obj* root;
+ obj* on_init;
+ obj* on_tick;
+ obj* on_draw;
+ obj* on_edit;
+ obj* on_quit;
+ // all of them (hierarchical)
+ array(obj*) objs; // @todo:set() world?
+ // all of them (flat)
+ set(obj*) world;
+ //
+ array(char*) cmds;
+ // subeditors
+ array(subeditor) subeditors;
+} editor = {
+ .active = 1,
+ .gamepad = 1,
+ .hz_high = 60, .hz_medium = 18, .hz_low = 5,
+};
+
+enum {
+ EDITOR_PANEL,
+ EDITOR_WINDOW,
+ EDITOR_WINDOW_NK,
+ EDITOR_WINDOW_NK_SMALL,
+};
+
+int editor_begin(const char *title, int mode) {
+ if( mode == 0 ) return ui_panel(title, PANEL_OPEN);
+ if( mode == 1 ) return ui_window(title, 0);
+
+ int ww = window_width(), w = ww * 0.66;
+ int hh = window_height(), h = hh * 0.66;
+
+ struct nk_rect position = { (ww-w)/2,(hh-h)/2, w,h };
+ nk_flags win_flags = NK_WINDOW_TITLE | NK_WINDOW_BORDER |
+ NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE |
+ NK_WINDOW_CLOSABLE | NK_WINDOW_MINIMIZABLE |
+ // NK_WINDOW_SCALE_LEFT|NK_WINDOW_SCALE_TOP| //< @fixme: move this logic into nuklear
+ // NK_WINDOW_MAXIMIZABLE | NK_WINDOW_PINNABLE |
+ 0; // NK_WINDOW_SCROLL_AUTO_HIDE;
+
+ if( mode == 3 ) {
+ mode = 2, position.x = input(MOUSE_X), position.w = w/3, win_flags =
+ NK_WINDOW_TITLE|NK_WINDOW_CLOSABLE|
+ NK_WINDOW_SCALABLE|NK_WINDOW_MOVABLE| //< nuklear requires these two to `remember` popup rects
+ 0;
+ }
+
+ if( mode == 2 || mode == 3 )
+ if (nk_begin(ui_ctx, title, position, win_flags))
+ return 1;
+ else
+ return nk_end(ui_ctx), 0;
+
+ return 0;
+}
+int editor_end(int mode) {
+ if( mode == 0 ) return ui_panel_end();
+ if( mode == 1 ) return ui_window_end();
+ if( mode == 2 ) nk_end(ui_ctx);
+ if( mode == 3 ) nk_end(ui_ctx);
+ return 0;
+}
+
+#if 0 // deprecate
+bool editor_active() {
+ return ui_hover() || ui_active() || gizmo_active() ? editor.active : 0;
+}
+#endif
+
+int editor_filter() {
+ if( editor.filter ) {
+ if (nk_begin(ui_ctx, "Filter", nk_rect(window_width()-window_width()*0.33,32, window_width()*0.33, 40),
+ NK_WINDOW_NO_SCROLLBAR)) {
+
+ char *bak = ui_filter; ui_filter = 0;
+ ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &bak);
+ ui_filter = bak;
+
+ if( input(KEY_ESC) || ( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 )) {
+ if( ui_filter ) ui_filter[0] = '\0';
+ editor.filter = 0;
+ }
+ }
+ nk_end(ui_ctx);
+ }
+
+ return editor.filter;
+ }
+
+static
+int editor_select_(void *o, const char *mask) {
+ int matches = 0;
+ int off = mask[0] == '!', inv = mask[0] == '~';
+ int match = strmatchi(obj_type(o), mask+off+inv) || strmatchi(obj_name(o), mask+off+inv);
+ if( match ) {
+ editor_setselected(o, inv ? editor_selected(o) ^ 1 : !off);
+ ++matches;
+ }
+ for each_objchild(o, obj*, oo) {
+ matches += editor_select_(oo, mask);
+ }
+ return matches;
+}
+void editor_select(const char *mask) {
+ for each_array( editor.objs, obj*, o )
+ editor_select_(o, mask);
+}
+void editor_unselect() { // same than editor_select("!**");
+ for each_map_ptr(*editor_selected_map(), void*,o, int, k) {
+ if( *k ) *k = 0;
+ }
+ }
+
+void editor_select_aabb(aabb box) {
+ int is_inv = input_held(KEY_CTRL);
+ int is_add = input_held(KEY_SHIFT);
+ if( !is_inv && !is_add ) editor_unselect();
+
+ aabb item = {0};
+ for each_set_ptr( editor.world, obj*, o ) {
+ if( obj_hasmethod(*o,aabb) && obj_aabb(*o, &item) ) {
+ if( aabb_test_aabb(item, box) ) {
+ if( is_inv )
+ editor_altselected(*o);
+ else
+ editor_setselected(*o, 1);
+ }
+ }
+ }
+}
+
+static obj* active_ = 0;
+static void editor_selectgroup_(obj *o, obj *first, obj *last) {
+ // printf("%s (looking for %s in [%s..%s])\n", obj_name(o), active_ ? obj_name(active_) : "", obj_name(first), obj_name(last));
+ if( !active_ ) if( o == first || o == last ) active_ = o == first ? last : first;
+ if( active_ ) editor_setselected(o, 1);
+ if( o == active_ ) active_ = 0;
+ for each_objchild(o, obj*, oo) {
+ editor_selectgroup_(oo, first, last);
+ }
+}
+void editor_selectgroup(obj *first, obj *last) {
+ if( last ) {
+ if( !first ) first = array_count(editor.objs) ? editor.objs[0] : NULL;
+ if( !first ) editor_setselected(last, 1);
+ else {
+ active_ = 0;
+ for each_array(editor.objs,obj*,o) {
+ editor_selectgroup_(o, first, last);
+ }
+ }
+ }
+ }
+
+static obj *find_any_selected_(obj *o) {
+ if( editor_selected(o) ) return o;
+ for each_objchild(o,obj*,oo) {
+ obj *ooo = find_any_selected_(oo);
+ if( ooo )
+ return ooo;
+ }
+ return 0;
+}
+void* editor_first_selected() {
+ for each_array(editor.objs,obj*,o) {
+ obj *oo = find_any_selected_(o);
+ // if( oo ) printf("1st found: %s\n", obj_name(oo));
+ if( oo ) return oo;
+}
+ return 0;
+}
+
+static obj *find_last_selected_(obj *o) {
+ void *last = 0;
+ if( editor_selected(o) ) last = o;
+ for each_objchild(o,obj*,oo) {
+ obj *ooo = find_last_selected_(oo);
+ if( ooo )
+ last = ooo;
+}
+ return last;
+}
+void* editor_last_selected() {
+ void *last = 0;
+ for each_array(editor.objs,obj*,o) {
+ obj *oo = find_last_selected_(o);
+ // if( oo ) printf("last found: %s\n", obj_name(oo));
+ if( oo ) last = oo;
+}
+ return last;
+}
+
+// ----------------------------------------------------------------------------------------
+
+void editor_addtoworld(obj *o) {
+ set_find_or_add(editor.world, o);
+ for each_objchild(o, obj*, oo) {
+ editor_addtoworld(oo);
+}
+}
+
+void editor_watch(const void *o) {
+ array_push(editor.objs, (obj*)o);
+ obj_push(o); // save state
+
+ editor_addtoworld((obj*)o);
+}
+void* editor_spawn(const char *ini) { // deprecate?
+ obj *o = obj_make(ini);
+ editor_watch(o);
+ return o;
+}
+void editor_spawn1() {
+ obj *selected = editor_first_selected();
+ obj *o = selected ? obj_make(obj_saveini(selected)) : obj_new(obj);
+ if( selected ) obj_attach(selected, o), editor_setopen(selected, 1);
+ else
+ editor_watch(o);
+
+ editor_unselect();
+ editor_setselected(o, 1);
+}
+
+typedef set(obj*) set_objp_t;
+static
+void editor_glob_recurse(set_objp_t*list, obj *o) {
+ set_find_or_add(*list, o);
+ for each_objchild(o,obj*,oo) {
+ editor_glob_recurse(list, oo);
+ }
+}
+void editor_destroy_selected() {
+ set_objp_t list = 0;
+ set_init_ptr(list);
+ for each_map_ptr(*editor_selected_map(), obj*,o, int,selected) {
+ if( *selected ) { editor_glob_recurse(&list, *o); }
+ }
+ for each_set(list, obj*, o) {
+ obj_detach(o);
+ }
+ for each_set(list, obj*, o) {
+ // printf("deleting %p %s\n", o, obj_name(o));
+ // remove from watched items
+ for (int i = 0, end = array_count(editor.objs); i < end; ++i) {
+ if (editor.objs[i] == o) {
+ editor.objs[i] = 0;
+ array_erase_slow(editor.objs, i);
+ --end;
+ --i;
+ }
+ }
+ // delete from world
+ set_erase(editor.world, o);
+ // delete properties + obj
+ editor_destroy_properties(o);
+ obj_free(o);
+ }
+ set_free(list);
+}
+void editor_inspect(obj *o) {
+ ui_section(va("%s (%s)", obj_type(o), obj_name(o)));
+
+ if( obj_hasmethod(o, menu) ) {
+ obj_menu(o);
+ }
+
+ for each_objmember(o,TYPE,NAME,PTR) {
+ if( !editor_changed(PTR) ) {
+ obj_push(o);
+ }
+ ui_label_icon_highlight = editor_changed(PTR); // @hack: remove ui_label_icon_highlight hack
+ char *label = va(ICON_MD_UNDO "%s", NAME);
+ int changed = 0;
+ /**/ if( !strcmp(TYPE,"float") ) changed = ui_float(label, PTR);
+ else if( !strcmp(TYPE,"int") ) changed = ui_int(label, PTR);
+ else if( !strcmp(TYPE,"vec2") ) changed = ui_float2(label, PTR);
+ else if( !strcmp(TYPE,"vec3") ) changed = ui_float3(label, PTR);
+ else if( !strcmp(TYPE,"vec4") ) changed = ui_float4(label, PTR);
+ else if( !strcmp(TYPE,"rgb") ) changed = ui_color3(label, PTR);
+ else if( !strcmp(TYPE,"rgba") ) changed = ui_color4(label, PTR);
+ else if( !strcmp(TYPE,"color") ) changed = ui_color4f(label, PTR);
+ else if( !strcmp(TYPE,"color3f") ) changed = ui_color3f(label, PTR);
+ else if( !strcmp(TYPE,"color4f") ) changed = ui_color4f(label, PTR);
+ else if( !strcmp(TYPE,"char*") ) changed = ui_string(label, PTR);
+ else ui_label2(label, va("(%s)", TYPE)); // INFO instead of (TYPE)?
+ if( changed ) {
+ editor_setchanged(PTR, 1);
+ }
+ if( ui_label_icon_highlight )
+ if( ui_label_icon_clicked_L.x >= 6 && ui_label_icon_clicked_L.x <= 26 ) { // @hack: if clicked on UNDO icon (1st icon)
+ editor_setchanged(PTR, 0);
+ }
+ if( !editor_changed(PTR) ) {
+ obj_pop(o);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------------------
+// tty
+
+static thread_mutex_t *console_lock;
+static array(char*) editor_jobs;
+int editor_send(const char *cmd) { // return job-id
+ int skip = strspn(cmd, " \t\r\n");
+ char *buf = STRDUP(cmd + skip);
+ strswap(buf, "\r\n", "");
+ int jobid;
+ do_threadlock(console_lock) {
+ array_push(editor_jobs, buf);
+ jobid = array_count(editor_jobs) - 1;
+ }
+ return jobid;
+}
+const char* editor_recv(int jobid, double timeout_ss) {
+ char *answer = 0;
+
+ while(!answer && timeout_ss >= 0 ) {
+ do_threadlock(console_lock) {
+ if( editor_jobs[jobid][0] == '\0' )
+ answer = editor_jobs[jobid];
+ }
+ timeout_ss -= 0.1;
+ if( timeout_ss > 0 ) sleep_ms(100); // thread_yield()
+ }
+
+ return answer + 1;
+}
+
+// plain and ctrl keys
+EDITOR_BIND(play, "down(F5)", { window_pause(0); /* if(!editor.slomo) editor.active = 0; */ editor.slomo = 1; } );
+EDITOR_BIND(stop, "down(ESC)", { if(editor.t > 0) { window_pause(1), editor.frame = 0, editor.t = 0, editor.dt = 0, editor.slomo = 0, editor.active = 1; editor_select("**"); editor_destroy_selected(); }} );
+EDITOR_BIND(eject, "down(F1)", { /*window_pause(!editor.active); editor.slomo = !!editor.active;*/ editor.active ^= 1; } );
+EDITOR_BIND(pause, "(held(CTRL) & down(P)) | down(PAUSE)", { window_pause( window_has_pause() ^ 1 ); } );
+EDITOR_BIND(frame, "held(CTRL) & down(LEFT)", { window_pause(1); editor.frame++, editor.t += (editor.dt = 1/60.f); } );
+EDITOR_BIND(slomo, "held(CTRL) & down(RIGHT)", { window_pause(0); editor.slomo = maxf(fmod(editor.slomo * 2, 16), 0.125); } );
+EDITOR_BIND(reload, "held(CTRL) & down(F5)", { window_reload(); } );
+EDITOR_BIND(filter, "held(CTRL) & down(F)", { editor.filter ^= 1; } );
+
+// alt keys
+EDITOR_BIND(quit, "held(ALT) & down(F4)", { record_stop(), exit(0); } );
+EDITOR_BIND(mute, "held(ALT) & down(M)", { audio_volume_master( 1 ^ !!audio_volume_master(-1) ); } );
+EDITOR_BIND(gamepad, "held(ALT) & down(G)", { editor.gamepad ^= 1; } );
+EDITOR_BIND(transparent, "held(ALT) & down(T)", { editor.transparent ^= 1; } );
+EDITOR_BIND(record, "held(ALT) & down(Z)", { if(record_active()) record_stop(), ui_notify(va("Video recorded"), date_string()); else { char *name = file_counter(va("%s.mp4",app_name())); app_beep(), window_record(name); } } );
+EDITOR_BIND(screenshot, "held(ALT) & down(S)", { char *name = file_counter(va("%s.png",app_name())); window_screenshot(name), ui_notify(va("Screenshot: %s", name), date_string()); } );
+EDITOR_BIND(battery, "held(ALT) & down(B)", { editor.battery ^= 1; } );
+EDITOR_BIND(outliner, "held(ALT) & down(O)", { ui_show("Outliner", ui_visible("Outliner") ^ true); } );
+EDITOR_BIND(profiler, "held(ALT) & down(P)", { ui_show("Profiler", profiler_enable(ui_visible("Profiler") ^ true)); } );
+EDITOR_BIND(fullscreen, "(held(ALT)&down(ENTER))|down(F11)",{ record_stop(), window_fullscreen( window_has_fullscreen() ^ 1 ); } ); // close any recording before framebuffer resizing, which would corrupt video stream
+EDITOR_BIND(unlit, "held(ALT) & down(U)", { editor.unlit ^= 1; } );
+EDITOR_BIND(ddraw, "held(ALT) & down(D)", { editor.ddraw ^= 1; } );
+
+void editor_pump() {
+ for each_array(editor_binds,editor_bind_t,b) {
+ if( input_eval(b.bindings) ) {
+ editor_send(b.command);
+ }
+ }
+
+ do_threadlock(console_lock) {
+ for each_array_ptr(editor_jobs,char*,cmd) {
+ if( (*cmd)[0] ) {
+ int found = 0;
+ for each_array(editor_binds,editor_bind_t,b) {
+ if( !strcmpi(b.command, *cmd)) {
+ b.fn();
+ found = 1;
+ break;
+ }
+ }
+
+ if( !found ) {
+ // alert(va("Editor: could not handle `%s` command.", *cmd));
+ (*cmd)[0] = '\0'; strcatf(&(*cmd), "\1%s\n", "Err\n"); (*cmd)[0] = '\0';
+ }
+
+ if( (*cmd)[0] ) {
+ (*cmd)[0] = '\0'; strcatf(&(*cmd), "\1%s\n", "Ok\n"); (*cmd)[0] = '\0';
+ }
+ }
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------------------
+
+void editor_symbol(int x, int y, const char *sym) {
+ #define FONT_SYMBOLS FONT_FACE2
+ #define FONT_WHITE FONT_COLOR1
+ #define FONT_YELLOW FONT_COLOR2
+ #define FONT_ORANGE FONT_COLOR3
+ #define FONT_CYAN FONT_COLOR4
+ // style: atlas size, unicode ranges and 6 font faces max
+ do_once font_face(FONT_SYMBOLS, "MaterialIconsSharp-Regular.otf", 24.f, FONT_EM|FONT_2048);
+ // style: 10 colors max
+ do_once font_color(FONT_WHITE, WHITE);
+ do_once font_color(FONT_YELLOW, YELLOW);
+ do_once font_color(FONT_CYAN, CYAN);
+ do_once font_color(FONT_ORANGE, ORANGE);
+ font_goto(x,y);
+ font_print(va(FONT_SYMBOLS FONT_WHITE FONT_H1 "%s", sym));
+}
+
+void editor_frame( void (*game)(unsigned, float, double) ) {
+ do_once {
+ set_init_ptr(editor.world);
+ //set_init_ptr(editor.selection);
+ profiler_enable( false );
+
+ window_pause( true );
+ window_cursor_shape(CURSOR_SW_AUTO);
+ editor.hz_high = window_fps_target();
+
+ fx_load("editorOutline.fs");
+ fx_enable(0, 1);
+
+ obj_setname(editor.root = obj_new(obj), "Signals");
+ obj_setname(editor.on_init = obj_new(obj), "onInit");
+ obj_setname(editor.on_tick = obj_new(obj), "onTick");
+ obj_setname(editor.on_draw = obj_new(obj), "onDraw");
+ obj_setname(editor.on_edit = obj_new(obj), "onEdit");
+ obj_setname(editor.on_quit = obj_new(obj), "onQuit");
+
+ obj_attach(editor.root, editor.on_init);
+ obj_attach(editor.root, editor.on_tick);
+ obj_attach(editor.root, editor.on_draw);
+ obj_attach(editor.root, editor.on_edit);
+ obj_attach(editor.root, editor.on_quit);
+
+ editor_seticoninstance(editor.root, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_init, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_tick, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_draw, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_edit, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_quit, ICON_MDI_SIGNAL_VARIANT);
+
+ editor_seticonclass(obj_type(editor.root), ICON_MDI_CUBE_OUTLINE);
+ }
+
+ // game tick
+ game(editor.frame, editor.dt, editor.t);
+
+ // timing
+ editor.dt = clampf(window_delta(), 0, 1/60.f) * !window_has_pause() * editor.slomo;
+ editor.t += editor.dt;
+ editor.frame += !window_has_pause();
+ editor.frame += !editor.frame;
+
+ // process inputs & messages
+ editor_pump();
+
+ // adaptive framerate
+ int app_on_background = !window_has_focus();
+ int hz = app_on_background ? editor.hz_low : editor.battery ? editor.hz_medium : editor.hz_high;
+ window_fps_lock( hz < 5 ? 5 : hz );
+
+ // draw menubar
+ static int stats_mode = 1;
+ static double last_fps = 0; if(!window_has_pause()) last_fps = window_fps();
+ const char *STATS = va("x%4.3f %03d.%03dss %02dF %s",
+ editor.slomo, (int)editor.t, (int)(1000 * (editor.t - (int)editor.t)),
+ (editor.frame-1) % ((int)window_fps_target() + !(int)window_fps_target()),
+ stats_mode == 1 ? va("%5.2f/%dfps", last_fps, (int)window_fps_target()) : stats_mode == 0 ? "0/0 KiB" : xstats());
+ const char *ICON_PL4Y = window_has_pause() ? ICON_MDI_PLAY : ICON_MDI_PAUSE;
+ const char *ICON_SKIP = window_has_pause() ? ICON_MDI_STEP_FORWARD/*ICON_MDI_SKIP_NEXT*/ : ICON_MDI_FAST_FORWARD;
+
+ int is_borderless = !glfwGetWindowAttrib(window, GLFW_DECORATED);
+ int ingame = !editor.active;
+ static double clicked_titlebar = 0;
+ UI_MENU(14+is_borderless, \
+ if(ingame) ui_disable(); \
+ UI_MENU_ITEM(ICON_MDI_FILE_TREE, editor_send("scene")) \
+ if(ingame) ui_enable(); \
+ UI_MENU_ITEM(ICON_PL4Y, if(editor.t == 0) editor_send("eject"); editor_send(window_has_pause() ? "play" : "pause")) \
+ UI_MENU_ITEM(ICON_SKIP, editor_send(window_has_pause() ? "frame" : "slomo")) \
+ UI_MENU_ITEM(ICON_MDI_STOP, editor_send("stop")) \
+ UI_MENU_ITEM(ICON_MDI_EJECT, editor_send("eject")) \
+ UI_MENU_ITEM(STATS, stats_mode = (++stats_mode) % 3) \
+ UI_MENU_ALIGN_RIGHT(32+32+32+32+32+32+34 + 32*is_borderless, clicked_titlebar = time_ms()) \
+ if(ingame) ui_disable(); \
+ UI_MENU_ITEM(ICON_MD_FOLDER_SPECIAL, editor_send("browser")) \
+ UI_MENU_ITEM(ICON_MDI_SCRIPT_TEXT, editor_send("script")) \
+ UI_MENU_ITEM(ICON_MDI_CHART_TIMELINE, editor_send("timeline")) \
+ UI_MENU_ITEM(ICON_MDI_CONSOLE, editor_send("console")) \
+ UI_MENU_ITEM(ICON_MDI_GRAPH, editor_send("nodes")) \
+ UI_MENU_ITEM(ICON_MD_SEARCH, editor_send("filter")) \
+ UI_MENU_POPUP(ICON_MD_SETTINGS, vec2(0.33,1.00), ui_debug()) \
+ if(ingame) ui_enable(); \
+ UI_MENU_ITEM(ICON_MD_CLOSE, editor_send("quit")) \
+ );
+
+ if( is_borderless ) {
+ static vec3 drag = {0};
+ if( clicked_titlebar ) {
+ static double clicks = 0;
+ if( input_up(MOUSE_L) ) ++clicks;
+ if( input_up(MOUSE_L) && clicks == 2 ) window_visible(false), window_maximize( window_has_maximize() ^ 1 ), window_visible(true);
+ if( (time_ms() - clicked_titlebar) > 400 ) clicks = 0, clicked_titlebar = 0;
+
+ if( input_down(MOUSE_L) ) drag = vec3(input(MOUSE_X), input(MOUSE_Y), 1);
+ }
+ if( drag.z *= !input_up(MOUSE_L) ) {
+ int wx = 0, wy = 0;
+ glfwGetWindowPos(window_handle(), &wx, &wy);
+ glfwSetWindowPos(window_handle(), wx + input(MOUSE_X) - drag.x, wy + input(MOUSE_Y) - drag.y);
+ }
+ }
+
+ if( !editor.active ) return;
+
+ // draw edit view (gizmos, position markers, etc).
+ for each_set_ptr(editor.world,obj*,o) {
+ if( obj_hasmethod(*o,edit) ) {
+ obj_edit(*o);
+ }
+}
+
+ // draw silhouettes
+ sprite_flush();
+ fx_begin();
+ for each_map_ptr(*editor_selected_map(),void*,o,int,selected) {
+ if( !*selected ) continue;
+ if( obj_hasmethod(*o,draw) ) {
+ obj_draw(*o);
+ }
+ if( obj_hasmethod(*o,edit) ) {
+ obj_edit(*o);
+}
+}
+ sprite_flush();
+ fx_end();
+
+ // draw box selection
+ if( !ui_active() ) { //< check that we're not moving a window
+ static vec2 from = {0}, to = {0};
+ if( input_down(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y)), from = to;
+ if( input(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y));
+ if( len2sq(sub2(from,to)) > 0 ) {
+ vec2 a = min2(from, to), b = max2(from, to);
+ ddraw_push_2d();
+ ddraw_color_push(YELLOW);
+ ddraw_line( vec3(a.x,a.y,0),vec3(b.x-1,a.y,0) );
+ ddraw_line( vec3(b.x,a.y,0),vec3(b.x,b.y-1,0) );
+ ddraw_line( vec3(b.x,b.y,0),vec3(a.x-1,b.y,0) );
+ ddraw_line( vec3(a.x,b.y,0),vec3(a.x,a.y-1,0) );
+ ddraw_color_pop();
+ ddraw_pop_2d();
+ }
+ if( input_up(MOUSE_L) ) {
+ vec2 a = min2(from, to), b = max2(from, to);
+ from = to = vec2(0,0);
+
+ editor_select_aabb(aabb(vec3(a.x,a.y,0),vec3(b.x,b.y,0)));
+ }
+ }
+
+ // draw mouse aabb
+ aabb mouse = { vec3(input(MOUSE_X),input(MOUSE_Y),0), vec3(input(MOUSE_X),input(MOUSE_Y),1)};
+ if( 1 ) {
+ ddraw_color_push(YELLOW);
+ ddraw_push_2d();
+ ddraw_aabb(mouse.min, mouse.max);
+ ddraw_pop_2d();
+ ddraw_color_pop();
+ }
+
+ // tick mouse aabb selection and contextual tab (RMB)
+ aabb box = {0};
+ for each_set(editor.world,obj*,o) {
+ if( !obj_hasmethod(o, aabb) ) continue;
+ if( !obj_aabb(o, &box) ) continue;
+
+ // trigger contextual inspector
+ if( input_down(MOUSE_R) ) {
+ int is_selected = editor_selected(o);
+ editor_setpopup(o, is_selected);
+ }
+
+ // draw contextual inspector
+ if( editor_popup(o) ) {
+ if( editor_begin(va("%s (%s)", obj_name(o), obj_type(o)),EDITOR_WINDOW_NK_SMALL) ) {
+ ui_label2(obj_name(o), obj_type(o));
+ editor_inspect(o);
+ editor_end(EDITOR_WINDOW_NK_SMALL);
+ } else {
+ editor_setpopup(o, 0);
+ }
+ }
+}
+
+
+ // draw subeditors
+ static int preferred_window_mode = EDITOR_WINDOW;
+ static struct nk_color bak, *on = 0; do_once bak = ui_ctx->style.window.fixed_background.data.color; // ui_ctx->style.window.fixed_background.data.color = !!(on = (on ? NULL : &bak)) ? AS_NKCOLOR(0) : bak; };
+ if( editor.transparent ) ui_ctx->style.window.fixed_background.data.color = AS_NKCOLOR(0);
+ for each_array(editor.subeditors, subeditor, fn) {
+ fn(preferred_window_mode);
+ }
+ ui_ctx->style.window.fixed_background.data.color = bak;
+
+ // draw ui filter (note: render at end-of-frame, so it's hopefully on-top)
+ editor_filter();
+}
+#line 0
+#line 1 "v4k_editor_scene.h"
+#define SCENE_ICON ICON_MDI_FILE_TREE
+#define SCENE_TITLE "Scene " SCENE_ICON
+
+EDITOR_BIND(scene, "held(CTRL)&down(1)", { ui_show(SCENE_TITLE, ui_visible(SCENE_TITLE) ^ true); });
+
+EDITOR_PROPERTY(bookmarked, int, 0);
+
+EDITOR_BIND(node_new, "down(INS)", { editor_spawn1(); } );
+EDITOR_BIND(node_del, "down(DEL)", { editor_destroy_selected(); } );
+EDITOR_BIND(node_save, "held(CTRL)&down(S)", { puts("@todo"); } );
+EDITOR_BIND(scene_save, "held(CTRL)&down(S)&held(SHIFT)",{ puts("@todo"); } );
+EDITOR_BIND(select_all, "held(CTRL) & down(A)", { editor_select("**"); } );
+EDITOR_BIND(select_none, "held(CTRL) & down(D)", { editor_select("!**"); } );
+EDITOR_BIND(select_invert, "held(CTRL) & down(I)", { editor_select("~**"); } );
+EDITOR_BIND(bookmark, "held(CTRL) & down(B)", { editor_selected_map_t *map = editor_selected_map(); \
+ int on = 0; \
+ for each_map_ptr(*map,void*,o,int,selected) if(*selected) on |= !editor_bookmarked(*o); \
+ for each_map_ptr(*map,void*,o,int,selected) if(*selected) editor_setbookmarked(*o, on); \
+} );
+
+enum {
+ SCENE_RECURSE = 1,
+ SCENE_SELECTION = 2,
+ SCENE_CHECKBOX = 4,
+ SCENE_INDENT = 8,
+ SCENE_ALL = ~0u
+};
+
+static
+void editor_scene_(obj *o, unsigned flags) {
+ static unsigned tabs = ~0u;
+ ++tabs;
+
+ if( o ) {
+ unsigned do_tags = 1;
+ unsigned do_indent = !!(flags & SCENE_INDENT);
+ unsigned do_checkbox = !!(flags & SCENE_CHECKBOX);
+ unsigned do_recurse = !!(flags & SCENE_RECURSE);
+ unsigned do_selection = !!(flags & SCENE_SELECTION);
+
+ nk_layout_row_dynamic(ui_ctx, 25, 1);
+
+ const char *objicon = editor_iconinstance(o);
+ if(!objicon) objicon = editor_iconclass(obj_type(o));
+ if(!objicon) objicon = ICON_MDI_CUBE_OUTLINE;
+
+ const char *objname = va("%s (%s)", obj_type(o), obj_name(o));
+
+ const char *objchevron =
+ !do_recurse || array_count(*obj_children(o)) <= 1 ? ICON_MDI_CIRCLE_SMALL :
+ editor_open(o) ? ICON_MDI_CHEVRON_DOWN : ICON_MDI_CHEVRON_RIGHT;
+
+ char *label = va("%*s%s%s %s", do_indent*(4+2*tabs), "", objchevron, objicon, objname);
+
+ const char *iconsL =
+ //editor_selected(o) ? ICON_MD_CHECK_BOX : ICON_MD_CHECK_BOX_OUTLINE_BLANK;
+ editor_selected(o) ? ICON_MDI_CHECKBOX_MARKED : ICON_MDI_CHECKBOX_BLANK_OUTLINE;
+
+ const char *iconsR = va("%s%s%s",
+ editor_script(o) ? ICON_MDI_SCRIPT : ICON_MDI_CIRCLE_SMALL,
+ editor_event(o) ? ICON_MDI_CALENDAR : ICON_MDI_CIRCLE_SMALL,
+ editor_visible(o) ? ICON_MDI_EYE_OUTLINE : ICON_MDI_EYE_CLOSED );
+
+ UI_TOOLBAR_OVERLAY_DECLARE(int choiceL, choiceR);
+
+ struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
+ struct nk_rect bounds; nk_layout_peek(&bounds, ui_ctx);
+
+ int clicked = nk_hovered_text(ui_ctx, label, strlen(label), NK_TEXT_LEFT, editor_selected(o));
+ if( clicked && nk_input_is_mouse_hovering_rect(&ui_ctx->input, ((struct nk_rect) { bounds.x,bounds.y,bounds.w*0.66,bounds.h })) )
+ editor_altselected( o );
+
+ vec2i offset_in_tree = {0};
+
+ if( do_indent ) {
+ float thickness = 2.f;
+ struct nk_color color = {255,255,255,64};
+
+ int offsx = 30;
+ int spacx = 10;
+ int lenx = (tabs+1)*spacx;
+ int halfy = bounds.h / 2;
+ int offsy = halfy + 2;
+
+ offset_in_tree = vec2i(bounds.x+offsx+lenx-spacx,bounds.y+offsy);
+
+ editor_settreeoffsety(o, offset_in_tree.y);
+
+ for( obj *p = obj_parent(o); p ; p = 0 )
+ nk_stroke_line(canvas, offset_in_tree.x-6,offset_in_tree.y, offset_in_tree.x-spacx,offset_in_tree.y, thickness, color),
+ nk_stroke_line(canvas, offset_in_tree.x-spacx,offset_in_tree.y,offset_in_tree.x-spacx,editor_treeoffsety(p)+4, thickness, color);
+ }
+
+ if( ui_contextual() ) {
+ int choice = ui_label(ICON_MD_BOOKMARK_ADDED "Toggle bookmarks (CTRL+B)");
+ if( choice & 1 ) editor_send("bookmark");
+
+ ui_contextual_end(!!choice);
+ }
+
+ UI_TOOLBAR_OVERLAY(choiceL,iconsL,nk_rgba_f(1,1,1,do_checkbox*ui_alpha*0.65),NK_TEXT_LEFT);
+
+ if( do_tags )
+ UI_TOOLBAR_OVERLAY(choiceR,iconsR,nk_rgba_f(1,1,1,ui_alpha*0.65),NK_TEXT_RIGHT);
+
+ if( choiceR == 3 ) editor_altscript( o );
+ if( choiceR == 2 ) editor_altevent( o);
+ if( choiceR == 1 ) editor_altvisible( o );
+
+ if( do_recurse && editor_open(o) ) {
+ for each_objchild(o,obj*,oo) {
+ editor_scene_(oo,flags);
+ }
+ }
+
+ if( clicked && !choiceL && !choiceR ) {
+ int is_picking = input(KEY_CTRL);
+ if( !is_picking ) {
+ if( input(KEY_SHIFT) ) {
+ editor_selectgroup( editor_first_selected(), editor_last_selected() );
+ } else {
+ editor_unselect();
+ editor_setselected(o, 1);
+ }
+ }
+ for( obj *p = obj_parent(o); p; p = obj_parent(p) ) {
+ editor_setopen(p, 1);
+ }
+ if( nk_input_is_mouse_hovering_rect(&ui_ctx->input, ((struct nk_rect) { bounds.x,bounds.y,offset_in_tree.x-bounds.x+UI_ICON_FONTSIZE/2,bounds.h })) ) {
+ editor_altopen( o );
+ }
+ }
+ }
+
+ --tabs;
+}
+
+int editor_scene(int window_mode) {
+ window_mode = EDITOR_WINDOW; // force window
+
+ if( editor_begin(SCENE_TITLE, window_mode)) {
+ // #define HELP ICON_MDI_INFORMATION_OUTLINE "@-A\n-B\n-C\n" ";"
+ int choice = ui_toolbar(ICON_MDI_PLUS "@New node (CTRL+N);" ICON_MDI_DOWNLOAD "@Save node (CTRL+S);" ICON_MDI_DOWNLOAD "@Save scene (SHIFT+CTRL+S);" ICON_MD_BOOKMARK_ADDED "@Toggle Bookmark (CTRL+B);");
+ if( choice == 1 ) editor_send("node_new");
+ if( choice == 2 ) editor_send("node_save");
+ if( choice == 3 ) editor_send("scene_save");
+ if( choice == 4 ) editor_send("bookmark");
+
+ array(obj*) bookmarks = 0;
+ for each_map_ptr(*editor_bookmarked_map(), void*,o,int,bookmarked) {
+ if( *bookmarked ) {
+ array_push(bookmarks, *o);
+ }
+ }
+ if( ui_collapse("!" ICON_MD_BOOKMARK "Bookmarks", "DEBUG:BOOKMARK")) {
+ for each_array( bookmarks, obj*, o )
+ editor_scene_( o, SCENE_ALL & ~(SCENE_RECURSE|SCENE_INDENT|SCENE_CHECKBOX) );
+ ui_collapse_end();
+ }
+ array_free(bookmarks);
+
+ editor_scene_( editor.root, SCENE_ALL );
+
+ for each_array( editor.objs, obj*, o )
+ editor_scene_( o, SCENE_ALL );
+
+ ui_separator();
+
+ // edit selection
+ for each_map(*editor_selected_map(), void*,o, int, k) {
+ if( k ) editor_inspect(o);
+ }
+
+ editor_end(window_mode);
+ }
+
+ return 0;
+}
+
+AUTORUN {
+ array_push(editor.subeditors, editor_scene);
+}
+#line 0
+#line 1 "v4k_editor_browser.h"
+#define BROWSER_ICON ICON_MD_FOLDER_SPECIAL
+#define BROWSER_TITLE "Browser " BROWSER_ICON
+
+EDITOR_BIND(browser, "held(CTRL)&down(2)", { ui_show(BROWSER_TITLE, ui_visible(BROWSER_TITLE) ^ true); });
+
+int editor_browser(int window_mode) {
+ window_mode = EDITOR_WINDOW; // force window
+ if( editor_begin(BROWSER_TITLE, window_mode) ) {
+ const char *file = 0;
+ if( ui_browse(&file, NULL) ) {
+ const char *sep = ifdef(win32, "\"", "'");
+ app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep));
+ }
+ editor_end(window_mode);
+ }
+ return 0;
+}
+
+AUTORUN {
+ array_push(editor.subeditors, editor_browser);
+}
+#line 0
+#line 1 "v4k_editor_timeline.h"
+#define TIMELINE_ICON ICON_MDI_CHART_TIMELINE
+#define TIMELINE_TITLE "Timeline " TIMELINE_ICON
+
+EDITOR_BIND(timeline, "held(CTRL)&down(3)", { ui_show(TIMELINE_TITLE, ui_visible(TIMELINE_TITLE) ^ true); });
+
+int ui_tween(const char *label, tween_t *t) {
+ if( ui_filter && ui_filter[0] ) if( !strstr(label, ui_filter) ) return 0;
+
+ int expand_keys = label[0] == '!'; label += expand_keys;
+ const char *id = label;
+ if( strchr(id, '@') ) *strchr((char*)(id = (const char*)va("%s", label)), '@') = '\0';
+
+ enum { LABEL_SPACING = 250 };
+ enum { ROUNDING = 0 };
+ enum { THICKNESS = 1 };
+ enum { PIXELS_PER_SECOND = 60 };
+ enum { KEY_WIDTH = 5, KEY_HEIGHT = 5 };
+ enum { TIMELINE_HEIGHT = 25 };
+ enum { MARKER1_HEIGHT = 5, MARKER10_HEIGHT = 20, MARKER5_HEIGHT = (MARKER1_HEIGHT + MARKER10_HEIGHT) / 2 };
+ unsigned base_color = WHITE;
+ unsigned time_color = YELLOW;
+ unsigned duration_color = ORANGE;
+ unsigned key_color = GREEN;
+
+ int changed = 0;
+
+#if 0
+ // two rows with height:30 composed of three widgets
+ nk_layout_row_template_begin(ui_ctx, 30);
+ nk_layout_row_template_push_variable(ui_ctx, t->duration * PIXELS_PER_SECOND); // min 80px. can grow
+ nk_layout_row_template_end(ui_ctx);
+#endif
+
+ char *sid = va("%s.%d", id, 0);
+ uint64_t hash = 14695981039346656037ULL, mult = 0x100000001b3ULL;
+ for(int i = 0; sid[i]; ++i) hash = (hash ^ sid[i]) * mult;
+ ui_hue = (hash & 0x3F) / (float)0x3F; ui_hue += !ui_hue;
+
+ ui_label(label);
+
+ struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
+ struct nk_rect bounds; nk_layout_peek(&bounds, ui_ctx);
+ bounds.y -= 30;
+
+ struct nk_rect baseline = bounds; baseline.y += 30/2;
+ baseline.x += LABEL_SPACING;
+ baseline.w -= LABEL_SPACING;
+
+ // tween duration
+ {
+ struct nk_rect pos = baseline;
+ pos.w = pos.x + t->duration * PIXELS_PER_SECOND;
+ pos.y -= TIMELINE_HEIGHT/2;
+ pos.h = TIMELINE_HEIGHT;
+ nk_stroke_rect(canvas, pos, ROUNDING, THICKNESS*2, AS_NKCOLOR(duration_color));
+ }
+
+ // tween ranges
+ for(int i = 0, end = array_count(t->keyframes) - 1; i < end; ++i) {
+ tween_keyframe_t *k = t->keyframes + i;
+ tween_keyframe_t *next = k + 1;
+
+ struct nk_rect pos = baseline;
+ pos.x += k->t * PIXELS_PER_SECOND;
+ pos.w = (next->t - k->t) * PIXELS_PER_SECOND;
+ pos.y -= TIMELINE_HEIGHT/2;
+ pos.h = TIMELINE_HEIGHT;
+
+ char *sid = va("%s.%d", id, i);
+ uint64_t hash = 14695981039346656037ULL, mult = 0x100000001b3ULL;
+ for(int i = 0; sid[i]; ++i) hash = (hash ^ sid[i]) * mult;
+ ui_hue = (hash & 0x3F) / (float)0x3F; ui_hue += !ui_hue;
+
+ struct nk_color c = nk_hsva_f(ui_hue, 0.75f, 0.8f, ui_alpha);
+ nk_fill_rect(canvas, pos, ROUNDING, k->ease == EASE_NOP ? AS_NKCOLOR(0) : c); // AS_NKCOLOR(track_color));
+ }
+
+ // horizontal line
+ nk_stroke_line(canvas, baseline.x, baseline.y, baseline.x+baseline.w,baseline.y, THICKNESS, AS_NKCOLOR(base_color));
+
+ // unit, 5-unit and 10-unit markers
+ for( float i = 0, j = 0; i < baseline.w; i += PIXELS_PER_SECOND/10, ++j ) {
+ int len = !((int)j%10) ? MARKER10_HEIGHT : !((int)j%5) ? MARKER5_HEIGHT : MARKER1_HEIGHT;
+ nk_stroke_line(canvas, baseline.x+i, baseline.y-len, baseline.x+i, baseline.y+len, THICKNESS, AS_NKCOLOR(base_color));
+ }
+
+ // time marker
+ float px = t->time * PIXELS_PER_SECOND;
+ nk_stroke_line(canvas, baseline.x+px, bounds.y, baseline.x+px, bounds.y+bounds.h, THICKNESS*2, AS_NKCOLOR(time_color));
+ nk_draw_symbol(canvas, NK_SYMBOL_TRIANGLE_DOWN, ((struct nk_rect){ baseline.x+px-4,bounds.y-4-8,8,8}), /*bg*/AS_NKCOLOR(0), /*fg*/AS_NKCOLOR(time_color), 0.f/*border_width*/, ui_ctx->style.font);
+
+ // key markers
+ for each_array_ptr(t->keyframes, tween_keyframe_t, k) {
+ struct nk_rect pos = baseline;
+ pos.x += k->t * PIXELS_PER_SECOND;
+
+ vec2 romboid[] = {
+ {pos.x-KEY_WIDTH,pos.y}, {pos.x,pos.y-KEY_HEIGHT},
+ {pos.x+KEY_WIDTH,pos.y}, {pos.x,pos.y+KEY_HEIGHT}
+ };
+
+ nk_fill_polygon(canvas, (float*)romboid, countof(romboid), AS_NKCOLOR(key_color));
+ }
+
+ // keys ui
+ if( expand_keys )
+ for(int i = 0, end = array_count(t->keyframes); i < end; ++i) {
+ tween_keyframe_t *k = t->keyframes + i;
+ if( ui_collapse(va("Key %d", i), va("%s.%d", id, i))) {
+ changed |= ui_float("Time", &k->t);
+ changed |= ui_float3("Value", &k->v.x);
+ changed |= ui_list("Ease", ease_enums(), EASE_NUM, &k->ease );
+ ui_collapse_end();
+ }
+ }
+
+ return changed;
+}
+
+tween_t* rand_tween() {
+ tween_t demo = tween();
+ int num_keys = randi(2,8);
+ double t = 0;
+ for( int i = 0; i < num_keys; ++i) {
+ tween_setkey(&demo, t, scale3(vec3(randf(),randf(),randf()),randi(-5,5)), randi(0,EASE_NUM) );
+ t += randi(1,5) / ((float)(1 << randi(0,2)));
+ }
+ tween_t *p = CALLOC(1, sizeof(tween_t));
+ memcpy(p, &demo, sizeof(tween_t));
+ return p;
+}
+
+int editor_timeline(int window_mode) {
+ static array(tween_t*) tweens = 0;
+
+ do_once {
+ array_push(tweens, rand_tween());
+ }
+
+ if( editor.t == 0 )
+ for each_array(tweens, tween_t*,t) {
+ tween_reset(t);
+ }
+ else
+ for each_array(tweens, tween_t*,t) {
+ tween_update(t, editor.dt);
+ }
+
+ static void *selected = NULL;
+ if( editor_begin(TIMELINE_TITLE, window_mode) ) {
+
+ int choice = ui_toolbar(ICON_MDI_PLUS ";" ICON_MDI_MINUS );
+ if( choice == 1 ) array_push(tweens, rand_tween());
+ if( choice == 2 && selected ) {
+ int target = -1;
+ for( int i = 0, end = array_count(tweens); i < end; ++i ) if( tweens[i] == selected ) { target = i; break; }
+ if( target >= 0 ) { array_erase_slow(tweens, target); selected = NULL; }
+ }
+
+ for each_array(tweens, tween_t*,t) {
+ ui_tween(va("%s%p@%05.2fs Value: %s", t == selected ? "!":"", t, t->time, ftoa3(t->result)), t);
+ if(ui_label_icon_clicked_L.x) selected = (t != selected) ? t : NULL;
+ }
+
+ editor_end(window_mode);
+ }
+ return 0;
+}
+
+AUTORUN {
+ array_push(editor.subeditors, editor_timeline);
+}
+#line 0
+#line 1 "v4k_editor_console.h"
+#define CONSOLE_ICON ICON_MDI_CONSOLE
+#define CONSOLE_TITLE "Console " CONSOLE_ICON
+
+EDITOR_BIND(console, "held(CTRL)&down(4)", { ui_show(CONSOLE_TITLE, ui_visible(CONSOLE_TITLE) ^ true); });
+
+int editor_console(int window_mode) {
+ if( editor_begin(CONSOLE_TITLE, window_mode) ) {
+
+ // peek complete window space
+ struct nk_rect bounds = nk_window_get_content_region(ui_ctx);
+
+ enum { CONSOLE_LINE_HEIGHT = 20 };
+ static array(char*) lines = 0;
+ do_once {
+ array_push(lines, stringf("> Editor v%s. Type `%s` for help.", EDITOR_VERSION, ""));
+ }
+ int max_lines = (bounds.h - UI_ROW_HEIGHT) / (CONSOLE_LINE_HEIGHT * 2);
+ if( max_lines >= 1 ) {
+ nk_layout_row_static(ui_ctx, bounds.h - UI_ROW_HEIGHT, bounds.w, 1);
+ if(nk_group_begin(ui_ctx, "console.group", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {
+ nk_layout_row_static(ui_ctx, CONSOLE_LINE_HEIGHT, bounds.w, 1);
+ for( int i = array_count(lines); i < max_lines; ++i )
+ array_push_front(lines, 0);
+ for( int i = array_count(lines) - max_lines; i < array_count(lines); ++i ) {
+ if( !lines[i] ) {
+ #if 0 // debug
+ nk_label_wrap(ui_ctx, va("%d.A/%d",i+1,max_lines));
+ nk_label_wrap(ui_ctx, va("%d.B/%d",i+1,max_lines));
+ #else
+ nk_label_wrap(ui_ctx, "");
+ nk_label_wrap(ui_ctx, "");
+ #endif
+ } else {
+ nk_label_wrap(ui_ctx, lines[i]);
+ const char *answer = isdigit(*lines[i]) ? editor_recv( atoi(lines[i]), 0 ) : NULL;
+ nk_label_wrap(ui_ctx, answer ? answer : "");
+ }
+ }
+ nk_group_end(ui_ctx);
+ }
+ }
+ static char *cmd = 0;
+ if( ui_string(NULL, &cmd) ) {
+ int jobid = editor_send(cmd);
+ array_push(lines, stringf("%d> %s", jobid, cmd));
+ cmd[0] = 0;
+ }
+
+ editor_end(window_mode);
+ }
+ return 0;
+}
+
+AUTORUN {
+ array_push(editor.subeditors, editor_console);
+}
+#line 0
+#line 1 "v4k_editor_nodes.h"
+#define NODES_ICON ICON_MDI_GRAPH
+#define NODES_TITLE "Nodes " NODES_ICON
+
+EDITOR_BIND(nodes, "held(CTRL)&down(5)", { ui_show(NODES_TITLE, ui_visible(NODES_TITLE) ^ true); });
+
+/*
+A basic node-based UI built with Nuklear.
+Builds on the node editor example included in Nuklear v1.00, with the aim of
+being used as a prototype for implementing a functioning node editor.
+
+Features:
+- Nodes of different types. Currently their implementations are #included in
+ the main file, but they could easily be turned into eg. a plugin system.
+- Pins/pins of different types -- currently float values and colors.
+- Adding and removing nodes.
+- Linking nodes, with validation (one link per input, only link similar pins).
+- Detaching and moving links.
+- Evaluation of output values of connected nodes.
+- Memory management based on fixed size arrays for links and node pointers
+- Multiple node types
+- Multiple pin types
+- Linking between pins of the same type
+- Detaching and reattaching links
+- Getting value from linked node if pin is connected
+
+Todo:
+- Complete pin types.
+- Allow dragging from output to input pin.
+- Cut link by CTRL+clicking input pin.
+- Cut link by drawing intersect line on a link.
+- Group elemnts together with mouse, or LSHIFT+clicking.
+- Drag groups.
+- DEL elements.
+- DEL groups.
+- CTRL-C/CTRL-V/CTRL-X elements.
+- CTRL-C/CTRL-V/CTRL-X groups.
+- CTRL-Z,CTRL-Y.
+- CTRL-N.
+- CTRL-L,CTRL-S.
+- CTRL-F.
+- CTRL-Wheel Zooming.
+- Allow to extend node types from Lua.
+
+Extra todo:
+- Execution Flow (see: nk_stroke_triangle, nk_fill_triangle)
+- Complete missing nodes (see: nk_draw_image, nk_draw_text)
+- Right-click could visualize node/board diagram as Lua script.
+- Once that done, copy/pasting scripts should work within editor.
+
+Sources:
+- https://github.com/Immediate-Mode-UI/Nuklear/pull/561
+- https://github.com/vurtun/nuklear/blob/master/demo/node_editor.c
+*/
+
+typedef enum pin_type_t {
+ type_flow,
+ type_int,type_float,
+ type_block,type_texture,type_image,
+ type_color,
+ /*
+ type_bool,
+ type_char, type_string,
+ type_int2, type_int3, type_int4,
+ type_float2, type_float3, type_float4,
+ type_array, type_map,
+ */
+
+ type_total
+} pin_type_t;
+
+struct node_pin {
+ pin_type_t pin_type;
+ nk_bool is_connected;
+ struct node* connected_node;
+ int connected_pin;
+};
+
+struct node {
+ int ID;
+ char name[32];
+ struct nk_rect bounds;
+ int input_count;
+ int output_count;
+ struct node_pin *inputs;
+ struct node_pin *outputs;
+ struct {
+ float in_padding_x;
+ float in_padding_y;
+ float in_spacing_y;
+ float out_padding_x;
+ float out_padding_y;
+ float out_spacing_y;
+ } pin_spacing; /* Maybe this should be called "node_layout" and include the bounds? */
+ struct node *next; /* Z ordering only */
+ struct node *prev; /* Z ordering only */
+
+ void* (*eval_func)(struct node*, int oIndex);
+ void (*display_func)(struct nk_context*, struct node*);
+};
+
+struct node_link {
+ struct node* input_node;
+ int input_pin;
+ struct node* output_node;
+ int output_pin;
+ nk_bool is_active;
+};
+
+struct node_linking {
+ int active;
+ struct node *node;
+ int input_id;
+ int input_pin;
+};
+
+struct node_editor {
+ int initialized;
+ struct node *node_buf[32];
+ struct node_link links[64];
+ struct node *output_node;
+ struct node *begin;
+ struct node *end;
+ int node_count;
+ int link_count;
+ struct nk_rect bounds;
+ struct node *selected;
+ int show_grid;
+ struct nk_vec2 scrolling;
+ struct node_linking linking;
+};
+
+/* === PROTOTYPES === */
+/* The node implementations need these two functions. */
+/* These could/should go in a header file along with the node and node_pin structs and be #included in the node implementations */
+
+struct node* node_editor_add(struct node_editor *editor, size_t nodeSize, const char *name, struct nk_rect bounds, int in_count, int out_count);
+void* node_editor_eval_connected(struct node *node, int input_pin_number);
+/* ================== */
+
+/* === NODE TYPE IMPLEMENTATIONS === */
+
+#define NODE_DEFAULT_ROW_HEIGHT 25
+
+
+// ----------------------------------------------------------------------------------------------------
+// #include "node_output.h"
+
+struct node_type_output {
+ struct node node;
+ struct nk_colorf input_val;
+};
+
+struct nk_colorf *node_output_get(struct node* node) {
+ struct node_type_output *output_node = (struct node_type_output*)node;
+ if (!node->inputs[0].is_connected) {
+ struct nk_colorf black = {0.0f, 0.0f, 0.0f, 0.0f};
+ output_node->input_val = black;
+ }
+ return &output_node->input_val;
+}
+
+static void node_output_display(struct nk_context *ctx, struct node *node) {
+ if (node->inputs[0].is_connected) {
+ struct node_type_output *output_node = (struct node_type_output*)node;
+ output_node->input_val = *(struct nk_colorf*)node_editor_eval_connected(node, 0);
+ nk_layout_row_dynamic(ctx, 60, 1);
+ nk_button_color(ctx, nk_rgba_cf(output_node->input_val));
+ }
+}
+
+struct node* node_output_create(struct node_editor *editor, struct nk_vec2 position) {
+ struct node_type_output *output_node = (struct node_type_output*)node_editor_add(editor, sizeof(struct node_type_output), "Output", nk_rect(position.x, position.y, 100, 100), 1, 0);
+ if (output_node){
+ output_node->node.inputs[0].pin_type = type_color;
+ output_node->node.display_func = node_output_display;
+ }
+ return (struct node*)output_node;
+}
+
+// ----------------------------------------------------------------------------------------------------
+// #include "node_float.h"
+
+struct node_type_float {
+ struct node node;
+ float output_val;
+};
+
+static float *node_float_eval(struct node* node, int oIndex) {
+ struct node_type_float *float_node = (struct node_type_float*)node;
+ NK_ASSERT(oIndex == 0);
+ return &float_node->output_val;
+}
+
+static void node_float_draw(struct nk_context *ctx, struct node *node) {
+ struct node_type_float *float_node = (struct node_type_float*)node;
+ nk_layout_row_dynamic(ctx, NODE_DEFAULT_ROW_HEIGHT, 1);
+ float_node->output_val = nk_propertyf(ctx, "#Value:", 0.0f, float_node->output_val, 1.0f, 0.01f, 0.01f);
+}
+
+void node_float_create(struct node_editor *editor, struct nk_vec2 position) {
+ struct node_type_float *float_node = (struct node_type_float*)node_editor_add(editor, sizeof(struct node_type_float), "Float", nk_rect(position.x, position.y, 180, 75), 0, 1);
+ if (float_node)
+ {
+ float_node->output_val = 1.0f;
+ float_node->node.display_func = node_float_draw;
+ float_node->node.eval_func = (void*(*)(struct node*, int)) node_float_eval;
+ }
+}
+
+// ----------------------------------------------------------------------------------------------------
+// #include "node_color.h"
+
+struct node_type_color {
+ struct node node;
+ float input_val[4];
+ struct nk_colorf output_val;
+};
+
+static struct nk_colorf *node_color_eval(struct node* node, int oIndex)
+{
+ struct node_type_color *color_node = (struct node_type_color*)node;
+ NK_ASSERT(oIndex == 0); /* only one output connector */
+
+ return &color_node->output_val;
+}
+
+
+static void node_color_draw(struct nk_context *ctx, struct node *node)
+{
+ struct node_type_color *color_node = (struct node_type_color*)node;
+ float eval_result; /* Get the values from connected nodes into this so the inputs revert on disconnect */
+ const char* labels[4] = {"#R:","#G:","#B:","#A:"};
+ float color_val[4]; /* Because we can't just loop through the struct... */
+ nk_layout_row_dynamic(ctx, NODE_DEFAULT_ROW_HEIGHT, 1);
+ nk_button_color(ctx, nk_rgba_cf(color_node->output_val));
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (color_node->node.inputs[i].is_connected) {
+ eval_result = *(float*)node_editor_eval_connected(node, i);
+ eval_result = nk_propertyf(ctx, labels[i], eval_result, eval_result, eval_result, 0.01f, 0.01f);
+ color_val[i] = eval_result;
+ }
+ else {
+ color_node->input_val[i] = nk_propertyf(ctx, labels[i], 0.0f, color_node->input_val[i], 1.0f, 0.01f, 0.01f);
+ color_val[i] = color_node->input_val[i];
+ }
+ }
+
+ color_node->output_val.r = color_val[0];
+ color_node->output_val.g = color_val[1];
+ color_node->output_val.b = color_val[2];
+ color_node->output_val.a = color_val[3];
+}
+
+void node_color_create(struct node_editor *editor, struct nk_vec2 position)
+{
+ struct node_type_color *color_node = (struct node_type_color*)node_editor_add(editor, sizeof(struct node_type_color), "Color", nk_rect(position.x, position.y, 180, 190), 4, 1);
+ if (color_node)
+ {
+ const struct nk_colorf black = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ for (int i = 0; i < color_node->node.input_count; i++)
+ color_node->node.inputs[i].pin_type = type_float;
+ color_node->node.outputs[0].pin_type = type_color;
+
+ color_node->node.pin_spacing.in_padding_y += NODE_DEFAULT_ROW_HEIGHT;
+
+ color_node->input_val[0] = 0.0f;
+ color_node->input_val[1] = 0.0f;
+ color_node->input_val[2] = 0.0f;
+ color_node->input_val[3] = 1.0f;
+
+ color_node->output_val = black;
+
+ color_node->node.display_func = node_color_draw;
+ color_node->node.eval_func = (void*(*)(struct node*, int)) node_color_eval;
+ }
+}
+
+// ----------------------------------------------------------------------------------------------------
+// #include "node_blend.h"
+
+struct node_type_blend {
+ struct node node;
+ struct nk_colorf input_val[2];
+ struct nk_colorf output_val;
+ float blend_val;
+};
+
+static struct nk_colorf *node_blend_eval(struct node *node, int oIndex) {
+ struct node_type_blend* blend_node = (struct node_type_blend*)node;
+ return &blend_node->output_val;
+}
+
+static void node_blend_display(struct nk_context *ctx, struct node *node) {
+ struct node_type_blend *blend_node = (struct node_type_blend*)node;
+ const struct nk_colorf blank = {0.0f, 0.0f, 0.0f, 0.0f};
+ float blend_amnt;
+
+ nk_layout_row_dynamic(ctx, NODE_DEFAULT_ROW_HEIGHT, 1);
+ for (int i = 0; i < 2; i++){
+ if(node->inputs[i].is_connected) {
+ blend_node->input_val[i] = *(struct nk_colorf*)node_editor_eval_connected(node, i);
+ }
+ else {
+ blend_node->input_val[i] = blank;
+ }
+ nk_button_color(ctx, nk_rgba_cf(blend_node->input_val[i]));
+ }
+
+ if (node->inputs[2].is_connected) {
+ blend_amnt = *(float*)node_editor_eval_connected(node, 2);
+ blend_amnt = nk_propertyf(ctx, "#Blend", blend_amnt, blend_amnt, blend_amnt, 0.01f, 0.01f);
+ }
+ else {
+ blend_node->blend_val = nk_propertyf(ctx, "#Blend", 0.0f, blend_node->blend_val, 1.0f, 0.01f, 0.01f);
+ blend_amnt = blend_node->blend_val;
+ }
+
+
+ if(node->inputs[0].is_connected && node->inputs[1].is_connected) {
+ blend_node->output_val.r = blend_node->input_val[0].r * (1.0f-blend_amnt) + blend_node->input_val[1].r * blend_amnt;
+ blend_node->output_val.g = blend_node->input_val[0].g * (1.0f-blend_amnt) + blend_node->input_val[1].g * blend_amnt;
+ blend_node->output_val.b = blend_node->input_val[0].b * (1.0f-blend_amnt) + blend_node->input_val[1].b * blend_amnt;
+ blend_node->output_val.a = blend_node->input_val[0].a * (1.0f-blend_amnt) + blend_node->input_val[1].a * blend_amnt;
+ }
+ else {
+ blend_node->output_val = blank;
+ }
+}
+
+void node_blend_create(struct node_editor *editor, struct nk_vec2 position) {
+ struct node_type_blend* blend_node = (struct node_type_blend*)node_editor_add(editor, sizeof(struct node_type_blend), "Blend", nk_rect(position.x, position.y, 180, 130), 3, 1);
+ if (blend_node) {
+ const struct nk_colorf blank = {0.0f, 0.0f, 0.0f, 0.0f};
+ for (int i = 0; i < (int)NK_LEN(blend_node->input_val); i++)
+ blend_node->node.inputs[i].pin_type = type_color;
+ blend_node->node.outputs[0].pin_type = type_color;
+
+ // blend_node->node.pin_spacing.in_padding_y = 42.0f;
+ // blend_node->node.pin_spacing.in_spacing_y = 29.0f;
+
+ for (int i = 0; i < (int)NK_LEN(blend_node->input_val); i++)
+ blend_node->input_val[i] = blank;
+ blend_node->output_val = blank;
+
+ blend_node->blend_val = 0.5f;
+
+ blend_node->node.display_func = node_blend_display;
+ blend_node->node.eval_func = (void*(*)(struct node*, int)) node_blend_eval;
+
+ }
+}
+
+/* ================================= */
+
+#define NK_RGB3(r,g,b) {r,g,b,255}
+#define BG_COLOR ((struct nk_color){60,60,60,192}) // nk_rgba(0,0,0,192)
+
+static
+struct editor_node_style {
+ int pin_type;
+ const char *shape;
+ struct nk_color color_idle;
+ struct nk_color color_hover;
+} styles[] = {
+ // order matters:
+ { type_flow, "triangle_right", NK_RGB3(200,200,200), NK_RGB3(255,255,255) }, // if .num_links == 0
+ { type_int, "circle", NK_RGB3(33,227,175), NK_RGB3(135,239,195) },
+ { type_float, "circle", NK_RGB3(156,253,65), NK_RGB3(144,225,137) },
+ { type_block, "circle", NK_RGB3(6,165,239), NK_RGB3(137,196,247) },
+ { type_texture, "circle", NK_RGB3(148,0,0), NK_RGB3(183,137,137) },
+ { type_image, "circle", NK_RGB3(200,130,255), NK_RGB3(220,170,255) },
+ { type_color, "circle", NK_RGB3(252,200,35), NK_RGB3(255,217,140) },
+};
+
+#define COLOR_FLOW_HI styles[type_flow].color_hover
+#define COLOR_FLOW_LO styles[type_flow].color_idle
+
+#define GRID_SIZE 64.0f
+#define GRID_COLOR ((struct nk_color)NK_RGB3(80,80,120))
+#define GRID_THICKNESS 1.0f
+
+// 4 colors: top-left, top-right, bottom-right, bottom-left
+#define GRID_BG_COLORS ((struct nk_color){30,30,30,255}), ((struct nk_color){40,20,0,255}), ((struct nk_color){30,30,30,255}), ((struct nk_color){20,30,40,255})
+
+#define LINK_THICKNESS 1.0f
+#define LINK_DRAW(POINT_A,POINT_B,COLOR) do { \
+ vec2 a = (POINT_A); \
+ vec2 b = (POINT_B); \
+ nk_stroke_line(canvas, a.x, a.y, b.x, b.y, LINK_THICKNESS, COLOR); \
+} while(0)
+#undef LINK_DRAW
+#define LINK_DRAW(POINT_A,POINT_B,COLOR) do { \
+ vec2 a = (POINT_A); \
+ vec2 b = (POINT_B); \
+ nk_stroke_curve(canvas, a.x, a.y, a.x+50, a.y, b.x-50, b.y, b.x, b.y, LINK_THICKNESS, COLOR); \
+} while(0)
+#undef LINK_DRAW
+#define LINK_DRAW(POINT_A,POINT_B,COLOR) do { \
+ vec2 a = (POINT_A); \
+ vec2 b = (POINT_B); \
+ float dist2 = len2( sub2( ptr2(&b.x), ptr2(&a.x) ) ); \
+ vec2 mid_a = mix2( ptr2(&a.x), ptr2(&b.x), 0.25 ); mid_a.y += dist2/2; \
+ vec2 mid_b = mix2( ptr2(&a.x), ptr2(&b.x), 0.75 ); mid_b.y += dist2/3; \
+ nk_stroke_curve(canvas, a.x, a.y, mid_a.x, mid_a.y, mid_b.x, mid_b.y, b.x, b.y, LINK_THICKNESS, COLOR); \
+} while(0)
+
+
+#define PIN_RADIUS 12
+#define PIN_THICKNESS 1.0f
+#define PIN_DRAW(PIN_ADDR,POINT,RADIUS) do { \
+ circle.x = (POINT).x - (RADIUS) / 2; \
+ circle.y = (POINT).y - (RADIUS) / 2; \
+ circle.w = circle.h = (RADIUS); \
+ struct nk_color color = node_get_type_color((PIN_ADDR).pin_type); \
+ if((PIN_ADDR).is_connected) \
+ nk_fill_circle(canvas, circle, color); \
+ else \
+ nk_stroke_circle(canvas, circle, PIN_THICKNESS, color); \
+} while(0)
+
+
+static struct nk_color node_get_type_color(unsigned pin_type) {
+ for( int i = 0; i < type_total; ++i )
+ if( styles[i].pin_type == pin_type )
+ return styles[i].color_idle;
+ return ((struct nk_color)NK_RGB3(255,0,255));
+}
+
+static void node_editor_push(struct node_editor *editor, struct node *node) {
+ if (!editor->begin) {
+ node->next = NULL;
+ node->prev = NULL;
+ editor->begin = node;
+ editor->end = node;
+ } else {
+ node->prev = editor->end;
+ if (editor->end)
+ editor->end->next = node;
+ node->next = NULL;
+ editor->end = node;
+ }
+}
+
+static void node_editor_pop(struct node_editor *editor, struct node *node) {
+ if (node->next)
+ node->next->prev = node->prev;
+ if (node->prev)
+ node->prev->next = node->next;
+ if (editor->end == node)
+ editor->end = node->prev;
+ if (editor->begin == node)
+ editor->begin = node->next;
+ node->next = NULL;
+ node->prev = NULL;
+}
+
+static struct node* node_editor_find_by_id(struct node_editor *editor, int ID) {
+ struct node *iter = editor->begin;
+ while (iter) {
+ if (iter->ID == ID)
+ return iter;
+ iter = iter->next;
+ }
+ return NULL;
+}
+
+static struct node_link* node_editor_find_link_by_output(struct node_editor *editor, struct node *output_node, int node_input_connector) {
+ for( int i = 0; i < editor->link_count; i++ ) {
+ if (editor->links[i].output_node == output_node &&
+ editor->links[i].output_pin == node_input_connector &&
+ editor->links[i].is_active == nk_true) {
+ return &editor->links[i];
+ }
+ }
+ return NULL;
+}
+
+static struct node_link* node_editor_find_link_by_input(struct node_editor *editor, struct node *input_node, int node_output_connector) {
+ for( int i = 0; i < editor->link_count; i++ ) {
+ if (editor->links[i].input_node == input_node &&
+ editor->links[i].input_pin == node_output_connector &&
+ editor->links[i].is_active == nk_true) {
+ return &editor->links[i];
+ }
+ }
+ return NULL;
+}
+
+static void node_editor_delete_link(struct node_link *link) {
+ link->is_active = nk_false;
+ link->input_node->outputs[link->input_pin].is_connected = nk_false;
+ link->output_node->inputs[link->output_pin].is_connected = nk_false;
+}
+
+struct node* node_editor_add(struct node_editor *editor, size_t nodeSize, const char *name, struct nk_rect bounds, int in_count, int out_count) {
+ static int IDs = 0;
+ struct node *node = NULL;
+
+ if ((nk_size)editor->node_count < NK_LEN(editor->node_buf)) {
+ /* node_buf has unused pins */
+ node = MALLOC(nodeSize);
+ editor->node_buf[editor->node_count++] = node;
+ node->ID = IDs++;
+ } else {
+ /* check for freed up pins in node_buf */
+ for (int i = 0; i < editor->node_count; i++) {
+ if (editor->node_buf[i] == NULL) {
+ node = MALLOC(nodeSize);
+ editor->node_buf[i] = node;
+ node->ID = i;
+ break;
+ }
+ }
+ }
+ if (node == NULL) {
+ puts("Node creation failed");
+ return NULL;
+ }
+
+ node->bounds = bounds;
+
+ node->input_count = in_count;
+ node->output_count = out_count;
+
+ node->inputs = MALLOC(node->input_count * sizeof(struct node_pin));
+ node->outputs = MALLOC(node->output_count * sizeof(struct node_pin));
+
+ for (int i = 0; i < node->input_count; i++) {
+ node->inputs[i].is_connected = nk_false;
+ node->inputs[i].pin_type = type_float; /* default pin type */
+ }
+ for (int i = 0; i < node->output_count; i++) {
+ node->outputs[i].is_connected = nk_false;
+ node->outputs[i].pin_type = type_float; /* default pin type */
+ }
+
+ /* default pin spacing */
+ node->pin_spacing.in_padding_x = 2;
+ node->pin_spacing.in_padding_y = 32 + 25/2 + 6; // titlebar height + next half row + adjust
+ node->pin_spacing.in_spacing_y = 25; // row height+border
+ node->pin_spacing.out_padding_x = 3;
+ node->pin_spacing.out_padding_y = 32 + 25/2 + 6; // titlebar height + next half row + adjust
+ node->pin_spacing.out_spacing_y = 25; // row height+border
+
+ strcpy(node->name, name);
+ node_editor_push(editor, node);
+
+ return node;
+}
+
+void *node_editor_eval_connected(struct node* node, int input_pin_number) {
+ NK_ASSERT(node->inputs[input_pin_number].is_connected);
+ return node->inputs[input_pin_number].connected_node->eval_func(node->inputs[input_pin_number].connected_node, node->inputs[input_pin_number].connected_pin);
+}
+
+static void node_editor_link(struct node_editor *editor, struct node *in_node, int in_pin, struct node *out_node, int out_pin) {
+ /* Confusingly, in and out nodes/pins here refer to the inputs and outputs OF THE LINK ITSELF, not the nodes */
+ struct node_link *link = NULL;
+
+ if ((nk_size)editor->link_count < NK_LEN(editor->links)) {
+ link = &editor->links[editor->link_count++];
+ } else {
+ for (int i = 0; i < (int)NK_LEN(editor->links); i++)
+ {
+ if (editor->links[i].is_active == nk_false) {
+ link = &editor->links[i];
+ break;
+ }
+ }
+ }
+ if (link) {
+ out_node->inputs[out_pin].is_connected = nk_true;
+ in_node->outputs[in_pin].is_connected = nk_true;
+ out_node->inputs[out_pin].connected_node = in_node;
+ out_node->inputs[out_pin].connected_pin = in_pin;
+
+ link->input_node = in_node;
+ link->input_pin = in_pin;
+ link->output_node = out_node;
+ link->output_pin = out_pin;
+ link->is_active = nk_true;
+ } else {
+ puts("Too many links");
+ }
+}
+
+static void node_editor_init(struct node_editor *editor) {
+ if (editor->initialized) return;
+
+ struct nk_rect total_space = nk_window_get_content_region(ui_ctx);
+ struct nk_vec2 output_node_position = { total_space.w*2/3, total_space.h/3 };
+ struct nk_vec2 color_node_position = { total_space.w*1/4, total_space.h/3 };
+
+ memset(editor, 0, sizeof(*editor));
+
+ editor->output_node = node_output_create(editor, output_node_position);
+ node_color_create(editor, color_node_position);
+ editor->show_grid = nk_true;
+
+ editor->initialized = 1;
+}
+
+static int node_editor(struct node_editor *editor) {
+ int n = 0;
+ struct nk_rect total_space;
+ const struct nk_input *in = &ui_ctx->input;
+ struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
+ struct node *updated = 0;
+
+ node_editor_init(editor);
+
+ {
+ /* allocate complete window space */
+ total_space = nk_window_get_content_region(ui_ctx);
+ nk_layout_space_begin(ui_ctx, NK_STATIC, total_space.h, editor->node_count);
+ {
+ struct node *it = editor->begin;
+ struct nk_rect size = nk_layout_space_bounds(ui_ctx);
+ struct nk_panel *nodePanel = 0;
+
+ //nk_fill_rect(canvas, size, 0/*rounding*/, ((struct nk_color){30,30,30,255})); // 20,30,40,255
+ nk_fill_rect_multi_color(canvas, size, GRID_BG_COLORS);
+
+ if (editor->show_grid) {
+ /* display grid */
+ for (float x = (float)fmod(size.x - editor->scrolling.x, GRID_SIZE); x < size.w; x += GRID_SIZE)
+ nk_stroke_line(canvas, x+size.x, size.y, x+size.x, size.y+size.h, GRID_THICKNESS, GRID_COLOR);
+ for (float y = (float)fmod(size.y - editor->scrolling.y, GRID_SIZE); y < size.h; y += GRID_SIZE)
+ nk_stroke_line(canvas, size.x, y+size.y, size.x+size.w, y+size.y, GRID_THICKNESS, GRID_COLOR);
+ }
+
+ /* execute each node as a movable group */
+ /* loop through nodes */
+ while (it) {
+ /* Output node window should not have a close button */
+ nk_flags nodePanel_flags = NK_WINDOW_MOVABLE|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_TITLE;
+ if (it != editor->output_node)
+ nodePanel_flags |= NK_WINDOW_CLOSABLE;
+
+ /* calculate scrolled node window position and size */
+ nk_layout_space_push(ui_ctx, nk_rect(it->bounds.x - editor->scrolling.x,
+ it->bounds.y - editor->scrolling.y, it->bounds.w, it->bounds.h));
+
+ /* execute node window */
+ char *name = va(" " ICON_MD_MENU " %s",it->name); //< @r-lyeh added some spacing+icon because of our UI customizations
+
+struct nk_color bak = ui_ctx->style.window.fixed_background.data.color;
+ui_ctx->style.window.fixed_background.data.color = BG_COLOR;
+
+ if (nk_group_begin(ui_ctx, name, nodePanel_flags))
+ {
+ /* always have last selected node on top */
+
+ nodePanel = nk_window_get_panel(ui_ctx);
+ if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, nodePanel->bounds) &&
+ (!(it->prev && nk_input_mouse_clicked(in, NK_BUTTON_LEFT,
+ nk_layout_space_rect_to_screen(ui_ctx, nodePanel->bounds)))) &&
+ editor->end != it)
+ {
+ updated = it;
+ }
+
+ if ((nodePanel->flags & NK_WINDOW_HIDDEN)) /* Node close button has been clicked */
+ {
+ /* Delete node */
+ struct node_link *link_remove;
+ node_editor_pop(editor, it);
+ for (int n = 0; n < it->input_count; n++) {
+ if ((link_remove = node_editor_find_link_by_output(editor, it, n)))
+ {
+ node_editor_delete_link(link_remove);
+ }
+ }
+ for (int n = 0; n < it -> output_count; n++) {
+ while((link_remove = node_editor_find_link_by_input(editor, it, n)))
+ {
+ node_editor_delete_link(link_remove);
+ }
+ }
+ NK_ASSERT(editor->node_buf[it->ID] == it);
+ editor->node_buf[it->ID] = NULL;
+ FREE(it->inputs);
+ FREE(it->outputs);
+ FREE(it);
+ }
+ else {
+
+ /* ================= NODE CONTENT ===================== */
+
+ it->display_func(ui_ctx, it);
+
+ /* ==================================================== */
+
+ }
+ nk_group_end(ui_ctx);
+
+ }
+
+ui_ctx->style.window.fixed_background.data.color = bak;
+
+ if (!(nodePanel->flags & NK_WINDOW_HIDDEN))
+ {
+ /* node pin and linking */
+ struct nk_rect bounds;
+ bounds = nk_layout_space_rect_to_local(ui_ctx, nodePanel->bounds);
+ bounds.x += editor->scrolling.x;
+ bounds.y += editor->scrolling.y;
+ it->bounds = bounds;
+
+ /* output pins */
+ for (int n = 0; n < it->output_count; ++n) {
+ struct nk_rect circle;
+ struct nk_vec2 pt = {nodePanel->bounds.x, nodePanel->bounds.y};
+ pt.x += nodePanel->bounds.w - PIN_RADIUS / 2 + it->pin_spacing.out_padding_x;
+ pt.y += it->pin_spacing.out_padding_y + it->pin_spacing.out_spacing_y * (n);
+ PIN_DRAW(it->outputs[n],pt,PIN_RADIUS);
+
+ /* start linking process */
+ /* set linking active */
+ if (nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, circle, nk_true)) {
+ editor->linking.active = nk_true;
+ editor->linking.node = it;
+ editor->linking.input_id = it->ID;
+ editor->linking.input_pin = n;
+ }
+
+ /* draw link being dragged (from linked pin to mouse position) */
+ if (editor->linking.active && editor->linking.node == it &&
+ editor->linking.input_pin == n) {
+ LINK_DRAW(vec2(circle.x+3,circle.y+3),ptr2(&in->mouse.pos.x),COLOR_FLOW_HI);
+ }
+ }
+
+ /* input pins */
+ for (int n = 0; n < it->input_count; ++n) {
+ struct nk_rect circle;
+ struct nk_vec2 pt = {nodePanel->bounds.x, nodePanel->bounds.y};
+ pt.x += it->pin_spacing.in_padding_x;
+ pt.y += it->pin_spacing.in_padding_y + it->pin_spacing.in_spacing_y * (n);
+ PIN_DRAW(it->inputs[n],pt,PIN_RADIUS);
+
+ /* Detach link */
+ if (nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, circle, nk_true) &&
+ editor->linking.active == nk_false &&
+ it->inputs[n].is_connected == nk_true) {
+ struct node_link *node_relink = node_editor_find_link_by_output(editor, it, n);
+ editor->linking.active = nk_true;
+ editor->linking.node = node_relink->input_node;
+ editor->linking.input_id = node_relink->input_node->ID;
+ editor->linking.input_pin = node_relink->input_pin;
+ node_editor_delete_link(node_relink);
+ }
+
+ /* Create link */
+ if (nk_input_is_mouse_released(in, NK_BUTTON_LEFT) &&
+ nk_input_is_mouse_hovering_rect(in, circle) &&
+ editor->linking.active &&
+ editor->linking.node != it &&
+ it->inputs[n].pin_type == editor->linking.node->outputs[editor->linking.input_pin].pin_type &&
+ it->inputs[n].is_connected != nk_true) {
+ editor->linking.active = nk_false;
+
+ node_editor_link(editor, editor->linking.node,
+ editor->linking.input_pin, it, n);
+ }
+ }
+ }
+ it = it->next;
+ }
+
+ /* reset (output) linking connection */
+ if (editor->linking.active && (!!input(KEY_LCTRL) || !!input(KEY_RCTRL) || nk_input_is_mouse_released(in, NK_BUTTON_LEFT))) {
+ editor->linking.active = nk_false;
+ editor->linking.node = NULL;
+ }
+
+ /* draw each static link */
+ for (int n = 0; n < editor->link_count; ++n) {
+ struct node_link *link = &editor->links[n];
+ if (link->is_active == nk_true){
+ struct node *ni = link->input_node;
+ struct node *no = link->output_node;
+ struct nk_vec2 l0 = nk_layout_space_to_screen(ui_ctx, nk_vec2(ni->bounds.x + ni->bounds.w + ni->pin_spacing.out_padding_x, 3.0f + ni->bounds.y + ni->pin_spacing.out_padding_y + ni->pin_spacing.out_spacing_y * (link->input_pin)));
+ struct nk_vec2 l1 = nk_layout_space_to_screen(ui_ctx, nk_vec2(no->bounds.x + no->pin_spacing.in_padding_x, 3.0f + no->bounds.y + no->pin_spacing.in_padding_y + no->pin_spacing.in_spacing_y * (link->output_pin)));
+
+ l0.x -= editor->scrolling.x;
+ l0.y -= editor->scrolling.y;
+ l1.x -= editor->scrolling.x;
+ l1.y -= editor->scrolling.y;
+
+ struct nk_color color = node_get_type_color(no->inputs[link->output_pin].pin_type);
+ LINK_DRAW(ptr2(&l0.x), ptr2(&l1.x), color);
+ }
+ }
+
+ if (updated) {
+ /* reshuffle nodes to have least recently selected node on top */
+ node_editor_pop(editor, updated);
+ node_editor_push(editor, updated);
+ }
+
+ /* node selection */
+ if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, nk_layout_space_bounds(ui_ctx))) {
+ it = editor->begin;
+ editor->selected = NULL;
+ editor->bounds = nk_rect(in->mouse.pos.x, in->mouse.pos.y, 100, 200);
+ while (it) {
+ struct nk_rect b = nk_layout_space_rect_to_screen(ui_ctx, it->bounds);
+ b.x -= editor->scrolling.x;
+ b.y -= editor->scrolling.y;
+ if (nk_input_is_mouse_hovering_rect(in, b))
+ editor->selected = it;
+ it = it->next;
+ }
+ }
+
+ /* contextual menu */
+ if (nk_contextual_begin(ui_ctx, 0, nk_vec2(150, 220), nk_window_get_bounds(ui_ctx))) {
+ struct nk_vec2 wincoords = { in->mouse.pos.x-total_space.x-50, in->mouse.pos.y-total_space.y-32 };
+
+#if 1
+ static char *filter = 0;
+ static int do_filter = 0;
+ if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1;
+ int choice = ui_toolbar(ICON_MD_SEARCH ";");
+ if( choice == 1 ) do_filter = 1;
+ if( do_filter ) {
+ ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &filter);
+ if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon)
+ do_filter = 0;
+ }
+ } else {
+ if( filter ) filter[0] = '\0';
+ }
+ char *filter_mask = filter && filter[0] ? va("*%s*", filter) : "*";
+#endif
+
+ #define ui_label_filtered(lbl) (strmatchi(lbl,filter_mask) && ui_label(lbl))
+
+ int close = 0;
+ if (ui_label_filtered("=Add Color node")) close=1,node_color_create(editor, wincoords);
+ if (ui_label_filtered("=Add Float node")) close=1,node_float_create(editor, wincoords);
+ if (ui_label_filtered("=Add Blend Node")) close=1,node_blend_create(editor, wincoords);
+ if (ui_label_filtered(editor->show_grid ? "=Hide Grid" : "=Show Grid"))
+ close=1,editor->show_grid = !editor->show_grid;
+ if(close) do_filter = 0, (filter ? filter[0] = '\0' : '\0'), nk_contextual_close(ui_ctx);
+ nk_contextual_end(ui_ctx);
+ }
+ }
+ nk_layout_space_end(ui_ctx);
+
+ /* window content scrolling */
+ if (nk_input_is_mouse_hovering_rect(in, nk_window_get_bounds(ui_ctx)) &&
+ nk_input_is_mouse_down(in, NK_BUTTON_MIDDLE)) {
+ editor->scrolling.x += in->mouse.delta.x;
+ editor->scrolling.y += in->mouse.delta.y;
+ }
+ }
+
+ return !nk_window_is_closed(ui_ctx, "NodeEdit");
+}
+
+int editor_nodes(int window_mode) {
+ window_mode = EDITOR_WINDOW; // force window
+
+ if( editor_begin(NODES_TITLE, window_mode) ) {
+
+ static struct node_editor nodeEditor = {0};
+ node_editor(&nodeEditor);
+
+ editor_end(window_mode);
+ }
+ return 0;
+}
+
+AUTORUN {
+ array_push(editor.subeditors, editor_nodes);
+}
+#line 0
+#line 1 "v4k_editor_script.h"
+
+int ui_texture_fit(texture_t t, struct nk_rect bounds) {
+ // allocate complete window space
+ struct nk_rect total_space = nk_window_get_content_region(ui_ctx);
+ nk_layout_space_begin(ui_ctx, NK_DYNAMIC, total_space.h - 4, 1); // -4 to hide scrollbar Y
+ nk_layout_space_push(ui_ctx, nk_rect(0,0,1,1));
+
+ struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
+ struct nk_image image = nk_image_id((int)t.id);
+ nk_draw_image(canvas, bounds, &image, nk_white);
+
+ nk_layout_space_end(ui_ctx);
+ return 0;
+}
+
+#define LITE_ICON ICON_MDI_SCRIPT_TEXT
+#define LITE_TITLE "Script " LITE_ICON
+
+EDITOR_BIND(script, "held(CTRL)&down(6)", { ui_show(LITE_TITLE, ui_visible(LITE_TITLE) ^ true); });
+
+int editor_scripted(int window_mode) {
+ window_mode = EDITOR_WINDOW; // force mode
+
+ static lua_State *L = 0;
+ do_once {
+ L = script_init_env(SCRIPT_LUA|SCRIPT_DEBUGGER);
+
+ const char *platform = "" // "Android" "FreeBSD" "OpenBSD" "NetBSD"
+ ifdef(ems, "Emscripten")
+ ifdef(linux, "Linux")
+ ifdef(osx, "macOS")
+ ifdef(win32, "Windows")
+ ;
+ const char *pathexe = vac("%s%s%s", app_path(), app_name(), ifdef(win32, ".exe", ""));
+
+ gleqInit();
+ gleqTrackWindow(window_handle());
+ lt_init(L, window_handle(), LT_DATAPATH, __argc, __argv, window_scale(), platform, pathexe);
+ }
+
+ unsigned lt_none = 0u;
+ unsigned lt_all = ~0u & ~(GLEQ_WINDOW_MOVED/*|GLEQ_WINDOW_RESIZED|GLEQ_WINDOW_REFRESH*/);
+ lt_events = lt_none;
+
+ int mouse_in_rect = 0;
+ if( editor_begin(LITE_TITLE, window_mode) ) {
+
+ lt_events = lt_all;
+ if( !nk_window_has_focus(ui_ctx) ) lt_events = lt_none;
+
+ struct nk_rect bounds = nk_window_get_content_region(ui_ctx);
+
+ lt_mx = input(MOUSE_X) - bounds.x;
+ lt_my = input(MOUSE_Y) - bounds.y;
+ lt_wx = bounds.x;
+ lt_wy = bounds.y;
+ lt_ww = bounds.w;
+ lt_wh = bounds.h;
+
+ if( lt_resizesurface(lt_getsurface(0), lt_ww, lt_wh) ) {
+ gleq_window_refresh_callback(window_handle());
+ }
+ // fullscreen_quad_rgb( lt_getsurface(0)->t, 1.2f );
+ ui_texture_fit(lt_getsurface(0)->t, bounds);
+
+ if( !!nk_input_is_mouse_hovering_rect(&ui_ctx->input, ((struct nk_rect){lt_wx+5,lt_wy+5,lt_ww-10,lt_wh-10})) ) {
+ lt_events &= ~(1<<31); // dont cursor shape
+ }
+
+ editor_end(window_mode);
+ }
+
+ lt_tick(L);
+ return 0;
+}
+
+AUTORUN {
+ array_push(editor.subeditors, editor_scripted);
+}
+#line 0
+
+#line 1 "v4k_end.c"
// Enable more performant GPUs on laptops. Does this work into a dll?
// int NvOptimusEnablement = 1;
// int AmdPowerXpressRequestHighPerformance = 1;
diff --git a/engine/split/3rd_base64.h b/engine/split/3rd_base64.h
index 60b29f3..90423fe 100644
--- a/engine/split/3rd_base64.h
+++ b/engine/split/3rd_base64.h
@@ -26,7 +26,7 @@ unsigned base64_bounds(unsigned size) {
char* base64_encode(const void *inp, unsigned inlen) { // free() after use
unsigned outlen = base64_bounds(inlen);
- char *out_ = malloc(outlen);
+ char *out_ = MALLOC(outlen);
out_[outlen] = 0;
uint_least32_t v;
@@ -43,21 +43,21 @@ char* base64_encode(const void *inp, unsigned inlen) { // free() after use
while (rem >= 6) {
rem -= 6;
if (io >= outlen)
- return (free(out_), 0); /* truncation is failure */
+ return (FREE(out_), NULL); /* truncation is failure */
out[io ++] = base64enc_tab[(v >> rem) & 63];
}
}
if (rem) {
v <<= (6 - rem);
if (io >= outlen)
- return (free(out_), 0); /* truncation is failure */
+ return (FREE(out_), NULL); /* truncation is failure */
out[io ++] = base64enc_tab[v & 63];
}
while(io&3) {
- if(io>=outlen) return (free(out_), 0); /* truncation is failure */
+ if(io>=outlen) return (FREE(out_), NULL); /* truncation is failure */
out[io++]='=';
}
- if(io>=outlen) return (free(out_), 0); /* no room for null terminator */
+ if(io>=outlen) return (FREE(out_), NULL); /* no room for null terminator */
out[io]=0;
return out_;
}
diff --git a/tools/editor/3rd_icon_mdi.h b/engine/split/3rd_icon_mdi.h
similarity index 100%
rename from tools/editor/3rd_icon_mdi.h
rename to engine/split/3rd_icon_mdi.h
diff --git a/tools/editor/3rd_lite.h b/engine/split/3rd_lite.h
similarity index 97%
rename from tools/editor/3rd_lite.h
rename to engine/split/3rd_lite.h
index 22c2a3b..dc7574a 100644
--- a/tools/editor/3rd_lite.h
+++ b/engine/split/3rd_lite.h
@@ -123,7 +123,7 @@ struct RenFont {
int height;
};
-static struct { int left, top, right, bottom; } clip;
+static struct { int left, top, right, bottom; } lt_clip;
static const char* codepoint_to_utf8(unsigned c) { //< @r-lyeh
static char s[4+1];
@@ -162,15 +162,15 @@ void ren_update_rects(RenRect *rects, int count) {
void ren_set_clip_rect(RenRect rect) {
- clip.left = rect.x;
- clip.top = rect.y;
- clip.right = rect.x + rect.width;
- clip.bottom = rect.y + rect.height;
+ lt_clip.left = rect.x;
+ lt_clip.top = rect.y;
+ lt_clip.right = rect.x + rect.width;
+ lt_clip.bottom = rect.y + rect.height;
}
void ren_get_size(int *x, int *y) {
- lt_surface *surf = lt_getsurface(window);
+ lt_surface *surf = lt_getsurface(lt_window());
*x = surf->w;
*y = surf->h;
}
@@ -355,14 +355,14 @@ static inline RenColor blend_pixel2(RenColor dst, RenColor src, RenColor color)
void ren_draw_rect(RenRect rect, RenColor color) {
if (color.a == 0) { return; }
- int x1 = rect.x < clip.left ? clip.left : rect.x;
- int y1 = rect.y < clip.top ? clip.top : rect.y;
+ int x1 = rect.x < lt_clip.left ? lt_clip.left : rect.x;
+ int y1 = rect.y < lt_clip.top ? lt_clip.top : rect.y;
int x2 = rect.x + rect.width;
int y2 = rect.y + rect.height;
- x2 = x2 > clip.right ? clip.right : x2;
- y2 = y2 > clip.bottom ? clip.bottom : y2;
+ x2 = x2 > lt_clip.right ? lt_clip.right : x2;
+ y2 = y2 > lt_clip.bottom ? lt_clip.bottom : y2;
- lt_surface *surf = lt_getsurface(window);
+ lt_surface *surf = lt_getsurface(lt_window());
RenColor *d = (RenColor*) surf->pixels;
d += x1 + y1 * surf->w;
int dr = surf->w - (x2 - x1);
@@ -380,17 +380,17 @@ void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color)
/* clip */
int n;
- if ((n = clip.left - x) > 0) { sub->width -= n; sub->x += n; x += n; }
- if ((n = clip.top - y) > 0) { sub->height -= n; sub->y += n; y += n; }
- if ((n = x + sub->width - clip.right ) > 0) { sub->width -= n; }
- if ((n = y + sub->height - clip.bottom) > 0) { sub->height -= n; }
+ if ((n = lt_clip.left - x) > 0) { sub->width -= n; sub->x += n; x += n; }
+ if ((n = lt_clip.top - y) > 0) { sub->height -= n; sub->y += n; y += n; }
+ if ((n = x + sub->width - lt_clip.right ) > 0) { sub->width -= n; }
+ if ((n = y + sub->height - lt_clip.bottom) > 0) { sub->height -= n; }
if (sub->width <= 0 || sub->height <= 0) {
return;
}
/* draw */
- lt_surface *surf = lt_getsurface(window);
+ lt_surface *surf = lt_getsurface(lt_window());
RenColor *s = image->pixels;
RenColor *d = (RenColor*) surf->pixels;
s += sub->x + sub->y * image->width;
@@ -450,7 +450,7 @@ static int f_set_tab_width(lua_State *L) {
}
-static int f_gc(lua_State *L) {
+static int f_GC(lua_State *L) {
RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT);
if (*self) { rencache_free_font(*self); }
return 0;
@@ -474,7 +474,7 @@ static int f_get_height(lua_State *L) {
int luaopen_renderer_font(lua_State *L) {
static const luaL_Reg lib[] = {
- { "__gc", f_gc },
+ { "__gc", f_GC },
{ "load", f_load },
{ "set_tab_width", f_set_tab_width },
{ "get_width", f_get_width },
diff --git a/tools/editor/3rd_lite_sys.h b/engine/split/3rd_lite_sys.h
similarity index 94%
rename from tools/editor/3rd_lite_sys.h
rename to engine/split/3rd_lite_sys.h
index a421e0f..475add4 100644
--- a/tools/editor/3rd_lite_sys.h
+++ b/engine/split/3rd_lite_sys.h
@@ -46,6 +46,16 @@ lt_surface *lt_getsurface(void *window) {
return &s;
}
void lt_updatesurfacerects(lt_surface *s, lt_rect* rects, unsigned count) {
+ if(0)
+ for( int i = 0; i < count; ++i ) {
+ memset( (unsigned*)s->pixels + (rects[i].x + rects[i].y * s->w), 0xFF, rects[i].width*4 );
+ memset( (unsigned*)s->pixels + (rects[i].x + (rects[i].y + (rects[i].height-1)) * s->w), 0xFF, rects[i].width*4 );
+ for( int y = 1; y < (rects[i].height-1); ++y ) {
+ ((unsigned*)s->pixels)[ rects[i].x + y * s->w ] =
+ ((unsigned*)s->pixels)[ rects[i].x + (rects[i].width-1) + y * s->w ] = 0xFFFFFFFF;
+ }
+ }
+
// update contents
texture_update(&s->t, s->w, s->h, 4, s->pixels, TEXTURE_LINEAR|TEXTURE_BGRA);
}
diff --git a/tools/editor/3rd_lite_sys_gleq.h b/engine/split/3rd_lite_sys_gleq.h
similarity index 100%
rename from tools/editor/3rd_lite_sys_gleq.h
rename to engine/split/3rd_lite_sys_gleq.h
diff --git a/engine/split/3rd_lua.h b/engine/split/3rd_lua.h
index c4d7f9f..0fe51ae 100644
--- a/engine/split/3rd_lua.h
+++ b/engine/split/3rd_lua.h
@@ -2,7 +2,7 @@
minilua.h -- Lua in a single header
Project URL: https://github.com/edubart/minilua
- This is Lua 5.4.4 contained in a single header to be bundled in C/C++ applications with ease.
+ This is Lua 5.4.6 contained in a single header to be bundled in C/C++ applications with ease.
Lua is a powerful, efficient, lightweight, embeddable scripting language.
Do the following in *one* C file to create the implementation:
@@ -22,7 +22,7 @@
*/
/* detect system platform */
-#if !defined(LUA_USE_WINDOWS) && !defined(LUA_USE_LINUX) && !defined(LUA_USE_MACOSX) && !defined(LUA_USE_POSIX) && !defined(LUA_USE_C89)
+#if !defined(LUA_USE_WINDOWS) && !defined(LUA_USE_LINUX) && !defined(LUA_USE_MACOSX) && !defined(LUA_USE_POSIX) && !defined(LUA_USE_C89) && !defined(LUA_USE_IOS)
#if defined(_WIN32)
#define LUA_USE_WINDOWS
#elif defined(__linux__)
@@ -158,6 +158,12 @@ extern "C" {
#endif
+#if defined(LUA_USE_IOS)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN
+#endif
+
+
/*
@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.
*/
@@ -816,7 +822,7 @@ extern "C" {
** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices).
-** (It must fit into max(size_t)/32.)
+** (It must fit into max(size_t)/32 and max(int)/2.)
*/
#if LUAI_IS32INT
#define LUAI_MAXSTACK 1000000
@@ -835,14 +841,15 @@ extern "C" {
/*
@@ LUA_IDSIZE gives the maximum size for the description of the source
-@@ of a function in debug information.
+** of a function in debug information.
** CHANGE it if you want a different size.
*/
#define LUA_IDSIZE 60
/*
-@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
+@@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
+** buffer system.
*/
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
@@ -892,14 +899,14 @@ extern "C" {
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4"
-#define LUA_VERSION_RELEASE "4"
+#define LUA_VERSION_RELEASE "6"
#define LUA_VERSION_NUM 504
-#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 4)
+#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
-#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 Lua.org, PUC-Rio"
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -1005,6 +1012,16 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
+/*
+** Type used by the debug API to collect debug information
+*/
+typedef struct lua_Debug lua_Debug;
+
+
+/*
+** Functions to be called by the debugger in specific events
+*/
+typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
/*
@@ -1027,7 +1044,8 @@ extern const char lua_ident[];
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
-LUA_API int (lua_resetthread) (lua_State *L);
+LUA_API int (lua_closethread) (lua_State *L, lua_State *from);
+LUA_API int (lua_resetthread) (lua_State *L); /* Deprecated! */
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
@@ -1316,12 +1334,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
-typedef struct lua_Debug lua_Debug; /* activation record */
-
-
-/* Functions to be called by the debugger in specific events */
-typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
-
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
@@ -1366,7 +1378,7 @@ struct lua_Debug {
/******************************************************************************
-* Copyright (C) 1994-2022 Lua.org, PUC-Rio.
+* Copyright (C) 1994-2023 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -1744,6 +1756,7 @@ LUALIB_API void (luaL_openlibs) (lua_State *L);
#endif
#ifdef LUA_IMPL
+typedef struct CallInfo CallInfo;
/*
** $Id: llimits.h $
** Limits, basic types, and some other 'installation-dependent' definitions
@@ -1817,11 +1830,24 @@ typedef signed char ls_byte;
/*
-** conversion of pointer to unsigned integer:
-** this is for hashing only; there is no problem if the integer
-** cannot hold the whole pointer value
+** conversion of pointer to unsigned integer: this is for hashing only;
+** there is no problem if the integer cannot hold the whole pointer
+** value. (In strict ISO C this may cause undefined behavior, but no
+** actual machine seems to bother.)
*/
-#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX))
+#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
+ __STDC_VERSION__ >= 199901L
+#include
+#if defined(UINTPTR_MAX) /* even in C99 this type is optional */
+#define L_P2I uintptr_t
+#else /* no 'intptr'? */
+#define L_P2I uintmax_t /* use the largest available integer */
+#endif
+#else /* C89 option */
+#define L_P2I size_t
+#endif
+
+#define point2uint(p) ((unsigned int)((L_P2I)(p) & UINT_MAX))
@@ -2165,6 +2191,8 @@ typedef union Value {
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
+ /* not used, but may avoid warnings for uninitialized value */
+ lu_byte ub;
} Value;
@@ -2268,6 +2296,17 @@ typedef union StackValue {
/* index to stack elements */
typedef StackValue *StkId;
+
+/*
+** When reallocating the stack, change all pointers to the stack into
+** proper offsets.
+*/
+typedef union {
+ StkId p; /* actual pointer */
+ ptrdiff_t offset; /* used while the stack is being reallocated */
+} StkIdRel;
+
+
/* convert a 'StackValue' to a 'TValue' */
#define s2v(o) (&(o)->val)
@@ -2728,8 +2767,10 @@ typedef struct Proto {
*/
typedef struct UpVal {
CommonHeader;
- lu_byte tbc; /* true if it represents a to-be-closed variable */
- TValue *v; /* points to stack or to its own value */
+ union {
+ TValue *p; /* points to stack or to its own value */
+ ptrdiff_t offset; /* used while the stack is being reallocated */
+ } v;
union {
struct { /* (when open) */
struct UpVal *next; /* linked list */
@@ -3015,6 +3056,7 @@ LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag);
/*#include "lobject.h"*/
+/*#include "lstate.h"*/
/*
@@ -3101,8 +3143,8 @@ LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
int inv, int isfloat, TMS event);
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
- struct CallInfo *ci, const Proto *p);
-LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
+ CallInfo *ci, const Proto *p);
+LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci,
StkId where, int wanted);
@@ -3118,6 +3160,11 @@ LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
/*#include "lua.h"*/
+
+/* Some header files included here need this definition */
+typedef struct CallInfo CallInfo;
+
+
/*#include "lobject.h"*/
/*#include "ltm.h"*/
/*#include "lzio.h"*/
@@ -3248,7 +3295,7 @@ struct lua_longjmp; /* defined in ldo.c */
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
-#define stacksize(th) cast_int((th)->stack_last - (th)->stack)
+#define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
/* kinds of Garbage Collection */
@@ -3278,9 +3325,9 @@ typedef struct stringtable {
** - field 'transferinfo' is used only during call/returnhooks,
** before the function starts or after it ends.
*/
-typedef struct CallInfo {
- StkId func; /* function index in the stack */
- StkId top; /* top for this function */
+struct CallInfo {
+ StkIdRel func; /* function index in the stack */
+ StkIdRel top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */
union {
struct { /* only for Lua functions */
@@ -3305,7 +3352,7 @@ typedef struct CallInfo {
} u2;
short nresults; /* expected number of results from this function */
unsigned short callstatus;
-} CallInfo;
+};
/*
@@ -3400,7 +3447,7 @@ typedef struct global_State {
struct lua_State *mainthread;
TString *memerrmsg; /* message for memory-allocation errors */
TString *tmname[TM_N]; /* array with tag-method names */
- struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
+ struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
lua_WarnFunction warnf; /* warning function */
void *ud_warn; /* auxiliary data to 'warnf' */
@@ -3415,13 +3462,13 @@ struct lua_State {
lu_byte status;
lu_byte allowhook;
unsigned short nci; /* number of items in 'ci' list */
- StkId top; /* first free slot in the stack */
+ StkIdRel top; /* first free slot in the stack */
global_State *l_G;
CallInfo *ci; /* call info for current function */
- StkId stack_last; /* end of stack (last element + 1) */
- StkId stack; /* stack base */
+ StkIdRel stack_last; /* end of stack (last element + 1) */
+ StkIdRel stack; /* stack base */
UpVal *openupval; /* list of open upvalues in this stack */
- StkId tbclist; /* list of to-be-closed variables */
+ StkIdRel tbclist; /* list of to-be-closed variables */
GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
@@ -3600,7 +3647,7 @@ iABC C(8) | B(8) |k| A(8) | Op(7) |
iABx Bx(17) | A(8) | Op(7) |
iAsBx sBx (signed)(17) | A(8) | Op(7) |
iAx Ax(25) | Op(7) |
-isJ sJ(25) | Op(7) |
+isJ sJ (signed)(25) | Op(7) |
A signed argument is represented in excess K: the represented value is
the written unsigned value minus K, where K is half the maximum for the
@@ -3999,7 +4046,7 @@ LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];)
/* Active Lua function (given call info) */
-#define ci_func(ci) (clLvalue(s2v((ci)->func)))
+#define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
#define resethookcount(L) (L->hookcount = L->basehookcount)
@@ -4055,6 +4102,7 @@ LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
#define ldo_h
+/*#include "llimits.h"*/
/*#include "lobject.h"*/
/*#include "lstate.h"*/
/*#include "lzio.h"*/
@@ -4070,7 +4118,7 @@ LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
** at every check.
*/
#define luaD_checkstackaux(L,n,pre,pos) \
- if (l_unlikely(L->stack_last - L->top <= (n))) \
+ if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
{ pre; luaD_growstack(L, n, 1); pos; } \
else { condmovestack(L,pre,pos); }
@@ -4079,11 +4127,18 @@ LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
-#define savestack(L,p) ((char *)(p) - (char *)L->stack)
-#define restorestack(L,n) ((StkId)((char *)L->stack + (n)))
+#define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
+#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
/* macro to check stack size, preserving 'p' */
+#define checkstackp(L,n,p) \
+ luaD_checkstackaux(L, n, \
+ ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
+ p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
+
+
+/* macro to check stack size and GC, preserving 'p' */
#define checkstackGCp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
@@ -4105,7 +4160,8 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
int fTransfer, int nTransfer);
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
-LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1, int delta);
+LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
+ int narg1, int delta);
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
@@ -4298,24 +4354,27 @@ LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
-#define luaC_barrier(L,p,v) ( \
- (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
- luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
-
-#define luaC_barrierback(L,p,v) ( \
- (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
- luaC_barrierback_(L,p) : cast_void(0))
-
#define luaC_objbarrier(L,p,o) ( \
(isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
+#define luaC_barrier(L,p,v) ( \
+ iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
+
+#define luaC_objbarrierback(L,p,o) ( \
+ (isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
+
+#define luaC_barrierback(L,p,v) ( \
+ iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
+
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
+LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz,
+ size_t offset);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
@@ -4354,10 +4413,10 @@ LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
#define MAXUPVAL 255
-#define upisopen(up) ((up)->v != &(up)->u.value)
+#define upisopen(up) ((up)->v.p != &(up)->u.value)
-#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v))
+#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
/*
@@ -4379,7 +4438,7 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
-LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
+LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy);
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
@@ -4494,23 +4553,26 @@ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
/*#include "lstate.h"*/
-/* Increments 'L->top', checking for stack overflows */
-#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
- "stack overflow");}
+/* Increments 'L->top.p', checking for stack overflows */
+#define api_incr_top(L) {L->top.p++; \
+ api_check(L, L->top.p <= L->ci->top.p, \
+ "stack overflow");}
/*
** If a call returns too many multiple returns, the callee may not have
** stack space to accommodate all results. In this case, this macro
-** increases its stack space ('L->ci->top').
+** increases its stack space ('L->ci->top.p').
*/
#define adjustresults(L,nres) \
- { if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
+ { if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
+ L->ci->top.p = L->top.p; }
/* Ensure the stack has at least 'n' elements */
-#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
- "not enough elements in the stack")
+#define api_checknelems(L,n) \
+ api_check(L, (n) < (L->top.p - L->ci->func.p), \
+ "not enough elements in the stack")
/*
@@ -4681,7 +4743,6 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t);
#if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
-LUAI_FUNC int luaH_isdummy (const Table *t);
#endif
@@ -5073,6 +5134,11 @@ typedef enum {
luaC_barrierback(L, gcvalue(t), v); }
+/*
+** Shift right is the same as shift left with a negative 'y'
+*/
+#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
+
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
@@ -5458,25 +5524,6 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
/*#include "lstate.h"*/
-#if defined(EMERGENCYGCTESTS)
-/*
-** First allocation will fail whenever not building initial state.
-** (This fail will trigger 'tryagain' and a full GC cycle at every
-** allocation.)
-*/
-static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
- if (completestate(g) && ns > 0) /* frees never fail */
- return NULL; /* fail */
- else /* normal allocation */
- return (*g->frealloc)(g->ud, block, os, ns);
-}
-#else
-#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
-#endif
-
-
-
-
/*
** About the realloc function:
@@ -5496,6 +5543,43 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
*/
+/*
+** Macro to call the allocation function.
+*/
+#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
+
+
+/*
+** When an allocation fails, it will try again after an emergency
+** collection, except when it cannot run a collection. The GC should
+** not be called while the state is not fully built, as the collector
+** is not yet fully initialized. Also, it should not be called when
+** 'gcstopem' is true, because then the interpreter is in the middle of
+** a collection step.
+*/
+#define cantryagain(g) (completestate(g) && !g->gcstopem)
+
+
+
+
+#if defined(EMERGENCYGCTESTS)
+/*
+** First allocation will fail except when freeing a block (frees never
+** fail) and when it cannot try again; this fail will trigger 'tryagain'
+** and a full GC cycle at every allocation.
+*/
+static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
+ if (ns > 0 && cantryagain(g))
+ return NULL; /* fail */
+ else /* normal allocation */
+ return callfrealloc(g, block, os, ns);
+}
+#else
+#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns)
+#endif
+
+
+
/*
@@ -5568,7 +5652,7 @@ l_noret luaM_toobig (lua_State *L) {
void luaM_free_ (lua_State *L, void *block, size_t osize) {
global_State *g = G(L);
lua_assert((osize == 0) == (block == NULL));
- (*g->frealloc)(g->ud, block, osize, 0);
+ callfrealloc(g, block, osize, 0);
g->GCdebt -= osize;
}
@@ -5576,19 +5660,15 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
/*
** In case of allocation fail, this function will do an emergency
** collection to free some memory and then try the allocation again.
-** The GC should not be called while state is not fully built, as the
-** collector is not yet fully initialized. Also, it should not be called
-** when 'gcstopem' is true, because then the interpreter is in the
-** middle of a collection step.
*/
static void *tryagain (lua_State *L, void *block,
size_t osize, size_t nsize) {
global_State *g = G(L);
- if (completestate(g) && !g->gcstopem) {
+ if (cantryagain(g)) {
luaC_fullgc(L, 1); /* try to free some memory... */
- return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
+ return callfrealloc(g, block, osize, nsize); /* try again */
}
- else return NULL; /* cannot free any memory without a full state */
+ else return NULL; /* cannot run an emergency collection */
}
@@ -5757,10 +5837,10 @@ static TString *loadStringN (LoadState *S, Proto *p) {
}
else { /* long string */
ts = luaS_createlngstrobj(L, size); /* create string */
- setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */
+ setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
luaD_inctop(L);
loadVector(S, getstr(ts), size); /* load directly in final place */
- L->top--; /* pop string */
+ L->top.p--; /* pop string */
}
luaC_objbarrier(L, p, ts);
return ts;
@@ -5885,6 +5965,8 @@ static void loadDebug (LoadState *S, Proto *f) {
f->locvars[i].endpc = loadInt(S);
}
n = loadInt(S);
+ if (n != 0) /* does it have debug information? */
+ n = f->sizeupvalues; /* must be this many */
for (i = 0; i < n; i++)
f->upvalues[i].name = loadStringN(S, f);
}
@@ -5958,7 +6040,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
S.Z = Z;
checkHeader(&S);
cl = luaF_newLclosure(L, loadByte(&S));
- setclLvalue2s(L, L->top, cl);
+ setclLvalue2s(L, L->top.p, cl);
luaD_inctop(L);
cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
@@ -5980,6 +6062,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
/*#include "lprefix.h"*/
+#include
#include
/*#include "lua.h"*/
@@ -6025,8 +6108,11 @@ static void dumpByte (DumpState *D, int y) {
}
-/* dumpInt Buff Size */
-#define DIBS ((sizeof(size_t) * 8 / 7) + 1)
+/*
+** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6"
+** rounds up the division.)
+*/
+#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7)
static void dumpSize (DumpState *D, size_t x) {
lu_byte buff[DIBS];
@@ -6376,33 +6462,33 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
static void stack_init (lua_State *L1, lua_State *L) {
int i; CallInfo *ci;
/* initialize stack array */
- L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
- L1->tbclist = L1->stack;
+ L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
+ L1->tbclist.p = L1->stack.p;
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
- setnilvalue(s2v(L1->stack + i)); /* erase new stack */
- L1->top = L1->stack;
- L1->stack_last = L1->stack + BASIC_STACK_SIZE;
+ setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
+ L1->top.p = L1->stack.p;
+ L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
/* initialize first ci */
ci = &L1->base_ci;
ci->next = ci->previous = NULL;
ci->callstatus = CIST_C;
- ci->func = L1->top;
+ ci->func.p = L1->top.p;
ci->u.c.k = NULL;
ci->nresults = 0;
- setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */
- L1->top++;
- ci->top = L1->top + LUA_MINSTACK;
+ setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */
+ L1->top.p++;
+ ci->top.p = L1->top.p + LUA_MINSTACK;
L1->ci = ci;
}
static void freestack (lua_State *L) {
- if (L->stack == NULL)
+ if (L->stack.p == NULL)
return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L);
lua_assert(L->nci == 0);
- luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK); /* free stack */
+ luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */
}
@@ -6444,7 +6530,7 @@ static void f_luaopen (lua_State *L, void *ud) {
*/
static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g;
- L->stack = NULL;
+ L->stack.p = NULL;
L->ci = NULL;
L->nci = 0;
L->twups = L; /* thread has no upvalues */
@@ -6480,20 +6566,16 @@ static void close_state (lua_State *L) {
LUA_API lua_State *lua_newthread (lua_State *L) {
- global_State *g;
+ global_State *g = G(L);
+ GCObject *o;
lua_State *L1;
lua_lock(L);
- g = G(L);
luaC_checkGC(L);
/* create new thread */
- L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
- L1->marked = luaC_white(g);
- L1->tt = LUA_VTHREAD;
- /* link it on list 'allgc' */
- L1->next = g->allgc;
- g->allgc = obj2gco(L1);
+ o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
+ L1 = gco2th(o);
/* anchor it on L stack */
- setthvalue2s(L, L->top, L1);
+ setthvalue2s(L, L->top.p, L1);
api_incr_top(L);
preinit_thread(L1, g);
L1->hookmask = L->hookmask;
@@ -6512,7 +6594,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1);
- luaF_closeupval(L1, L1->stack); /* close all upvalues */
+ luaF_closeupval(L1, L1->stack.p); /* close all upvalues */
lua_assert(L1->openupval == NULL);
luai_userstatefree(L, L1);
freestack(L1);
@@ -6522,32 +6604,41 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
int luaE_resetthread (lua_State *L, int status) {
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
- setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */
- ci->func = L->stack;
+ setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */
+ ci->func.p = L->stack.p;
ci->callstatus = CIST_C;
if (status == LUA_YIELD)
status = LUA_OK;
L->status = LUA_OK; /* so it can run __close metamethods */
status = luaD_closeprotected(L, 1, status);
if (status != LUA_OK) /* errors? */
- luaD_seterrorobj(L, status, L->stack + 1);
+ luaD_seterrorobj(L, status, L->stack.p + 1);
else
- L->top = L->stack + 1;
- ci->top = L->top + LUA_MINSTACK;
- luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
+ L->top.p = L->stack.p + 1;
+ ci->top.p = L->top.p + LUA_MINSTACK;
+ luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0);
return status;
}
-LUA_API int lua_resetthread (lua_State *L) {
+LUA_API int lua_closethread (lua_State *L, lua_State *from) {
int status;
lua_lock(L);
+ L->nCcalls = (from) ? getCcalls(from) : 0;
status = luaE_resetthread(L, L->status);
lua_unlock(L);
return status;
}
+/*
+** Deprecated! Use 'lua_closethread' instead.
+*/
+LUA_API int lua_resetthread (lua_State *L) {
+ return lua_closethread(L, NULL);
+}
+
+
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i;
lua_State *L;
@@ -6622,7 +6713,7 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
** Generate a warning from an error message
*/
void luaE_warnerror (lua_State *L, const char *where) {
- TValue *errobj = s2v(L->top - 1); /* error object */
+ TValue *errobj = s2v(L->top.p - 1); /* error object */
const char *msg = (ttisstring(errobj))
? svalue(errobj)
: "error object is not a string";
@@ -6888,12 +6979,13 @@ void luaC_fix (lua_State *L, GCObject *o) {
/*
-** create a new collectable object (with given type and size) and link
-** it to 'allgc' list.
+** create a new collectable object (with given type, size, and offset)
+** and link it to 'allgc' list.
*/
-GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
+GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
global_State *g = G(L);
- GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));
+ char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
+ GCObject *o = cast(GCObject *, p + offset);
o->marked = luaC_white(g);
o->tt = tt;
o->next = g->allgc;
@@ -6901,6 +6993,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return o;
}
+
+GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
+ return luaC_newobjdt(L, tt, sz, 0);
+}
+
/* }====================================================== */
@@ -6937,7 +7034,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
set2gray(uv); /* open upvalues are kept gray */
else
set2black(uv); /* closed upvalues are visited here */
- markvalue(g, uv->v); /* mark its content */
+ markvalue(g, uv->v.p); /* mark its content */
break;
}
case LUA_VUSERDATA: {
@@ -7012,7 +7109,7 @@ static int remarkupvals (global_State *g) {
work++;
if (!iswhite(uv)) { /* upvalue already visited? */
lua_assert(upisopen(uv) && isgray(uv));
- markvalue(g, uv->v); /* mark its value */
+ markvalue(g, uv->v.p); /* mark its value */
}
}
}
@@ -7256,19 +7353,19 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
*/
static int traversethread (global_State *g, lua_State *th) {
UpVal *uv;
- StkId o = th->stack;
+ StkId o = th->stack.p;
if (isold(th) || g->gcstate == GCSpropagate)
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
if (o == NULL)
return 1; /* stack not completely built yet */
lua_assert(g->gcstate == GCSatomic ||
th->openupval == NULL || isintwups(th));
- for (; o < th->top; o++) /* mark live elements in the stack */
+ for (; o < th->top.p; o++) /* mark live elements in the stack */
markvalue(g, s2v(o));
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
markobject(g, uv); /* open upvalues cannot be collected */
if (g->gcstate == GCSatomic) { /* final traversal? */
- for (; o < th->stack_last + EXTRA_STACK; o++)
+ for (; o < th->stack_last.p + EXTRA_STACK; o++)
setnilvalue(s2v(o)); /* clear dead stack slice */
/* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) {
@@ -7528,7 +7625,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) {
UNUSED(ud);
- luaD_callnoyield(L, L->top - 2, 0);
+ luaD_callnoyield(L, L->top.p - 2, 0);
}
@@ -7545,16 +7642,16 @@ static void GCTM (lua_State *L) {
int oldgcstp = g->gcstp;
g->gcstp |= GCSTPGC; /* avoid GC steps */
L->allowhook = 0; /* stop debug hooks during GC metamethod */
- setobj2s(L, L->top++, tm); /* push finalizer... */
- setobj2s(L, L->top++, &v); /* ... and its argument */
+ setobj2s(L, L->top.p++, tm); /* push finalizer... */
+ setobj2s(L, L->top.p++, &v); /* ... and its argument */
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
- status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
+ status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */
g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc");
- L->top--; /* pops error object */
+ L->top.p--; /* pops error object */
}
}
}
@@ -7677,7 +7774,25 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
** =======================================================
*/
-static void setpause (global_State *g);
+
+/*
+** Set the "time" to wait before starting a new GC cycle; cycle will
+** start when memory use hits the threshold of ('estimate' * pause /
+** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
+** because Lua cannot even start with less than PAUSEADJ bytes).
+*/
+static void setpause (global_State *g) {
+ l_mem threshold, debt;
+ int pause = getgcparam(g->gcpause);
+ l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
+ lua_assert(estimate > 0);
+ threshold = (pause < MAX_LMEM / estimate) /* overflow? */
+ ? estimate * pause /* no overflow */
+ : MAX_LMEM; /* overflow; truncate to maximum */
+ debt = gettotalbytes(g) - threshold;
+ if (debt > 0) debt = 0;
+ luaE_setdebt(g, debt);
+}
/*
@@ -7921,6 +8036,15 @@ static void atomic2gen (lua_State *L, global_State *g) {
}
+/*
+** Set debt for the next minor collection, which will happen when
+** memory grows 'genminormul'%.
+*/
+static void setminordebt (global_State *g) {
+ luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
+}
+
+
/*
** Enter generational mode. Must go until the end of an atomic cycle
** to ensure that all objects are correctly marked and weak tables
@@ -7933,6 +8057,7 @@ static lu_mem entergen (lua_State *L, global_State *g) {
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
numobjs = atomic(L); /* propagates all and then do the atomic stuff */
atomic2gen(L, g);
+ setminordebt(g); /* set debt assuming next cycle will be minor */
return numobjs;
}
@@ -7978,15 +8103,6 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
}
-/*
-** Set debt for the next minor collection, which will happen when
-** memory grows 'genminormul'%.
-*/
-static void setminordebt (global_State *g) {
- luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
-}
-
-
/*
** Does a major collection after last collection was a "bad collection".
**
@@ -8058,8 +8174,8 @@ static void genstep (lua_State *L, global_State *g) {
lu_mem numobjs = fullgen(L, g); /* do a major collection */
if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
/* collected at least half of memory growth since last major
- collection; keep doing minor collections */
- setminordebt(g);
+ collection; keep doing minor collections. */
+ lua_assert(g->lastatomic == 0);
}
else { /* bad collection */
g->lastatomic = numobjs; /* signal that last collection was bad */
@@ -8085,26 +8201,6 @@ static void genstep (lua_State *L, global_State *g) {
*/
-/*
-** Set the "time" to wait before starting a new GC cycle; cycle will
-** start when memory use hits the threshold of ('estimate' * pause /
-** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
-** because Lua cannot even start with less than PAUSEADJ bytes).
-*/
-static void setpause (global_State *g) {
- l_mem threshold, debt;
- int pause = getgcparam(g->gcpause);
- l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
- lua_assert(estimate > 0);
- threshold = (pause < MAX_LMEM / estimate) /* overflow? */
- ? estimate * pause /* no overflow */
- : MAX_LMEM; /* overflow; truncate to maximum */
- debt = gettotalbytes(g) - threshold;
- if (debt > 0) debt = 0;
- luaE_setdebt(g, debt);
-}
-
-
/*
** Enter first sweep phase.
** The call to 'sweeptolive' makes the pointer point to an object
@@ -8312,12 +8408,15 @@ static void incstep (lua_State *L, global_State *g) {
}
/*
-** performs a basic GC step if collector is running
+** Performs a basic GC step if collector is running. (If collector is
+** not running, set a reasonable debt to avoid it being called at
+** every single check.)
*/
void luaC_step (lua_State *L) {
global_State *g = G(L);
- lua_assert(!g->gcemergency);
- if (gcrunning(g)) { /* running? */
+ if (!gcrunning(g)) /* not running? */
+ luaE_setdebt(g, -2000);
+ else {
if(isdecGCmodegen(g))
genstep(L, g);
else
@@ -8495,7 +8594,7 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
** ensuring there is only one copy of each unique string. The table
** here is used as a set: the string enters as the key, while its value
** is irrelevant. We use the string itself as the value only because it
-** is a TValue readly available. Later, the code generation can change
+** is a TValue readily available. Later, the code generation can change
** this value.
*/
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
@@ -8505,12 +8604,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
if (!ttisnil(o)) /* string already present? */
ts = keystrval(nodefromval(o)); /* get saved copy */
else { /* not in use yet */
- TValue *stv = s2v(L->top++); /* reserve stack space for string */
+ TValue *stv = s2v(L->top.p++); /* reserve stack space for string */
setsvalue(L, stv, ts); /* temporarily anchor the string */
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
/* table is not a metatable, so it does not need to invalidate cache */
luaC_checkGC(L);
- L->top--; /* remove string from stack */
+ L->top.p--; /* remove string from stack */
}
return ts;
}
@@ -10299,6 +10398,35 @@ static int constfolding (FuncState *fs, int op, expdesc *e1,
}
+/*
+** Convert a BinOpr to an OpCode (ORDER OPR - ORDER OP)
+*/
+l_sinline OpCode binopr2op (BinOpr opr, BinOpr baser, OpCode base) {
+ lua_assert(baser <= opr &&
+ ((baser == OPR_ADD && opr <= OPR_SHR) ||
+ (baser == OPR_LT && opr <= OPR_LE)));
+ return cast(OpCode, (cast_int(opr) - cast_int(baser)) + cast_int(base));
+}
+
+
+/*
+** Convert a UnOpr to an OpCode (ORDER OPR - ORDER OP)
+*/
+l_sinline OpCode unopr2op (UnOpr opr) {
+ return cast(OpCode, (cast_int(opr) - cast_int(OPR_MINUS)) +
+ cast_int(OP_UNM));
+}
+
+
+/*
+** Convert a BinOpr to a tag method (ORDER OPR - ORDER TM)
+*/
+l_sinline TMS binopr2TM (BinOpr opr) {
+ lua_assert(OPR_ADD <= opr && opr <= OPR_SHR);
+ return cast(TMS, (cast_int(opr) - cast_int(OPR_ADD)) + cast_int(TM_ADD));
+}
+
+
/*
** Emit code for unary expressions that "produce values"
** (everything but 'not').
@@ -10337,12 +10465,15 @@ static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
** Emit code for binary expressions that "produce values" over
** two registers.
*/
-static void codebinexpval (FuncState *fs, OpCode op,
+static void codebinexpval (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) {
- int v2 = luaK_exp2anyreg(fs, e2); /* both operands are in registers */
+ OpCode op = binopr2op(opr, OPR_ADD, OP_ADD);
+ int v2 = luaK_exp2anyreg(fs, e2); /* make sure 'e2' is in a register */
+ /* 'e1' must be already in a register or it is a constant */
+ lua_assert((VNIL <= e1->k && e1->k <= VKSTR) ||
+ e1->k == VNONRELOC || e1->k == VRELOC);
lua_assert(OP_ADD <= op && op <= OP_SHR);
- finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN,
- cast(TMS, (op - OP_ADD) + TM_ADD));
+ finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, binopr2TM(opr));
}
@@ -10358,6 +10489,18 @@ static void codebini (FuncState *fs, OpCode op,
}
+/*
+** Code binary operators with K operand.
+*/
+static void codebinK (FuncState *fs, BinOpr opr,
+ expdesc *e1, expdesc *e2, int flip, int line) {
+ TMS event = binopr2TM(opr);
+ int v2 = e2->u.info; /* K index */
+ OpCode op = binopr2op(opr, OPR_ADD, OP_ADDK);
+ finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
+}
+
+
/* Try to code a binary operator negating its second operand.
** For the metamethod, 2nd operand must keep its original value.
*/
@@ -10385,24 +10528,27 @@ static void swapexps (expdesc *e1, expdesc *e2) {
}
+/*
+** Code binary operators with no constant operand.
+*/
+static void codebinNoK (FuncState *fs, BinOpr opr,
+ expdesc *e1, expdesc *e2, int flip, int line) {
+ if (flip)
+ swapexps(e1, e2); /* back to original order */
+ codebinexpval(fs, opr, e1, e2, line); /* use standard operators */
+}
+
+
/*
** Code arithmetic operators ('+', '-', ...). If second operand is a
** constant in the proper range, use variant opcodes with K operands.
*/
static void codearith (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
- TMS event = cast(TMS, opr + TM_ADD);
- if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */
- int v2 = e2->u.info; /* K index */
- OpCode op = cast(OpCode, opr + OP_ADDK);
- finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
- }
- else { /* 'e2' is neither an immediate nor a K operand */
- OpCode op = cast(OpCode, opr + OP_ADD);
- if (flip)
- swapexps(e1, e2); /* back to original order */
- codebinexpval(fs, op, e1, e2, line); /* use standard operators */
- }
+ if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) /* K operand? */
+ codebinK(fs, opr, e1, e2, flip, line);
+ else /* 'e2' is neither an immediate nor a K operand */
+ codebinNoK(fs, opr, e1, e2, flip, line);
}
@@ -10419,35 +10565,27 @@ static void codecommutative (FuncState *fs, BinOpr op,
flip = 1;
}
if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */
- codebini(fs, cast(OpCode, OP_ADDI), e1, e2, flip, line, TM_ADD);
+ codebini(fs, OP_ADDI, e1, e2, flip, line, TM_ADD);
else
codearith(fs, op, e1, e2, flip, line);
}
/*
-** Code bitwise operations; they are all associative, so the function
+** Code bitwise operations; they are all commutative, so the function
** tries to put an integer constant as the 2nd operand (a K operand).
*/
static void codebitwise (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) {
int flip = 0;
- int v2;
- OpCode op;
- if (e1->k == VKINT && luaK_exp2RK(fs, e1)) {
+ if (e1->k == VKINT) {
swapexps(e1, e2); /* 'e2' will be the constant operand */
flip = 1;
}
- else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) { /* no constants? */
- op = cast(OpCode, opr + OP_ADD);
- codebinexpval(fs, op, e1, e2, line); /* all-register opcodes */
- return;
- }
- v2 = e2->u.info; /* index in K array */
- op = cast(OpCode, opr + OP_ADDK);
- lua_assert(ttisinteger(&fs->f->k[v2]));
- finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK,
- cast(TMS, opr + TM_ADD));
+ if (e2->k == VKINT && luaK_exp2K(fs, e2)) /* K operand? */
+ codebinK(fs, opr, e1, e2, flip, line);
+ else /* no constants */
+ codebinNoK(fs, opr, e1, e2, flip, line);
}
@@ -10455,25 +10593,27 @@ static void codebitwise (FuncState *fs, BinOpr opr,
** Emit code for order comparisons. When using an immediate operand,
** 'isfloat' tells whether the original value was a float.
*/
-static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
+static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
int r1, r2;
int im;
int isfloat = 0;
+ OpCode op;
if (isSCnumber(e2, &im, &isfloat)) {
/* use immediate operand */
r1 = luaK_exp2anyreg(fs, e1);
r2 = im;
- op = cast(OpCode, (op - OP_LT) + OP_LTI);
+ op = binopr2op(opr, OPR_LT, OP_LTI);
}
else if (isSCnumber(e1, &im, &isfloat)) {
/* transform (A < B) to (B > A) and (A <= B) to (B >= A) */
r1 = luaK_exp2anyreg(fs, e2);
r2 = im;
- op = (op == OP_LT) ? OP_GTI : OP_GEI;
+ op = binopr2op(opr, OPR_LT, OP_GTI);
}
else { /* regular case, compare two registers */
r1 = luaK_exp2anyreg(fs, e1);
r2 = luaK_exp2anyreg(fs, e2);
+ op = binopr2op(opr, OPR_LT, OP_LT);
}
freeexps(fs, e1, e2);
e1->u.info = condjump(fs, op, r1, r2, isfloat, 1);
@@ -10499,7 +10639,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
op = OP_EQI;
r2 = im; /* immediate operand */
}
- else if (luaK_exp2RK(fs, e2)) { /* 1st expression is constant? */
+ else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */
op = OP_EQK;
r2 = e2->u.info; /* constant index */
}
@@ -10516,16 +10656,16 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
/*
** Apply prefix operation 'op' to expression 'e'.
*/
-void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
+void luaK_prefix (FuncState *fs, UnOpr opr, expdesc *e, int line) {
static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
luaK_dischargevars(fs, e);
- switch (op) {
+ switch (opr) {
case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
- if (constfolding(fs, op + LUA_OPUNM, e, &ef))
+ if (constfolding(fs, opr + LUA_OPUNM, e, &ef))
break;
/* else */ /* FALLTHROUGH */
case OPR_LEN:
- codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
+ codeunexpval(fs, unopr2op(opr), e, line);
break;
case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0);
@@ -10559,7 +10699,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
case OPR_SHL: case OPR_SHR: {
if (!tonumeral(v, NULL))
luaK_exp2anyreg(fs, v);
- /* else keep numeral, which may be folded with 2nd operand */
+ /* else keep numeral, which may be folded or used as an immediate
+ operand */
break;
}
case OPR_EQ: case OPR_NE: {
@@ -10654,30 +10795,27 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
/* coded as (r1 >> -I) */;
}
else /* regular case (two registers) */
- codebinexpval(fs, OP_SHL, e1, e2, line);
+ codebinexpval(fs, opr, e1, e2, line);
break;
}
case OPR_SHR: {
if (isSCint(e2))
codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */
else /* regular case (two registers) */
- codebinexpval(fs, OP_SHR, e1, e2, line);
+ codebinexpval(fs, opr, e1, e2, line);
break;
}
case OPR_EQ: case OPR_NE: {
codeeq(fs, opr, e1, e2);
break;
}
- case OPR_LT: case OPR_LE: {
- OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
- codeorder(fs, op, e1, e2);
- break;
- }
case OPR_GT: case OPR_GE: {
/* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */
- OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
swapexps(e1, e2);
- codeorder(fs, op, e1, e2);
+ opr = cast(BinOpr, (opr - OPR_GT) + OPR_LT);
+ } /* FALLTHROUGH */
+ case OPR_LT: case OPR_LE: {
+ codeorder(fs, opr, e1, e2);
break;
}
default: lua_assert(0);
@@ -11248,6 +11386,7 @@ static void singlevar (LexState *ls, expdesc *var) {
expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k != VVOID); /* this one must exist */
+ luaK_exp2anyregup(fs, var); /* but could be a constant */
codestring(&key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */
}
@@ -11300,12 +11439,12 @@ static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
/*
** Solves the goto at index 'g' to given 'label' and removes it
-** from the list of pending goto's.
+** from the list of pending gotos.
** If it jumps into the scope of some variable, raises an error.
*/
static void solvegoto (LexState *ls, int g, Labeldesc *label) {
int i;
- Labellist *gl = &ls->dyd->gt; /* list of goto's */
+ Labellist *gl = &ls->dyd->gt; /* list of gotos */
Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */
lua_assert(eqstr(gt->name, label->name));
if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
@@ -11359,7 +11498,7 @@ static int newgotoentry (LexState *ls, TString *name, int line, int pc) {
/*
** Solves forward jumps. Check whether new label 'lb' matches any
** pending gotos in current block and solves them. Return true
-** if any of the goto's need to close upvalues.
+** if any of the gotos need to close upvalues.
*/
static int solvegotos (LexState *ls, Labeldesc *lb) {
Labellist *gl = &ls->dyd->gt;
@@ -11380,7 +11519,7 @@ static int solvegotos (LexState *ls, Labeldesc *lb) {
/*
** Create a new label with the given 'name' at the given 'line'.
** 'last' tells whether label is the last non-op statement in its
-** block. Solves all pending goto's to this new label and adds
+** block. Solves all pending gotos to this new label and adds
** a close instruction if necessary.
** Returns true iff it added a close instruction.
*/
@@ -11453,19 +11592,19 @@ static void leaveblock (FuncState *fs) {
LexState *ls = fs->ls;
int hasclose = 0;
int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
- if (bl->isloop) /* fix pending breaks? */
+ removevars(fs, bl->nactvar); /* remove block locals */
+ lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */
+ if (bl->isloop) /* has to fix pending breaks? */
hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
- if (!hasclose && bl->previous && bl->upval)
+ if (!hasclose && bl->previous && bl->upval) /* still need a 'close'? */
luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
- fs->bl = bl->previous;
- removevars(fs, bl->nactvar);
- lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = stklevel; /* free registers */
ls->dyd->label.n = bl->firstlabel; /* remove local labels */
- if (bl->previous) /* inner block? */
- movegotosout(fs, bl); /* update pending gotos to outer block */
+ fs->bl = bl->previous; /* current block now is previous one */
+ if (bl->previous) /* was it a nested block? */
+ movegotosout(fs, bl); /* update pending gotos to enclosing block */
else {
- if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */
+ if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */
undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
}
}
@@ -12723,10 +12862,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
LexState lexstate;
FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
- setclLvalue2s(L, L->top, cl); /* anchor it (to avoid being collected) */
+ setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */
- sethvalue2s(L, L->top, lexstate.h); /* anchor it */
+ sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
@@ -12740,7 +12879,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
- L->top--; /* remove scanner's table */
+ L->top.p--; /* remove scanner's table */
return cl; /* closure is on the stack, too */
}
@@ -12928,10 +13067,10 @@ static const char *upvalname (const Proto *p, int uv) {
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
- if (clLvalue(s2v(ci->func))->p->is_vararg) {
+ if (clLvalue(s2v(ci->func.p))->p->is_vararg) {
int nextra = ci->u.l.nextraargs;
if (n >= -nextra) { /* 'n' is negative */
- *pos = ci->func - nextra - (n + 1);
+ *pos = ci->func.p - nextra - (n + 1);
return "(vararg)"; /* generic name for any vararg */
}
}
@@ -12940,7 +13079,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
- StkId base = ci->func + 1;
+ StkId base = ci->func.p + 1;
const char *name = NULL;
if (isLua(ci)) {
if (n < 0) /* access to vararg values? */
@@ -12949,7 +13088,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
}
if (name == NULL) { /* no 'standard' name? */
- StkId limit = (ci == L->ci) ? L->top : ci->next->func;
+ StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
/* generic name for any valid slot */
name = isLua(ci) ? "(temporary)" : "(C temporary)";
@@ -12967,16 +13106,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name;
lua_lock(L);
if (ar == NULL) { /* information about non-active function? */
- if (!isLfunction(s2v(L->top - 1))) /* not a Lua function? */
+ if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
name = NULL;
else /* consider live variables at function start (parameters) */
- name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0);
+ name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
}
else { /* active function; get information through 'ar' */
StkId pos = NULL; /* to avoid warnings */
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
- setobjs2s(L, L->top, pos);
+ setobjs2s(L, L->top.p, pos);
api_incr_top(L);
}
}
@@ -12991,8 +13130,8 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
lua_lock(L);
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
- setobjs2s(L, pos, L->top - 1);
- L->top--; /* pop value */
+ setobjs2s(L, pos, L->top.p - 1);
+ L->top.p--; /* pop value */
}
lua_unlock(L);
return name;
@@ -13035,7 +13174,7 @@ static int nextline (const Proto *p, int currentline, int pc) {
static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) {
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
api_incr_top(L);
}
else {
@@ -13044,7 +13183,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
const Proto *p = f->l.p;
int currentline = p->linedefined;
Table *t = luaH_new(L); /* new table to store active lines */
- sethvalue2s(L, L->top, t); /* push it on stack */
+ sethvalue2s(L, L->top.p, t); /* push it on stack */
api_incr_top(L);
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
if (!p->is_vararg) /* regular function? */
@@ -13134,20 +13273,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
lua_lock(L);
if (*what == '>') {
ci = NULL;
- func = s2v(L->top - 1);
+ func = s2v(L->top.p - 1);
api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */
- L->top--; /* pop function */
+ L->top.p--; /* pop function */
}
else {
ci = ar->i_ci;
- func = s2v(ci->func);
+ func = s2v(ci->func.p);
lua_assert(ttisfunction(func));
}
cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) {
- setobj2s(L, L->top, func);
+ setobj2s(L, L->top.p, func);
api_incr_top(L);
}
if (strchr(what, 'L'))
@@ -13402,18 +13541,19 @@ static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
/*
-** Check whether pointer 'o' points to some value in the stack
-** frame of the current function. Because 'o' may not point to a
-** value in this stack, we cannot compare it with the region
-** boundaries (undefined behaviour in ISO C).
+** Check whether pointer 'o' points to some value in the stack frame of
+** the current function and, if so, returns its index. Because 'o' may
+** not point to a value in this stack, we cannot compare it with the
+** region boundaries (undefined behavior in ISO C).
*/
-static int isinstack (CallInfo *ci, const TValue *o) {
- StkId pos;
- for (pos = ci->func + 1; pos < ci->top; pos++) {
- if (o == s2v(pos))
- return 1;
+static int instack (CallInfo *ci, const TValue *o) {
+ int pos;
+ StkId base = ci->func.p + 1;
+ for (pos = 0; base + pos < ci->top.p; pos++) {
+ if (o == s2v(base + pos))
+ return pos;
}
- return 0; /* not found */
+ return -1; /* not found */
}
@@ -13427,7 +13567,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
LClosure *c = ci_func(ci);
int i;
for (i = 0; i < c->nupvalues; i++) {
- if (c->upvals[i]->v == o) {
+ if (c->upvals[i]->v.p == o) {
*name = upvalname(c->p, i);
return "upvalue";
}
@@ -13454,9 +13594,11 @@ static const char *varinfo (lua_State *L, const TValue *o) {
const char *kind = NULL;
if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
- if (!kind && isinstack(ci, o)) /* no? try a register */
- kind = getobjname(ci_func(ci)->p, currentpc(ci),
- cast_int(cast(StkId, o) - (ci->func + 1)), &name);
+ if (!kind) { /* not an upvalue? */
+ int reg = instack(ci, o); /* try a register */
+ if (reg >= 0) /* is 'o' a register? */
+ kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
+ }
}
return formatvarinfo(L, kind, name);
}
@@ -13553,10 +13695,10 @@ l_noret luaG_errormsg (lua_State *L) {
if (L->errfunc != 0) { /* is there an error handling function? */
StkId errfunc = restorestack(L, L->errfunc);
lua_assert(ttisfunction(s2v(errfunc)));
- setobjs2s(L, L->top, L->top - 1); /* move argument */
- setobjs2s(L, L->top - 1, errfunc); /* push function */
- L->top++; /* assume EXTRA_STACK */
- luaD_callnoyield(L, L->top - 2, 1); /* call it */
+ setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
+ setobjs2s(L, L->top.p - 1, errfunc); /* push function */
+ L->top.p++; /* assume EXTRA_STACK */
+ luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
}
luaD_throw(L, LUA_ERRRUN);
}
@@ -13570,8 +13712,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
va_start(argp, fmt);
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp);
- if (isLua(ci)) /* if Lua function, add source:line information */
+ if (isLua(ci)) { /* if Lua function, add source:line information */
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
+ setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
+ L->top.p--;
+ }
luaG_errormsg(L);
}
@@ -13588,7 +13733,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
if (p->lineinfo == NULL) /* no debug information? */
return 0;
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
- int delta = 0; /* line diference */
+ int delta = 0; /* line difference */
int pc = oldpc;
for (;;) {
int lineinfo = p->lineinfo[++pc];
@@ -13615,7 +13760,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
** at most causes an extra call to a line hook.)
** This function is not "Protected" when called, so it should correct
-** 'L->top' before calling anything that can run the GC.
+** 'L->top.p' before calling anything that can run the GC.
*/
int luaG_traceexec (lua_State *L, const Instruction *pc) {
CallInfo *ci = L->ci;
@@ -13638,7 +13783,7 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
return 1; /* do not call hook again (VM yielded, so it did not move) */
}
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
- L->top = ci->top; /* correct top */
+ L->top.p = ci->top.p; /* correct top */
if (counthook)
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
if (mask & LUA_MASKLINE) {
@@ -13714,8 +13859,8 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
for (i = 0; i < cl->nupvalues; i++) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
- uv->v = &uv->u.value; /* make it closed */
- setnilvalue(uv->v);
+ uv->v.p = &uv->u.value; /* make it closed */
+ setnilvalue(uv->v.p);
cl->upvals[i] = uv;
luaC_objbarrier(L, cl, uv);
}
@@ -13726,12 +13871,11 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
** Create a new upvalue at the given level, and link it to the list of
** open upvalues of 'L' after entry 'prev'.
**/
-static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) {
+static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
UpVal *next = *prev;
- uv->v = s2v(level); /* current value lives in the stack */
- uv->tbc = tbc;
+ uv->v.p = s2v(level); /* current value lives in the stack */
uv->u.open.next = next; /* link it to list of open upvalues */
uv->u.open.previous = prev;
if (next)
@@ -13760,7 +13904,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
pp = &p->u.open.next;
}
/* not found: create a new upvalue after 'pp' */
- return newupval(L, 0, level, pp);
+ return newupval(L, level, pp);
}
@@ -13770,12 +13914,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
** (This function assumes EXTRA_STACK.)
*/
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
- StkId top = L->top;
+ StkId top = L->top.p;
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
setobj2s(L, top, tm); /* will call metamethod... */
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
- L->top = top + 3; /* add function and arguments */
+ L->top.p = top + 3; /* add function and arguments */
if (yy)
luaD_call(L, top, 0);
else
@@ -13790,7 +13934,7 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
static void checkclosemth (lua_State *L, StkId level) {
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
if (ttisnil(tm)) { /* no metamethod? */
- int idx = cast_int(level - L->ci->func); /* variable index */
+ int idx = cast_int(level - L->ci->func.p); /* variable index */
const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
if (vname == NULL) vname = "?";
luaG_runerror(L, "variable '%s' got a non-closable value", vname);
@@ -13824,23 +13968,23 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
** is used.)
*/
#define MAXDELTA \
- ((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
+ ((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1)
/*
** Insert a variable in the list of to-be-closed variables.
*/
void luaF_newtbcupval (lua_State *L, StkId level) {
- lua_assert(level > L->tbclist);
+ lua_assert(level > L->tbclist.p);
if (l_isfalse(s2v(level)))
return; /* false doesn't need to be closed */
checkclosemth(L, level); /* value must have a close method */
- while (cast_uint(level - L->tbclist) > MAXDELTA) {
- L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */
- L->tbclist->tbclist.delta = 0;
+ while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
+ L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */
+ L->tbclist.p->tbclist.delta = 0;
}
- level->tbclist.delta = cast(unsigned short, level - L->tbclist);
- L->tbclist = level;
+ level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
+ L->tbclist.p = level;
}
@@ -13860,10 +14004,10 @@ void luaF_closeupval (lua_State *L, StkId level) {
StkId upl; /* stack index pointed by 'uv' */
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
TValue *slot = &uv->u.value; /* new position for value */
- lua_assert(uplevel(uv) < L->top);
+ lua_assert(uplevel(uv) < L->top.p);
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
- setobj(L, slot, uv->v); /* move value to upvalue slot */
- uv->v = slot; /* now current value lives here */
+ setobj(L, slot, uv->v.p); /* move value to upvalue slot */
+ uv->v.p = slot; /* now current value lives here */
if (!iswhite(uv)) { /* neither white nor dead? */
nw2black(uv); /* closed upvalues cannot be gray */
luaC_barrier(L, uv, slot);
@@ -13873,31 +14017,32 @@ void luaF_closeupval (lua_State *L, StkId level) {
/*
-** Remove firt element from the tbclist plus its dummy nodes.
+** Remove first element from the tbclist plus its dummy nodes.
*/
static void poptbclist (lua_State *L) {
- StkId tbc = L->tbclist;
+ StkId tbc = L->tbclist.p;
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
tbc -= tbc->tbclist.delta;
- while (tbc > L->stack && tbc->tbclist.delta == 0)
+ while (tbc > L->stack.p && tbc->tbclist.delta == 0)
tbc -= MAXDELTA; /* remove dummy nodes */
- L->tbclist = tbc;
+ L->tbclist.p = tbc;
}
/*
** Close all upvalues and to-be-closed variables up to the given stack
-** level.
+** level. Return restored 'level'.
*/
-void luaF_close (lua_State *L, StkId level, int status, int yy) {
+StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
ptrdiff_t levelrel = savestack(L, level);
luaF_closeupval(L, level); /* first, close the upvalues */
- while (L->tbclist >= level) { /* traverse tbc's down to that level */
- StkId tbc = L->tbclist; /* get variable index */
+ while (L->tbclist.p >= level) { /* traverse tbc's down to that level */
+ StkId tbc = L->tbclist.p; /* get variable index */
poptbclist(L); /* remove it from list */
prepcallclosemth(L, tbc, status, yy); /* close variable */
level = restorestack(L, levelrel);
}
+ return level;
}
@@ -14020,7 +14165,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
case LUA_OPBOR: return intop(|, v1, v2);
case LUA_OPBXOR: return intop(^, v1, v2);
case LUA_OPSHL: return luaV_shiftl(v1, v2);
- case LUA_OPSHR: return luaV_shiftl(v1, -v2);
+ case LUA_OPSHR: return luaV_shiftr(v1, v2);
case LUA_OPUNM: return intop(-, 0, v1);
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
default: lua_assert(0); return 0;
@@ -14344,29 +14489,39 @@ void luaO_tostring (lua_State *L, TValue *obj) {
** ===================================================================
*/
-/* size for buffer space used by 'luaO_pushvfstring' */
-#define BUFVFS 200
+/*
+** Size for buffer space used by 'luaO_pushvfstring'. It should be
+** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
+** so that 'luaG_addinfo' can work directly on the buffer.
+*/
+#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95)
/* buffer used by 'luaO_pushvfstring' */
typedef struct BuffFS {
lua_State *L;
- int pushed; /* number of string pieces already on the stack */
+ int pushed; /* true if there is a part of the result on the stack */
int blen; /* length of partial string in 'space' */
char space[BUFVFS]; /* holds last part of the result */
} BuffFS;
/*
-** Push given string to the stack, as part of the buffer, and
-** join the partial strings in the stack into one.
+** Push given string to the stack, as part of the result, and
+** join it to previous partial result if there is one.
+** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
+** This call cannot invoke metamethods, as both operands must be
+** strings. It can, however, raise an error if the result is too
+** long. In that case, 'luaV_concat' frees the extra slot before
+** raising the error.
*/
-static void pushstr (BuffFS *buff, const char *str, size_t l) {
+static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
lua_State *L = buff->L;
- setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
- L->top++; /* may use one extra slot */
- buff->pushed++;
- luaV_concat(L, buff->pushed); /* join partial results into one */
- buff->pushed = 1;
+ setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr));
+ L->top.p++; /* may use one slot from EXTRA_STACK */
+ if (!buff->pushed) /* no previous string on the stack? */
+ buff->pushed = 1; /* now there is one */
+ else /* join previous string with new one */
+ luaV_concat(L, 2);
}
@@ -14412,7 +14567,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
/*
-** Add a number to the buffer.
+** Add a numeral to the buffer.
*/
static void addnum2buff (BuffFS *buff, TValue *num) {
char *numbuff = getbuff(buff, MAXNUMBER2STR);
@@ -14490,7 +14645,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
clearbuff(&buff); /* empty buffer into the stack */
lua_assert(buff.pushed == 1);
- return svalue(s2v(L->top - 1));
+ return svalue(s2v(L->top.p - 1));
}
@@ -14652,12 +14807,12 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) {
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, const TValue *p3) {
- StkId func = L->top;
+ StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
setobj2s(L, func + 3, p3); /* 3rd argument */
- L->top = func + 4;
+ L->top.p = func + 4;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 0);
@@ -14669,18 +14824,18 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, StkId res) {
ptrdiff_t result = savestack(L, res);
- StkId func = L->top;
+ StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
- L->top += 3;
+ L->top.p += 3;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 1);
else
luaD_callnoyield(L, func, 1);
res = restorestack(L, result);
- setobjs2s(L, res, --L->top); /* move result to its place */
+ setobjs2s(L, res, --L->top.p); /* move result to its place */
}
@@ -14715,7 +14870,7 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
void luaT_tryconcatTM (lua_State *L) {
- StkId top = L->top;
+ StkId top = L->top.p;
if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
TM_CONCAT)))
luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
@@ -14750,15 +14905,15 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
*/
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
TMS event) {
- if (callbinTM(L, p1, p2, L->top, event)) /* try original event */
- return !l_isfalse(s2v(L->top));
+ if (callbinTM(L, p1, p2, L->top.p, event)) /* try original event */
+ return !l_isfalse(s2v(L->top.p));
#if defined(LUA_COMPAT_LT_LE)
else if (event == TM_LE) {
/* try '!(p2 < p1)' for '(p1 <= p2)' */
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
- if (callbinTM(L, p2, p1, L->top, TM_LT)) {
+ if (callbinTM(L, p2, p1, L->top.p, TM_LT)) {
L->ci->callstatus ^= CIST_LEQ; /* clear mark */
- return l_isfalse(s2v(L->top));
+ return l_isfalse(s2v(L->top.p));
}
/* else error will remove this 'ci'; no need to clear mark */
}
@@ -14788,20 +14943,20 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
const Proto *p) {
int i;
- int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */
+ int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */
int nextra = actual - nfixparams; /* number of extra arguments */
ci->u.l.nextraargs = nextra;
luaD_checkstack(L, p->maxstacksize + 1);
/* copy function to the top of the stack */
- setobjs2s(L, L->top++, ci->func);
+ setobjs2s(L, L->top.p++, ci->func.p);
/* move fixed parameters to the top of the stack */
for (i = 1; i <= nfixparams; i++) {
- setobjs2s(L, L->top++, ci->func + i);
- setnilvalue(s2v(ci->func + i)); /* erase original parameter (for GC) */
+ setobjs2s(L, L->top.p++, ci->func.p + i);
+ setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
}
- ci->func += actual + 1;
- ci->top += actual + 1;
- lua_assert(L->top <= ci->top && ci->top <= L->stack_last);
+ ci->func.p += actual + 1;
+ ci->top.p += actual + 1;
+ lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
}
@@ -14811,10 +14966,10 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
if (wanted < 0) {
wanted = nextra; /* get all extra arguments available */
checkstackGCp(L, nextra, where); /* ensure stack space */
- L->top = where + nextra; /* next instruction will need top */
+ L->top.p = where + nextra; /* next instruction will need top */
}
for (i = 0; i < wanted && i < nextra; i++)
- setobjs2s(L, where + i, ci->func - nextra + i);
+ setobjs2s(L, where + i, ci->func.p - nextra + i);
for (; i < wanted; i++) /* complete required results with nil */
setnilvalue(s2v(where + i));
}
@@ -15201,7 +15356,7 @@ static const TValue absentkey = {ABSTKEYCONSTANT};
*/
static Node *hashint (const Table *t, lua_Integer i) {
lua_Unsigned ui = l_castS2U(i);
- if (ui <= (unsigned int)INT_MAX)
+ if (ui <= cast_uint(INT_MAX))
return hashmod(t, cast_int(ui));
else
return hashmod(t, ui);
@@ -15351,9 +15506,11 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
size |= (size >> 2);
size |= (size >> 4);
size |= (size >> 8);
+#if (UINT_MAX >> 14) > 3 /* unsigned int has more than 16 bits */
size |= (size >> 16);
#if (UINT_MAX >> 30) > 3
size |= (size >> 32); /* unsigned int has more than 32 bits */
+#endif
#endif
size++;
lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
@@ -15582,7 +15739,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
luaG_runerror(L, "table overflow");
size = twoto(lsize);
t->node = luaM_newvector(L, size, Node);
- for (i = 0; i < (int)size; i++) {
+ for (i = 0; i < cast_int(size); i++) {
Node *n = gnode(t, i);
gnext(n) = 0;
setnilkey(n);
@@ -16069,8 +16226,6 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainpositionTV(t, key);
}
-int luaH_isdummy (const Table *t) { return isdummy(t); }
-
#endif
/*
** $Id: ldo.c $
@@ -16178,11 +16333,11 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
}
default: {
lua_assert(errorstatus(errcode)); /* real error */
- setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
+ setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */
break;
}
}
- L->top = oldtop + 1;
+ L->top.p = oldtop + 1;
}
@@ -16195,7 +16350,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
global_State *g = G(L);
errcode = luaE_resetthread(L, errcode); /* close all upvalues */
if (g->mainthread->errorJmp) { /* main thread has a handler? */
- setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
+ setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */
luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
}
else { /* no handler at all; abort */
@@ -16231,16 +16386,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
** Stack reallocation
** ===================================================================
*/
-static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
+
+
+/*
+** Change all pointers to the stack into offsets.
+*/
+static void relstack (lua_State *L) {
CallInfo *ci;
UpVal *up;
- L->top = (L->top - oldstack) + newstack;
- L->tbclist = (L->tbclist - oldstack) + newstack;
+ L->top.offset = savestack(L, L->top.p);
+ L->tbclist.offset = savestack(L, L->tbclist.p);
for (up = L->openupval; up != NULL; up = up->u.open.next)
- up->v = s2v((uplevel(up) - oldstack) + newstack);
+ up->v.offset = savestack(L, uplevel(up));
for (ci = L->ci; ci != NULL; ci = ci->previous) {
- ci->top = (ci->top - oldstack) + newstack;
- ci->func = (ci->func - oldstack) + newstack;
+ ci->top.offset = savestack(L, ci->top.p);
+ ci->func.offset = savestack(L, ci->func.p);
+ }
+}
+
+
+/*
+** Change back all offsets into pointers.
+*/
+static void correctstack (lua_State *L) {
+ CallInfo *ci;
+ UpVal *up;
+ L->top.p = restorestack(L, L->top.offset);
+ L->tbclist.p = restorestack(L, L->tbclist.offset);
+ for (up = L->openupval; up != NULL; up = up->u.open.next)
+ up->v.p = s2v(restorestack(L, up->v.offset));
+ for (ci = L->ci; ci != NULL; ci = ci->previous) {
+ ci->top.p = restorestack(L, ci->top.offset);
+ ci->func.p = restorestack(L, ci->func.offset);
if (isLua(ci))
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
}
@@ -16250,44 +16427,45 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/* some space for error handling */
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
-
/*
-** Reallocate the stack to a new size, correcting all pointers into
-** it. (There are pointers to a stack from its upvalues, from its list
-** of call infos, plus a few individual pointers.) The reallocation is
-** done in two steps (allocation + free) because the correction must be
-** done while both addresses (the old stack and the new one) are valid.
-** (In ISO C, any pointer use after the pointer has been deallocated is
-** undefined behavior.)
+** Reallocate the stack to a new size, correcting all pointers into it.
+** In ISO C, any pointer use after the pointer has been deallocated is
+** undefined behavior. So, before the reallocation, all pointers are
+** changed to offsets, and after the reallocation they are changed back
+** to pointers. As during the reallocation the pointers are invalid, the
+** reallocation cannot run emergency collections.
+**
** In case of allocation error, raise an error or return false according
** to 'raiseerror'.
*/
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
int oldsize = stacksize(L);
int i;
- StkId newstack = luaM_reallocvector(L, NULL, 0,
- newsize + EXTRA_STACK, StackValue);
+ StkId newstack;
+ int oldgcstop = G(L)->gcstopem;
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
+ relstack(L); /* change pointers to offsets */
+ G(L)->gcstopem = 1; /* stop emergency collection */
+ newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
+ newsize + EXTRA_STACK, StackValue);
+ G(L)->gcstopem = oldgcstop; /* restore emergency collection */
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
+ correctstack(L); /* change offsets back to pointers */
if (raiseerror)
luaM_error(L);
else return 0; /* do not raise an error */
}
- /* number of elements to be copied to the new stack */
- i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK;
- memcpy(newstack, L->stack, i * sizeof(StackValue));
- for (; i < newsize + EXTRA_STACK; i++)
+ L->stack.p = newstack;
+ correctstack(L); /* change offsets back to pointers */
+ L->stack_last.p = L->stack.p + newsize;
+ for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
setnilvalue(s2v(newstack + i)); /* erase new segment */
- correctstack(L, L->stack, newstack);
- luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
- L->stack = newstack;
- L->stack_last = L->stack + newsize;
return 1;
}
/*
-** Try to grow the stack by at least 'n' elements. when 'raiseerror'
+** Try to grow the stack by at least 'n' elements. When 'raiseerror'
** is true, raises any error; otherwise, return 0 in case of errors.
*/
int luaD_growstack (lua_State *L, int n, int raiseerror) {
@@ -16301,35 +16479,38 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
luaD_throw(L, LUA_ERRERR); /* error inside message handler */
return 0; /* if not 'raiseerror', just signal it */
}
- else {
+ else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */
int newsize = 2 * size; /* tentative new size */
- int needed = cast_int(L->top - L->stack) + n;
+ int needed = cast_int(L->top.p - L->stack.p) + n;
if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */
newsize = LUAI_MAXSTACK;
if (newsize < needed) /* but must respect what was asked for */
newsize = needed;
if (l_likely(newsize <= LUAI_MAXSTACK))
return luaD_reallocstack(L, newsize, raiseerror);
- else { /* stack overflow */
- /* add extra size to be able to handle the error message */
- luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
- if (raiseerror)
- luaG_runerror(L, "stack overflow");
- return 0;
- }
}
+ /* else stack overflow */
+ /* add extra size to be able to handle the error message */
+ luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
+ if (raiseerror)
+ luaG_runerror(L, "stack overflow");
+ return 0;
}
+/*
+** Compute how much of the stack is being used, by computing the
+** maximum top of all call frames in the stack and the current top.
+*/
static int stackinuse (lua_State *L) {
CallInfo *ci;
int res;
- StkId lim = L->top;
+ StkId lim = L->top.p;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
- if (lim < ci->top) lim = ci->top;
+ if (lim < ci->top.p) lim = ci->top.p;
}
- lua_assert(lim <= L->stack_last);
- res = cast_int(lim - L->stack) + 1; /* part of stack in use */
+ lua_assert(lim <= L->stack_last.p + EXTRA_STACK);
+ res = cast_int(lim - L->stack.p) + 1; /* part of stack in use */
if (res < LUA_MINSTACK)
res = LUA_MINSTACK; /* ensure a minimum size */
return res;
@@ -16347,17 +16528,13 @@ static int stackinuse (lua_State *L) {
*/
void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
- int nsize = inuse * 2; /* proposed new size */
- int max = inuse * 3; /* maximum "reasonable" size */
- if (max > LUAI_MAXSTACK) {
- max = LUAI_MAXSTACK; /* respect stack limit */
- if (nsize > LUAI_MAXSTACK)
- nsize = LUAI_MAXSTACK;
- }
+ int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3;
/* if thread is currently not handling a stack overflow and its
size is larger than maximum "reasonable" size, shrink it */
- if (inuse <= LUAI_MAXSTACK && stacksize(L) > max)
+ if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) {
+ int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2;
luaD_reallocstack(L, nsize, 0); /* ok if that fails */
+ }
else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */
luaE_shrinkCI(L); /* shrink CI list */
@@ -16366,7 +16543,7 @@ void luaD_shrinkstack (lua_State *L) {
void luaD_inctop (lua_State *L) {
luaD_checkstack(L, 1);
- L->top++;
+ L->top.p++;
}
/* }================================================================== */
@@ -16383,8 +16560,8 @@ void luaD_hook (lua_State *L, int event, int line,
if (hook && L->allowhook) { /* make sure there is a hook */
int mask = CIST_HOOKED;
CallInfo *ci = L->ci;
- ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */
- ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */
+ ptrdiff_t top = savestack(L, L->top.p); /* preserve original 'top' */
+ ptrdiff_t ci_top = savestack(L, ci->top.p); /* idem for 'ci->top' */
lua_Debug ar;
ar.event = event;
ar.currentline = line;
@@ -16394,11 +16571,11 @@ void luaD_hook (lua_State *L, int event, int line,
ci->u2.transferinfo.ftransfer = ftransfer;
ci->u2.transferinfo.ntransfer = ntransfer;
}
- if (isLua(ci) && L->top < ci->top)
- L->top = ci->top; /* protect entire activation register */
+ if (isLua(ci) && L->top.p < ci->top.p)
+ L->top.p = ci->top.p; /* protect entire activation register */
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
- if (ci->top < L->top + LUA_MINSTACK)
- ci->top = L->top + LUA_MINSTACK;
+ if (ci->top.p < L->top.p + LUA_MINSTACK)
+ ci->top.p = L->top.p + LUA_MINSTACK;
L->allowhook = 0; /* cannot call hooks inside a hook */
ci->callstatus |= mask;
lua_unlock(L);
@@ -16406,8 +16583,8 @@ void luaD_hook (lua_State *L, int event, int line,
lua_lock(L);
lua_assert(!L->allowhook);
L->allowhook = 1;
- ci->top = restorestack(L, ci_top);
- L->top = restorestack(L, top);
+ ci->top.p = restorestack(L, ci_top);
+ L->top.p = restorestack(L, top);
ci->callstatus &= ~mask;
}
}
@@ -16438,7 +16615,7 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
*/
static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
- StkId firstres = L->top - nres; /* index of first result */
+ StkId firstres = L->top.p - nres; /* index of first result */
int delta = 0; /* correction for vararg functions */
int ftransfer;
if (isLua(ci)) {
@@ -16446,10 +16623,10 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (p->is_vararg)
delta = ci->u.l.nextraargs + p->numparams + 1;
}
- ci->func += delta; /* if vararg, back to virtual 'func' */
- ftransfer = cast(unsigned short, firstres - ci->func);
+ ci->func.p += delta; /* if vararg, back to virtual 'func' */
+ ftransfer = cast(unsigned short, firstres - ci->func.p);
luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */
- ci->func -= delta;
+ ci->func.p -= delta;
}
if (isLua(ci = ci->previous))
L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */
@@ -16468,9 +16645,9 @@ StkId luaD_tryfuncTM (lua_State *L, StkId func) {
tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */
if (l_unlikely(ttisnil(tm)))
luaG_callerror(L, s2v(func)); /* nothing to call */
- for (p = L->top; p > func; p--) /* open space for metamethod */
+ for (p = L->top.p; p > func; p--) /* open space for metamethod */
setobjs2s(L, p, p-1);
- L->top++; /* stack space pre-allocated by the caller */
+ L->top.p++; /* stack space pre-allocated by the caller */
setobj2s(L, func, tm); /* metamethod is the new function to be called */
return func;
}
@@ -16487,28 +16664,29 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
int i;
switch (wanted) { /* handle typical cases separately */
case 0: /* no values needed */
- L->top = res;
+ L->top.p = res;
return;
case 1: /* one value needed */
if (nres == 0) /* no results? */
setnilvalue(s2v(res)); /* adjust with nil */
else /* at least one result */
- setobjs2s(L, res, L->top - nres); /* move it to proper place */
- L->top = res + 1;
+ setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
+ L->top.p = res + 1;
return;
case LUA_MULTRET:
wanted = nres; /* we want all results */
break;
default: /* two/more results and/or to-be-closed variables */
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
- ptrdiff_t savedres = savestack(L, res);
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
L->ci->u2.nres = nres;
- luaF_close(L, res, CLOSEKTOP, 1);
+ res = luaF_close(L, res, CLOSEKTOP, 1);
L->ci->callstatus &= ~CIST_CLSRET;
- if (L->hookmask) /* if needed, call hook after '__close's */
+ if (L->hookmask) { /* if needed, call hook after '__close's */
+ ptrdiff_t savedres = savestack(L, res);
rethook(L, L->ci, nres);
- res = restorestack(L, savedres); /* close and hook can move stack */
+ res = restorestack(L, savedres); /* hook can move stack */
+ }
wanted = decodeNresults(wanted);
if (wanted == LUA_MULTRET)
wanted = nres; /* we want all results */
@@ -16516,14 +16694,14 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
break;
}
/* generic case */
- firstresult = L->top - nres; /* index of first result */
+ firstresult = L->top.p - nres; /* index of first result */
if (nres > wanted) /* extra results? */
nres = wanted; /* don't need them */
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstresult + i);
for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(s2v(res + i));
- L->top = res + wanted; /* top points after the last result */
+ L->top.p = res + wanted; /* top points after the last result */
}
@@ -16538,7 +16716,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
rethook(L, ci, nres);
/* move results to proper place */
- moveresults(L, ci->func, nres, wanted);
+ moveresults(L, ci->func.p, nres, wanted);
/* function cannot be in any of these cases when returning */
lua_assert(!(ci->callstatus &
(CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
@@ -16553,10 +16731,10 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
int mask, StkId top) {
CallInfo *ci = L->ci = next_ci(L); /* new frame */
- ci->func = func;
+ ci->func.p = func;
ci->nresults = nret;
ci->callstatus = mask;
- ci->top = top;
+ ci->top.p = top;
return ci;
}
@@ -16570,10 +16748,10 @@ l_sinline int precallC (lua_State *L, StkId func, int nresults,
CallInfo *ci;
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
- L->top + LUA_MINSTACK);
- lua_assert(ci->top <= L->stack_last);
+ L->top.p + LUA_MINSTACK);
+ lua_assert(ci->top.p <= L->stack_last.p);
if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
- int narg = cast_int(L->top - func) - 1;
+ int narg = cast_int(L->top.p - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
}
lua_unlock(L);
@@ -16605,17 +16783,17 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int nfixparams = p->numparams;
int i;
checkstackGCp(L, fsize - delta, func);
- ci->func -= delta; /* restore 'func' (if vararg) */
+ ci->func.p -= delta; /* restore 'func' (if vararg) */
for (i = 0; i < narg1; i++) /* move down function and arguments */
- setobjs2s(L, ci->func + i, func + i);
- func = ci->func; /* moved-down function */
+ setobjs2s(L, ci->func.p + i, func + i);
+ func = ci->func.p; /* moved-down function */
for (; narg1 <= nfixparams; narg1++)
setnilvalue(s2v(func + narg1)); /* complete missing arguments */
- ci->top = func + 1 + fsize; /* top for new function */
- lua_assert(ci->top <= L->stack_last);
+ ci->top.p = func + 1 + fsize; /* top for new function */
+ lua_assert(ci->top.p <= L->stack_last.p);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus |= CIST_TAIL;
- L->top = func + narg1; /* set top */
+ L->top.p = func + narg1; /* set top */
return -1;
}
default: { /* not a function */
@@ -16648,15 +16826,15 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
case LUA_VLCL: { /* Lua function */
CallInfo *ci;
Proto *p = clLvalue(s2v(func))->p;
- int narg = cast_int(L->top - func) - 1; /* number of real arguments */
+ int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */
int nfixparams = p->numparams;
int fsize = p->maxstacksize; /* frame size */
checkstackGCp(L, fsize, func);
L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
ci->u.l.savedpc = p->code; /* starting point */
for (; narg < nfixparams; narg++)
- setnilvalue(s2v(L->top++)); /* complete missing arguments */
- lua_assert(ci->top <= L->stack_last);
+ setnilvalue(s2v(L->top.p++)); /* complete missing arguments */
+ lua_assert(ci->top.p <= L->stack_last.p);
return ci;
}
default: { /* not a function */
@@ -16672,12 +16850,17 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
** Call a function (C or Lua) through C. 'inc' can be 1 (increment
** number of recursive invocations in the C stack) or nyci (the same
** plus increment number of non-yieldable calls).
+** This function can be called with some use of EXTRA_STACK, so it should
+** check the stack before doing anything else. 'luaD_precall' already
+** does that.
*/
-l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) {
+l_sinline void ccall (lua_State *L, StkId func, int nResults, l_uint32 inc) {
CallInfo *ci;
L->nCcalls += inc;
- if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
+ if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
+ checkstackp(L, 0, func); /* free any use of EXTRA_STACK */
luaE_checkcstack(L);
+ }
if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */
ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */
luaV_execute(L, ci); /* call it */
@@ -16725,8 +16908,7 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
else { /* error */
StkId func = restorestack(L, ci->u2.funcidx);
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
- luaF_close(L, func, status, 1); /* can yield or raise an error */
- func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
+ func = luaF_close(L, func, status, 1); /* can yield or raise an error */
luaD_seterrorobj(L, status, func);
luaD_shrinkstack(L); /* restore stack size in case of overflow */
setcistrecst(ci, LUA_OK); /* clear original status */
@@ -16814,8 +16996,8 @@ static CallInfo *findpcall (lua_State *L) {
** coroutine error handler and should not kill the coroutine.)
*/
static int resume_error (lua_State *L, const char *msg, int narg) {
- L->top -= narg; /* remove args from the stack */
- setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
+ L->top.p -= narg; /* remove args from the stack */
+ setsvalue2s(L, L->top.p, luaS_new(L, msg)); /* push error message */
api_incr_top(L);
lua_unlock(L);
return LUA_ERRRUN;
@@ -16831,7 +17013,7 @@ static int resume_error (lua_State *L, const char *msg, int narg) {
*/
static void resume (lua_State *L, void *ud) {
int n = *(cast(int*, ud)); /* number of arguments */
- StkId firstArg = L->top - n; /* first argument */
+ StkId firstArg = L->top.p - n; /* first argument */
CallInfo *ci = L->ci;
if (L->status == LUA_OK) /* starting a coroutine? */
ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */
@@ -16839,7 +17021,7 @@ static void resume (lua_State *L, void *ud) {
lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */
if (isLua(ci)) { /* yielded inside a hook? */
- L->top = firstArg; /* discard arguments */
+ L->top.p = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */
}
else { /* 'common' yield */
@@ -16882,7 +17064,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
if (L->status == LUA_OK) { /* may be starting a coroutine */
if (L->ci != &L->base_ci) /* not in base level? */
return resume_error(L, "cannot resume non-suspended coroutine", nargs);
- else if (L->top - (L->ci->func + 1) == nargs) /* no function? */
+ else if (L->top.p - (L->ci->func.p + 1) == nargs) /* no function? */
return resume_error(L, "cannot resume dead coroutine", nargs);
}
else if (L->status != LUA_YIELD) /* ended with errors? */
@@ -16900,11 +17082,11 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
lua_assert(status == L->status); /* normal end or yield */
else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as 'dead' */
- luaD_seterrorobj(L, status, L->top); /* push error message */
- L->ci->top = L->top;
+ luaD_seterrorobj(L, status, L->top.p); /* push error message */
+ L->ci->top.p = L->top.p;
}
*nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
- : cast_int(L->top - (L->ci->func + 1));
+ : cast_int(L->top.p - (L->ci->func.p + 1));
lua_unlock(L);
return status;
}
@@ -17059,7 +17241,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
p.dyd.label.arr = NULL; p.dyd.label.size = 0;
luaZ_initbuffer(L, &p.buff);
- status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
+ status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc);
luaZ_freebuffer(L, &p.buff);
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
@@ -17679,8 +17861,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
if (tm == NULL) /* no TM? */
return 0; /* objects are different */
else {
- luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */
- return !l_isfalse(s2v(L->top));
+ luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
+ return !l_isfalse(s2v(L->top.p));
}
}
@@ -17704,17 +17886,17 @@ static void copy2buff (StkId top, int n, char *buff) {
/*
** Main operation for concatenation: concat 'total' values in the stack,
-** from 'L->top - total' up to 'L->top - 1'.
+** from 'L->top.p - total' up to 'L->top.p - 1'.
*/
void luaV_concat (lua_State *L, int total) {
if (total == 1)
return; /* "all" values already concatenated */
do {
- StkId top = L->top;
+ StkId top = L->top.p;
int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) ||
!tostring(L, s2v(top - 1)))
- luaT_tryconcatTM(L);
+ luaT_tryconcatTM(L); /* may invalidate 'top' */
else if (isemptystr(s2v(top - 1))) /* second operand is empty? */
cast_void(tostring(L, s2v(top - 2))); /* result is first operand */
else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */
@@ -17727,8 +17909,10 @@ void luaV_concat (lua_State *L, int total) {
/* collect total length and number of strings */
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
size_t l = vslen(s2v(top - n - 1));
- if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl))
+ if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) {
+ L->top.p = top - total; /* pop strings to avoid wasting stack */
luaG_runerror(L, "string length overflow");
+ }
tl += l;
}
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
@@ -17742,8 +17926,8 @@ void luaV_concat (lua_State *L, int total) {
}
setsvalue2s(L, top - n, ts); /* create result */
}
- total -= n-1; /* got 'n' strings to create 1 new */
- L->top -= n-1; /* popped 'n' strings and pushed one */
+ total -= n - 1; /* got 'n' strings to create one new */
+ L->top.p -= n - 1; /* popped 'n' strings and pushed one */
} while (total > 1); /* repeat until only 1 result left */
}
@@ -17834,12 +18018,10 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
/* number of bits in an integer */
#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT)
+
/*
** Shift left operation. (Shift right just negates 'y'.)
*/
-#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
-
-
lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
if (y < 0) { /* shift right? */
if (y <= -NBITS) return 0;
@@ -17879,26 +18061,26 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
*/
void luaV_finishOp (lua_State *L) {
CallInfo *ci = L->ci;
- StkId base = ci->func + 1;
+ StkId base = ci->func.p + 1;
Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
OpCode op = GET_OPCODE(inst);
switch (op) { /* finish its execution */
case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
- setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top);
+ setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top.p);
break;
}
case OP_UNM: case OP_BNOT: case OP_LEN:
case OP_GETTABUP: case OP_GETTABLE: case OP_GETI:
case OP_GETFIELD: case OP_SELF: {
- setobjs2s(L, base + GETARG_A(inst), --L->top);
+ setobjs2s(L, base + GETARG_A(inst), --L->top.p);
break;
}
case OP_LT: case OP_LE:
case OP_LTI: case OP_LEI:
case OP_GTI: case OP_GEI:
case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */
- int res = !l_isfalse(s2v(L->top - 1));
- L->top--;
+ int res = !l_isfalse(s2v(L->top.p - 1));
+ L->top.p--;
#if defined(LUA_COMPAT_LT_LE)
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
ci->callstatus ^= CIST_LEQ; /* clear mark */
@@ -17911,11 +18093,11 @@ void luaV_finishOp (lua_State *L) {
break;
}
case OP_CONCAT: {
- StkId top = L->top - 1; /* top when 'luaT_tryconcatTM' was called */
+ StkId top = L->top.p - 1; /* top when 'luaT_tryconcatTM' was called */
int a = GETARG_A(inst); /* first element to concatenate */
int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */
setobjs2s(L, top - 2, top); /* put TM result in proper position */
- L->top = top - 1; /* top is one after last element (at top-2) */
+ L->top.p = top - 1; /* top is one after last element (at top-2) */
luaV_concat(L, total); /* concat them (may yield again) */
break;
}
@@ -17927,7 +18109,7 @@ void luaV_finishOp (lua_State *L) {
StkId ra = base + GETARG_A(inst);
/* adjust top to signal correct number of returns, in case the
return is "up to top" ('isIT') */
- L->top = ra + ci->u2.nres;
+ L->top.p = ra + ci->u2.nres;
/* repeat instruction to close other vars. and complete the return */
ci->u.l.savedpc--;
break;
@@ -17969,6 +18151,7 @@ void luaV_finishOp (lua_State *L) {
** operation, 'fop' is the float operation.
*/
#define op_arithI(L,iop,fop) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
int imm = GETARG_sC(i); \
if (ttisinteger(v1)) { \
@@ -17997,6 +18180,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over floats and others with register operands.
*/
#define op_arithf(L,fop) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
op_arithf_aux(L, v1, v2, fop); }
@@ -18006,6 +18190,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations with K operands for floats.
*/
#define op_arithfK(L,fop) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
op_arithf_aux(L, v1, v2, fop); }
@@ -18015,6 +18200,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over integers and floats.
*/
#define op_arith_aux(L,v1,v2,iop,fop) { \
+ StkId ra = RA(i); \
if (ttisinteger(v1) && ttisinteger(v2)) { \
lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \
pc++; setivalue(s2v(ra), iop(L, i1, i2)); \
@@ -18044,6 +18230,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with constant operand.
*/
#define op_bitwiseK(L,op) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); \
lua_Integer i1; \
@@ -18057,6 +18244,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with register operands.
*/
#define op_bitwise(L,op) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
lua_Integer i1; lua_Integer i2; \
@@ -18071,18 +18259,19 @@ void luaV_finishOp (lua_State *L) {
** integers.
*/
#define op_order(L,opi,opn,other) { \
- int cond; \
- TValue *rb = vRB(i); \
- if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
- lua_Integer ia = ivalue(s2v(ra)); \
- lua_Integer ib = ivalue(rb); \
- cond = opi(ia, ib); \
- } \
- else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
- cond = opn(s2v(ra), rb); \
- else \
- Protect(cond = other(L, s2v(ra), rb)); \
- docondjump(); }
+ StkId ra = RA(i); \
+ int cond; \
+ TValue *rb = vRB(i); \
+ if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
+ lua_Integer ia = ivalue(s2v(ra)); \
+ lua_Integer ib = ivalue(rb); \
+ cond = opi(ia, ib); \
+ } \
+ else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
+ cond = opn(s2v(ra), rb); \
+ else \
+ Protect(cond = other(L, s2v(ra), rb)); \
+ docondjump(); }
/*
@@ -18090,20 +18279,21 @@ void luaV_finishOp (lua_State *L) {
** always small enough to have an exact representation as a float.)
*/
#define op_orderI(L,opi,opf,inv,tm) { \
- int cond; \
- int im = GETARG_sB(i); \
- if (ttisinteger(s2v(ra))) \
- cond = opi(ivalue(s2v(ra)), im); \
- else if (ttisfloat(s2v(ra))) { \
- lua_Number fa = fltvalue(s2v(ra)); \
- lua_Number fim = cast_num(im); \
- cond = opf(fa, fim); \
- } \
- else { \
- int isf = GETARG_C(i); \
- Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
- } \
- docondjump(); }
+ StkId ra = RA(i); \
+ int cond; \
+ int im = GETARG_sB(i); \
+ if (ttisinteger(s2v(ra))) \
+ cond = opi(ivalue(s2v(ra)), im); \
+ else if (ttisfloat(s2v(ra))) { \
+ lua_Number fa = fltvalue(s2v(ra)); \
+ lua_Number fim = cast_num(im); \
+ cond = opf(fa, fim); \
+ } \
+ else { \
+ int isf = GETARG_C(i); \
+ Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
+ } \
+ docondjump(); }
/* }================================================================== */
@@ -18132,7 +18322,7 @@ void luaV_finishOp (lua_State *L) {
#define updatetrap(ci) (trap = ci->u.l.trap)
-#define updatebase(ci) (base = ci->func + 1)
+#define updatebase(ci) (base = ci->func.p + 1)
#define updatestack(ci) \
@@ -18167,7 +18357,7 @@ void luaV_finishOp (lua_State *L) {
** Whenever code can raise errors, the global 'pc' and the global
** 'top' must be correct to report occasional errors.
*/
-#define savestate(L,ci) (savepc(L), L->top = ci->top)
+#define savestate(L,ci) (savepc(L), L->top.p = ci->top.p)
/*
@@ -18187,7 +18377,7 @@ void luaV_finishOp (lua_State *L) {
/* 'c' is the limit of live values in the stack */
#define checkGC(L,c) \
- { luaC_condGC(L, (savepc(L), L->top = (c)), \
+ { luaC_condGC(L, (savepc(L), L->top.p = (c)), \
updatetrap(ci)); \
luai_threadyield(L); }
@@ -18199,7 +18389,6 @@ void luaV_finishOp (lua_State *L) {
updatebase(ci); /* correct stack */ \
} \
i = *(pc++); \
- ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
}
#define vmdispatch(o) switch(o)
@@ -18331,7 +18520,7 @@ static const void *const disptab[NUM_OPCODES] = {
startfunc:
trap = L->hookmask;
returning: /* trap already set */
- cl = clLvalue(s2v(ci->func));
+ cl = clLvalue(s2v(ci->func.p));
k = cl->p->k;
pc = ci->u.l.savedpc;
if (l_unlikely(trap)) {
@@ -18343,60 +18532,68 @@ static const void *const disptab[NUM_OPCODES] = {
}
ci->u.l.trap = 1; /* assume trap is on, for now */
}
- base = ci->func + 1;
+ base = ci->func.p + 1;
/* main loop of interpreter */
for (;;) {
Instruction i; /* instruction being executed */
- StkId ra; /* instruction's A register */
vmfetch();
#if 0
/* low-level line tracing for debugging Lua */
printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
#endif
- lua_assert(base == ci->func + 1);
- lua_assert(base <= L->top && L->top < L->stack_last);
+ lua_assert(base == ci->func.p + 1);
+ lua_assert(base <= L->top.p && L->top.p <= L->stack_last.p);
/* invalidate top for instructions not expecting it */
- lua_assert(isIT(i) || (cast_void(L->top = base), 1));
+ lua_assert(isIT(i) || (cast_void(L->top.p = base), 1));
vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) {
+ StkId ra = RA(i);
setobjs2s(L, ra, RB(i));
vmbreak;
}
vmcase(OP_LOADI) {
+ StkId ra = RA(i);
lua_Integer b = GETARG_sBx(i);
setivalue(s2v(ra), b);
vmbreak;
}
vmcase(OP_LOADF) {
+ StkId ra = RA(i);
int b = GETARG_sBx(i);
setfltvalue(s2v(ra), cast_num(b));
vmbreak;
}
vmcase(OP_LOADK) {
+ StkId ra = RA(i);
TValue *rb = k + GETARG_Bx(i);
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADKX) {
+ StkId ra = RA(i);
TValue *rb;
rb = k + GETARG_Ax(*pc); pc++;
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADFALSE) {
+ StkId ra = RA(i);
setbfvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LFALSESKIP) {
+ StkId ra = RA(i);
setbfvalue(s2v(ra));
pc++; /* skip next instruction */
vmbreak;
}
vmcase(OP_LOADTRUE) {
+ StkId ra = RA(i);
setbtvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LOADNIL) {
+ StkId ra = RA(i);
int b = GETARG_B(i);
do {
setnilvalue(s2v(ra++));
@@ -18404,19 +18601,22 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_GETUPVAL) {
+ StkId ra = RA(i);
int b = GETARG_B(i);
- setobj2s(L, ra, cl->upvals[b]->v);
+ setobj2s(L, ra, cl->upvals[b]->v.p);
vmbreak;
}
vmcase(OP_SETUPVAL) {
+ StkId ra = RA(i);
UpVal *uv = cl->upvals[GETARG_B(i)];
- setobj(L, uv->v, s2v(ra));
+ setobj(L, uv->v.p, s2v(ra));
luaC_barrier(L, uv, s2v(ra));
vmbreak;
}
vmcase(OP_GETTABUP) {
+ StkId ra = RA(i);
const TValue *slot;
- TValue *upval = cl->upvals[GETARG_B(i)]->v;
+ TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
TValue *rc = KC(i);
TString *key = tsvalue(rc); /* key must be a string */
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
@@ -18427,6 +18627,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_GETTABLE) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = vRC(i);
@@ -18441,6 +18642,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_GETI) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
int c = GETARG_C(i);
@@ -18455,6 +18657,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_GETFIELD) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = KC(i);
@@ -18468,7 +18671,7 @@ static const void *const disptab[NUM_OPCODES] = {
}
vmcase(OP_SETTABUP) {
const TValue *slot;
- TValue *upval = cl->upvals[GETARG_A(i)]->v;
+ TValue *upval = cl->upvals[GETARG_A(i)]->v.p;
TValue *rb = KB(i);
TValue *rc = RKC(i);
TString *key = tsvalue(rb); /* key must be a string */
@@ -18480,6 +18683,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SETTABLE) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i); /* key (table is in 'ra') */
TValue *rc = RKC(i); /* value */
@@ -18494,6 +18698,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SETI) {
+ StkId ra = RA(i);
const TValue *slot;
int c = GETARG_B(i);
TValue *rc = RKC(i);
@@ -18508,6 +18713,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SETFIELD) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = KB(i);
TValue *rc = RKC(i);
@@ -18520,6 +18726,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_NEWTABLE) {
+ StkId ra = RA(i);
int b = GETARG_B(i); /* log2(hash size) + 1 */
int c = GETARG_C(i); /* array size */
Table *t;
@@ -18529,7 +18736,7 @@ static const void *const disptab[NUM_OPCODES] = {
if (TESTARG_k(i)) /* non-zero extra argument? */
c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */
pc++; /* skip extra argument */
- L->top = ra + 1; /* correct top in case of emergency GC */
+ L->top.p = ra + 1; /* correct top in case of emergency GC */
t = luaH_new(L); /* memory allocation */
sethvalue2s(L, ra, t);
if (b != 0 || c != 0)
@@ -18538,6 +18745,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SELF) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = RKC(i);
@@ -18567,6 +18775,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MODK) {
+ savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_mod, luaV_modf);
vmbreak;
}
@@ -18579,6 +18788,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_IDIVK) {
+ savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_idiv, luai_numidiv);
vmbreak;
}
@@ -18595,6 +18805,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SHRI) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
@@ -18604,6 +18815,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SHLI) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
@@ -18625,6 +18837,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MOD) {
+ savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_mod, luaV_modf);
vmbreak;
}
@@ -18637,6 +18850,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_IDIV) { /* floor division */
+ savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_idiv, luai_numidiv);
vmbreak;
}
@@ -18661,6 +18875,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MMBIN) {
+ StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
TValue *rb = vRB(i);
TMS tm = (TMS)GETARG_C(i);
@@ -18670,6 +18885,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MMBINI) {
+ StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
int imm = GETARG_sB(i);
TMS tm = (TMS)GETARG_C(i);
@@ -18679,6 +18895,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MMBINK) {
+ StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
TValue *imm = KB(i);
TMS tm = (TMS)GETARG_C(i);
@@ -18688,6 +18905,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_UNM) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Number nb;
if (ttisinteger(rb)) {
@@ -18702,6 +18920,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_BNOT) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Integer ib;
if (tointegerns(rb, &ib)) {
@@ -18712,6 +18931,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_NOT) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb))
setbtvalue(s2v(ra));
@@ -18720,21 +18940,25 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_LEN) {
+ StkId ra = RA(i);
Protect(luaV_objlen(L, ra, vRB(i)));
vmbreak;
}
vmcase(OP_CONCAT) {
+ StkId ra = RA(i);
int n = GETARG_B(i); /* number of elements to concatenate */
- L->top = ra + n; /* mark the end of concat operands */
+ L->top.p = ra + n; /* mark the end of concat operands */
ProtectNT(luaV_concat(L, n));
- checkGC(L, L->top); /* 'luaV_concat' ensures correct top */
+ checkGC(L, L->top.p); /* 'luaV_concat' ensures correct top */
vmbreak;
}
vmcase(OP_CLOSE) {
+ StkId ra = RA(i);
Protect(luaF_close(L, ra, LUA_OK, 1));
vmbreak;
}
vmcase(OP_TBC) {
+ StkId ra = RA(i);
/* create new to-be-closed upvalue */
halfProtect(luaF_newtbcupval(L, ra));
vmbreak;
@@ -18744,6 +18968,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_EQ) {
+ StkId ra = RA(i);
int cond;
TValue *rb = vRB(i);
Protect(cond = luaV_equalobj(L, s2v(ra), rb));
@@ -18759,6 +18984,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_EQK) {
+ StkId ra = RA(i);
TValue *rb = KB(i);
/* basic types do not use '__eq'; we can use raw equality */
int cond = luaV_rawequalobj(s2v(ra), rb);
@@ -18766,6 +18992,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_EQI) {
+ StkId ra = RA(i);
int cond;
int im = GETARG_sB(i);
if (ttisinteger(s2v(ra)))
@@ -18794,11 +19021,13 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_TEST) {
+ StkId ra = RA(i);
int cond = !l_isfalse(s2v(ra));
docondjump();
vmbreak;
}
vmcase(OP_TESTSET) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb) == GETARG_k(i))
pc++;
@@ -18809,11 +19038,12 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_CALL) {
+ StkId ra = RA(i);
CallInfo *newci;
int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1;
if (b != 0) /* fixed number of arguments? */
- L->top = ra + b; /* top signals number of arguments */
+ L->top.p = ra + b; /* top signals number of arguments */
/* else previous instruction set top */
savepc(L); /* in case of errors */
if ((newci = luaD_precall(L, ra, nresults)) == NULL)
@@ -18825,54 +19055,57 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_TAILCALL) {
+ StkId ra = RA(i);
int b = GETARG_B(i); /* number of arguments + 1 (function) */
int n; /* number of results when calling a C function */
int nparams1 = GETARG_C(i);
/* delta is virtual 'func' - real 'func' (vararg functions) */
int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
if (b != 0)
- L->top = ra + b;
+ L->top.p = ra + b;
else /* previous instruction set top */
- b = cast_int(L->top - ra);
+ b = cast_int(L->top.p - ra);
savepc(ci); /* several calls here can raise errors */
if (TESTARG_k(i)) {
luaF_closeupval(L, base); /* close upvalues from current call */
- lua_assert(L->tbclist < base); /* no pending tbc variables */
- lua_assert(base == ci->func + 1);
+ lua_assert(L->tbclist.p < base); /* no pending tbc variables */
+ lua_assert(base == ci->func.p + 1);
}
if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */
goto startfunc; /* execute the callee */
else { /* C function? */
- ci->func -= delta; /* restore 'func' (if vararg) */
+ ci->func.p -= delta; /* restore 'func' (if vararg) */
luaD_poscall(L, ci, n); /* finish caller */
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; /* caller returns after the tail call */
}
}
vmcase(OP_RETURN) {
+ StkId ra = RA(i);
int n = GETARG_B(i) - 1; /* number of results */
int nparams1 = GETARG_C(i);
if (n < 0) /* not fixed? */
- n = cast_int(L->top - ra); /* get what is available */
+ n = cast_int(L->top.p - ra); /* get what is available */
savepc(ci);
if (TESTARG_k(i)) { /* may there be open upvalues? */
ci->u2.nres = n; /* save number of returns */
- if (L->top < ci->top)
- L->top = ci->top;
+ if (L->top.p < ci->top.p)
+ L->top.p = ci->top.p;
luaF_close(L, base, CLOSEKTOP, 1);
updatetrap(ci);
updatestack(ci);
}
if (nparams1) /* vararg function? */
- ci->func -= ci->u.l.nextraargs + nparams1;
- L->top = ra + n; /* set call for 'luaD_poscall' */
+ ci->func.p -= ci->u.l.nextraargs + nparams1;
+ L->top.p = ra + n; /* set call for 'luaD_poscall' */
luaD_poscall(L, ci, n);
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret;
}
vmcase(OP_RETURN0) {
if (l_unlikely(L->hookmask)) {
- L->top = ra;
+ StkId ra = RA(i);
+ L->top.p = ra;
savepc(ci);
luaD_poscall(L, ci, 0); /* no hurry... */
trap = 1;
@@ -18880,15 +19113,16 @@ static const void *const disptab[NUM_OPCODES] = {
else { /* do the 'poscall' here */
int nres;
L->ci = ci->previous; /* back to caller */
- L->top = base - 1;
+ L->top.p = base - 1;
for (nres = ci->nresults; l_unlikely(nres > 0); nres--)
- setnilvalue(s2v(L->top++)); /* all results are nil */
+ setnilvalue(s2v(L->top.p++)); /* all results are nil */
}
goto ret;
}
vmcase(OP_RETURN1) {
if (l_unlikely(L->hookmask)) {
- L->top = ra + 1;
+ StkId ra = RA(i);
+ L->top.p = ra + 1;
savepc(ci);
luaD_poscall(L, ci, 1); /* no hurry... */
trap = 1;
@@ -18897,12 +19131,13 @@ static const void *const disptab[NUM_OPCODES] = {
int nres = ci->nresults;
L->ci = ci->previous; /* back to caller */
if (nres == 0)
- L->top = base - 1; /* asked for no results */
+ L->top.p = base - 1; /* asked for no results */
else {
+ StkId ra = RA(i);
setobjs2s(L, base - 1, ra); /* at least this result */
- L->top = base;
+ L->top.p = base;
for (; l_unlikely(nres > 1); nres--)
- setnilvalue(s2v(L->top++)); /* complete missing results */
+ setnilvalue(s2v(L->top.p++)); /* complete missing results */
}
}
ret: /* return from a Lua function */
@@ -18914,6 +19149,7 @@ static const void *const disptab[NUM_OPCODES] = {
}
}
vmcase(OP_FORLOOP) {
+ StkId ra = RA(i);
if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));
if (count > 0) { /* still more iterations? */
@@ -18932,12 +19168,14 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_FORPREP) {
+ StkId ra = RA(i);
savestate(L, ci); /* in case of errors */
if (forprep(L, ra))
pc += GETARG_Bx(i) + 1; /* skip the loop */
vmbreak;
}
vmcase(OP_TFORPREP) {
+ StkId ra = RA(i);
/* create to-be-closed upvalue (if needed) */
halfProtect(luaF_newtbcupval(L, ra + 3));
pc += GETARG_Bx(i);
@@ -18946,7 +19184,8 @@ static const void *const disptab[NUM_OPCODES] = {
goto l_tforcall;
}
vmcase(OP_TFORCALL) {
- l_tforcall:
+ l_tforcall: {
+ StkId ra = RA(i);
/* 'ra' has the iterator function, 'ra + 1' has the state,
'ra + 2' has the control variable, and 'ra + 3' has the
to-be-closed variable. The call will use the stack after
@@ -18954,29 +19193,31 @@ static const void *const disptab[NUM_OPCODES] = {
*/
/* push function, state, and control variable */
memcpy(ra + 4, ra, 3 * sizeof(*ra));
- L->top = ra + 4 + 3;
+ L->top.p = ra + 4 + 3;
ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */
updatestack(ci); /* stack may have changed */
i = *(pc++); /* go to next instruction */
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
goto l_tforloop;
- }
+ }}
vmcase(OP_TFORLOOP) {
- l_tforloop:
+ l_tforloop: {
+ StkId ra = RA(i);
if (!ttisnil(s2v(ra + 4))) { /* continue loop? */
setobjs2s(L, ra + 2, ra + 4); /* save control variable */
pc -= GETARG_Bx(i); /* jump back */
}
vmbreak;
- }
+ }}
vmcase(OP_SETLIST) {
+ StkId ra = RA(i);
int n = GETARG_B(i);
unsigned int last = GETARG_C(i);
Table *h = hvalue(s2v(ra));
if (n == 0)
- n = cast_int(L->top - ra) - 1; /* get up to the top */
+ n = cast_int(L->top.p - ra) - 1; /* get up to the top */
else
- L->top = ci->top; /* correct top in case of emergency GC */
+ L->top.p = ci->top.p; /* correct top in case of emergency GC */
last += n;
if (TESTARG_k(i)) {
last += GETARG_Ax(*pc) * (MAXARG_C + 1);
@@ -18993,12 +19234,14 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_CLOSURE) {
+ StkId ra = RA(i);
Proto *p = cl->p->p[GETARG_Bx(i)];
halfProtect(pushclosure(L, p, cl->upvals, base, ra));
checkGC(L, ra + 1);
vmbreak;
}
vmcase(OP_VARARG) {
+ StkId ra = RA(i);
int n = GETARG_C(i) - 1; /* required results */
Protect(luaT_getvarargs(L, ci, ra, n));
vmbreak;
@@ -19083,27 +19326,28 @@ const char lua_ident[] =
static TValue *index2value (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
- StkId o = ci->func + idx;
- api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index");
- if (o >= L->top) return &G(L)->nilvalue;
+ StkId o = ci->func.p + idx;
+ api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index");
+ if (o >= L->top.p) return &G(L)->nilvalue;
else return s2v(o);
}
else if (!ispseudo(idx)) { /* negative index */
- api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
- return s2v(L->top + idx);
+ api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
+ "invalid index");
+ return s2v(L->top.p + idx);
}
else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry;
else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
- if (ttisCclosure(s2v(ci->func))) { /* C closure? */
- CClosure *func = clCvalue(s2v(ci->func));
+ if (ttisCclosure(s2v(ci->func.p))) { /* C closure? */
+ CClosure *func = clCvalue(s2v(ci->func.p));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue;
}
else { /* light C function or Lua function (through a hook)?) */
- api_check(L, ttislcf(s2v(ci->func)), "caller not a C function");
+ api_check(L, ttislcf(s2v(ci->func.p)), "caller not a C function");
return &G(L)->nilvalue; /* no upvalues */
}
}
@@ -19117,14 +19361,15 @@ static TValue *index2value (lua_State *L, int idx) {
l_sinline StkId index2stack (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
- StkId o = ci->func + idx;
- api_check(L, o < L->top, "invalid index");
+ StkId o = ci->func.p + idx;
+ api_check(L, o < L->top.p, "invalid index");
return o;
}
else { /* non-positive index */
- api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
+ api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
+ "invalid index");
api_check(L, !ispseudo(idx), "invalid index");
- return L->top + idx;
+ return L->top.p + idx;
}
}
@@ -19135,17 +19380,12 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
lua_lock(L);
ci = L->ci;
api_check(L, n >= 0, "negative 'n'");
- if (L->stack_last - L->top > n) /* stack large enough? */
+ if (L->stack_last.p - L->top.p > n) /* stack large enough? */
res = 1; /* yes; check is OK */
- else { /* no; need to grow stack */
- int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;
- if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */
- res = 0; /* no */
- else /* try to grow stack */
- res = luaD_growstack(L, n, 0);
- }
- if (res && ci->top < L->top + n)
- ci->top = L->top + n; /* adjust frame top */
+ else /* need to grow stack */
+ res = luaD_growstack(L, n, 0);
+ if (res && ci->top.p < L->top.p + n)
+ ci->top.p = L->top.p + n; /* adjust frame top */
lua_unlock(L);
return res;
}
@@ -19157,11 +19397,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
lua_lock(to);
api_checknelems(from, n);
api_check(from, G(from) == G(to), "moving among independent states");
- api_check(from, to->ci->top - to->top >= n, "stack overflow");
- from->top -= n;
+ api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow");
+ from->top.p -= n;
for (i = 0; i < n; i++) {
- setobjs2s(to, to->top, from->top + i);
- to->top++; /* stack already checked by previous 'api_check' */
+ setobjs2s(to, to->top.p, from->top.p + i);
+ to->top.p++; /* stack already checked by previous 'api_check' */
}
lua_unlock(to);
}
@@ -19195,12 +19435,12 @@ LUA_API lua_Number lua_version (lua_State *L) {
LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx))
? idx
- : cast_int(L->top - L->ci->func) + idx;
+ : cast_int(L->top.p - L->ci->func.p) + idx;
}
LUA_API int lua_gettop (lua_State *L) {
- return cast_int(L->top - (L->ci->func + 1));
+ return cast_int(L->top.p - (L->ci->func.p + 1));
}
@@ -19210,24 +19450,24 @@ LUA_API void lua_settop (lua_State *L, int idx) {
ptrdiff_t diff; /* difference for new top */
lua_lock(L);
ci = L->ci;
- func = ci->func;
+ func = ci->func.p;
if (idx >= 0) {
- api_check(L, idx <= ci->top - (func + 1), "new top too large");
- diff = ((func + 1) + idx) - L->top;
+ api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
+ diff = ((func + 1) + idx) - L->top.p;
for (; diff > 0; diff--)
- setnilvalue(s2v(L->top++)); /* clear new slots */
+ setnilvalue(s2v(L->top.p++)); /* clear new slots */
}
else {
- api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
+ api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top");
diff = idx + 1; /* will "subtract" index (as it is negative) */
}
- api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot");
- newtop = L->top + diff;
- if (diff < 0 && L->tbclist >= newtop) {
+ api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot");
+ newtop = L->top.p + diff;
+ if (diff < 0 && L->tbclist.p >= newtop) {
lua_assert(hastocloseCfunc(ci->nresults));
- luaF_close(L, newtop, CLOSEKTOP, 0);
+ newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
}
- L->top = newtop; /* correct top only after closing any upvalue */
+ L->top.p = newtop; /* correct top only after closing any upvalue */
lua_unlock(L);
}
@@ -19236,10 +19476,9 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
StkId level;
lua_lock(L);
level = index2stack(L, idx);
- api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
+ api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
"no variable to close at given level");
- luaF_close(L, level, CLOSEKTOP, 0);
- level = index2stack(L, idx); /* stack may be moved */
+ level = luaF_close(L, level, CLOSEKTOP, 0);
setnilvalue(s2v(level));
lua_unlock(L);
}
@@ -19268,7 +19507,7 @@ l_sinline void reverse (lua_State *L, StkId from, StkId to) {
LUA_API void lua_rotate (lua_State *L, int idx, int n) {
StkId p, t, m;
lua_lock(L);
- t = L->top - 1; /* end of stack segment being rotated */
+ t = L->top.p - 1; /* end of stack segment being rotated */
p = index2stack(L, idx); /* start of segment */
api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
@@ -19287,7 +19526,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
api_check(L, isvalid(L, to), "invalid index");
setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */
- luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr);
+ luaC_barrier(L, clCvalue(s2v(L->ci->func.p)), fr);
/* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */
lua_unlock(L);
@@ -19296,7 +19535,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
LUA_API void lua_pushvalue (lua_State *L, int idx) {
lua_lock(L);
- setobj2s(L, L->top, index2value(L, idx));
+ setobj2s(L, L->top.p, index2value(L, idx));
api_incr_top(L);
lua_unlock(L);
}
@@ -19365,12 +19604,12 @@ LUA_API void lua_arith (lua_State *L, int op) {
api_checknelems(L, 2); /* all other operations expect two operands */
else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1);
- setobjs2s(L, L->top, L->top - 1);
+ setobjs2s(L, L->top.p, L->top.p - 1);
api_incr_top(L);
}
/* first operand at top - 2, second at top - 1; result go to top - 2 */
- luaO_arith(L, op, s2v(L->top - 2), s2v(L->top - 1), L->top - 2);
- L->top--; /* remove second operand */
+ luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2);
+ L->top.p--; /* remove second operand */
lua_unlock(L);
}
@@ -19396,7 +19635,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
- size_t sz = luaO_str2num(s, s2v(L->top));
+ size_t sz = luaO_str2num(s, s2v(L->top.p));
if (sz != 0)
api_incr_top(L);
return sz;
@@ -19523,7 +19762,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
LUA_API void lua_pushnil (lua_State *L) {
lua_lock(L);
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
api_incr_top(L);
lua_unlock(L);
}
@@ -19531,7 +19770,7 @@ LUA_API void lua_pushnil (lua_State *L) {
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
lua_lock(L);
- setfltvalue(s2v(L->top), n);
+ setfltvalue(s2v(L->top.p), n);
api_incr_top(L);
lua_unlock(L);
}
@@ -19539,7 +19778,7 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
lua_lock(L);
- setivalue(s2v(L->top), n);
+ setivalue(s2v(L->top.p), n);
api_incr_top(L);
lua_unlock(L);
}
@@ -19554,7 +19793,7 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts;
lua_lock(L);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
- setsvalue2s(L, L->top, ts);
+ setsvalue2s(L, L->top.p, ts);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
@@ -19565,11 +19804,11 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
lua_lock(L);
if (s == NULL)
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
else {
TString *ts;
ts = luaS_new(L, s);
- setsvalue2s(L, L->top, ts);
+ setsvalue2s(L, L->top.p, ts);
s = getstr(ts); /* internal copy's address */
}
api_incr_top(L);
@@ -19606,7 +19845,7 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L);
if (n == 0) {
- setfvalue(s2v(L->top), fn);
+ setfvalue(s2v(L->top.p), fn);
api_incr_top(L);
}
else {
@@ -19615,13 +19854,13 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n);
cl->f = fn;
- L->top -= n;
+ L->top.p -= n;
while (n--) {
- setobj2n(L, &cl->upvalue[n], s2v(L->top + n));
+ setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n));
/* does not need barrier because closure is white */
lua_assert(iswhite(cl));
}
- setclCvalue(L, s2v(L->top), cl);
+ setclCvalue(L, s2v(L->top.p), cl);
api_incr_top(L);
luaC_checkGC(L);
}
@@ -19632,9 +19871,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
LUA_API void lua_pushboolean (lua_State *L, int b) {
lua_lock(L);
if (b)
- setbtvalue(s2v(L->top));
+ setbtvalue(s2v(L->top.p));
else
- setbfvalue(s2v(L->top));
+ setbfvalue(s2v(L->top.p));
api_incr_top(L);
lua_unlock(L);
}
@@ -19642,7 +19881,7 @@ LUA_API void lua_pushboolean (lua_State *L, int b) {
LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
lua_lock(L);
- setpvalue(s2v(L->top), p);
+ setpvalue(s2v(L->top.p), p);
api_incr_top(L);
lua_unlock(L);
}
@@ -19650,7 +19889,7 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
LUA_API int lua_pushthread (lua_State *L) {
lua_lock(L);
- setthvalue(L, s2v(L->top), L);
+ setthvalue(L, s2v(L->top.p), L);
api_incr_top(L);
lua_unlock(L);
return (G(L)->mainthread == L);
@@ -19667,16 +19906,16 @@ l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
- setobj2s(L, L->top, slot);
+ setobj2s(L, L->top.p, slot);
api_incr_top(L);
}
else {
- setsvalue2s(L, L->top, str);
+ setsvalue2s(L, L->top.p, str);
api_incr_top(L);
- luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
+ luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
}
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
@@ -19703,13 +19942,13 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
TValue *t;
lua_lock(L);
t = index2value(L, idx);
- if (luaV_fastget(L, t, s2v(L->top - 1), slot, luaH_get)) {
- setobj2s(L, L->top - 1, slot);
+ if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) {
+ setobj2s(L, L->top.p - 1, slot);
}
else
- luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
+ luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
@@ -19725,27 +19964,27 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) {
- setobj2s(L, L->top, slot);
+ setobj2s(L, L->top.p, slot);
}
else {
TValue aux;
setivalue(&aux, n);
- luaV_finishget(L, t, &aux, L->top, slot);
+ luaV_finishget(L, t, &aux, L->top.p, slot);
}
api_incr_top(L);
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
l_sinline int finishrawget (lua_State *L, const TValue *val) {
if (isempty(val)) /* avoid copying empty items to the stack */
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
else
- setobj2s(L, L->top, val);
+ setobj2s(L, L->top.p, val);
api_incr_top(L);
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
@@ -19762,8 +20001,8 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
- val = luaH_get(t, s2v(L->top - 1));
- L->top--; /* remove key */
+ val = luaH_get(t, s2v(L->top.p - 1));
+ L->top.p--; /* remove key */
return finishrawget(L, val);
}
@@ -19790,7 +20029,7 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t;
lua_lock(L);
t = luaH_new(L);
- sethvalue2s(L, L->top, t);
+ sethvalue2s(L, L->top.p, t);
api_incr_top(L);
if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec);
@@ -19817,7 +20056,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
break;
}
if (mt != NULL) {
- sethvalue2s(L, L->top, mt);
+ sethvalue2s(L, L->top.p, mt);
api_incr_top(L);
res = 1;
}
@@ -19833,12 +20072,12 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
o = index2value(L, idx);
api_check(L, ttisfulluserdata(o), "full userdata expected");
if (n <= 0 || n > uvalue(o)->nuvalue) {
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
t = LUA_TNONE;
}
else {
- setobj2s(L, L->top, &uvalue(o)->uv[n - 1].uv);
- t = ttype(s2v(L->top));
+ setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv);
+ t = ttype(s2v(L->top.p));
}
api_incr_top(L);
lua_unlock(L);
@@ -19858,14 +20097,14 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
TString *str = luaS_new(L, k);
api_checknelems(L, 1);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
- luaV_finishfastset(L, t, slot, s2v(L->top - 1));
- L->top--; /* pop value */
+ luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
+ L->top.p--; /* pop value */
}
else {
- setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
+ setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */
api_incr_top(L);
- luaV_finishset(L, t, s2v(L->top - 1), s2v(L->top - 2), slot);
- L->top -= 2; /* pop value and key */
+ luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot);
+ L->top.p -= 2; /* pop value and key */
}
lua_unlock(L); /* lock done by caller */
}
@@ -19885,12 +20124,12 @@ LUA_API void lua_settable (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 2);
t = index2value(L, idx);
- if (luaV_fastget(L, t, s2v(L->top - 2), slot, luaH_get)) {
- luaV_finishfastset(L, t, slot, s2v(L->top - 1));
+ if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) {
+ luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
}
else
- luaV_finishset(L, t, s2v(L->top - 2), s2v(L->top - 1), slot);
- L->top -= 2; /* pop index and value */
+ luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot);
+ L->top.p -= 2; /* pop index and value */
lua_unlock(L);
}
@@ -19908,14 +20147,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
api_checknelems(L, 1);
t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) {
- luaV_finishfastset(L, t, slot, s2v(L->top - 1));
+ luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
}
else {
TValue aux;
setivalue(&aux, n);
- luaV_finishset(L, t, &aux, s2v(L->top - 1), slot);
+ luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot);
}
- L->top--; /* pop value */
+ L->top.p--; /* pop value */
lua_unlock(L);
}
@@ -19925,16 +20164,16 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
lua_lock(L);
api_checknelems(L, n);
t = gettable(L, idx);
- luaH_set(L, t, key, s2v(L->top - 1));
+ luaH_set(L, t, key, s2v(L->top.p - 1));
invalidateTMcache(t);
- luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
- L->top -= n;
+ luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
+ L->top.p -= n;
lua_unlock(L);
}
LUA_API void lua_rawset (lua_State *L, int idx) {
- aux_rawset(L, idx, s2v(L->top - 2), 2);
+ aux_rawset(L, idx, s2v(L->top.p - 2), 2);
}
@@ -19950,9 +20189,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
- luaH_setint(L, t, n, s2v(L->top - 1));
- luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
- L->top--;
+ luaH_setint(L, t, n, s2v(L->top.p - 1));
+ luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
+ L->top.p--;
lua_unlock(L);
}
@@ -19963,11 +20202,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
lua_lock(L);
api_checknelems(L, 1);
obj = index2value(L, objindex);
- if (ttisnil(s2v(L->top - 1)))
+ if (ttisnil(s2v(L->top.p - 1)))
mt = NULL;
else {
- api_check(L, ttistable(s2v(L->top - 1)), "table expected");
- mt = hvalue(s2v(L->top - 1));
+ api_check(L, ttistable(s2v(L->top.p - 1)), "table expected");
+ mt = hvalue(s2v(L->top.p - 1));
}
switch (ttype(obj)) {
case LUA_TTABLE: {
@@ -19991,7 +20230,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
break;
}
}
- L->top--;
+ L->top.p--;
lua_unlock(L);
return 1;
}
@@ -20007,11 +20246,11 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */
else {
- setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1));
- luaC_barrierback(L, gcvalue(o), s2v(L->top - 1));
+ setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1));
+ luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1));
res = 1;
}
- L->top--;
+ L->top.p--;
lua_unlock(L);
return res;
}
@@ -20023,7 +20262,8 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
#define checkresults(L,na,nr) \
- api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
+ api_check(L, (nr) == LUA_MULTRET \
+ || (L->ci->top.p - L->top.p >= (nr) - (na)), \
"results from function overflow current stack size")
@@ -20036,7 +20276,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
api_checknelems(L, nargs+1);
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults);
- func = L->top - (nargs+1);
+ func = L->top.p - (nargs+1);
if (k != NULL && yieldable(L)) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */
@@ -20084,7 +20324,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
api_check(L, ttisfunction(s2v(o)), "error handler must be a function");
func = savestack(L, o);
}
- c.func = L->top - (nargs+1); /* function to be called */
+ c.func = L->top.p - (nargs+1); /* function to be called */
if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */
c.nresults = nresults; /* do a 'conventional' protected call */
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
@@ -20119,12 +20359,12 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname, mode);
if (status == LUA_OK) { /* no errors? */
- LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */
+ LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */
if (f->nupvalues >= 1) { /* does it have an upvalue? */
/* get global table from registry */
const TValue *gt = getGtable(L);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
- setobj(L, f->upvals[0]->v, gt);
+ setobj(L, f->upvals[0]->v.p, gt);
luaC_barrier(L, f->upvals[0], gt);
}
}
@@ -20138,7 +20378,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
TValue *o;
lua_lock(L);
api_checknelems(L, 1);
- o = s2v(L->top - 1);
+ o = s2v(L->top.p - 1);
if (isLfunction(o))
status = luaU_dump(L, getproto(o), writer, data, strip);
else
@@ -20264,7 +20504,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
LUA_API int lua_error (lua_State *L) {
TValue *errobj;
lua_lock(L);
- errobj = s2v(L->top - 1);
+ errobj = s2v(L->top.p - 1);
api_checknelems(L, 1);
/* error object is the memory error message? */
if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
@@ -20282,12 +20522,12 @@ LUA_API int lua_next (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
- more = luaH_next(L, t, L->top - 1);
+ more = luaH_next(L, t, L->top.p - 1);
if (more) {
api_incr_top(L);
}
else /* no more elements */
- L->top -= 1; /* remove key */
+ L->top.p -= 1; /* remove key */
lua_unlock(L);
return more;
}
@@ -20299,7 +20539,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
lua_lock(L);
o = index2stack(L, idx);
nresults = L->ci->nresults;
- api_check(L, L->tbclist < o, "given index below or equal a marked one");
+ api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
if (!hastocloseCfunc(nresults)) /* function not marked yet? */
L->ci->nresults = codeNresults(nresults); /* mark it */
@@ -20314,7 +20554,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
if (n > 0)
luaV_concat(L, n);
else { /* nothing to concatenate */
- setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */
+ setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */
api_incr_top(L);
}
luaC_checkGC(L);
@@ -20326,7 +20566,7 @@ LUA_API void lua_len (lua_State *L, int idx) {
TValue *t;
lua_lock(L);
t = index2value(L, idx);
- luaV_objlen(L, L->top, t);
+ luaV_objlen(L, L->top.p, t);
api_incr_top(L);
lua_unlock(L);
}
@@ -20371,7 +20611,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
lua_lock(L);
api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value");
u = luaS_newudata(L, size, nuvalue);
- setuvalue(L, s2v(L->top), u);
+ setuvalue(L, s2v(L->top.p), u);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
@@ -20397,7 +20637,7 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
Proto *p = f->p;
if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues)))
return NULL; /* 'n' not in [1, p->sizeupvalues] */
- *val = f->upvals[n-1]->v;
+ *val = f->upvals[n-1]->v.p;
if (owner) *owner = obj2gco(f->upvals[n - 1]);
name = p->upvalues[n-1].name;
return (name == NULL) ? "(no name)" : getstr(name);
@@ -20413,7 +20653,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
lua_lock(L);
name = aux_upvalue(index2value(L, funcindex), n, &val, NULL);
if (name) {
- setobj2s(L, L->top, val);
+ setobj2s(L, L->top.p, val);
api_incr_top(L);
}
lua_unlock(L);
@@ -20431,8 +20671,8 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
api_checknelems(L, 1);
name = aux_upvalue(fi, n, &val, &owner);
if (name) {
- L->top--;
- setobj(L, val, s2v(L->top));
+ L->top.p--;
+ setobj(L, val, s2v(L->top.p));
luaC_barrier(L, owner, val);
}
lua_unlock(L);
@@ -21015,13 +21255,14 @@ static void newbox (lua_State *L) {
/*
** Compute new size for buffer 'B', enough to accommodate extra 'sz'
-** bytes.
+** bytes. (The test for "not big enough" also gets the case when the
+** computation of 'newsize' overflows.)
*/
static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
- size_t newsize = B->size * 2; /* double buffer size */
+ size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */
if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
return luaL_error(B->L, "buffer too large");
- if (newsize < B->n + sz) /* double is not big enough? */
+ if (newsize < B->n + sz) /* not big enough? */
newsize = B->n + sz;
return newsize;
}
@@ -21100,7 +21341,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
** box (if existent) is not on the top of the stack. So, instead of
** calling 'luaL_addlstring', it replicates the code using -2 as the
** last argument to 'prepbuffsize', signaling that the box is (or will
-** be) bellow the string being added to the buffer. (Box creation can
+** be) below the string being added to the buffer. (Box creation can
** trigger an emergency GC, so we should not remove the string from the
** stack before we have the space guaranteed.)
*/
@@ -21228,17 +21469,18 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
}
-static int skipBOM (LoadF *lf) {
- const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
- int c;
- lf->n = 0;
- do {
- c = getc(lf->f);
- if (c == EOF || c != *(const unsigned char *)p++) return c;
- lf->buff[lf->n++] = c; /* to be read by the parser */
- } while (*p != '\0');
- lf->n = 0; /* prefix matched; discard it */
- return getc(lf->f); /* return next character */
+/*
+** Skip an optional BOM at the start of a stream. If there is an
+** incomplete BOM (the first character is correct but the rest is
+** not), returns the first character anyway to force an error
+** (as no chunk can start with 0xEF).
+*/
+static int skipBOM (FILE *f) {
+ int c = getc(f); /* read first character */
+ if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */
+ return getc(f); /* ignore BOM and return next char */
+ else /* no (valid) BOM */
+ return c; /* return first character */
}
@@ -21249,13 +21491,13 @@ static int skipBOM (LoadF *lf) {
** first "valid" character of the file (after the optional BOM and
** a first-line comment).
*/
-static int skipcomment (LoadF *lf, int *cp) {
- int c = *cp = skipBOM(lf);
+static int skipcomment (FILE *f, int *cp) {
+ int c = *cp = skipBOM(f);
if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */
- c = getc(lf->f);
+ c = getc(f);
} while (c != EOF && c != '\n');
- *cp = getc(lf->f); /* skip end-of-line, if present */
+ *cp = getc(f); /* next character after comment, if present */
return 1; /* there was a comment */
}
else return 0; /* no comment */
@@ -21277,12 +21519,16 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex);
}
- if (skipcomment(&lf, &c)) /* read initial portion */
- lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
- if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
- lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
- if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
- skipcomment(&lf, &c); /* re-read initial portion */
+ lf.n = 0;
+ if (skipcomment(lf.f, &c)) /* read initial portion */
+ lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */
+ if (c == LUA_SIGNATURE[0]) { /* binary file? */
+ lf.n = 0; /* remove possible newline */
+ if (filename) { /* "real" file? */
+ lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
+ if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
+ skipcomment(lf.f, &c); /* re-read initial portion */
+ }
}
if (c != EOF)
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
@@ -22220,7 +22466,7 @@ static int luaB_auxwrap (lua_State *L) {
if (l_unlikely(r < 0)) { /* error? */
int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
- stat = lua_resetthread(co); /* close its tbc variables */
+ stat = lua_closethread(co, L); /* close its tbc variables */
lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* move error message to the caller */
}
@@ -22316,7 +22562,7 @@ static int luaB_close (lua_State *L) {
int status = auxstatus(L, co);
switch (status) {
case COS_DEAD: case COS_YIELD: {
- status = lua_resetthread(co);
+ status = lua_closethread(co, L);
if (status == LUA_OK) {
lua_pushboolean(L, 1);
return 1;
@@ -23932,7 +24178,7 @@ static int math_type (lua_State *L) {
/* try to find an integer type with at least 64 bits */
-#if (ULONG_MAX >> 31 >> 31) >= 3
+#if ((ULONG_MAX >> 31) >> 31) >= 3
/* 'long' has at least 64 bits */
#define Rand64 unsigned long
@@ -23942,9 +24188,9 @@ static int math_type (lua_State *L) {
/* there is a 'long long' type (which must have at least 64 bits) */
#define Rand64 unsigned long long
-#elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3
+#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
-/* 'lua_Integer' has at least 64 bits */
+/* 'lua_Unsigned' has at least 64 bits */
#define Rand64 lua_Unsigned
#endif
@@ -24165,12 +24411,12 @@ static lua_Number I2d (Rand64 x) {
/* convert a 'Rand64' to a 'lua_Unsigned' */
static lua_Unsigned I2UInt (Rand64 x) {
- return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l);
+ return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
}
/* convert a 'lua_Unsigned' to a 'Rand64' */
static Rand64 Int2I (lua_Unsigned n) {
- return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n);
+ return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n);
}
#endif /* } */
@@ -25137,8 +25383,13 @@ static const luaL_Reg ll_funcs[] = {
static void createsearcherstable (lua_State *L) {
- static const lua_CFunction searchers[] =
- {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
+ static const lua_CFunction searchers[] = {
+ searcher_preload,
+ searcher_Lua,
+ searcher_C,
+ searcher_Croot,
+ NULL
+ };
int i;
/* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
@@ -25221,23 +25472,14 @@ LUAMOD_API int luaopen_package (lua_State *L) {
*/
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
-/* options for ANSI C 89 (only 1-char options) */
-#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
-
-/* options for ISO C 99 and POSIX */
-#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
- "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
-
-/* options for Windows */
-#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
- "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
-
#if defined(LUA_USE_WINDOWS)
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
-#elif defined(LUA_USE_C89)
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
+#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
+ "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
+#elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */
+#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
#else /* C99 specification */
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
+#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
+ "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
#endif
#endif /* } */
@@ -25329,12 +25571,21 @@ LUAMOD_API int luaopen_package (lua_State *L) {
/* }================================================================== */
+#if !defined(l_system)
+#if defined(LUA_USE_IOS)
+/* Despite claiming to be ISO C, iOS does not implement 'system'. */
+#define l_system(cmd) ((cmd) == NULL ? 0 : -1)
+#else
+#define l_system(cmd) system(cmd) /* default definition */
+#endif
+#endif
+
static int os_execute (lua_State *L) {
const char *cmd = luaL_optstring(L, 1, NULL);
int stat;
errno = 0;
- stat = system(cmd);
+ stat = l_system(cmd);
if (cmd != NULL)
return luaL_execresult(L, stat);
else {
@@ -25451,9 +25702,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
res = d;
}
else {
- /* unsigned avoids overflow when lua_Integer has 32 bits */
- if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta
- : (lua_Integer)INT_MIN + delta <= res))
+ if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta;
}
@@ -26191,7 +26440,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
static const char *match (MatchState *ms, const char *s, const char *p) {
if (l_unlikely(ms->matchdepth-- == 0))
luaL_error(ms->L, "pattern too complex");
- init: /* using goto's to optimize tail recursion */
+ init: /* using goto to optimize tail recursion */
if (p != ms->p_end) { /* end of pattern? */
switch (*p) {
case '(': { /* start capture */
@@ -27588,7 +27837,7 @@ static int tremove (lua_State *L) {
lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */
/* check whether 'pos' is in [1, size + 1] */
- luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1,
+ luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
"position out of bounds");
lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) {
@@ -27950,6 +28199,9 @@ LUAMOD_API int luaopen_table (lua_State *L) {
#define MAXUTF 0x7FFFFFFFu
+
+#define MSGInvalid "invalid UTF-8 code"
+
/*
** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
*/
@@ -27960,7 +28212,8 @@ typedef unsigned long utfint;
#endif
-#define iscont(p) ((*(p) & 0xC0) == 0x80)
+#define iscont(c) (((c) & 0xC0) == 0x80)
+#define iscontp(p) iscont(*(p))
/* from strlib */
@@ -27990,7 +28243,7 @@ static const char *utf8_decode (const char *s, utfint *val, int strict) {
int count = 0; /* to count number of continuation bytes */
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
unsigned int cc = (unsigned char)s[++count]; /* read next byte */
- if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
+ if (!iscont(cc)) /* not a continuation byte? */
return NULL; /* invalid byte sequence */
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
}
@@ -28065,7 +28318,7 @@ static int codepoint (lua_State *L) {
utfint code;
s = utf8_decode(s, &code, !lax);
if (s == NULL)
- return luaL_error(L, "invalid UTF-8 code");
+ return luaL_error(L, MSGInvalid);
lua_pushinteger(L, code);
n++;
}
@@ -28115,16 +28368,16 @@ static int byteoffset (lua_State *L) {
"position out of bounds");
if (n == 0) {
/* find beginning of current byte sequence */
- while (posi > 0 && iscont(s + posi)) posi--;
+ while (posi > 0 && iscontp(s + posi)) posi--;
}
else {
- if (iscont(s + posi))
+ if (iscontp(s + posi))
return luaL_error(L, "initial position is a continuation byte");
if (n < 0) {
while (n < 0 && posi > 0) { /* move back */
do { /* find beginning of previous character */
posi--;
- } while (posi > 0 && iscont(s + posi));
+ } while (posi > 0 && iscontp(s + posi));
n++;
}
}
@@ -28133,7 +28386,7 @@ static int byteoffset (lua_State *L) {
while (n > 0 && posi < (lua_Integer)len) {
do { /* find beginning of next character */
posi++;
- } while (iscont(s + posi)); /* (cannot pass final '\0') */
+ } while (iscontp(s + posi)); /* (cannot pass final '\0') */
n--;
}
}
@@ -28151,15 +28404,15 @@ static int iter_aux (lua_State *L, int strict) {
const char *s = luaL_checklstring(L, 1, &len);
lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
if (n < len) {
- while (iscont(s + n)) n++; /* skip continuation bytes */
+ while (iscontp(s + n)) n++; /* go to next character */
}
if (n >= len) /* (also handles original 'n' being negative) */
return 0; /* no more codepoints */
else {
utfint code;
const char *next = utf8_decode(s + n, &code, strict);
- if (next == NULL)
- return luaL_error(L, "invalid UTF-8 code");
+ if (next == NULL || iscontp(next))
+ return luaL_error(L, MSGInvalid);
lua_pushinteger(L, n + 1);
lua_pushinteger(L, code);
return 2;
@@ -28178,7 +28431,8 @@ static int iter_auxlax (lua_State *L) {
static int iter_codes (lua_State *L) {
int lax = lua_toboolean(L, 2);
- luaL_checkstring(L, 1);
+ const char *s = luaL_checkstring(L, 1);
+ luaL_argcheck(L, !iscontp(s), 1, MSGInvalid);
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
lua_pushvalue(L, 1);
lua_pushinteger(L, 0);
@@ -28458,10 +28712,11 @@ static void print_version (void) {
** to the script (everything after 'script') go to positive indices;
** other arguments (before the script name) go to negative indices.
** If there is no script name, assume interpreter's name as base.
+** (If there is no interpreter's name either, 'script' is -1, so
+** table sizes are zero.)
*/
static void createargtable (lua_State *L, char **argv, int argc, int script) {
int i, narg;
- if (script == argc) script = 0; /* no script name? */
narg = argc - (script + 1); /* number of positive indices */
lua_createtable(L, narg, script + 1);
for (i = 0; i < argc; i++) {
@@ -28549,14 +28804,23 @@ static int handle_script (lua_State *L, char **argv) {
/*
** Traverses all arguments from 'argv', returning a mask with those
-** needed before running any Lua code (or an error code if it finds
-** any invalid argument). 'first' returns the first not-handled argument
-** (either the script name or a bad argument in case of error).
+** needed before running any Lua code or an error code if it finds any
+** invalid argument. In case of error, 'first' is the index of the bad
+** argument. Otherwise, 'first' is -1 if there is no program name,
+** 0 if there is no script name, or the index of the script name.
*/
static int collectargs (char **argv, int *first) {
int args = 0;
int i;
- for (i = 1; argv[i] != NULL; i++) {
+ if (argv[0] != NULL) { /* is there a program name? */
+ if (argv[0][0]) /* not empty? */
+ progname = argv[0]; /* save it */
+ }
+ else { /* no program name */
+ *first = -1;
+ return 0;
+ }
+ for (i = 1; argv[i] != NULL; i++) { /* handle arguments */
*first = i;
if (argv[i][0] != '-') /* not an option? */
return args; /* stop handling options */
@@ -28597,7 +28861,7 @@ static int collectargs (char **argv, int *first) {
return has_error;
}
}
- *first = i; /* no script name */
+ *first = 0; /* no script name */
return args;
}
@@ -28890,8 +29154,8 @@ static int pmain (lua_State *L) {
char **argv = (char **)lua_touserdata(L, 2);
int script;
int args = collectargs(argv, &script);
+ int optlim = (script > 0) ? script : argc; /* first argv not an option */
luaL_checkversion(L); /* check that interpreter has correct version */
- if (argv[0] && argv[0][0]) progname = argv[0];
if (args == has_error) { /* bad arg? */
print_usage(argv[script]); /* 'script' has index of bad arg. */
return 0;
@@ -28904,19 +29168,21 @@ static int pmain (lua_State *L) {
}
luaL_openlibs(L); /* open standard libraries */
createargtable(L, argv, argc, script); /* create table 'arg' */
- lua_gc(L, LUA_GCGEN, 0, 0); /* GC in generational mode */
+ lua_gc(L, LUA_GCRESTART); /* start GC... */
+ lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */
if (!(args & has_E)) { /* no option '-E'? */
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */
}
- if (!runargs(L, argv, script)) /* execute arguments -e and -l */
+ if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */
return 0; /* something failed */
- if (script < argc && /* execute main script (if there is one) */
- handle_script(L, argv + script) != LUA_OK)
- return 0;
+ if (script > 0) { /* execute main script (if there is one) */
+ if (handle_script(L, argv + script) != LUA_OK)
+ return 0; /* interrupt in case of error */
+ }
if (args & has_i) /* -i option? */
doREPL(L); /* do read-eval-print loop */
- else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */
+ else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */
if (lua_stdin_is_tty()) { /* running in interactive mode? */
print_version();
doREPL(L); /* do read-eval-print loop */
@@ -28935,6 +29201,7 @@ int main (int argc, char **argv) {
l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE;
}
+ lua_gc(L, LUA_GCSTOP); /* stop GC while building state */
lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
lua_pushinteger(L, argc); /* 1st argument */
lua_pushlightuserdata(L, argv); /* 2nd argument */
@@ -28951,7 +29218,7 @@ int main (int argc, char **argv) {
MIT License
Copyright (c) 1994–2019 Lua.org, PUC-Rio.
- Copyright (c) 2020-2022 Eduardo Bart (https://github.com/edubart).
+ Copyright (c) 2020-2023 Eduardo Bart (https://github.com/edubart).
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/engine/split/3rd_rpmalloc.c b/engine/split/3rd_rpmalloc.c
new file mode 100644
index 0000000..3b99b52
--- /dev/null
+++ b/engine/split/3rd_rpmalloc.c
@@ -0,0 +1,3629 @@
+/* rpmalloc.c - Memory allocator - Public Domain - 2016-2020 Mattias Jansson
+ *
+ * This library provides a cross-platform lock free thread caching malloc implementation in C11.
+ * The latest source code is always available at
+ *
+ * https://github.com/mjansson/rpmalloc
+ *
+ * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
+ *
+ */
+
+// #include "rpmalloc.h" //< @r-lyeh
+
+////////////
+///
+/// Build time configurable limits
+///
+//////
+
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wunused-macros"
+#pragma clang diagnostic ignored "-Wunused-function"
+#if __has_warning("-Wreserved-identifier")
+#pragma clang diagnostic ignored "-Wreserved-identifier"
+#endif
+#if __has_warning("-Wstatic-in-inline")
+#pragma clang diagnostic ignored "-Wstatic-in-inline"
+#endif
+#elif defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-macros"
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+#if !defined(__has_builtin)
+#define __has_builtin(b) 0
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+
+#if __has_builtin(__builtin_memcpy_inline)
+#define _rpmalloc_memcpy_const(x, y, s) __builtin_memcpy_inline(x, y, s)
+#else
+#define _rpmalloc_memcpy_const(x, y, s) \
+ do { \
+ _Static_assert(__builtin_choose_expr(__builtin_constant_p(s), 1, 0), "len must be a constant integer"); \
+ memcpy(x, y, s); \
+ } while (0)
+#endif
+
+#if __has_builtin(__builtin_memset_inline)
+#define _rpmalloc_memset_const(x, y, s) __builtin_memset_inline(x, y, s)
+#else
+#define _rpmalloc_memset_const(x, y, s) \
+ do { \
+ _Static_assert(__builtin_choose_expr(__builtin_constant_p(s), 1, 0), "len must be a constant integer"); \
+ memset(x, y, s); \
+ } while (0)
+#endif
+#else
+#define _rpmalloc_memcpy_const(x, y, s) memcpy(x, y, s)
+#define _rpmalloc_memset_const(x, y, s) memset(x, y, s)
+#endif
+
+#if __has_builtin(__builtin_assume)
+#define rpmalloc_assume(cond) __builtin_assume(cond)
+#elif defined(__GNUC__)
+#define rpmalloc_assume(cond) \
+ do { \
+ if (!__builtin_expect(cond, 0)) \
+ __builtin_unreachable(); \
+ } while (0)
+#elif defined(_MSC_VER)
+#define rpmalloc_assume(cond) __assume(cond)
+#else
+#define rpmalloc_assume(cond) 0
+#endif
+
+#ifndef HEAP_ARRAY_SIZE
+//! Size of heap hashmap
+#define HEAP_ARRAY_SIZE 47
+#endif
+#ifndef ENABLE_THREAD_CACHE
+//! Enable per-thread cache
+#define ENABLE_THREAD_CACHE 1
+#endif
+#ifndef ENABLE_GLOBAL_CACHE
+//! Enable global cache shared between all threads, requires thread cache
+#define ENABLE_GLOBAL_CACHE 1
+#endif
+#ifndef ENABLE_VALIDATE_ARGS
+//! Enable validation of args to public entry points
+#define ENABLE_VALIDATE_ARGS 0
+#endif
+#ifndef ENABLE_STATISTICS
+//! Enable statistics collection
+#define ENABLE_STATISTICS 0
+#endif
+#ifndef ENABLE_ASSERTS
+//! Enable asserts
+#define ENABLE_ASSERTS 0
+#endif
+#ifndef ENABLE_OVERRIDE
+//! Override standard library malloc/free and new/delete entry points
+#define ENABLE_OVERRIDE 0
+#endif
+#ifndef ENABLE_PRELOAD
+//! Support preloading
+#define ENABLE_PRELOAD 0
+#endif
+#ifndef DISABLE_UNMAP
+//! Disable unmapping memory pages (also enables unlimited cache)
+#define DISABLE_UNMAP 0
+#endif
+#ifndef ENABLE_UNLIMITED_CACHE
+//! Enable unlimited global cache (no unmapping until finalization)
+#define ENABLE_UNLIMITED_CACHE 0
+#endif
+#ifndef ENABLE_ADAPTIVE_THREAD_CACHE
+//! Enable adaptive thread cache size based on use heuristics
+#define ENABLE_ADAPTIVE_THREAD_CACHE 0
+#endif
+#ifndef DEFAULT_SPAN_MAP_COUNT
+//! Default number of spans to map in call to map more virtual memory (default values yield 4MiB here)
+#define DEFAULT_SPAN_MAP_COUNT 64
+#endif
+#ifndef GLOBAL_CACHE_MULTIPLIER
+//! Multiplier for global cache
+#define GLOBAL_CACHE_MULTIPLIER 8
+#endif
+
+#if DISABLE_UNMAP && !ENABLE_GLOBAL_CACHE
+#error Must use global cache if unmap is disabled
+#endif
+
+#if DISABLE_UNMAP
+#undef ENABLE_UNLIMITED_CACHE
+#define ENABLE_UNLIMITED_CACHE 1
+#endif
+
+#if !ENABLE_GLOBAL_CACHE
+#undef ENABLE_UNLIMITED_CACHE
+#define ENABLE_UNLIMITED_CACHE 0
+#endif
+
+#if !ENABLE_THREAD_CACHE
+#undef ENABLE_ADAPTIVE_THREAD_CACHE
+#define ENABLE_ADAPTIVE_THREAD_CACHE 0
+#endif
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
+# define PLATFORM_WINDOWS 1
+# define PLATFORM_POSIX 0
+#else
+# define PLATFORM_WINDOWS 0
+# define PLATFORM_POSIX 1
+#endif
+
+/// Platform and arch specifics
+#if defined(_MSC_VER) && !defined(__clang__)
+# pragma warning (disable: 5105)
+# ifndef FORCEINLINE
+# define FORCEINLINE inline __forceinline
+# endif
+# define _Static_assert static_assert
+#else
+# ifndef FORCEINLINE
+# define FORCEINLINE inline __attribute__((__always_inline__))
+# endif
+#endif
+#if PLATFORM_WINDOWS
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include
+# if ENABLE_VALIDATE_ARGS
+# include
+# endif
+#else
+# include
+# include
+# include
+# include
+# if defined(__linux__) || defined(__ANDROID__)
+# include
+# if !defined(PR_SET_VMA)
+# define PR_SET_VMA 0x53564d41
+# define PR_SET_VMA_ANON_NAME 0
+# endif
+# endif
+# if defined(__APPLE__)
+# include
+# if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+# include
+# include
+# endif
+# include
+# endif
+# if defined(__HAIKU__) || defined(__TINYC__)
+# include
+# endif
+#endif
+
+#include
+#include
+#include
+
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+#include
+static DWORD fls_key;
+#endif
+
+#if PLATFORM_POSIX
+# include
+# include
+# ifdef __FreeBSD__
+# include
+# define MAP_HUGETLB MAP_ALIGNED_SUPER
+# ifndef PROT_MAX
+# define PROT_MAX(f) 0
+# endif
+# else
+# define PROT_MAX(f) 0
+# endif
+# ifdef __sun
+extern int madvise(caddr_t, size_t, int);
+# endif
+# ifndef MAP_UNINITIALIZED
+# define MAP_UNINITIALIZED 0
+# endif
+#endif
+#include
+
+#if ENABLE_ASSERTS
+# undef NDEBUG
+# if defined(_MSC_VER) && !defined(_DEBUG)
+# define _DEBUG
+# endif
+# include
+#define RPMALLOC_TOSTRING_M(x) #x
+#define RPMALLOC_TOSTRING(x) RPMALLOC_TOSTRING_M(x)
+#define rpmalloc_assert(truth, message) \
+ do { \
+ if (!(truth)) { \
+ if (_memory_config.error_callback) { \
+ _memory_config.error_callback( \
+ message " (" RPMALLOC_TOSTRING(truth) ") at " __FILE__ ":" RPMALLOC_TOSTRING(__LINE__)); \
+ } else { \
+ assert((truth) && message); \
+ } \
+ } \
+ } while (0)
+#else
+# define rpmalloc_assert(truth, message) do {} while(0)
+#endif
+#if ENABLE_STATISTICS
+# include
+#endif
+
+//////
+///
+/// Atomic access abstraction (since MSVC does not do C11 yet)
+///
+//////
+
+#if defined(_MSC_VER) && !defined(__clang__)
+
+typedef volatile long atomic32_t;
+typedef volatile long long atomic64_t;
+typedef volatile void* atomicptr_t;
+
+static FORCEINLINE int32_t atomic_load32(atomic32_t* src) { return *src; }
+static FORCEINLINE void atomic_store32(atomic32_t* dst, int32_t val) { *dst = val; }
+static FORCEINLINE int32_t atomic_incr32(atomic32_t* val) { return (int32_t)InterlockedIncrement(val); }
+static FORCEINLINE int32_t atomic_decr32(atomic32_t* val) { return (int32_t)InterlockedDecrement(val); }
+static FORCEINLINE int32_t atomic_add32(atomic32_t* val, int32_t add) { return (int32_t)InterlockedExchangeAdd(val, add) + add; }
+static FORCEINLINE int atomic_cas32_acquire(atomic32_t* dst, int32_t val, int32_t ref) { return (InterlockedCompareExchange(dst, val, ref) == ref) ? 1 : 0; }
+static FORCEINLINE void atomic_store32_release(atomic32_t* dst, int32_t val) { *dst = val; }
+static FORCEINLINE int64_t atomic_load64(atomic64_t* src) { return *src; }
+static FORCEINLINE int64_t atomic_add64(atomic64_t* val, int64_t add) { return (int64_t)InterlockedExchangeAdd64(val, add) + add; }
+static FORCEINLINE void* atomic_load_ptr(atomicptr_t* src) { return (void*)*src; }
+static FORCEINLINE void atomic_store_ptr(atomicptr_t* dst, void* val) { *dst = val; }
+static FORCEINLINE void atomic_store_ptr_release(atomicptr_t* dst, void* val) { *dst = val; }
+static FORCEINLINE void* atomic_exchange_ptr_acquire(atomicptr_t* dst, void* val) { return (void*)InterlockedExchangePointer((void* volatile*)dst, val); }
+static FORCEINLINE int atomic_cas_ptr(atomicptr_t* dst, void* val, void* ref) { return (InterlockedCompareExchangePointer((void* volatile*)dst, val, ref) == ref) ? 1 : 0; }
+
+#define EXPECTED(x) (x)
+#define UNEXPECTED(x) (x)
+
+#else
+
+#include
+
+typedef volatile _Atomic(int32_t) atomic32_t;
+typedef volatile _Atomic(int64_t) atomic64_t;
+typedef volatile _Atomic(void*) atomicptr_t;
+
+static FORCEINLINE int32_t atomic_load32(atomic32_t* src) { return atomic_load_explicit(src, memory_order_relaxed); }
+static FORCEINLINE void atomic_store32(atomic32_t* dst, int32_t val) { atomic_store_explicit(dst, val, memory_order_relaxed); }
+static FORCEINLINE int32_t atomic_incr32(atomic32_t* val) { return atomic_fetch_add_explicit(val, 1, memory_order_relaxed) + 1; }
+static FORCEINLINE int32_t atomic_decr32(atomic32_t* val) { return atomic_fetch_add_explicit(val, -1, memory_order_relaxed) - 1; }
+static FORCEINLINE int32_t atomic_add32(atomic32_t* val, int32_t add) { return atomic_fetch_add_explicit(val, add, memory_order_relaxed) + add; }
+static FORCEINLINE int atomic_cas32_acquire(atomic32_t* dst, int32_t val, int32_t ref) { return atomic_compare_exchange_weak_explicit(dst, &ref, val, memory_order_acquire, memory_order_relaxed); }
+static FORCEINLINE void atomic_store32_release(atomic32_t* dst, int32_t val) { atomic_store_explicit(dst, val, memory_order_release); }
+static FORCEINLINE int64_t atomic_load64(atomic64_t* val) { return atomic_load_explicit(val, memory_order_relaxed); }
+static FORCEINLINE int64_t atomic_add64(atomic64_t* val, int64_t add) { return atomic_fetch_add_explicit(val, add, memory_order_relaxed) + add; }
+static FORCEINLINE void* atomic_load_ptr(atomicptr_t* src) { return atomic_load_explicit(src, memory_order_relaxed); }
+static FORCEINLINE void atomic_store_ptr(atomicptr_t* dst, void* val) { atomic_store_explicit(dst, val, memory_order_relaxed); }
+static FORCEINLINE void atomic_store_ptr_release(atomicptr_t* dst, void* val) { atomic_store_explicit(dst, val, memory_order_release); }
+static FORCEINLINE void* atomic_exchange_ptr_acquire(atomicptr_t* dst, void* val) { return atomic_exchange_explicit(dst, val, memory_order_acquire); }
+static FORCEINLINE int atomic_cas_ptr(atomicptr_t* dst, void* val, void* ref) { return atomic_compare_exchange_weak_explicit(dst, &ref, val, memory_order_relaxed, memory_order_relaxed); }
+
+#define EXPECTED(x) __builtin_expect((x), 1)
+#define UNEXPECTED(x) __builtin_expect((x), 0)
+
+#endif
+
+////////////
+///
+/// Statistics related functions (evaluate to nothing when statistics not enabled)
+///
+//////
+
+#if ENABLE_STATISTICS
+# define _rpmalloc_stat_inc(counter) atomic_incr32(counter)
+# define _rpmalloc_stat_dec(counter) atomic_decr32(counter)
+# define _rpmalloc_stat_add(counter, value) atomic_add32(counter, (int32_t)(value))
+# define _rpmalloc_stat_add64(counter, value) atomic_add64(counter, (int64_t)(value))
+# define _rpmalloc_stat_add_peak(counter, value, peak) do { int32_t _cur_count = atomic_add32(counter, (int32_t)(value)); if (_cur_count > (peak)) peak = _cur_count; } while (0)
+# define _rpmalloc_stat_sub(counter, value) atomic_add32(counter, -(int32_t)(value))
+# define _rpmalloc_stat_inc_alloc(heap, class_idx) do { \
+ int32_t alloc_current = atomic_incr32(&heap->size_class_use[class_idx].alloc_current); \
+ if (alloc_current > heap->size_class_use[class_idx].alloc_peak) \
+ heap->size_class_use[class_idx].alloc_peak = alloc_current; \
+ atomic_incr32(&heap->size_class_use[class_idx].alloc_total); \
+} while(0)
+# define _rpmalloc_stat_inc_free(heap, class_idx) do { \
+ atomic_decr32(&heap->size_class_use[class_idx].alloc_current); \
+ atomic_incr32(&heap->size_class_use[class_idx].free_total); \
+} while(0)
+#else
+# define _rpmalloc_stat_inc(counter) do {} while(0)
+# define _rpmalloc_stat_dec(counter) do {} while(0)
+# define _rpmalloc_stat_add(counter, value) do {} while(0)
+# define _rpmalloc_stat_add64(counter, value) do {} while(0)
+# define _rpmalloc_stat_add_peak(counter, value, peak) do {} while (0)
+# define _rpmalloc_stat_sub(counter, value) do {} while(0)
+# define _rpmalloc_stat_inc_alloc(heap, class_idx) do {} while(0)
+# define _rpmalloc_stat_inc_free(heap, class_idx) do {} while(0)
+#endif
+
+
+///
+/// Preconfigured limits and sizes
+///
+
+//! Granularity of a small allocation block (must be power of two)
+#define SMALL_GRANULARITY 16
+//! Small granularity shift count
+#define SMALL_GRANULARITY_SHIFT 4
+//! Number of small block size classes
+#define SMALL_CLASS_COUNT 65
+//! Maximum size of a small block
+#define SMALL_SIZE_LIMIT (SMALL_GRANULARITY * (SMALL_CLASS_COUNT - 1))
+//! Granularity of a medium allocation block
+#define MEDIUM_GRANULARITY 512
+//! Medium granularity shift count
+#define MEDIUM_GRANULARITY_SHIFT 9
+//! Number of medium block size classes
+#define MEDIUM_CLASS_COUNT 61
+//! Total number of small + medium size classes
+#define SIZE_CLASS_COUNT (SMALL_CLASS_COUNT + MEDIUM_CLASS_COUNT)
+//! Number of large block size classes
+#define LARGE_CLASS_COUNT 63
+//! Maximum size of a medium block
+#define MEDIUM_SIZE_LIMIT (SMALL_SIZE_LIMIT + (MEDIUM_GRANULARITY * MEDIUM_CLASS_COUNT))
+//! Maximum size of a large block
+#define LARGE_SIZE_LIMIT ((LARGE_CLASS_COUNT * _memory_span_size) - SPAN_HEADER_SIZE)
+//! Size of a span header (must be a multiple of SMALL_GRANULARITY and a power of two)
+#define SPAN_HEADER_SIZE 128
+//! Number of spans in thread cache
+#define MAX_THREAD_SPAN_CACHE 400
+//! Number of spans to transfer between thread and global cache
+#define THREAD_SPAN_CACHE_TRANSFER 64
+//! Number of spans in thread cache for large spans (must be greater than LARGE_CLASS_COUNT / 2)
+#define MAX_THREAD_SPAN_LARGE_CACHE 100
+//! Number of spans to transfer between thread and global cache for large spans
+#define THREAD_SPAN_LARGE_CACHE_TRANSFER 6
+
+_Static_assert((SMALL_GRANULARITY & (SMALL_GRANULARITY - 1)) == 0, "Small granularity must be power of two");
+_Static_assert((SPAN_HEADER_SIZE & (SPAN_HEADER_SIZE - 1)) == 0, "Span header size must be power of two");
+
+#if ENABLE_VALIDATE_ARGS
+//! Maximum allocation size to avoid integer overflow
+#undef MAX_ALLOC_SIZE
+#define MAX_ALLOC_SIZE (((size_t)-1) - _memory_span_size)
+#endif
+
+#define pointer_offset(ptr, ofs) (void*)((char*)(ptr) + (ptrdiff_t)(ofs))
+#define pointer_diff(first, second) (ptrdiff_t)((const char*)(first) - (const char*)(second))
+
+#define INVALID_POINTER ((void*)((uintptr_t)-1))
+
+#define SIZE_CLASS_LARGE SIZE_CLASS_COUNT
+#define SIZE_CLASS_HUGE ((uint32_t)-1)
+
+////////////
+///
+/// Data types
+///
+//////
+
+//! A memory heap, per thread
+typedef struct heap_t heap_t;
+//! Span of memory pages
+typedef struct span_t span_t;
+//! Span list
+typedef struct span_list_t span_list_t;
+//! Span active data
+typedef struct span_active_t span_active_t;
+//! Size class definition
+typedef struct size_class_t size_class_t;
+//! Global cache
+typedef struct global_cache_t global_cache_t;
+
+//! Flag indicating span is the first (master) span of a split superspan
+#define SPAN_FLAG_MASTER 1U
+//! Flag indicating span is a secondary (sub) span of a split superspan
+#define SPAN_FLAG_SUBSPAN 2U
+//! Flag indicating span has blocks with increased alignment
+#define SPAN_FLAG_ALIGNED_BLOCKS 4U
+//! Flag indicating an unmapped master span
+#define SPAN_FLAG_UNMAPPED_MASTER 8U
+
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+struct span_use_t {
+ //! Current number of spans used (actually used, not in cache)
+ atomic32_t current;
+ //! High water mark of spans used
+ atomic32_t high;
+#if ENABLE_STATISTICS
+ //! Number of spans in deferred list
+ atomic32_t spans_deferred;
+ //! Number of spans transitioned to global cache
+ atomic32_t spans_to_global;
+ //! Number of spans transitioned from global cache
+ atomic32_t spans_from_global;
+ //! Number of spans transitioned to thread cache
+ atomic32_t spans_to_cache;
+ //! Number of spans transitioned from thread cache
+ atomic32_t spans_from_cache;
+ //! Number of spans transitioned to reserved state
+ atomic32_t spans_to_reserved;
+ //! Number of spans transitioned from reserved state
+ atomic32_t spans_from_reserved;
+ //! Number of raw memory map calls
+ atomic32_t spans_map_calls;
+#endif
+};
+typedef struct span_use_t span_use_t;
+#endif
+
+#if ENABLE_STATISTICS
+struct size_class_use_t {
+ //! Current number of allocations
+ atomic32_t alloc_current;
+ //! Peak number of allocations
+ int32_t alloc_peak;
+ //! Total number of allocations
+ atomic32_t alloc_total;
+ //! Total number of frees
+ atomic32_t free_total;
+ //! Number of spans in use
+ atomic32_t spans_current;
+ //! Number of spans transitioned to cache
+ int32_t spans_peak;
+ //! Number of spans transitioned to cache
+ atomic32_t spans_to_cache;
+ //! Number of spans transitioned from cache
+ atomic32_t spans_from_cache;
+ //! Number of spans transitioned from reserved state
+ atomic32_t spans_from_reserved;
+ //! Number of spans mapped
+ atomic32_t spans_map_calls;
+ int32_t unused;
+};
+typedef struct size_class_use_t size_class_use_t;
+#endif
+
+// A span can either represent a single span of memory pages with size declared by span_map_count configuration variable,
+// or a set of spans in a continuous region, a super span. Any reference to the term "span" usually refers to both a single
+// span or a super span. A super span can further be divided into multiple spans (or this, super spans), where the first
+// (super)span is the master and subsequent (super)spans are subspans. The master span keeps track of how many subspans
+// that are still alive and mapped in virtual memory, and once all subspans and master have been unmapped the entire
+// superspan region is released and unmapped (on Windows for example, the entire superspan range has to be released
+// in the same call to release the virtual memory range, but individual subranges can be decommitted individually
+// to reduce physical memory use).
+struct span_t {
+ //! Free list
+ void* free_list;
+ //! Total block count of size class
+ uint32_t block_count;
+ //! Size class
+ uint32_t size_class;
+ //! Index of last block initialized in free list
+ uint32_t free_list_limit;
+ //! Number of used blocks remaining when in partial state
+ uint32_t used_count;
+ //! Deferred free list
+ atomicptr_t free_list_deferred;
+ //! Size of deferred free list, or list of spans when part of a cache list
+ uint32_t list_size;
+ //! Size of a block
+ uint32_t block_size;
+ //! Flags and counters
+ uint32_t flags;
+ //! Number of spans
+ uint32_t span_count;
+ //! Total span counter for master spans
+ uint32_t total_spans;
+ //! Offset from master span for subspans
+ uint32_t offset_from_master;
+ //! Remaining span counter, for master spans
+ atomic32_t remaining_spans;
+ //! Alignment offset
+ uint32_t align_offset;
+ //! Owning heap
+ heap_t* heap;
+ //! Next span
+ span_t* next;
+ //! Previous span
+ span_t* prev;
+};
+_Static_assert(sizeof(span_t) <= SPAN_HEADER_SIZE, "span size mismatch");
+
+struct span_cache_t {
+ size_t count;
+ span_t* span[MAX_THREAD_SPAN_CACHE];
+};
+typedef struct span_cache_t span_cache_t;
+
+struct span_large_cache_t {
+ size_t count;
+ span_t* span[MAX_THREAD_SPAN_LARGE_CACHE];
+};
+typedef struct span_large_cache_t span_large_cache_t;
+
+struct heap_size_class_t {
+ //! Free list of active span
+ void* free_list;
+ //! Double linked list of partially used spans with free blocks.
+ // Previous span pointer in head points to tail span of list.
+ span_t* partial_span;
+ //! Early level cache of fully free spans
+ span_t* cache;
+};
+typedef struct heap_size_class_t heap_size_class_t;
+
+// Control structure for a heap, either a thread heap or a first class heap if enabled
+struct heap_t {
+ //! Owning thread ID
+ uintptr_t owner_thread;
+ //! Free lists for each size class
+ heap_size_class_t size_class[SIZE_CLASS_COUNT];
+#if ENABLE_THREAD_CACHE
+ //! Arrays of fully freed spans, single span
+ span_cache_t span_cache;
+#endif
+ //! List of deferred free spans (single linked list)
+ atomicptr_t span_free_deferred;
+ //! Number of full spans
+ size_t full_span_count;
+ //! Mapped but unused spans
+ span_t* span_reserve;
+ //! Master span for mapped but unused spans
+ span_t* span_reserve_master;
+ //! Number of mapped but unused spans
+ uint32_t spans_reserved;
+ //! Child count
+ atomic32_t child_count;
+ //! Next heap in id list
+ heap_t* next_heap;
+ //! Next heap in orphan list
+ heap_t* next_orphan;
+ //! Heap ID
+ int32_t id;
+ //! Finalization state flag
+ int finalize;
+ //! Master heap owning the memory pages
+ heap_t* master_heap;
+#if ENABLE_THREAD_CACHE
+ //! Arrays of fully freed spans, large spans with > 1 span count
+ span_large_cache_t span_large_cache[LARGE_CLASS_COUNT - 1];
+#endif
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ //! Double linked list of fully utilized spans with free blocks for each size class.
+ // Previous span pointer in head points to tail span of list.
+ span_t* full_span[SIZE_CLASS_COUNT];
+ //! Double linked list of large and huge spans allocated by this heap
+ span_t* large_huge_span;
+#endif
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+ //! Current and high water mark of spans used per span count
+ span_use_t span_use[LARGE_CLASS_COUNT];
+#endif
+#if ENABLE_STATISTICS
+ //! Allocation stats per size class
+ size_class_use_t size_class_use[SIZE_CLASS_COUNT + 1];
+ //! Number of bytes transitioned thread -> global
+ atomic64_t thread_to_global;
+ //! Number of bytes transitioned global -> thread
+ atomic64_t global_to_thread;
+#endif
+};
+
+// Size class for defining a block size bucket
+struct size_class_t {
+ //! Size of blocks in this class
+ uint32_t block_size;
+ //! Number of blocks in each chunk
+ uint16_t block_count;
+ //! Class index this class is merged with
+ uint16_t class_idx;
+};
+_Static_assert(sizeof(size_class_t) == 8, "Size class size mismatch");
+
+struct global_cache_t {
+ //! Cache lock
+ atomic32_t lock;
+ //! Cache count
+ uint32_t count;
+#if ENABLE_STATISTICS
+ //! Insert count
+ size_t insert_count;
+ //! Extract count
+ size_t extract_count;
+#endif
+ //! Cached spans
+ span_t* span[GLOBAL_CACHE_MULTIPLIER * MAX_THREAD_SPAN_CACHE];
+ //! Unlimited cache overflow
+ span_t* overflow;
+};
+
+////////////
+///
+/// Global data
+///
+//////
+
+//! Default span size (64KiB)
+#define _memory_default_span_size (64 * 1024)
+#define _memory_default_span_size_shift 16
+#define _memory_default_span_mask (~((uintptr_t)(_memory_span_size - 1)))
+
+//! Initialized flag
+static int _rpmalloc_initialized;
+//! Main thread ID
+static uintptr_t _rpmalloc_main_thread_id;
+//! Configuration
+static rpmalloc_config_t _memory_config;
+//! Memory page size
+static size_t _memory_page_size;
+//! Shift to divide by page size
+static size_t _memory_page_size_shift;
+//! Granularity at which memory pages are mapped by OS
+static size_t _memory_map_granularity;
+#if RPMALLOC_CONFIGURABLE
+//! Size of a span of memory pages
+static size_t _memory_span_size;
+//! Shift to divide by span size
+static size_t _memory_span_size_shift;
+//! Mask to get to start of a memory span
+static uintptr_t _memory_span_mask;
+#else
+//! Hardwired span size
+#define _memory_span_size _memory_default_span_size
+#define _memory_span_size_shift _memory_default_span_size_shift
+#define _memory_span_mask _memory_default_span_mask
+#endif
+//! Number of spans to map in each map call
+static size_t _memory_span_map_count;
+//! Number of spans to keep reserved in each heap
+static size_t _memory_heap_reserve_count;
+//! Global size classes
+static size_class_t _memory_size_class[SIZE_CLASS_COUNT];
+//! Run-time size limit of medium blocks
+static size_t _memory_medium_size_limit;
+//! Heap ID counter
+static atomic32_t _memory_heap_id;
+//! Huge page support
+static int _memory_huge_pages;
+#if ENABLE_GLOBAL_CACHE
+//! Global span cache
+static global_cache_t _memory_span_cache[LARGE_CLASS_COUNT];
+#endif
+//! Global reserved spans
+static span_t* _memory_global_reserve;
+//! Global reserved count
+static size_t _memory_global_reserve_count;
+//! Global reserved master
+static span_t* _memory_global_reserve_master;
+//! All heaps
+static heap_t* _memory_heaps[HEAP_ARRAY_SIZE];
+//! Used to restrict access to mapping memory for huge pages
+static atomic32_t _memory_global_lock;
+//! Orphaned heaps
+static heap_t* _memory_orphan_heaps;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+//! Orphaned heaps (first class heaps)
+static heap_t* _memory_first_class_orphan_heaps;
+#endif
+#if ENABLE_STATISTICS
+//! Allocations counter
+static atomic64_t _allocation_counter;
+//! Deallocations counter
+static atomic64_t _deallocation_counter;
+//! Active heap count
+static atomic32_t _memory_active_heaps;
+//! Number of currently mapped memory pages
+static atomic32_t _mapped_pages;
+//! Peak number of concurrently mapped memory pages
+static int32_t _mapped_pages_peak;
+//! Number of mapped master spans
+static atomic32_t _master_spans;
+//! Number of unmapped dangling master spans
+static atomic32_t _unmapped_master_spans;
+//! Running counter of total number of mapped memory pages since start
+static atomic32_t _mapped_total;
+//! Running counter of total number of unmapped memory pages since start
+static atomic32_t _unmapped_total;
+//! Number of currently mapped memory pages in OS calls
+static atomic32_t _mapped_pages_os;
+//! Number of currently allocated pages in huge allocations
+static atomic32_t _huge_pages_current;
+//! Peak number of currently allocated pages in huge allocations
+static int32_t _huge_pages_peak;
+#endif
+
+////////////
+///
+/// Thread local heap and ID
+///
+//////
+
+//! Current thread heap
+#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)
+static pthread_key_t _memory_thread_heap;
+#else
+# ifdef _MSC_VER
+# define _Thread_local __declspec(thread)
+# define TLS_MODEL
+# else
+# ifndef __HAIKU__
+# define TLS_MODEL __attribute__((tls_model("initial-exec")))
+# else
+# define TLS_MODEL
+# endif
+# if !defined(__clang__) && defined(__GNUC__)
+# define _Thread_local __thread
+# endif
+# endif
+static _Thread_local heap_t* _memory_thread_heap TLS_MODEL;
+#endif
+
+static inline heap_t*
+get_thread_heap_raw(void) {
+#if (defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD
+ return pthread_getspecific(_memory_thread_heap);
+#else
+ return _memory_thread_heap;
+#endif
+}
+
+//! Get the current thread heap
+static inline heap_t*
+get_thread_heap(void) {
+ heap_t* heap = get_thread_heap_raw();
+#if ENABLE_PRELOAD
+ if (EXPECTED(heap != 0))
+ return heap;
+ rpmalloc_initialize();
+ return get_thread_heap_raw();
+#else
+ return heap;
+#endif
+}
+
+//! Fast thread ID
+static inline uintptr_t
+get_thread_id(void) {
+#if defined(_WIN32)
+ return (uintptr_t)((void*)NtCurrentTeb());
+#elif (defined(__GNUC__) || defined(__clang__)) && !defined(__CYGWIN__)
+ uintptr_t tid;
+# if defined(__i386__)
+ __asm__("movl %%gs:0, %0" : "=r" (tid) : : );
+# elif defined(__x86_64__)
+# if defined(__MACH__)
+ __asm__("movq %%gs:0, %0" : "=r" (tid) : : );
+# else
+ __asm__("movq %%fs:0, %0" : "=r" (tid) : : );
+# endif
+# elif defined(__arm__)
+ __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3" : "=r" (tid));
+# elif defined(__aarch64__)
+# if defined(__MACH__)
+ // tpidr_el0 likely unused, always return 0 on iOS
+ __asm__ volatile ("mrs %0, tpidrro_el0" : "=r" (tid));
+# else
+ __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tid));
+# endif
+# else
+# error This platform needs implementation of get_thread_id()
+# endif
+ return tid;
+#else
+# error This platform needs implementation of get_thread_id()
+#endif
+}
+
+//! Set the current thread heap
+static void
+set_thread_heap(heap_t* heap) {
+#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)
+ pthread_setspecific(_memory_thread_heap, heap);
+#else
+ _memory_thread_heap = heap;
+#endif
+ if (heap)
+ heap->owner_thread = get_thread_id();
+}
+
+//! Set main thread ID
+extern void
+rpmalloc_set_main_thread(void);
+
+void
+rpmalloc_set_main_thread(void) {
+ _rpmalloc_main_thread_id = get_thread_id();
+}
+
+static void
+_rpmalloc_spin(void) {
+#if defined(_MSC_VER)
+ _mm_pause();
+#elif defined(__x86_64__) || defined(__i386__)
+ __asm__ volatile("pause" ::: "memory");
+#elif defined(__aarch64__) || (defined(__arm__) && __ARM_ARCH >= 7)
+ __asm__ volatile("yield" ::: "memory");
+#elif defined(__powerpc__) || defined(__powerpc64__)
+ // No idea if ever been compiled in such archs but ... as precaution
+ __asm__ volatile("or 27,27,27");
+#elif defined(__sparc__)
+ __asm__ volatile("rd %ccr, %g0 \n\trd %ccr, %g0 \n\trd %ccr, %g0");
+#else
+ struct timespec ts = {0};
+ nanosleep(&ts, 0);
+#endif
+}
+
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+static void NTAPI
+_rpmalloc_thread_destructor(void* value) {
+#if ENABLE_OVERRIDE
+ // If this is called on main thread it means rpmalloc_finalize
+ // has not been called and shutdown is forced (through _exit) or unclean
+ if (get_thread_id() == _rpmalloc_main_thread_id)
+ return;
+#endif
+ if (value)
+ rpmalloc_thread_finalize(1);
+}
+#endif
+
+
+////////////
+///
+/// Low level memory map/unmap
+///
+//////
+
+static void
+_rpmalloc_set_name(void* address, size_t size) {
+#if defined(__linux__) || defined(__ANDROID__)
+ const char *name = _memory_huge_pages ? _memory_config.huge_page_name : _memory_config.page_name;
+ if (address == MAP_FAILED || !name)
+ return;
+ // If the kernel does not support CONFIG_ANON_VMA_NAME or if the call fails
+ // (e.g. invalid name) it is a no-op basically.
+ (void)prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (uintptr_t)address, size, (uintptr_t)name);
+#else
+ (void)sizeof(size);
+ (void)sizeof(address);
+#endif
+}
+
+
+//! Map more virtual memory
+// size is number of bytes to map
+// offset receives the offset in bytes from start of mapped region
+// returns address to start of mapped region to use
+static void*
+_rpmalloc_mmap(size_t size, size_t* offset) {
+ rpmalloc_assert(!(size % _memory_page_size), "Invalid mmap size");
+ rpmalloc_assert(size >= _memory_page_size, "Invalid mmap size");
+ void* address = _memory_config.memory_map(size, offset);
+ if (EXPECTED(address != 0)) {
+ _rpmalloc_stat_add_peak(&_mapped_pages, (size >> _memory_page_size_shift), _mapped_pages_peak);
+ _rpmalloc_stat_add(&_mapped_total, (size >> _memory_page_size_shift));
+ }
+ return address;
+}
+
+//! Unmap virtual memory
+// address is the memory address to unmap, as returned from _memory_map
+// size is the number of bytes to unmap, which might be less than full region for a partial unmap
+// offset is the offset in bytes to the actual mapped region, as set by _memory_map
+// release is set to 0 for partial unmap, or size of entire range for a full unmap
+static void
+_rpmalloc_unmap(void* address, size_t size, size_t offset, size_t release) {
+ rpmalloc_assert(!release || (release >= size), "Invalid unmap size");
+ rpmalloc_assert(!release || (release >= _memory_page_size), "Invalid unmap size");
+ if (release) {
+ rpmalloc_assert(!(release % _memory_page_size), "Invalid unmap size");
+ _rpmalloc_stat_sub(&_mapped_pages, (release >> _memory_page_size_shift));
+ _rpmalloc_stat_add(&_unmapped_total, (release >> _memory_page_size_shift));
+ }
+ _memory_config.memory_unmap(address, size, offset, release);
+}
+
+//! Default implementation to map new pages to virtual memory
+static void*
+_rpmalloc_mmap_os(size_t size, size_t* offset) {
+ //Either size is a heap (a single page) or a (multiple) span - we only need to align spans, and only if larger than map granularity
+ size_t padding = ((size >= _memory_span_size) && (_memory_span_size > _memory_map_granularity)) ? _memory_span_size : 0;
+ rpmalloc_assert(size >= _memory_page_size, "Invalid mmap size");
+#if PLATFORM_WINDOWS
+ //Ok to MEM_COMMIT - according to MSDN, "actual physical pages are not allocated unless/until the virtual addresses are actually accessed"
+ void* ptr = VirtualAlloc(0, size + padding, (_memory_huge_pages ? MEM_LARGE_PAGES : 0) | MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ if (!ptr) {
+ if (_memory_config.map_fail_callback) {
+ if (_memory_config.map_fail_callback(size + padding))
+ return _rpmalloc_mmap_os(size, offset);
+ } else {
+ rpmalloc_assert(ptr, "Failed to map virtual memory block");
+ }
+ return 0;
+ }
+#else
+ int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_UNINITIALIZED;
+# if defined(__APPLE__) && !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+ int fd = (int)VM_MAKE_TAG(240U);
+ if (_memory_huge_pages)
+ fd |= VM_FLAGS_SUPERPAGE_SIZE_2MB;
+ void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, fd, 0);
+# elif defined(MAP_HUGETLB)
+ void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE | PROT_MAX(PROT_READ | PROT_WRITE), (_memory_huge_pages ? MAP_HUGETLB : 0) | flags, -1, 0);
+# if defined(MADV_HUGEPAGE)
+ // In some configurations, huge pages allocations might fail thus
+ // we fallback to normal allocations and promote the region as transparent huge page
+ if ((ptr == MAP_FAILED || !ptr) && _memory_huge_pages) {
+ ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, -1, 0);
+ if (ptr && ptr != MAP_FAILED) {
+ int prm = madvise(ptr, size + padding, MADV_HUGEPAGE);
+ (void)prm;
+ rpmalloc_assert((prm == 0), "Failed to promote the page to THP");
+ }
+ }
+# endif
+ _rpmalloc_set_name(ptr, size + padding);
+# elif defined(MAP_ALIGNED)
+ const size_t align = (sizeof(size_t) * 8) - (size_t)(__builtin_clzl(size - 1));
+ void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, (_memory_huge_pages ? MAP_ALIGNED(align) : 0) | flags, -1, 0);
+# elif defined(MAP_ALIGN)
+ caddr_t base = (_memory_huge_pages ? (caddr_t)(4 << 20) : 0);
+ void* ptr = mmap(base, size + padding, PROT_READ | PROT_WRITE, (_memory_huge_pages ? MAP_ALIGN : 0) | flags, -1, 0);
+# else
+ void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, -1, 0);
+# endif
+ if ((ptr == MAP_FAILED) || !ptr) {
+ if (_memory_config.map_fail_callback) {
+ if (_memory_config.map_fail_callback(size + padding))
+ return _rpmalloc_mmap_os(size, offset);
+ } else if (errno != ENOMEM) {
+ rpmalloc_assert((ptr != MAP_FAILED) && ptr, "Failed to map virtual memory block");
+ }
+ return 0;
+ }
+#endif
+ _rpmalloc_stat_add(&_mapped_pages_os, (int32_t)((size + padding) >> _memory_page_size_shift));
+ if (padding) {
+ size_t final_padding = padding - ((uintptr_t)ptr & ~_memory_span_mask);
+ rpmalloc_assert(final_padding <= _memory_span_size, "Internal failure in padding");
+ rpmalloc_assert(final_padding <= padding, "Internal failure in padding");
+ rpmalloc_assert(!(final_padding % 8), "Internal failure in padding");
+ ptr = pointer_offset(ptr, final_padding);
+ *offset = final_padding >> 3;
+ }
+ rpmalloc_assert((size < _memory_span_size) || !((uintptr_t)ptr & ~_memory_span_mask), "Internal failure in padding");
+ return ptr;
+}
+
+//! Default implementation to unmap pages from virtual memory
+static void
+_rpmalloc_unmap_os(void* address, size_t size, size_t offset, size_t release) {
+ rpmalloc_assert(release || (offset == 0), "Invalid unmap size");
+ rpmalloc_assert(!release || (release >= _memory_page_size), "Invalid unmap size");
+ rpmalloc_assert(size >= _memory_page_size, "Invalid unmap size");
+ if (release && offset) {
+ offset <<= 3;
+ address = pointer_offset(address, -(int32_t)offset);
+ if ((release >= _memory_span_size) && (_memory_span_size > _memory_map_granularity)) {
+ //Padding is always one span size
+ release += _memory_span_size;
+ }
+ }
+#if !DISABLE_UNMAP
+#if PLATFORM_WINDOWS
+ if (!VirtualFree(address, release ? 0 : size, release ? MEM_RELEASE : MEM_DECOMMIT)) {
+ rpmalloc_assert(0, "Failed to unmap virtual memory block");
+ }
+#else
+ if (release) {
+ if (munmap(address, release)) {
+ rpmalloc_assert(0, "Failed to unmap virtual memory block");
+ }
+ } else {
+#if defined(MADV_FREE_REUSABLE)
+ int ret;
+ while ((ret = madvise(address, size, MADV_FREE_REUSABLE)) == -1 && (errno == EAGAIN))
+ errno = 0;
+ if ((ret == -1) && (errno != 0)) {
+#elif defined(MADV_DONTNEED)
+ if (madvise(address, size, MADV_DONTNEED)) {
+#elif defined(MADV_PAGEOUT)
+ if (madvise(address, size, MADV_PAGEOUT)) {
+#elif defined(MADV_FREE)
+ if (madvise(address, size, MADV_FREE)) {
+#else
+ if (posix_madvise(address, size, POSIX_MADV_DONTNEED)) {
+#endif
+ rpmalloc_assert(0, "Failed to madvise virtual memory block as free");
+ }
+ }
+#endif
+#endif
+ if (release)
+ _rpmalloc_stat_sub(&_mapped_pages_os, release >> _memory_page_size_shift);
+}
+
+static void
+_rpmalloc_span_mark_as_subspan_unless_master(span_t* master, span_t* subspan, size_t span_count);
+
+//! Use global reserved spans to fulfill a memory map request (reserve size must be checked by caller)
+static span_t*
+_rpmalloc_global_get_reserved_spans(size_t span_count) {
+ span_t* span = _memory_global_reserve;
+ _rpmalloc_span_mark_as_subspan_unless_master(_memory_global_reserve_master, span, span_count);
+ _memory_global_reserve_count -= span_count;
+ if (_memory_global_reserve_count)
+ _memory_global_reserve = (span_t*)pointer_offset(span, span_count << _memory_span_size_shift);
+ else
+ _memory_global_reserve = 0;
+ return span;
+}
+
+//! Store the given spans as global reserve (must only be called from within new heap allocation, not thread safe)
+static void
+_rpmalloc_global_set_reserved_spans(span_t* master, span_t* reserve, size_t reserve_span_count) {
+ _memory_global_reserve_master = master;
+ _memory_global_reserve_count = reserve_span_count;
+ _memory_global_reserve = reserve;
+}
+
+
+////////////
+///
+/// Span linked list management
+///
+//////
+
+//! Add a span to double linked list at the head
+static void
+_rpmalloc_span_double_link_list_add(span_t** head, span_t* span) {
+ if (*head)
+ (*head)->prev = span;
+ span->next = *head;
+ *head = span;
+}
+
+//! Pop head span from double linked list
+static void
+_rpmalloc_span_double_link_list_pop_head(span_t** head, span_t* span) {
+ rpmalloc_assert(*head == span, "Linked list corrupted");
+ span = *head;
+ *head = span->next;
+}
+
+//! Remove a span from double linked list
+static void
+_rpmalloc_span_double_link_list_remove(span_t** head, span_t* span) {
+ rpmalloc_assert(*head, "Linked list corrupted");
+ if (*head == span) {
+ *head = span->next;
+ } else {
+ span_t* next_span = span->next;
+ span_t* prev_span = span->prev;
+ prev_span->next = next_span;
+ if (EXPECTED(next_span != 0))
+ next_span->prev = prev_span;
+ }
+}
+
+
+////////////
+///
+/// Span control
+///
+//////
+
+static void
+_rpmalloc_heap_cache_insert(heap_t* heap, span_t* span);
+
+static void
+_rpmalloc_heap_finalize(heap_t* heap);
+
+static void
+_rpmalloc_heap_set_reserved_spans(heap_t* heap, span_t* master, span_t* reserve, size_t reserve_span_count);
+
+//! Declare the span to be a subspan and store distance from master span and span count
+static void
+_rpmalloc_span_mark_as_subspan_unless_master(span_t* master, span_t* subspan, size_t span_count) {
+ rpmalloc_assert((subspan != master) || (subspan->flags & SPAN_FLAG_MASTER), "Span master pointer and/or flag mismatch");
+ if (subspan != master) {
+ subspan->flags = SPAN_FLAG_SUBSPAN;
+ subspan->offset_from_master = (uint32_t)((uintptr_t)pointer_diff(subspan, master) >> _memory_span_size_shift);
+ subspan->align_offset = 0;
+ }
+ subspan->span_count = (uint32_t)span_count;
+}
+
+//! Use reserved spans to fulfill a memory map request (reserve size must be checked by caller)
+static span_t*
+_rpmalloc_span_map_from_reserve(heap_t* heap, size_t span_count) {
+ //Update the heap span reserve
+ span_t* span = heap->span_reserve;
+ heap->span_reserve = (span_t*)pointer_offset(span, span_count * _memory_span_size);
+ heap->spans_reserved -= (uint32_t)span_count;
+
+ _rpmalloc_span_mark_as_subspan_unless_master(heap->span_reserve_master, span, span_count);
+ if (span_count <= LARGE_CLASS_COUNT)
+ _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_from_reserved);
+
+ return span;
+}
+
+//! Get the aligned number of spans to map in based on wanted count, configured mapping granularity and the page size
+static size_t
+_rpmalloc_span_align_count(size_t span_count) {
+ size_t request_count = (span_count > _memory_span_map_count) ? span_count : _memory_span_map_count;
+ if ((_memory_page_size > _memory_span_size) && ((request_count * _memory_span_size) % _memory_page_size))
+ request_count += _memory_span_map_count - (request_count % _memory_span_map_count);
+ return request_count;
+}
+
+//! Setup a newly mapped span
+static void
+_rpmalloc_span_initialize(span_t* span, size_t total_span_count, size_t span_count, size_t align_offset) {
+ span->total_spans = (uint32_t)total_span_count;
+ span->span_count = (uint32_t)span_count;
+ span->align_offset = (uint32_t)align_offset;
+ span->flags = SPAN_FLAG_MASTER;
+ atomic_store32(&span->remaining_spans, (int32_t)total_span_count);
+}
+
+static void
+_rpmalloc_span_unmap(span_t* span);
+
+//! Map an aligned set of spans, taking configured mapping granularity and the page size into account
+static span_t*
+_rpmalloc_span_map_aligned_count(heap_t* heap, size_t span_count) {
+ //If we already have some, but not enough, reserved spans, release those to heap cache and map a new
+ //full set of spans. Otherwise we would waste memory if page size > span size (huge pages)
+ size_t aligned_span_count = _rpmalloc_span_align_count(span_count);
+ size_t align_offset = 0;
+ span_t* span = (span_t*)_rpmalloc_mmap(aligned_span_count * _memory_span_size, &align_offset);
+ if (!span)
+ return 0;
+ _rpmalloc_span_initialize(span, aligned_span_count, span_count, align_offset);
+ _rpmalloc_stat_inc(&_master_spans);
+ if (span_count <= LARGE_CLASS_COUNT)
+ _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_map_calls);
+ if (aligned_span_count > span_count) {
+ span_t* reserved_spans = (span_t*)pointer_offset(span, span_count * _memory_span_size);
+ size_t reserved_count = aligned_span_count - span_count;
+ if (heap->spans_reserved) {
+ _rpmalloc_span_mark_as_subspan_unless_master(heap->span_reserve_master, heap->span_reserve, heap->spans_reserved);
+ _rpmalloc_heap_cache_insert(heap, heap->span_reserve);
+ }
+ if (reserved_count > _memory_heap_reserve_count) {
+ // If huge pages or eager spam map count, the global reserve spin lock is held by caller, _rpmalloc_span_map
+ rpmalloc_assert(atomic_load32(&_memory_global_lock) == 1, "Global spin lock not held as expected");
+ size_t remain_count = reserved_count - _memory_heap_reserve_count;
+ reserved_count = _memory_heap_reserve_count;
+ span_t* remain_span = (span_t*)pointer_offset(reserved_spans, reserved_count * _memory_span_size);
+ if (_memory_global_reserve) {
+ _rpmalloc_span_mark_as_subspan_unless_master(_memory_global_reserve_master, _memory_global_reserve, _memory_global_reserve_count);
+ _rpmalloc_span_unmap(_memory_global_reserve);
+ }
+ _rpmalloc_global_set_reserved_spans(span, remain_span, remain_count);
+ }
+ _rpmalloc_heap_set_reserved_spans(heap, span, reserved_spans, reserved_count);
+ }
+ return span;
+}
+
+//! Map in memory pages for the given number of spans (or use previously reserved pages)
+static span_t*
+_rpmalloc_span_map(heap_t* heap, size_t span_count) {
+ if (span_count <= heap->spans_reserved)
+ return _rpmalloc_span_map_from_reserve(heap, span_count);
+ span_t* span = 0;
+ int use_global_reserve = (_memory_page_size > _memory_span_size) || (_memory_span_map_count > _memory_heap_reserve_count);
+ if (use_global_reserve) {
+ // If huge pages, make sure only one thread maps more memory to avoid bloat
+ while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))
+ _rpmalloc_spin();
+ if (_memory_global_reserve_count >= span_count) {
+ size_t reserve_count = (!heap->spans_reserved ? _memory_heap_reserve_count : span_count);
+ if (_memory_global_reserve_count < reserve_count)
+ reserve_count = _memory_global_reserve_count;
+ span = _rpmalloc_global_get_reserved_spans(reserve_count);
+ if (span) {
+ if (reserve_count > span_count) {
+ span_t* reserved_span = (span_t*)pointer_offset(span, span_count << _memory_span_size_shift);
+ _rpmalloc_heap_set_reserved_spans(heap, _memory_global_reserve_master, reserved_span, reserve_count - span_count);
+ }
+ // Already marked as subspan in _rpmalloc_global_get_reserved_spans
+ span->span_count = (uint32_t)span_count;
+ }
+ }
+ }
+ if (!span)
+ span = _rpmalloc_span_map_aligned_count(heap, span_count);
+ if (use_global_reserve)
+ atomic_store32_release(&_memory_global_lock, 0);
+ return span;
+}
+
+//! Unmap memory pages for the given number of spans (or mark as unused if no partial unmappings)
+static void
+_rpmalloc_span_unmap(span_t* span) {
+ rpmalloc_assert((span->flags & SPAN_FLAG_MASTER) || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ rpmalloc_assert(!(span->flags & SPAN_FLAG_MASTER) || !(span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+
+ int is_master = !!(span->flags & SPAN_FLAG_MASTER);
+ span_t* master = is_master ? span : ((span_t*)pointer_offset(span, -(intptr_t)((uintptr_t)span->offset_from_master * _memory_span_size)));
+ rpmalloc_assert(is_master || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ rpmalloc_assert(master->flags & SPAN_FLAG_MASTER, "Span flag corrupted");
+
+ size_t span_count = span->span_count;
+ if (!is_master) {
+ //Directly unmap subspans (unless huge pages, in which case we defer and unmap entire page range with master)
+ rpmalloc_assert(span->align_offset == 0, "Span align offset corrupted");
+ if (_memory_span_size >= _memory_page_size)
+ _rpmalloc_unmap(span, span_count * _memory_span_size, 0, 0);
+ } else {
+ //Special double flag to denote an unmapped master
+ //It must be kept in memory since span header must be used
+ span->flags |= SPAN_FLAG_MASTER | SPAN_FLAG_SUBSPAN | SPAN_FLAG_UNMAPPED_MASTER;
+ _rpmalloc_stat_add(&_unmapped_master_spans, 1);
+ }
+
+ if (atomic_add32(&master->remaining_spans, -(int32_t)span_count) <= 0) {
+ //Everything unmapped, unmap the master span with release flag to unmap the entire range of the super span
+ rpmalloc_assert(!!(master->flags & SPAN_FLAG_MASTER) && !!(master->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ size_t unmap_count = master->span_count;
+ if (_memory_span_size < _memory_page_size)
+ unmap_count = master->total_spans;
+ _rpmalloc_stat_sub(&_master_spans, 1);
+ _rpmalloc_stat_sub(&_unmapped_master_spans, 1);
+ _rpmalloc_unmap(master, unmap_count * _memory_span_size, master->align_offset, (size_t)master->total_spans * _memory_span_size);
+ }
+}
+
+//! Move the span (used for small or medium allocations) to the heap thread cache
+static void
+_rpmalloc_span_release_to_cache(heap_t* heap, span_t* span) {
+ rpmalloc_assert(heap == span->heap, "Span heap pointer corrupted");
+ rpmalloc_assert(span->size_class < SIZE_CLASS_COUNT, "Invalid span size class");
+ rpmalloc_assert(span->span_count == 1, "Invalid span count");
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+ atomic_decr32(&heap->span_use[0].current);
+#endif
+ _rpmalloc_stat_dec(&heap->size_class_use[span->size_class].spans_current);
+ if (!heap->finalize) {
+ _rpmalloc_stat_inc(&heap->span_use[0].spans_to_cache);
+ _rpmalloc_stat_inc(&heap->size_class_use[span->size_class].spans_to_cache);
+ if (heap->size_class[span->size_class].cache)
+ _rpmalloc_heap_cache_insert(heap, heap->size_class[span->size_class].cache);
+ heap->size_class[span->size_class].cache = span;
+ } else {
+ _rpmalloc_span_unmap(span);
+ }
+}
+
+//! Initialize a (partial) free list up to next system memory page, while reserving the first block
+//! as allocated, returning number of blocks in list
+static uint32_t
+free_list_partial_init(void** list, void** first_block, void* page_start, void* block_start, uint32_t block_count, uint32_t block_size) {
+ rpmalloc_assert(block_count, "Internal failure");
+ *first_block = block_start;
+ if (block_count > 1) {
+ void* free_block = pointer_offset(block_start, block_size);
+ void* block_end = pointer_offset(block_start, (size_t)block_size * block_count);
+ //If block size is less than half a memory page, bound init to next memory page boundary
+ if (block_size < (_memory_page_size >> 1)) {
+ void* page_end = pointer_offset(page_start, _memory_page_size);
+ if (page_end < block_end)
+ block_end = page_end;
+ }
+ *list = free_block;
+ block_count = 2;
+ void* next_block = pointer_offset(free_block, block_size);
+ while (next_block < block_end) {
+ *((void**)free_block) = next_block;
+ free_block = next_block;
+ ++block_count;
+ next_block = pointer_offset(next_block, block_size);
+ }
+ *((void**)free_block) = 0;
+ } else {
+ *list = 0;
+ }
+ return block_count;
+}
+
+//! Initialize an unused span (from cache or mapped) to be new active span, putting the initial free list in heap class free list
+static void*
+_rpmalloc_span_initialize_new(heap_t* heap, heap_size_class_t* heap_size_class, span_t* span, uint32_t class_idx) {
+ rpmalloc_assert(span->span_count == 1, "Internal failure");
+ size_class_t* size_class = _memory_size_class + class_idx;
+ span->size_class = class_idx;
+ span->heap = heap;
+ span->flags &= ~SPAN_FLAG_ALIGNED_BLOCKS;
+ span->block_size = size_class->block_size;
+ span->block_count = size_class->block_count;
+ span->free_list = 0;
+ span->list_size = 0;
+ atomic_store_ptr_release(&span->free_list_deferred, 0);
+
+ //Setup free list. Only initialize one system page worth of free blocks in list
+ void* block;
+ span->free_list_limit = free_list_partial_init(&heap_size_class->free_list, &block,
+ span, pointer_offset(span, SPAN_HEADER_SIZE), size_class->block_count, size_class->block_size);
+ //Link span as partial if there remains blocks to be initialized as free list, or full if fully initialized
+ if (span->free_list_limit < span->block_count) {
+ _rpmalloc_span_double_link_list_add(&heap_size_class->partial_span, span);
+ span->used_count = span->free_list_limit;
+ } else {
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->full_span[class_idx], span);
+#endif
+ ++heap->full_span_count;
+ span->used_count = span->block_count;
+ }
+ return block;
+}
+
+static void
+_rpmalloc_span_extract_free_list_deferred(span_t* span) {
+ // We need acquire semantics on the CAS operation since we are interested in the list size
+ // Refer to _rpmalloc_deallocate_defer_small_or_medium for further comments on this dependency
+ do {
+ span->free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);
+ } while (span->free_list == INVALID_POINTER);
+ span->used_count -= span->list_size;
+ span->list_size = 0;
+ atomic_store_ptr_release(&span->free_list_deferred, 0);
+}
+
+static int
+_rpmalloc_span_is_fully_utilized(span_t* span) {
+ rpmalloc_assert(span->free_list_limit <= span->block_count, "Span free list corrupted");
+ return !span->free_list && (span->free_list_limit >= span->block_count);
+}
+
+static int
+_rpmalloc_span_finalize(heap_t* heap, size_t iclass, span_t* span, span_t** list_head) {
+ void* free_list = heap->size_class[iclass].free_list;
+ span_t* class_span = (span_t*)((uintptr_t)free_list & _memory_span_mask);
+ if (span == class_span) {
+ // Adopt the heap class free list back into the span free list
+ void* block = span->free_list;
+ void* last_block = 0;
+ while (block) {
+ last_block = block;
+ block = *((void**)block);
+ }
+ uint32_t free_count = 0;
+ block = free_list;
+ while (block) {
+ ++free_count;
+ block = *((void**)block);
+ }
+ if (last_block) {
+ *((void**)last_block) = free_list;
+ } else {
+ span->free_list = free_list;
+ }
+ heap->size_class[iclass].free_list = 0;
+ span->used_count -= free_count;
+ }
+ //If this assert triggers you have memory leaks
+ rpmalloc_assert(span->list_size == span->used_count, "Memory leak detected");
+ if (span->list_size == span->used_count) {
+ _rpmalloc_stat_dec(&heap->span_use[0].current);
+ _rpmalloc_stat_dec(&heap->size_class_use[iclass].spans_current);
+ // This function only used for spans in double linked lists
+ if (list_head)
+ _rpmalloc_span_double_link_list_remove(list_head, span);
+ _rpmalloc_span_unmap(span);
+ return 1;
+ }
+ return 0;
+}
+
+
+////////////
+///
+/// Global cache
+///
+//////
+
+#if ENABLE_GLOBAL_CACHE
+
+//! Finalize a global cache
+static void
+_rpmalloc_global_cache_finalize(global_cache_t* cache) {
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+
+ for (size_t ispan = 0; ispan < cache->count; ++ispan)
+ _rpmalloc_span_unmap(cache->span[ispan]);
+ cache->count = 0;
+
+ while (cache->overflow) {
+ span_t* span = cache->overflow;
+ cache->overflow = span->next;
+ _rpmalloc_span_unmap(span);
+ }
+
+ atomic_store32_release(&cache->lock, 0);
+}
+
+static void
+_rpmalloc_global_cache_insert_spans(span_t** span, size_t span_count, size_t count) {
+ const size_t cache_limit = (span_count == 1) ?
+ GLOBAL_CACHE_MULTIPLIER * MAX_THREAD_SPAN_CACHE :
+ GLOBAL_CACHE_MULTIPLIER * (MAX_THREAD_SPAN_LARGE_CACHE - (span_count >> 1));
+
+ global_cache_t* cache = &_memory_span_cache[span_count - 1];
+
+ size_t insert_count = count;
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+
+#if ENABLE_STATISTICS
+ cache->insert_count += count;
+#endif
+ if ((cache->count + insert_count) > cache_limit)
+ insert_count = cache_limit - cache->count;
+
+ memcpy(cache->span + cache->count, span, sizeof(span_t*) * insert_count);
+ cache->count += (uint32_t)insert_count;
+
+#if ENABLE_UNLIMITED_CACHE
+ while (insert_count < count) {
+#else
+ // Enable unlimited cache if huge pages, or we will leak since it is unlikely that an entire huge page
+ // will be unmapped, and we're unable to partially decommit a huge page
+ while ((_memory_page_size > _memory_span_size) && (insert_count < count)) {
+#endif
+ span_t* current_span = span[insert_count++];
+ current_span->next = cache->overflow;
+ cache->overflow = current_span;
+ }
+ atomic_store32_release(&cache->lock, 0);
+
+ span_t* keep = 0;
+ for (size_t ispan = insert_count; ispan < count; ++ispan) {
+ span_t* current_span = span[ispan];
+ // Keep master spans that has remaining subspans to avoid dangling them
+ if ((current_span->flags & SPAN_FLAG_MASTER) &&
+ (atomic_load32(¤t_span->remaining_spans) > (int32_t)current_span->span_count)) {
+ current_span->next = keep;
+ keep = current_span;
+ } else {
+ _rpmalloc_span_unmap(current_span);
+ }
+ }
+
+ if (keep) {
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+
+ size_t islot = 0;
+ while (keep) {
+ for (; islot < cache->count; ++islot) {
+ span_t* current_span = cache->span[islot];
+ if (!(current_span->flags & SPAN_FLAG_MASTER) || ((current_span->flags & SPAN_FLAG_MASTER) &&
+ (atomic_load32(¤t_span->remaining_spans) <= (int32_t)current_span->span_count))) {
+ _rpmalloc_span_unmap(current_span);
+ cache->span[islot] = keep;
+ break;
+ }
+ }
+ if (islot == cache->count)
+ break;
+ keep = keep->next;
+ }
+
+ if (keep) {
+ span_t* tail = keep;
+ while (tail->next)
+ tail = tail->next;
+ tail->next = cache->overflow;
+ cache->overflow = keep;
+ }
+
+ atomic_store32_release(&cache->lock, 0);
+ }
+}
+
+static size_t
+_rpmalloc_global_cache_extract_spans(span_t** span, size_t span_count, size_t count) {
+ global_cache_t* cache = &_memory_span_cache[span_count - 1];
+
+ size_t extract_count = 0;
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+
+#if ENABLE_STATISTICS
+ cache->extract_count += count;
+#endif
+ size_t want = count - extract_count;
+ if (want > cache->count)
+ want = cache->count;
+
+ memcpy(span + extract_count, cache->span + (cache->count - want), sizeof(span_t*) * want);
+ cache->count -= (uint32_t)want;
+ extract_count += want;
+
+ while ((extract_count < count) && cache->overflow) {
+ span_t* current_span = cache->overflow;
+ span[extract_count++] = current_span;
+ cache->overflow = current_span->next;
+ }
+
+#if ENABLE_ASSERTS
+ for (size_t ispan = 0; ispan < extract_count; ++ispan) {
+ rpmalloc_assert(span[ispan]->span_count == span_count, "Global cache span count mismatch");
+ }
+#endif
+
+ atomic_store32_release(&cache->lock, 0);
+
+ return extract_count;
+}
+
+#endif
+
+////////////
+///
+/// Heap control
+///
+//////
+
+static void _rpmalloc_deallocate_huge(span_t*);
+
+//! Store the given spans as reserve in the given heap
+static void
+_rpmalloc_heap_set_reserved_spans(heap_t* heap, span_t* master, span_t* reserve, size_t reserve_span_count) {
+ heap->span_reserve_master = master;
+ heap->span_reserve = reserve;
+ heap->spans_reserved = (uint32_t)reserve_span_count;
+}
+
+//! Adopt the deferred span cache list, optionally extracting the first single span for immediate re-use
+static void
+_rpmalloc_heap_cache_adopt_deferred(heap_t* heap, span_t** single_span) {
+ span_t* span = (span_t*)((void*)atomic_exchange_ptr_acquire(&heap->span_free_deferred, 0));
+ while (span) {
+ span_t* next_span = (span_t*)span->free_list;
+ rpmalloc_assert(span->heap == heap, "Span heap pointer corrupted");
+ if (EXPECTED(span->size_class < SIZE_CLASS_COUNT)) {
+ rpmalloc_assert(heap->full_span_count, "Heap span counter corrupted");
+ --heap->full_span_count;
+ _rpmalloc_stat_dec(&heap->span_use[0].spans_deferred);
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&heap->full_span[span->size_class], span);
+#endif
+ _rpmalloc_stat_dec(&heap->span_use[0].current);
+ _rpmalloc_stat_dec(&heap->size_class_use[span->size_class].spans_current);
+ if (single_span && !*single_span)
+ *single_span = span;
+ else
+ _rpmalloc_heap_cache_insert(heap, span);
+ } else {
+ if (span->size_class == SIZE_CLASS_HUGE) {
+ _rpmalloc_deallocate_huge(span);
+ } else {
+ rpmalloc_assert(span->size_class == SIZE_CLASS_LARGE, "Span size class invalid");
+ rpmalloc_assert(heap->full_span_count, "Heap span counter corrupted");
+ --heap->full_span_count;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&heap->large_huge_span, span);
+#endif
+ uint32_t idx = span->span_count - 1;
+ _rpmalloc_stat_dec(&heap->span_use[idx].spans_deferred);
+ _rpmalloc_stat_dec(&heap->span_use[idx].current);
+ if (!idx && single_span && !*single_span)
+ *single_span = span;
+ else
+ _rpmalloc_heap_cache_insert(heap, span);
+ }
+ }
+ span = next_span;
+ }
+}
+
+static void
+_rpmalloc_heap_unmap(heap_t* heap) {
+ if (!heap->master_heap) {
+ if ((heap->finalize > 1) && !atomic_load32(&heap->child_count)) {
+ span_t* span = (span_t*)((uintptr_t)heap & _memory_span_mask);
+ _rpmalloc_span_unmap(span);
+ }
+ } else {
+ if (atomic_decr32(&heap->master_heap->child_count) == 0) {
+ _rpmalloc_heap_unmap(heap->master_heap);
+ }
+ }
+}
+
+static void
+_rpmalloc_heap_global_finalize(heap_t* heap) {
+ if (heap->finalize++ > 1) {
+ --heap->finalize;
+ return;
+ }
+
+ _rpmalloc_heap_finalize(heap);
+
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+ span_cache->count = 0;
+ }
+#endif
+
+ if (heap->full_span_count) {
+ --heap->finalize;
+ return;
+ }
+
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ if (heap->size_class[iclass].free_list || heap->size_class[iclass].partial_span) {
+ --heap->finalize;
+ return;
+ }
+ }
+ //Heap is now completely free, unmap and remove from heap list
+ size_t list_idx = (size_t)heap->id % HEAP_ARRAY_SIZE;
+ heap_t* list_heap = _memory_heaps[list_idx];
+ if (list_heap == heap) {
+ _memory_heaps[list_idx] = heap->next_heap;
+ } else {
+ while (list_heap->next_heap != heap)
+ list_heap = list_heap->next_heap;
+ list_heap->next_heap = heap->next_heap;
+ }
+
+ _rpmalloc_heap_unmap(heap);
+}
+
+//! Insert a single span into thread heap cache, releasing to global cache if overflow
+static void
+_rpmalloc_heap_cache_insert(heap_t* heap, span_t* span) {
+ if (UNEXPECTED(heap->finalize != 0)) {
+ _rpmalloc_span_unmap(span);
+ _rpmalloc_heap_global_finalize(heap);
+ return;
+ }
+#if ENABLE_THREAD_CACHE
+ size_t span_count = span->span_count;
+ _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_to_cache);
+ if (span_count == 1) {
+ span_cache_t* span_cache = &heap->span_cache;
+ span_cache->span[span_cache->count++] = span;
+ if (span_cache->count == MAX_THREAD_SPAN_CACHE) {
+ const size_t remain_count = MAX_THREAD_SPAN_CACHE - THREAD_SPAN_CACHE_TRANSFER;
+#if ENABLE_GLOBAL_CACHE
+ _rpmalloc_stat_add64(&heap->thread_to_global, THREAD_SPAN_CACHE_TRANSFER * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_to_global, THREAD_SPAN_CACHE_TRANSFER);
+ _rpmalloc_global_cache_insert_spans(span_cache->span + remain_count, span_count, THREAD_SPAN_CACHE_TRANSFER);
+#else
+ for (size_t ispan = 0; ispan < THREAD_SPAN_CACHE_TRANSFER; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[remain_count + ispan]);
+#endif
+ span_cache->count = remain_count;
+ }
+ } else {
+ size_t cache_idx = span_count - 2;
+ span_large_cache_t* span_cache = heap->span_large_cache + cache_idx;
+ span_cache->span[span_cache->count++] = span;
+ const size_t cache_limit = (MAX_THREAD_SPAN_LARGE_CACHE - (span_count >> 1));
+ if (span_cache->count == cache_limit) {
+ const size_t transfer_limit = 2 + (cache_limit >> 2);
+ const size_t transfer_count = (THREAD_SPAN_LARGE_CACHE_TRANSFER <= transfer_limit ? THREAD_SPAN_LARGE_CACHE_TRANSFER : transfer_limit);
+ const size_t remain_count = cache_limit - transfer_count;
+#if ENABLE_GLOBAL_CACHE
+ _rpmalloc_stat_add64(&heap->thread_to_global, transfer_count * span_count * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_to_global, transfer_count);
+ _rpmalloc_global_cache_insert_spans(span_cache->span + remain_count, span_count, transfer_count);
+#else
+ for (size_t ispan = 0; ispan < transfer_count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[remain_count + ispan]);
+#endif
+ span_cache->count = remain_count;
+ }
+ }
+#else
+ (void)sizeof(heap);
+ _rpmalloc_span_unmap(span);
+#endif
+}
+
+//! Extract the given number of spans from the different cache levels
+static span_t*
+_rpmalloc_heap_thread_cache_extract(heap_t* heap, size_t span_count) {
+ span_t* span = 0;
+#if ENABLE_THREAD_CACHE
+ span_cache_t* span_cache;
+ if (span_count == 1)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (span_count - 2));
+ if (span_cache->count) {
+ _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_from_cache);
+ return span_cache->span[--span_cache->count];
+ }
+#endif
+ return span;
+}
+
+static span_t*
+_rpmalloc_heap_thread_cache_deferred_extract(heap_t* heap, size_t span_count) {
+ span_t* span = 0;
+ if (span_count == 1) {
+ _rpmalloc_heap_cache_adopt_deferred(heap, &span);
+ } else {
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+ span = _rpmalloc_heap_thread_cache_extract(heap, span_count);
+ }
+ return span;
+}
+
+static span_t*
+_rpmalloc_heap_reserved_extract(heap_t* heap, size_t span_count) {
+ if (heap->spans_reserved >= span_count)
+ return _rpmalloc_span_map(heap, span_count);
+ return 0;
+}
+
+//! Extract a span from the global cache
+static span_t*
+_rpmalloc_heap_global_cache_extract(heap_t* heap, size_t span_count) {
+#if ENABLE_GLOBAL_CACHE
+#if ENABLE_THREAD_CACHE
+ span_cache_t* span_cache;
+ size_t wanted_count;
+ if (span_count == 1) {
+ span_cache = &heap->span_cache;
+ wanted_count = THREAD_SPAN_CACHE_TRANSFER;
+ } else {
+ span_cache = (span_cache_t*)(heap->span_large_cache + (span_count - 2));
+ wanted_count = THREAD_SPAN_LARGE_CACHE_TRANSFER;
+ }
+ span_cache->count = _rpmalloc_global_cache_extract_spans(span_cache->span, span_count, wanted_count);
+ if (span_cache->count) {
+ _rpmalloc_stat_add64(&heap->global_to_thread, span_count * span_cache->count * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_from_global, span_cache->count);
+ return span_cache->span[--span_cache->count];
+ }
+#else
+ span_t* span = 0;
+ size_t count = _rpmalloc_global_cache_extract_spans(&span, span_count, 1);
+ if (count) {
+ _rpmalloc_stat_add64(&heap->global_to_thread, span_count * count * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_from_global, count);
+ return span;
+ }
+#endif
+#endif
+ (void)sizeof(heap);
+ (void)sizeof(span_count);
+ return 0;
+}
+
+static void
+_rpmalloc_inc_span_statistics(heap_t* heap, size_t span_count, uint32_t class_idx) {
+ (void)sizeof(heap);
+ (void)sizeof(span_count);
+ (void)sizeof(class_idx);
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+ uint32_t idx = (uint32_t)span_count - 1;
+ uint32_t current_count = (uint32_t)atomic_incr32(&heap->span_use[idx].current);
+ if (current_count > (uint32_t)atomic_load32(&heap->span_use[idx].high))
+ atomic_store32(&heap->span_use[idx].high, (int32_t)current_count);
+ _rpmalloc_stat_add_peak(&heap->size_class_use[class_idx].spans_current, 1, heap->size_class_use[class_idx].spans_peak);
+#endif
+}
+
+//! Get a span from one of the cache levels (thread cache, reserved, global cache) or fallback to mapping more memory
+static span_t*
+_rpmalloc_heap_extract_new_span(heap_t* heap, heap_size_class_t* heap_size_class, size_t span_count, uint32_t class_idx) {
+ span_t* span;
+#if ENABLE_THREAD_CACHE
+ if (heap_size_class && heap_size_class->cache) {
+ span = heap_size_class->cache;
+ heap_size_class->cache = (heap->span_cache.count ? heap->span_cache.span[--heap->span_cache.count] : 0);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+#endif
+ (void)sizeof(class_idx);
+ // Allow 50% overhead to increase cache hits
+ size_t base_span_count = span_count;
+ size_t limit_span_count = (span_count > 2) ? (span_count + (span_count >> 1)) : span_count;
+ if (limit_span_count > LARGE_CLASS_COUNT)
+ limit_span_count = LARGE_CLASS_COUNT;
+ do {
+ span = _rpmalloc_heap_thread_cache_extract(heap, span_count);
+ if (EXPECTED(span != 0)) {
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+ span = _rpmalloc_heap_thread_cache_deferred_extract(heap, span_count);
+ if (EXPECTED(span != 0)) {
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+ span = _rpmalloc_heap_reserved_extract(heap, span_count);
+ if (EXPECTED(span != 0)) {
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_reserved);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+ span = _rpmalloc_heap_global_cache_extract(heap, span_count);
+ if (EXPECTED(span != 0)) {
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+ ++span_count;
+ } while (span_count <= limit_span_count);
+ //Final fallback, map in more virtual memory
+ span = _rpmalloc_span_map(heap, base_span_count);
+ _rpmalloc_inc_span_statistics(heap, base_span_count, class_idx);
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_map_calls);
+ return span;
+}
+
+static void
+_rpmalloc_heap_initialize(heap_t* heap) {
+ _rpmalloc_memset_const(heap, 0, sizeof(heap_t));
+ //Get a new heap ID
+ heap->id = 1 + atomic_incr32(&_memory_heap_id);
+
+ //Link in heap in heap ID map
+ size_t list_idx = (size_t)heap->id % HEAP_ARRAY_SIZE;
+ heap->next_heap = _memory_heaps[list_idx];
+ _memory_heaps[list_idx] = heap;
+}
+
+static void
+_rpmalloc_heap_orphan(heap_t* heap, int first_class) {
+ heap->owner_thread = (uintptr_t)-1;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ heap_t** heap_list = (first_class ? &_memory_first_class_orphan_heaps : &_memory_orphan_heaps);
+#else
+ (void)sizeof(first_class);
+ heap_t** heap_list = &_memory_orphan_heaps;
+#endif
+ heap->next_orphan = *heap_list;
+ *heap_list = heap;
+}
+
+//! Allocate a new heap from newly mapped memory pages
+static heap_t*
+_rpmalloc_heap_allocate_new(void) {
+ // Map in pages for a 16 heaps. If page size is greater than required size for this, map a page and
+ // use first part for heaps and remaining part for spans for allocations. Adds a lot of complexity,
+ // but saves a lot of memory on systems where page size > 64 spans (4MiB)
+ size_t heap_size = sizeof(heap_t);
+ size_t aligned_heap_size = 16 * ((heap_size + 15) / 16);
+ size_t request_heap_count = 16;
+ size_t heap_span_count = ((aligned_heap_size * request_heap_count) + sizeof(span_t) + _memory_span_size - 1) / _memory_span_size;
+ size_t block_size = _memory_span_size * heap_span_count;
+ size_t span_count = heap_span_count;
+ span_t* span = 0;
+ // If there are global reserved spans, use these first
+ if (_memory_global_reserve_count >= heap_span_count) {
+ span = _rpmalloc_global_get_reserved_spans(heap_span_count);
+ }
+ if (!span) {
+ if (_memory_page_size > block_size) {
+ span_count = _memory_page_size / _memory_span_size;
+ block_size = _memory_page_size;
+ // If using huge pages, make sure to grab enough heaps to avoid reallocating a huge page just to serve new heaps
+ size_t possible_heap_count = (block_size - sizeof(span_t)) / aligned_heap_size;
+ if (possible_heap_count >= (request_heap_count * 16))
+ request_heap_count *= 16;
+ else if (possible_heap_count < request_heap_count)
+ request_heap_count = possible_heap_count;
+ heap_span_count = ((aligned_heap_size * request_heap_count) + sizeof(span_t) + _memory_span_size - 1) / _memory_span_size;
+ }
+
+ size_t align_offset = 0;
+ span = (span_t*)_rpmalloc_mmap(block_size, &align_offset);
+ if (!span)
+ return 0;
+
+ // Master span will contain the heaps
+ _rpmalloc_stat_inc(&_master_spans);
+ _rpmalloc_span_initialize(span, span_count, heap_span_count, align_offset);
+ }
+
+ size_t remain_size = _memory_span_size - sizeof(span_t);
+ heap_t* heap = (heap_t*)pointer_offset(span, sizeof(span_t));
+ _rpmalloc_heap_initialize(heap);
+
+ // Put extra heaps as orphans
+ size_t num_heaps = remain_size / aligned_heap_size;
+ if (num_heaps < request_heap_count)
+ num_heaps = request_heap_count;
+ atomic_store32(&heap->child_count, (int32_t)num_heaps - 1);
+ heap_t* extra_heap = (heap_t*)pointer_offset(heap, aligned_heap_size);
+ while (num_heaps > 1) {
+ _rpmalloc_heap_initialize(extra_heap);
+ extra_heap->master_heap = heap;
+ _rpmalloc_heap_orphan(extra_heap, 1);
+ extra_heap = (heap_t*)pointer_offset(extra_heap, aligned_heap_size);
+ --num_heaps;
+ }
+
+ if (span_count > heap_span_count) {
+ // Cap reserved spans
+ size_t remain_count = span_count - heap_span_count;
+ size_t reserve_count = (remain_count > _memory_heap_reserve_count ? _memory_heap_reserve_count : remain_count);
+ span_t* remain_span = (span_t*)pointer_offset(span, heap_span_count * _memory_span_size);
+ _rpmalloc_heap_set_reserved_spans(heap, span, remain_span, reserve_count);
+
+ if (remain_count > reserve_count) {
+ // Set to global reserved spans
+ remain_span = (span_t*)pointer_offset(remain_span, reserve_count * _memory_span_size);
+ reserve_count = remain_count - reserve_count;
+ _rpmalloc_global_set_reserved_spans(span, remain_span, reserve_count);
+ }
+ }
+
+ return heap;
+}
+
+static heap_t*
+_rpmalloc_heap_extract_orphan(heap_t** heap_list) {
+ heap_t* heap = *heap_list;
+ *heap_list = (heap ? heap->next_orphan : 0);
+ return heap;
+}
+
+//! Allocate a new heap, potentially reusing a previously orphaned heap
+static heap_t*
+_rpmalloc_heap_allocate(int first_class) {
+ heap_t* heap = 0;
+ while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))
+ _rpmalloc_spin();
+ if (first_class == 0)
+ heap = _rpmalloc_heap_extract_orphan(&_memory_orphan_heaps);
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ if (!heap)
+ heap = _rpmalloc_heap_extract_orphan(&_memory_first_class_orphan_heaps);
+#endif
+ if (!heap)
+ heap = _rpmalloc_heap_allocate_new();
+ atomic_store32_release(&_memory_global_lock, 0);
+ if (heap)
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+ return heap;
+}
+
+static void
+_rpmalloc_heap_release(void* heapptr, int first_class, int release_cache) {
+ heap_t* heap = (heap_t*)heapptr;
+ if (!heap)
+ return;
+ //Release thread cache spans back to global cache
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+ if (release_cache || heap->finalize) {
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ if (!span_cache->count)
+ continue;
+#if ENABLE_GLOBAL_CACHE
+ if (heap->finalize) {
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+ } else {
+ _rpmalloc_stat_add64(&heap->thread_to_global, span_cache->count * (iclass + 1) * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[iclass].spans_to_global, span_cache->count);
+ _rpmalloc_global_cache_insert_spans(span_cache->span, iclass + 1, span_cache->count);
+ }
+#else
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+#endif
+ span_cache->count = 0;
+ }
+#endif
+ }
+
+ if (get_thread_heap_raw() == heap)
+ set_thread_heap(0);
+
+#if ENABLE_STATISTICS
+ atomic_decr32(&_memory_active_heaps);
+ rpmalloc_assert(atomic_load32(&_memory_active_heaps) >= 0, "Still active heaps during finalization");
+#endif
+
+ // If we are forcibly terminating with _exit the state of the
+ // lock atomic is unknown and it's best to just go ahead and exit
+ if (get_thread_id() != _rpmalloc_main_thread_id) {
+ while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))
+ _rpmalloc_spin();
+ }
+ _rpmalloc_heap_orphan(heap, first_class);
+ atomic_store32_release(&_memory_global_lock, 0);
+}
+
+static void
+_rpmalloc_heap_release_raw(void* heapptr, int release_cache) {
+ _rpmalloc_heap_release(heapptr, 0, release_cache);
+}
+
+static void
+_rpmalloc_heap_release_raw_fc(void* heapptr) {
+ _rpmalloc_heap_release_raw(heapptr, 1);
+}
+
+static void
+_rpmalloc_heap_finalize(heap_t* heap) {
+ if (heap->spans_reserved) {
+ span_t* span = _rpmalloc_span_map(heap, heap->spans_reserved);
+ _rpmalloc_span_unmap(span);
+ heap->spans_reserved = 0;
+ }
+
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ if (heap->size_class[iclass].cache)
+ _rpmalloc_span_unmap(heap->size_class[iclass].cache);
+ heap->size_class[iclass].cache = 0;
+ span_t* span = heap->size_class[iclass].partial_span;
+ while (span) {
+ span_t* next = span->next;
+ _rpmalloc_span_finalize(heap, iclass, span, &heap->size_class[iclass].partial_span);
+ span = next;
+ }
+ // If class still has a free list it must be a full span
+ if (heap->size_class[iclass].free_list) {
+ span_t* class_span = (span_t*)((uintptr_t)heap->size_class[iclass].free_list & _memory_span_mask);
+ span_t** list = 0;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ list = &heap->full_span[iclass];
+#endif
+ --heap->full_span_count;
+ if (!_rpmalloc_span_finalize(heap, iclass, class_span, list)) {
+ if (list)
+ _rpmalloc_span_double_link_list_remove(list, class_span);
+ _rpmalloc_span_double_link_list_add(&heap->size_class[iclass].partial_span, class_span);
+ }
+ }
+ }
+
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+ span_cache->count = 0;
+ }
+#endif
+ rpmalloc_assert(!atomic_load_ptr(&heap->span_free_deferred), "Heaps still active during finalization");
+}
+
+
+////////////
+///
+/// Allocation entry points
+///
+//////
+
+//! Pop first block from a free list
+static void*
+free_list_pop(void** list) {
+ void* block = *list;
+ *list = *((void**)block);
+ return block;
+}
+
+//! Allocate a small/medium sized memory block from the given heap
+static void*
+_rpmalloc_allocate_from_heap_fallback(heap_t* heap, heap_size_class_t* heap_size_class, uint32_t class_idx) {
+ span_t* span = heap_size_class->partial_span;
+ rpmalloc_assume(heap != 0);
+ if (EXPECTED(span != 0)) {
+ rpmalloc_assert(span->block_count == _memory_size_class[span->size_class].block_count, "Span block count corrupted");
+ rpmalloc_assert(!_rpmalloc_span_is_fully_utilized(span), "Internal failure");
+ void* block;
+ if (span->free_list) {
+ //Span local free list is not empty, swap to size class free list
+ block = free_list_pop(&span->free_list);
+ heap_size_class->free_list = span->free_list;
+ span->free_list = 0;
+ } else {
+ //If the span did not fully initialize free list, link up another page worth of blocks
+ void* block_start = pointer_offset(span, SPAN_HEADER_SIZE + ((size_t)span->free_list_limit * span->block_size));
+ span->free_list_limit += free_list_partial_init(&heap_size_class->free_list, &block,
+ (void*)((uintptr_t)block_start & ~(_memory_page_size - 1)), block_start,
+ span->block_count - span->free_list_limit, span->block_size);
+ }
+ rpmalloc_assert(span->free_list_limit <= span->block_count, "Span block count corrupted");
+ span->used_count = span->free_list_limit;
+
+ //Swap in deferred free list if present
+ if (atomic_load_ptr(&span->free_list_deferred))
+ _rpmalloc_span_extract_free_list_deferred(span);
+
+ //If span is still not fully utilized keep it in partial list and early return block
+ if (!_rpmalloc_span_is_fully_utilized(span))
+ return block;
+
+ //The span is fully utilized, unlink from partial list and add to fully utilized list
+ _rpmalloc_span_double_link_list_pop_head(&heap_size_class->partial_span, span);
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->full_span[class_idx], span);
+#endif
+ ++heap->full_span_count;
+ return block;
+ }
+
+ //Find a span in one of the cache levels
+ span = _rpmalloc_heap_extract_new_span(heap, heap_size_class, 1, class_idx);
+ if (EXPECTED(span != 0)) {
+ //Mark span as owned by this heap and set base data, return first block
+ return _rpmalloc_span_initialize_new(heap, heap_size_class, span, class_idx);
+ }
+
+ return 0;
+}
+
+//! Allocate a small sized memory block from the given heap
+static void*
+_rpmalloc_allocate_small(heap_t* heap, size_t size) {
+ rpmalloc_assert(heap, "No thread heap");
+ //Small sizes have unique size classes
+ const uint32_t class_idx = (uint32_t)((size + (SMALL_GRANULARITY - 1)) >> SMALL_GRANULARITY_SHIFT);
+ heap_size_class_t* heap_size_class = heap->size_class + class_idx;
+ _rpmalloc_stat_inc_alloc(heap, class_idx);
+ if (EXPECTED(heap_size_class->free_list != 0))
+ return free_list_pop(&heap_size_class->free_list);
+ return _rpmalloc_allocate_from_heap_fallback(heap, heap_size_class, class_idx);
+}
+
+//! Allocate a medium sized memory block from the given heap
+static void*
+_rpmalloc_allocate_medium(heap_t* heap, size_t size) {
+ rpmalloc_assert(heap, "No thread heap");
+ //Calculate the size class index and do a dependent lookup of the final class index (in case of merged classes)
+ const uint32_t base_idx = (uint32_t)(SMALL_CLASS_COUNT + ((size - (SMALL_SIZE_LIMIT + 1)) >> MEDIUM_GRANULARITY_SHIFT));
+ const uint32_t class_idx = _memory_size_class[base_idx].class_idx;
+ heap_size_class_t* heap_size_class = heap->size_class + class_idx;
+ _rpmalloc_stat_inc_alloc(heap, class_idx);
+ if (EXPECTED(heap_size_class->free_list != 0))
+ return free_list_pop(&heap_size_class->free_list);
+ return _rpmalloc_allocate_from_heap_fallback(heap, heap_size_class, class_idx);
+}
+
+//! Allocate a large sized memory block from the given heap
+static void*
+_rpmalloc_allocate_large(heap_t* heap, size_t size) {
+ rpmalloc_assert(heap, "No thread heap");
+ //Calculate number of needed max sized spans (including header)
+ //Since this function is never called if size > LARGE_SIZE_LIMIT
+ //the span_count is guaranteed to be <= LARGE_CLASS_COUNT
+ size += SPAN_HEADER_SIZE;
+ size_t span_count = size >> _memory_span_size_shift;
+ if (size & (_memory_span_size - 1))
+ ++span_count;
+
+ //Find a span in one of the cache levels
+ span_t* span = _rpmalloc_heap_extract_new_span(heap, 0, span_count, SIZE_CLASS_LARGE);
+ if (!span)
+ return span;
+
+ //Mark span as owned by this heap and set base data
+ rpmalloc_assert(span->span_count >= span_count, "Internal failure");
+ span->size_class = SIZE_CLASS_LARGE;
+ span->heap = heap;
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);
+#endif
+ ++heap->full_span_count;
+
+ return pointer_offset(span, SPAN_HEADER_SIZE);
+}
+
+//! Allocate a huge block by mapping memory pages directly
+static void*
+_rpmalloc_allocate_huge(heap_t* heap, size_t size) {
+ rpmalloc_assert(heap, "No thread heap");
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+ size += SPAN_HEADER_SIZE;
+ size_t num_pages = size >> _memory_page_size_shift;
+ if (size & (_memory_page_size - 1))
+ ++num_pages;
+ size_t align_offset = 0;
+ span_t* span = (span_t*)_rpmalloc_mmap(num_pages * _memory_page_size, &align_offset);
+ if (!span)
+ return span;
+
+ //Store page count in span_count
+ span->size_class = SIZE_CLASS_HUGE;
+ span->span_count = (uint32_t)num_pages;
+ span->align_offset = (uint32_t)align_offset;
+ span->heap = heap;
+ _rpmalloc_stat_add_peak(&_huge_pages_current, num_pages, _huge_pages_peak);
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);
+#endif
+ ++heap->full_span_count;
+
+ return pointer_offset(span, SPAN_HEADER_SIZE);
+}
+
+//! Allocate a block of the given size
+static void*
+_rpmalloc_allocate(heap_t* heap, size_t size) {
+ _rpmalloc_stat_add64(&_allocation_counter, 1);
+ if (EXPECTED(size <= SMALL_SIZE_LIMIT))
+ return _rpmalloc_allocate_small(heap, size);
+ else if (size <= _memory_medium_size_limit)
+ return _rpmalloc_allocate_medium(heap, size);
+ else if (size <= LARGE_SIZE_LIMIT)
+ return _rpmalloc_allocate_large(heap, size);
+ return _rpmalloc_allocate_huge(heap, size);
+}
+
+static void*
+_rpmalloc_aligned_allocate(heap_t* heap, size_t alignment, size_t size) {
+ if (alignment <= SMALL_GRANULARITY)
+ return _rpmalloc_allocate(heap, size);
+
+#if ENABLE_VALIDATE_ARGS
+ if ((size + alignment) < size) {
+ errno = EINVAL;
+ return 0;
+ }
+ if (alignment & (alignment - 1)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+
+ if ((alignment <= SPAN_HEADER_SIZE) && ((size + SPAN_HEADER_SIZE) < _memory_medium_size_limit)) {
+ // If alignment is less or equal to span header size (which is power of two),
+ // and size aligned to span header size multiples is less than size + alignment,
+ // then use natural alignment of blocks to provide alignment
+ size_t multiple_size = size ? (size + (SPAN_HEADER_SIZE - 1)) & ~(uintptr_t)(SPAN_HEADER_SIZE - 1) : SPAN_HEADER_SIZE;
+ rpmalloc_assert(!(multiple_size % SPAN_HEADER_SIZE), "Failed alignment calculation");
+ if (multiple_size <= (size + alignment))
+ return _rpmalloc_allocate(heap, multiple_size);
+ }
+
+ void* ptr = 0;
+ size_t align_mask = alignment - 1;
+ if (alignment <= _memory_page_size) {
+ ptr = _rpmalloc_allocate(heap, size + alignment);
+ if ((uintptr_t)ptr & align_mask) {
+ ptr = (void*)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment);
+ //Mark as having aligned blocks
+ span_t* span = (span_t*)((uintptr_t)ptr & _memory_span_mask);
+ span->flags |= SPAN_FLAG_ALIGNED_BLOCKS;
+ }
+ return ptr;
+ }
+
+ // Fallback to mapping new pages for this request. Since pointers passed
+ // to rpfree must be able to reach the start of the span by bitmasking of
+ // the address with the span size, the returned aligned pointer from this
+ // function must be with a span size of the start of the mapped area.
+ // In worst case this requires us to loop and map pages until we get a
+ // suitable memory address. It also means we can never align to span size
+ // or greater, since the span header will push alignment more than one
+ // span size away from span start (thus causing pointer mask to give us
+ // an invalid span start on free)
+ if (alignment & align_mask) {
+ errno = EINVAL;
+ return 0;
+ }
+ if (alignment >= _memory_span_size) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ size_t extra_pages = alignment / _memory_page_size;
+
+ // Since each span has a header, we will at least need one extra memory page
+ size_t num_pages = 1 + (size / _memory_page_size);
+ if (size & (_memory_page_size - 1))
+ ++num_pages;
+
+ if (extra_pages > num_pages)
+ num_pages = 1 + extra_pages;
+
+ size_t original_pages = num_pages;
+ size_t limit_pages = (_memory_span_size / _memory_page_size) * 2;
+ if (limit_pages < (original_pages * 2))
+ limit_pages = original_pages * 2;
+
+ size_t mapped_size, align_offset;
+ span_t* span;
+
+retry:
+ align_offset = 0;
+ mapped_size = num_pages * _memory_page_size;
+
+ span = (span_t*)_rpmalloc_mmap(mapped_size, &align_offset);
+ if (!span) {
+ errno = ENOMEM;
+ return 0;
+ }
+ ptr = pointer_offset(span, SPAN_HEADER_SIZE);
+
+ if ((uintptr_t)ptr & align_mask)
+ ptr = (void*)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment);
+
+ if (((size_t)pointer_diff(ptr, span) >= _memory_span_size) ||
+ (pointer_offset(ptr, size) > pointer_offset(span, mapped_size)) ||
+ (((uintptr_t)ptr & _memory_span_mask) != (uintptr_t)span)) {
+ _rpmalloc_unmap(span, mapped_size, align_offset, mapped_size);
+ ++num_pages;
+ if (num_pages > limit_pages) {
+ errno = EINVAL;
+ return 0;
+ }
+ goto retry;
+ }
+
+ //Store page count in span_count
+ span->size_class = SIZE_CLASS_HUGE;
+ span->span_count = (uint32_t)num_pages;
+ span->align_offset = (uint32_t)align_offset;
+ span->heap = heap;
+ _rpmalloc_stat_add_peak(&_huge_pages_current, num_pages, _huge_pages_peak);
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);
+#endif
+ ++heap->full_span_count;
+
+ _rpmalloc_stat_add64(&_allocation_counter, 1);
+
+ return ptr;
+}
+
+
+////////////
+///
+/// Deallocation entry points
+///
+//////
+
+//! Deallocate the given small/medium memory block in the current thread local heap
+static void
+_rpmalloc_deallocate_direct_small_or_medium(span_t* span, void* block) {
+ heap_t* heap = span->heap;
+ rpmalloc_assert(heap->owner_thread == get_thread_id() || !heap->owner_thread || heap->finalize, "Internal failure");
+ //Add block to free list
+ if (UNEXPECTED(_rpmalloc_span_is_fully_utilized(span))) {
+ span->used_count = span->block_count;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&heap->full_span[span->size_class], span);
+#endif
+ _rpmalloc_span_double_link_list_add(&heap->size_class[span->size_class].partial_span, span);
+ --heap->full_span_count;
+ }
+ *((void**)block) = span->free_list;
+ --span->used_count;
+ span->free_list = block;
+ if (UNEXPECTED(span->used_count == span->list_size)) {
+ // If there are no used blocks it is guaranteed that no other external thread is accessing the span
+ if (span->used_count) {
+ // Make sure we have synchronized the deferred list and list size by using acquire semantics
+ // and guarantee that no external thread is accessing span concurrently
+ void* free_list;
+ do {
+ free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);
+ } while (free_list == INVALID_POINTER);
+ atomic_store_ptr_release(&span->free_list_deferred, free_list);
+ }
+ _rpmalloc_span_double_link_list_remove(&heap->size_class[span->size_class].partial_span, span);
+ _rpmalloc_span_release_to_cache(heap, span);
+ }
+}
+
+static void
+_rpmalloc_deallocate_defer_free_span(heap_t* heap, span_t* span) {
+ if (span->size_class != SIZE_CLASS_HUGE)
+ _rpmalloc_stat_inc(&heap->span_use[span->span_count - 1].spans_deferred);
+ //This list does not need ABA protection, no mutable side state
+ do {
+ span->free_list = (void*)atomic_load_ptr(&heap->span_free_deferred);
+ } while (!atomic_cas_ptr(&heap->span_free_deferred, span, span->free_list));
+}
+
+//! Put the block in the deferred free list of the owning span
+static void
+_rpmalloc_deallocate_defer_small_or_medium(span_t* span, void* block) {
+ // The memory ordering here is a bit tricky, to avoid having to ABA protect
+ // the deferred free list to avoid desynchronization of list and list size
+ // we need to have acquire semantics on successful CAS of the pointer to
+ // guarantee the list_size variable validity + release semantics on pointer store
+ void* free_list;
+ do {
+ free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);
+ } while (free_list == INVALID_POINTER);
+ *((void**)block) = free_list;
+ uint32_t free_count = ++span->list_size;
+ int all_deferred_free = (free_count == span->block_count);
+ atomic_store_ptr_release(&span->free_list_deferred, block);
+ if (all_deferred_free) {
+ // Span was completely freed by this block. Due to the INVALID_POINTER spin lock
+ // no other thread can reach this state simultaneously on this span.
+ // Safe to move to owner heap deferred cache
+ _rpmalloc_deallocate_defer_free_span(span->heap, span);
+ }
+}
+
+static void
+_rpmalloc_deallocate_small_or_medium(span_t* span, void* p) {
+ _rpmalloc_stat_inc_free(span->heap, span->size_class);
+ if (span->flags & SPAN_FLAG_ALIGNED_BLOCKS) {
+ //Realign pointer to block start
+ void* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);
+ uint32_t block_offset = (uint32_t)pointer_diff(p, blocks_start);
+ p = pointer_offset(p, -(int32_t)(block_offset % span->block_size));
+ }
+ //Check if block belongs to this heap or if deallocation should be deferred
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#else
+ int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#endif
+ if (!defer)
+ _rpmalloc_deallocate_direct_small_or_medium(span, p);
+ else
+ _rpmalloc_deallocate_defer_small_or_medium(span, p);
+}
+
+//! Deallocate the given large memory block to the current heap
+static void
+_rpmalloc_deallocate_large(span_t* span) {
+ rpmalloc_assert(span->size_class == SIZE_CLASS_LARGE, "Bad span size class");
+ rpmalloc_assert(!(span->flags & SPAN_FLAG_MASTER) || !(span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ rpmalloc_assert((span->flags & SPAN_FLAG_MASTER) || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ //We must always defer (unless finalizing) if from another heap since we cannot touch the list or counters of another heap
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#else
+ int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#endif
+ if (defer) {
+ _rpmalloc_deallocate_defer_free_span(span->heap, span);
+ return;
+ }
+ rpmalloc_assert(span->heap->full_span_count, "Heap span counter corrupted");
+ --span->heap->full_span_count;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&span->heap->large_huge_span, span);
+#endif
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+ //Decrease counter
+ size_t idx = span->span_count - 1;
+ atomic_decr32(&span->heap->span_use[idx].current);
+#endif
+ heap_t* heap = span->heap;
+ rpmalloc_assert(heap, "No thread heap");
+#if ENABLE_THREAD_CACHE
+ const int set_as_reserved = ((span->span_count > 1) && (heap->span_cache.count == 0) && !heap->finalize && !heap->spans_reserved);
+#else
+ const int set_as_reserved = ((span->span_count > 1) && !heap->finalize && !heap->spans_reserved);
+#endif
+ if (set_as_reserved) {
+ heap->span_reserve = span;
+ heap->spans_reserved = span->span_count;
+ if (span->flags & SPAN_FLAG_MASTER) {
+ heap->span_reserve_master = span;
+ } else { //SPAN_FLAG_SUBSPAN
+ span_t* master = (span_t*)pointer_offset(span, -(intptr_t)((size_t)span->offset_from_master * _memory_span_size));
+ heap->span_reserve_master = master;
+ rpmalloc_assert(master->flags & SPAN_FLAG_MASTER, "Span flag corrupted");
+ rpmalloc_assert(atomic_load32(&master->remaining_spans) >= (int32_t)span->span_count, "Master span count corrupted");
+ }
+ _rpmalloc_stat_inc(&heap->span_use[idx].spans_to_reserved);
+ } else {
+ //Insert into cache list
+ _rpmalloc_heap_cache_insert(heap, span);
+ }
+}
+
+//! Deallocate the given huge span
+static void
+_rpmalloc_deallocate_huge(span_t* span) {
+ rpmalloc_assert(span->heap, "No span heap");
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#else
+ int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#endif
+ if (defer) {
+ _rpmalloc_deallocate_defer_free_span(span->heap, span);
+ return;
+ }
+ rpmalloc_assert(span->heap->full_span_count, "Heap span counter corrupted");
+ --span->heap->full_span_count;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&span->heap->large_huge_span, span);
+#endif
+
+ //Oversized allocation, page count is stored in span_count
+ size_t num_pages = span->span_count;
+ _rpmalloc_unmap(span, num_pages * _memory_page_size, span->align_offset, num_pages * _memory_page_size);
+ _rpmalloc_stat_sub(&_huge_pages_current, num_pages);
+}
+
+//! Deallocate the given block
+static void
+_rpmalloc_deallocate(void* p) {
+ _rpmalloc_stat_add64(&_deallocation_counter, 1);
+ //Grab the span (always at start of span, using span alignment)
+ span_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);
+ if (UNEXPECTED(!span))
+ return;
+ if (EXPECTED(span->size_class < SIZE_CLASS_COUNT))
+ _rpmalloc_deallocate_small_or_medium(span, p);
+ else if (span->size_class == SIZE_CLASS_LARGE)
+ _rpmalloc_deallocate_large(span);
+ else
+ _rpmalloc_deallocate_huge(span);
+}
+
+////////////
+///
+/// Reallocation entry points
+///
+//////
+
+static size_t
+_rpmalloc_usable_size(void* p);
+
+//! Reallocate the given block to the given size
+static void*
+_rpmalloc_reallocate(heap_t* heap, void* p, size_t size, size_t oldsize, unsigned int flags) {
+ if (p) {
+ //Grab the span using guaranteed span alignment
+ span_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);
+ if (EXPECTED(span->size_class < SIZE_CLASS_COUNT)) {
+ //Small/medium sized block
+ rpmalloc_assert(span->span_count == 1, "Span counter corrupted");
+ void* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);
+ uint32_t block_offset = (uint32_t)pointer_diff(p, blocks_start);
+ uint32_t block_idx = block_offset / span->block_size;
+ void* block = pointer_offset(blocks_start, (size_t)block_idx * span->block_size);
+ if (!oldsize)
+ oldsize = (size_t)((ptrdiff_t)span->block_size - pointer_diff(p, block));
+ if ((size_t)span->block_size >= size) {
+ //Still fits in block, never mind trying to save memory, but preserve data if alignment changed
+ if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))
+ memmove(block, p, oldsize);
+ return block;
+ }
+ } else if (span->size_class == SIZE_CLASS_LARGE) {
+ //Large block
+ size_t total_size = size + SPAN_HEADER_SIZE;
+ size_t num_spans = total_size >> _memory_span_size_shift;
+ if (total_size & (_memory_span_mask - 1))
+ ++num_spans;
+ size_t current_spans = span->span_count;
+ void* block = pointer_offset(span, SPAN_HEADER_SIZE);
+ if (!oldsize)
+ oldsize = (current_spans * _memory_span_size) - (size_t)pointer_diff(p, block) - SPAN_HEADER_SIZE;
+ if ((current_spans >= num_spans) && (total_size >= (oldsize / 2))) {
+ //Still fits in block, never mind trying to save memory, but preserve data if alignment changed
+ if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))
+ memmove(block, p, oldsize);
+ return block;
+ }
+ } else {
+ //Oversized block
+ size_t total_size = size + SPAN_HEADER_SIZE;
+ size_t num_pages = total_size >> _memory_page_size_shift;
+ if (total_size & (_memory_page_size - 1))
+ ++num_pages;
+ //Page count is stored in span_count
+ size_t current_pages = span->span_count;
+ void* block = pointer_offset(span, SPAN_HEADER_SIZE);
+ if (!oldsize)
+ oldsize = (current_pages * _memory_page_size) - (size_t)pointer_diff(p, block) - SPAN_HEADER_SIZE;
+ if ((current_pages >= num_pages) && (num_pages >= (current_pages / 2))) {
+ //Still fits in block, never mind trying to save memory, but preserve data if alignment changed
+ if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))
+ memmove(block, p, oldsize);
+ return block;
+ }
+ }
+ } else {
+ oldsize = 0;
+ }
+
+ if (!!(flags & RPMALLOC_GROW_OR_FAIL))
+ return 0;
+
+ //Size is greater than block size, need to allocate a new block and deallocate the old
+ //Avoid hysteresis by overallocating if increase is small (below 37%)
+ size_t lower_bound = oldsize + (oldsize >> 2) + (oldsize >> 3);
+ size_t new_size = (size > lower_bound) ? size : ((size > oldsize) ? lower_bound : size);
+ void* block = _rpmalloc_allocate(heap, new_size);
+ if (p && block) {
+ if (!(flags & RPMALLOC_NO_PRESERVE))
+ memcpy(block, p, oldsize < new_size ? oldsize : new_size);
+ _rpmalloc_deallocate(p);
+ }
+
+ return block;
+}
+
+static void*
+_rpmalloc_aligned_reallocate(heap_t* heap, void* ptr, size_t alignment, size_t size, size_t oldsize,
+ unsigned int flags) {
+ if (alignment <= SMALL_GRANULARITY)
+ return _rpmalloc_reallocate(heap, ptr, size, oldsize, flags);
+
+ int no_alloc = !!(flags & RPMALLOC_GROW_OR_FAIL);
+ size_t usablesize = (ptr ? _rpmalloc_usable_size(ptr) : 0);
+ if ((usablesize >= size) && !((uintptr_t)ptr & (alignment - 1))) {
+ if (no_alloc || (size >= (usablesize / 2)))
+ return ptr;
+ }
+ // Aligned alloc marks span as having aligned blocks
+ void* block = (!no_alloc ? _rpmalloc_aligned_allocate(heap, alignment, size) : 0);
+ if (EXPECTED(block != 0)) {
+ if (!(flags & RPMALLOC_NO_PRESERVE) && ptr) {
+ if (!oldsize)
+ oldsize = usablesize;
+ memcpy(block, ptr, oldsize < size ? oldsize : size);
+ }
+ _rpmalloc_deallocate(ptr);
+ }
+ return block;
+}
+
+
+////////////
+///
+/// Initialization, finalization and utility
+///
+//////
+
+//! Get the usable size of the given block
+static size_t
+_rpmalloc_usable_size(void* p) {
+ //Grab the span using guaranteed span alignment
+ span_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);
+ if (span->size_class < SIZE_CLASS_COUNT) {
+ //Small/medium block
+ void* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);
+ return span->block_size - ((size_t)pointer_diff(p, blocks_start) % span->block_size);
+ }
+ if (span->size_class == SIZE_CLASS_LARGE) {
+ //Large block
+ size_t current_spans = span->span_count;
+ return (current_spans * _memory_span_size) - (size_t)pointer_diff(p, span);
+ }
+ //Oversized block, page count is stored in span_count
+ size_t current_pages = span->span_count;
+ return (current_pages * _memory_page_size) - (size_t)pointer_diff(p, span);
+}
+
+//! Adjust and optimize the size class properties for the given class
+static void
+_rpmalloc_adjust_size_class(size_t iclass) {
+ size_t block_size = _memory_size_class[iclass].block_size;
+ size_t block_count = (_memory_span_size - SPAN_HEADER_SIZE) / block_size;
+
+ _memory_size_class[iclass].block_count = (uint16_t)block_count;
+ _memory_size_class[iclass].class_idx = (uint16_t)iclass;
+
+ //Check if previous size classes can be merged
+ if (iclass >= SMALL_CLASS_COUNT) {
+ size_t prevclass = iclass;
+ while (prevclass > 0) {
+ --prevclass;
+ //A class can be merged if number of pages and number of blocks are equal
+ if (_memory_size_class[prevclass].block_count == _memory_size_class[iclass].block_count)
+ _rpmalloc_memcpy_const(_memory_size_class + prevclass, _memory_size_class + iclass, sizeof(_memory_size_class[iclass]));
+ else
+ break;
+ }
+ }
+}
+
+//! Initialize the allocator and setup global data
+extern inline int
+rpmalloc_initialize(void) {
+ if (_rpmalloc_initialized) {
+ rpmalloc_thread_initialize();
+ return 0;
+ }
+ return rpmalloc_initialize_config(0);
+}
+
+int
+rpmalloc_initialize_config(const rpmalloc_config_t* config) {
+ if (_rpmalloc_initialized) {
+ rpmalloc_thread_initialize();
+ return 0;
+ }
+ _rpmalloc_initialized = 1;
+
+ if (config)
+ memcpy(&_memory_config, config, sizeof(rpmalloc_config_t));
+ else
+ _rpmalloc_memset_const(&_memory_config, 0, sizeof(rpmalloc_config_t));
+
+ if (!_memory_config.memory_map || !_memory_config.memory_unmap) {
+ _memory_config.memory_map = _rpmalloc_mmap_os;
+ _memory_config.memory_unmap = _rpmalloc_unmap_os;
+ }
+
+#if PLATFORM_WINDOWS
+ SYSTEM_INFO system_info;
+ memset(&system_info, 0, sizeof(system_info));
+ GetSystemInfo(&system_info);
+ _memory_map_granularity = system_info.dwAllocationGranularity;
+#else
+ _memory_map_granularity = (size_t)sysconf(_SC_PAGESIZE);
+#endif
+
+#if RPMALLOC_CONFIGURABLE
+ _memory_page_size = _memory_config.page_size;
+#else
+ _memory_page_size = 0;
+#endif
+ _memory_huge_pages = 0;
+ if (!_memory_page_size) {
+#if PLATFORM_WINDOWS
+ _memory_page_size = system_info.dwPageSize;
+#else
+ _memory_page_size = _memory_map_granularity;
+ if (_memory_config.enable_huge_pages) {
+#if defined(__linux__)
+ size_t huge_page_size = 0;
+ FILE* meminfo = fopen("/proc/meminfo", "r");
+ if (meminfo) {
+ char line[128];
+ while (!huge_page_size && fgets(line, sizeof(line) - 1, meminfo)) {
+ line[sizeof(line) - 1] = 0;
+ if (strstr(line, "Hugepagesize:"))
+ huge_page_size = (size_t)strtol(line + 13, 0, 10) * 1024;
+ }
+ fclose(meminfo);
+ }
+ if (huge_page_size) {
+ _memory_huge_pages = 1;
+ _memory_page_size = huge_page_size;
+ _memory_map_granularity = huge_page_size;
+ }
+#elif defined(__FreeBSD__)
+ int rc;
+ size_t sz = sizeof(rc);
+
+ if (sysctlbyname("vm.pmap.pg_ps_enabled", &rc, &sz, NULL, 0) == 0 && rc == 1) {
+ static size_t defsize = 2 * 1024 * 1024;
+ int nsize = 0;
+ size_t sizes[4] = {0};
+ _memory_huge_pages = 1;
+ _memory_page_size = defsize;
+ if ((nsize = getpagesizes(sizes, 4)) >= 2) {
+ nsize --;
+ for (size_t csize = sizes[nsize]; nsize >= 0 && csize; --nsize, csize = sizes[nsize]) {
+ //! Unlikely, but as a precaution..
+ rpmalloc_assert(!(csize & (csize -1)) && !(csize % 1024), "Invalid page size");
+ if (defsize < csize) {
+ _memory_page_size = csize;
+ break;
+ }
+ }
+ }
+ _memory_map_granularity = _memory_page_size;
+ }
+#elif defined(__APPLE__) || defined(__NetBSD__)
+ _memory_huge_pages = 1;
+ _memory_page_size = 2 * 1024 * 1024;
+ _memory_map_granularity = _memory_page_size;
+#endif
+ }
+#endif
+ } else {
+ if (_memory_config.enable_huge_pages)
+ _memory_huge_pages = 1;
+ }
+
+#if PLATFORM_WINDOWS
+ if (_memory_config.enable_huge_pages) {
+ HANDLE token = 0;
+ size_t large_page_minimum = GetLargePageMinimum();
+ if (large_page_minimum)
+ OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token);
+ if (token) {
+ LUID luid;
+ if (LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid)) {
+ TOKEN_PRIVILEGES token_privileges;
+ memset(&token_privileges, 0, sizeof(token_privileges));
+ token_privileges.PrivilegeCount = 1;
+ token_privileges.Privileges[0].Luid = luid;
+ token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ if (AdjustTokenPrivileges(token, FALSE, &token_privileges, 0, 0, 0)) {
+ if (GetLastError() == ERROR_SUCCESS)
+ _memory_huge_pages = 1;
+ }
+ }
+ CloseHandle(token);
+ }
+ if (_memory_huge_pages) {
+ if (large_page_minimum > _memory_page_size)
+ _memory_page_size = large_page_minimum;
+ if (large_page_minimum > _memory_map_granularity)
+ _memory_map_granularity = large_page_minimum;
+ }
+ }
+#endif
+
+ size_t min_span_size = 256;
+ size_t max_page_size;
+#if UINTPTR_MAX > 0xFFFFFFFF
+ max_page_size = 4096ULL * 1024ULL * 1024ULL;
+#else
+ max_page_size = 4 * 1024 * 1024;
+#endif
+ if (_memory_page_size < min_span_size)
+ _memory_page_size = min_span_size;
+ if (_memory_page_size > max_page_size)
+ _memory_page_size = max_page_size;
+ _memory_page_size_shift = 0;
+ size_t page_size_bit = _memory_page_size;
+ while (page_size_bit != 1) {
+ ++_memory_page_size_shift;
+ page_size_bit >>= 1;
+ }
+ _memory_page_size = ((size_t)1 << _memory_page_size_shift);
+
+#if RPMALLOC_CONFIGURABLE
+ if (!_memory_config.span_size) {
+ _memory_span_size = _memory_default_span_size;
+ _memory_span_size_shift = _memory_default_span_size_shift;
+ _memory_span_mask = _memory_default_span_mask;
+ } else {
+ size_t span_size = _memory_config.span_size;
+ if (span_size > (256 * 1024))
+ span_size = (256 * 1024);
+ _memory_span_size = 4096;
+ _memory_span_size_shift = 12;
+ while (_memory_span_size < span_size) {
+ _memory_span_size <<= 1;
+ ++_memory_span_size_shift;
+ }
+ _memory_span_mask = ~(uintptr_t)(_memory_span_size - 1);
+ }
+#endif
+
+ _memory_span_map_count = ( _memory_config.span_map_count ? _memory_config.span_map_count : DEFAULT_SPAN_MAP_COUNT);
+ if ((_memory_span_size * _memory_span_map_count) < _memory_page_size)
+ _memory_span_map_count = (_memory_page_size / _memory_span_size);
+ if ((_memory_page_size >= _memory_span_size) && ((_memory_span_map_count * _memory_span_size) % _memory_page_size))
+ _memory_span_map_count = (_memory_page_size / _memory_span_size);
+ _memory_heap_reserve_count = (_memory_span_map_count > DEFAULT_SPAN_MAP_COUNT) ? DEFAULT_SPAN_MAP_COUNT : _memory_span_map_count;
+
+ _memory_config.page_size = _memory_page_size;
+ _memory_config.span_size = _memory_span_size;
+ _memory_config.span_map_count = _memory_span_map_count;
+ _memory_config.enable_huge_pages = _memory_huge_pages;
+
+#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)
+ if (pthread_key_create(&_memory_thread_heap, _rpmalloc_heap_release_raw_fc))
+ return -1;
+#endif
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+ fls_key = FlsAlloc(&_rpmalloc_thread_destructor);
+#endif
+
+ //Setup all small and medium size classes
+ size_t iclass = 0;
+ _memory_size_class[iclass].block_size = SMALL_GRANULARITY;
+ _rpmalloc_adjust_size_class(iclass);
+ for (iclass = 1; iclass < SMALL_CLASS_COUNT; ++iclass) {
+ size_t size = iclass * SMALL_GRANULARITY;
+ _memory_size_class[iclass].block_size = (uint32_t)size;
+ _rpmalloc_adjust_size_class(iclass);
+ }
+ //At least two blocks per span, then fall back to large allocations
+ _memory_medium_size_limit = (_memory_span_size - SPAN_HEADER_SIZE) >> 1;
+ if (_memory_medium_size_limit > MEDIUM_SIZE_LIMIT)
+ _memory_medium_size_limit = MEDIUM_SIZE_LIMIT;
+ for (iclass = 0; iclass < MEDIUM_CLASS_COUNT; ++iclass) {
+ size_t size = SMALL_SIZE_LIMIT + ((iclass + 1) * MEDIUM_GRANULARITY);
+ if (size > _memory_medium_size_limit) {
+ _memory_medium_size_limit = SMALL_SIZE_LIMIT + (iclass * MEDIUM_GRANULARITY);
+ break;
+ }
+ _memory_size_class[SMALL_CLASS_COUNT + iclass].block_size = (uint32_t)size;
+ _rpmalloc_adjust_size_class(SMALL_CLASS_COUNT + iclass);
+ }
+
+ _memory_orphan_heaps = 0;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _memory_first_class_orphan_heaps = 0;
+#endif
+#if ENABLE_STATISTICS
+ atomic_store32(&_memory_active_heaps, 0);
+ atomic_store32(&_mapped_pages, 0);
+ _mapped_pages_peak = 0;
+ atomic_store32(&_master_spans, 0);
+ atomic_store32(&_mapped_total, 0);
+ atomic_store32(&_unmapped_total, 0);
+ atomic_store32(&_mapped_pages_os, 0);
+ atomic_store32(&_huge_pages_current, 0);
+ _huge_pages_peak = 0;
+#endif
+ memset(_memory_heaps, 0, sizeof(_memory_heaps));
+ atomic_store32_release(&_memory_global_lock, 0);
+
+ rpmalloc_linker_reference();
+
+ //Initialize this thread
+ rpmalloc_thread_initialize();
+ return 0;
+}
+
+//! Finalize the allocator
+void
+rpmalloc_finalize(void) {
+ rpmalloc_thread_finalize(1);
+ //rpmalloc_dump_statistics(stdout);
+
+ if (_memory_global_reserve) {
+ atomic_add32(&_memory_global_reserve_master->remaining_spans, -(int32_t)_memory_global_reserve_count);
+ _memory_global_reserve_master = 0;
+ _memory_global_reserve_count = 0;
+ _memory_global_reserve = 0;
+ }
+ atomic_store32_release(&_memory_global_lock, 0);
+
+ //Free all thread caches and fully free spans
+ for (size_t list_idx = 0; list_idx < HEAP_ARRAY_SIZE; ++list_idx) {
+ heap_t* heap = _memory_heaps[list_idx];
+ while (heap) {
+ heap_t* next_heap = heap->next_heap;
+ heap->finalize = 1;
+ _rpmalloc_heap_global_finalize(heap);
+ heap = next_heap;
+ }
+ }
+
+#if ENABLE_GLOBAL_CACHE
+ //Free global caches
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass)
+ _rpmalloc_global_cache_finalize(&_memory_span_cache[iclass]);
+#endif
+
+#if (defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD
+ pthread_key_delete(_memory_thread_heap);
+#endif
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+ FlsFree(fls_key);
+ fls_key = 0;
+#endif
+#if ENABLE_STATISTICS
+ //If you hit these asserts you probably have memory leaks (perhaps global scope data doing dynamic allocations) or double frees in your code
+ rpmalloc_assert(atomic_load32(&_mapped_pages) == 0, "Memory leak detected");
+ rpmalloc_assert(atomic_load32(&_mapped_pages_os) == 0, "Memory leak detected");
+#endif
+
+ _rpmalloc_initialized = 0;
+}
+
+//! Initialize thread, assign heap
+extern inline void
+rpmalloc_thread_initialize(void) {
+ if (!get_thread_heap_raw()) {
+ heap_t* heap = _rpmalloc_heap_allocate(0);
+ if (heap) {
+ _rpmalloc_stat_inc(&_memory_active_heaps);
+ set_thread_heap(heap);
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+ FlsSetValue(fls_key, heap);
+#endif
+ }
+ }
+}
+
+//! Finalize thread, orphan heap
+void
+rpmalloc_thread_finalize(int release_caches) {
+ heap_t* heap = get_thread_heap_raw();
+ if (heap)
+ _rpmalloc_heap_release_raw(heap, release_caches);
+ set_thread_heap(0);
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+ FlsSetValue(fls_key, 0);
+#endif
+}
+
+int
+rpmalloc_is_thread_initialized(void) {
+ return (get_thread_heap_raw() != 0) ? 1 : 0;
+}
+
+const rpmalloc_config_t*
+rpmalloc_config(void) {
+ return &_memory_config;
+}
+
+// Extern interface
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc(size_t size) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ heap_t* heap = get_thread_heap();
+ return _rpmalloc_allocate(heap, size);
+}
+
+extern inline void
+rpfree(void* ptr) {
+ _rpmalloc_deallocate(ptr);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpcalloc(size_t num, size_t size) {
+ size_t total;
+#if ENABLE_VALIDATE_ARGS
+#if PLATFORM_WINDOWS
+ int err = SizeTMult(num, size, &total);
+ if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#else
+ int err = __builtin_umull_overflow(num, size, &total);
+ if (err || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+#else
+ total = num * size;
+#endif
+ heap_t* heap = get_thread_heap();
+ void* block = _rpmalloc_allocate(heap, total);
+ if (block)
+ memset(block, 0, total);
+ return block;
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rprealloc(void* ptr, size_t size) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return ptr;
+ }
+#endif
+ heap_t* heap = get_thread_heap();
+ return _rpmalloc_reallocate(heap, ptr, size, 0, 0);
+}
+
+extern RPMALLOC_ALLOCATOR void*
+rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize,
+ unsigned int flags) {
+#if ENABLE_VALIDATE_ARGS
+ if ((size + alignment < size) || (alignment > _memory_page_size)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ heap_t* heap = get_thread_heap();
+ return _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, oldsize, flags);
+}
+
+extern RPMALLOC_ALLOCATOR void*
+rpaligned_alloc(size_t alignment, size_t size) {
+ heap_t* heap = get_thread_heap();
+ return _rpmalloc_aligned_allocate(heap, alignment, size);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpaligned_calloc(size_t alignment, size_t num, size_t size) {
+ size_t total;
+#if ENABLE_VALIDATE_ARGS
+#if PLATFORM_WINDOWS
+ int err = SizeTMult(num, size, &total);
+ if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#else
+ int err = __builtin_umull_overflow(num, size, &total);
+ if (err || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+#else
+ total = num * size;
+#endif
+ void* block = rpaligned_alloc(alignment, total);
+ if (block)
+ memset(block, 0, total);
+ return block;
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmemalign(size_t alignment, size_t size) {
+ return rpaligned_alloc(alignment, size);
+}
+
+extern inline int
+rpposix_memalign(void **memptr, size_t alignment, size_t size) {
+ if (memptr)
+ *memptr = rpaligned_alloc(alignment, size);
+ else
+ return EINVAL;
+ return *memptr ? 0 : ENOMEM;
+}
+
+extern inline size_t
+rpmalloc_usable_size(void* ptr) {
+ return (ptr ? _rpmalloc_usable_size(ptr) : 0);
+}
+
+extern inline void
+rpmalloc_thread_collect(void) {
+}
+
+void
+rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats) {
+ memset(stats, 0, sizeof(rpmalloc_thread_statistics_t));
+ heap_t* heap = get_thread_heap_raw();
+ if (!heap)
+ return;
+
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ size_class_t* size_class = _memory_size_class + iclass;
+ span_t* span = heap->size_class[iclass].partial_span;
+ while (span) {
+ size_t free_count = span->list_size;
+ size_t block_count = size_class->block_count;
+ if (span->free_list_limit < block_count)
+ block_count = span->free_list_limit;
+ free_count += (block_count - span->used_count);
+ stats->sizecache += free_count * size_class->block_size;
+ span = span->next;
+ }
+ }
+
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ stats->spancache += span_cache->count * (iclass + 1) * _memory_span_size;
+ }
+#endif
+
+ span_t* deferred = (span_t*)atomic_load_ptr(&heap->span_free_deferred);
+ while (deferred) {
+ if (deferred->size_class != SIZE_CLASS_HUGE)
+ stats->spancache += (size_t)deferred->span_count * _memory_span_size;
+ deferred = (span_t*)deferred->free_list;
+ }
+
+#if ENABLE_STATISTICS
+ stats->thread_to_global = (size_t)atomic_load64(&heap->thread_to_global);
+ stats->global_to_thread = (size_t)atomic_load64(&heap->global_to_thread);
+
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ stats->span_use[iclass].current = (size_t)atomic_load32(&heap->span_use[iclass].current);
+ stats->span_use[iclass].peak = (size_t)atomic_load32(&heap->span_use[iclass].high);
+ stats->span_use[iclass].to_global = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_global);
+ stats->span_use[iclass].from_global = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_global);
+ stats->span_use[iclass].to_cache = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_cache);
+ stats->span_use[iclass].from_cache = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_cache);
+ stats->span_use[iclass].to_reserved = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_reserved);
+ stats->span_use[iclass].from_reserved = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_reserved);
+ stats->span_use[iclass].map_calls = (size_t)atomic_load32(&heap->span_use[iclass].spans_map_calls);
+ }
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ stats->size_use[iclass].alloc_current = (size_t)atomic_load32(&heap->size_class_use[iclass].alloc_current);
+ stats->size_use[iclass].alloc_peak = (size_t)heap->size_class_use[iclass].alloc_peak;
+ stats->size_use[iclass].alloc_total = (size_t)atomic_load32(&heap->size_class_use[iclass].alloc_total);
+ stats->size_use[iclass].free_total = (size_t)atomic_load32(&heap->size_class_use[iclass].free_total);
+ stats->size_use[iclass].spans_to_cache = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_to_cache);
+ stats->size_use[iclass].spans_from_cache = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_cache);
+ stats->size_use[iclass].spans_from_reserved = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_reserved);
+ stats->size_use[iclass].map_calls = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_map_calls);
+ }
+#endif
+}
+
+void
+rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats) {
+ memset(stats, 0, sizeof(rpmalloc_global_statistics_t));
+#if ENABLE_STATISTICS
+ stats->mapped = (size_t)atomic_load32(&_mapped_pages) * _memory_page_size;
+ stats->mapped_peak = (size_t)_mapped_pages_peak * _memory_page_size;
+ stats->mapped_total = (size_t)atomic_load32(&_mapped_total) * _memory_page_size;
+ stats->unmapped_total = (size_t)atomic_load32(&_unmapped_total) * _memory_page_size;
+ stats->huge_alloc = (size_t)atomic_load32(&_huge_pages_current) * _memory_page_size;
+ stats->huge_alloc_peak = (size_t)_huge_pages_peak * _memory_page_size;
+#endif
+#if ENABLE_GLOBAL_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ global_cache_t* cache = &_memory_span_cache[iclass];
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+ uint32_t count = cache->count;
+#if ENABLE_UNLIMITED_CACHE
+ span_t* current_span = cache->overflow;
+ while (current_span) {
+ ++count;
+ current_span = current_span->next;
+ }
+#endif
+ atomic_store32_release(&cache->lock, 0);
+ stats->cached += count * (iclass + 1) * _memory_span_size;
+ }
+#endif
+}
+
+#if ENABLE_STATISTICS
+
+static void
+_memory_heap_dump_statistics(heap_t* heap, void* file) {
+ fprintf(file, "Heap %d stats:\n", heap->id);
+ fprintf(file, "Class CurAlloc PeakAlloc TotAlloc TotFree BlkSize BlkCount SpansCur SpansPeak PeakAllocMiB ToCacheMiB FromCacheMiB FromReserveMiB MmapCalls\n");
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ if (!atomic_load32(&heap->size_class_use[iclass].alloc_total))
+ continue;
+ fprintf(file, "%3u: %10u %10u %10u %10u %8u %8u %8d %9d %13zu %11zu %12zu %14zu %9u\n", (uint32_t)iclass,
+ atomic_load32(&heap->size_class_use[iclass].alloc_current),
+ heap->size_class_use[iclass].alloc_peak,
+ atomic_load32(&heap->size_class_use[iclass].alloc_total),
+ atomic_load32(&heap->size_class_use[iclass].free_total),
+ _memory_size_class[iclass].block_size,
+ _memory_size_class[iclass].block_count,
+ atomic_load32(&heap->size_class_use[iclass].spans_current),
+ heap->size_class_use[iclass].spans_peak,
+ ((size_t)heap->size_class_use[iclass].alloc_peak * (size_t)_memory_size_class[iclass].block_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_to_cache) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_cache) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_reserved) * _memory_span_size) / (size_t)(1024 * 1024),
+ atomic_load32(&heap->size_class_use[iclass].spans_map_calls));
+ }
+ fprintf(file, "Spans Current Peak Deferred PeakMiB Cached ToCacheMiB FromCacheMiB ToReserveMiB FromReserveMiB ToGlobalMiB FromGlobalMiB MmapCalls\n");
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ if (!atomic_load32(&heap->span_use[iclass].high) && !atomic_load32(&heap->span_use[iclass].spans_map_calls))
+ continue;
+ fprintf(file, "%4u: %8d %8u %8u %8zu %7u %11zu %12zu %12zu %14zu %11zu %13zu %10u\n", (uint32_t)(iclass + 1),
+ atomic_load32(&heap->span_use[iclass].current),
+ atomic_load32(&heap->span_use[iclass].high),
+ atomic_load32(&heap->span_use[iclass].spans_deferred),
+ ((size_t)atomic_load32(&heap->span_use[iclass].high) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),
+#if ENABLE_THREAD_CACHE
+ (unsigned int)(!iclass ? heap->span_cache.count : heap->span_large_cache[iclass - 1].count),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_cache) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_cache) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
+#else
+ 0, (size_t)0, (size_t)0,
+#endif
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_reserved) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_reserved) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_global) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_global) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),
+ atomic_load32(&heap->span_use[iclass].spans_map_calls));
+ }
+ fprintf(file, "Full spans: %zu\n", heap->full_span_count);
+ fprintf(file, "ThreadToGlobalMiB GlobalToThreadMiB\n");
+ fprintf(file, "%17zu %17zu\n", (size_t)atomic_load64(&heap->thread_to_global) / (size_t)(1024 * 1024), (size_t)atomic_load64(&heap->global_to_thread) / (size_t)(1024 * 1024));
+}
+
+#endif
+
+void
+rpmalloc_dump_statistics(void* file) {
+#if ENABLE_STATISTICS
+ for (size_t list_idx = 0; list_idx < HEAP_ARRAY_SIZE; ++list_idx) {
+ heap_t* heap = _memory_heaps[list_idx];
+ while (heap) {
+ int need_dump = 0;
+ for (size_t iclass = 0; !need_dump && (iclass < SIZE_CLASS_COUNT); ++iclass) {
+ if (!atomic_load32(&heap->size_class_use[iclass].alloc_total)) {
+ rpmalloc_assert(!atomic_load32(&heap->size_class_use[iclass].free_total), "Heap statistics counter mismatch");
+ rpmalloc_assert(!atomic_load32(&heap->size_class_use[iclass].spans_map_calls), "Heap statistics counter mismatch");
+ continue;
+ }
+ need_dump = 1;
+ }
+ for (size_t iclass = 0; !need_dump && (iclass < LARGE_CLASS_COUNT); ++iclass) {
+ if (!atomic_load32(&heap->span_use[iclass].high) && !atomic_load32(&heap->span_use[iclass].spans_map_calls))
+ continue;
+ need_dump = 1;
+ }
+ if (need_dump)
+ _memory_heap_dump_statistics(heap, file);
+ heap = heap->next_heap;
+ }
+ }
+ fprintf(file, "Global stats:\n");
+ size_t huge_current = (size_t)atomic_load32(&_huge_pages_current) * _memory_page_size;
+ size_t huge_peak = (size_t)_huge_pages_peak * _memory_page_size;
+ fprintf(file, "HugeCurrentMiB HugePeakMiB\n");
+ fprintf(file, "%14zu %11zu\n", huge_current / (size_t)(1024 * 1024), huge_peak / (size_t)(1024 * 1024));
+
+#if ENABLE_GLOBAL_CACHE
+ fprintf(file, "GlobalCacheMiB\n");
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ global_cache_t* cache = _memory_span_cache + iclass;
+ size_t global_cache = (size_t)cache->count * iclass * _memory_span_size;
+
+ size_t global_overflow_cache = 0;
+ span_t* span = cache->overflow;
+ while (span) {
+ global_overflow_cache += iclass * _memory_span_size;
+ span = span->next;
+ }
+ if (global_cache || global_overflow_cache || cache->insert_count || cache->extract_count)
+ fprintf(file, "%4zu: %8zuMiB (%8zuMiB overflow) %14zu insert %14zu extract\n", iclass + 1, global_cache / (size_t)(1024 * 1024), global_overflow_cache / (size_t)(1024 * 1024), cache->insert_count, cache->extract_count);
+ }
+#endif
+
+ size_t mapped = (size_t)atomic_load32(&_mapped_pages) * _memory_page_size;
+ size_t mapped_os = (size_t)atomic_load32(&_mapped_pages_os) * _memory_page_size;
+ size_t mapped_peak = (size_t)_mapped_pages_peak * _memory_page_size;
+ size_t mapped_total = (size_t)atomic_load32(&_mapped_total) * _memory_page_size;
+ size_t unmapped_total = (size_t)atomic_load32(&_unmapped_total) * _memory_page_size;
+ fprintf(file, "MappedMiB MappedOSMiB MappedPeakMiB MappedTotalMiB UnmappedTotalMiB\n");
+ fprintf(file, "%9zu %11zu %13zu %14zu %16zu\n",
+ mapped / (size_t)(1024 * 1024),
+ mapped_os / (size_t)(1024 * 1024),
+ mapped_peak / (size_t)(1024 * 1024),
+ mapped_total / (size_t)(1024 * 1024),
+ unmapped_total / (size_t)(1024 * 1024));
+
+ fprintf(file, "\n");
+#if 0
+ int64_t allocated = atomic_load64(&_allocation_counter);
+ int64_t deallocated = atomic_load64(&_deallocation_counter);
+ fprintf(file, "Allocation count: %lli\n", allocated);
+ fprintf(file, "Deallocation count: %lli\n", deallocated);
+ fprintf(file, "Current allocations: %lli\n", (allocated - deallocated));
+ fprintf(file, "Master spans: %d\n", atomic_load32(&_master_spans));
+ fprintf(file, "Dangling master spans: %d\n", atomic_load32(&_unmapped_master_spans));
+#endif
+#endif
+ (void)sizeof(file);
+}
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+
+extern inline rpmalloc_heap_t*
+rpmalloc_heap_acquire(void) {
+ // Must be a pristine heap from newly mapped memory pages, or else memory blocks
+ // could already be allocated from the heap which would (wrongly) be released when
+ // heap is cleared with rpmalloc_heap_free_all(). Also heaps guaranteed to be
+ // pristine from the dedicated orphan list can be used.
+ heap_t* heap = _rpmalloc_heap_allocate(1);
+ rpmalloc_assume(heap != NULL);
+ heap->owner_thread = 0;
+ _rpmalloc_stat_inc(&_memory_active_heaps);
+ return heap;
+}
+
+extern inline void
+rpmalloc_heap_release(rpmalloc_heap_t* heap) {
+ if (heap)
+ _rpmalloc_heap_release(heap, 1, 1);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ return _rpmalloc_allocate(heap, size);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ return _rpmalloc_aligned_allocate(heap, alignment, size);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) {
+ return rpmalloc_heap_aligned_calloc(heap, 0, num, size);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) {
+ size_t total;
+#if ENABLE_VALIDATE_ARGS
+#if PLATFORM_WINDOWS
+ int err = SizeTMult(num, size, &total);
+ if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#else
+ int err = __builtin_umull_overflow(num, size, &total);
+ if (err || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+#else
+ total = num * size;
+#endif
+ void* block = _rpmalloc_aligned_allocate(heap, alignment, total);
+ if (block)
+ memset(block, 0, total);
+ return block;
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return ptr;
+ }
+#endif
+ return _rpmalloc_reallocate(heap, ptr, size, 0, flags);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) {
+#if ENABLE_VALIDATE_ARGS
+ if ((size + alignment < size) || (alignment > _memory_page_size)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ return _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, 0, flags);
+}
+
+extern inline void
+rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr) {
+ (void)sizeof(heap);
+ _rpmalloc_deallocate(ptr);
+}
+
+extern inline void
+rpmalloc_heap_free_all(rpmalloc_heap_t* heap) {
+ span_t* span;
+ span_t* next_span;
+
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ span = heap->size_class[iclass].partial_span;
+ while (span) {
+ next_span = span->next;
+ _rpmalloc_heap_cache_insert(heap, span);
+ span = next_span;
+ }
+ heap->size_class[iclass].partial_span = 0;
+ span = heap->full_span[iclass];
+ while (span) {
+ next_span = span->next;
+ _rpmalloc_heap_cache_insert(heap, span);
+ span = next_span;
+ }
+ }
+ memset(heap->size_class, 0, sizeof(heap->size_class));
+ memset(heap->full_span, 0, sizeof(heap->full_span));
+
+ span = heap->large_huge_span;
+ while (span) {
+ next_span = span->next;
+ if (UNEXPECTED(span->size_class == SIZE_CLASS_HUGE))
+ _rpmalloc_deallocate_huge(span);
+ else
+ _rpmalloc_heap_cache_insert(heap, span);
+ span = next_span;
+ }
+ heap->large_huge_span = 0;
+ heap->full_span_count = 0;
+
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ if (!span_cache->count)
+ continue;
+#if ENABLE_GLOBAL_CACHE
+ _rpmalloc_stat_add64(&heap->thread_to_global, span_cache->count * (iclass + 1) * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[iclass].spans_to_global, span_cache->count);
+ _rpmalloc_global_cache_insert_spans(span_cache->span, iclass + 1, span_cache->count);
+#else
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+#endif
+ span_cache->count = 0;
+ }
+#endif
+
+#if ENABLE_STATISTICS
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ atomic_store32(&heap->size_class_use[iclass].alloc_current, 0);
+ atomic_store32(&heap->size_class_use[iclass].spans_current, 0);
+ }
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ atomic_store32(&heap->span_use[iclass].current, 0);
+ }
+#endif
+}
+
+extern inline void
+rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap) {
+ heap_t* prev_heap = get_thread_heap_raw();
+ if (prev_heap != heap) {
+ set_thread_heap(heap);
+ if (prev_heap)
+ rpmalloc_heap_release(prev_heap);
+ }
+}
+
+extern inline rpmalloc_heap_t*
+rpmalloc_get_heap_for_ptr(void* ptr)
+{
+ //Grab the span, and then the heap from the span
+ span_t* span = (span_t*)((uintptr_t)ptr & _memory_span_mask);
+ if (span)
+ {
+ return span->heap;
+ }
+ return 0;
+}
+
+#endif
+
+#if ENABLE_PRELOAD || ENABLE_OVERRIDE
+
+#include "malloc.c"
+
+#endif
+
+void
+rpmalloc_linker_reference(void) {
+ (void)sizeof(_rpmalloc_initialized);
+}
diff --git a/engine/split/3rd_rpmalloc.h b/engine/split/3rd_rpmalloc.h
new file mode 100644
index 0000000..db5be48
--- /dev/null
+++ b/engine/split/3rd_rpmalloc.h
@@ -0,0 +1,373 @@
+/* rpmalloc.h - Memory allocator - Public Domain - 2016 Mattias Jansson
+ *
+ * This library provides a cross-platform lock free thread caching malloc implementation in C11.
+ * The latest source code is always available at
+ *
+ * https://github.com/mjansson/rpmalloc
+ *
+ * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
+ *
+ */
+
+#pragma once
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__clang__) || defined(__GNUC__)
+# define RPMALLOC_EXPORT __attribute__((visibility("default")))
+# define RPMALLOC_ALLOCATOR
+# if (defined(__clang_major__) && (__clang_major__ < 4)) || (defined(__GNUC__) && defined(ENABLE_PRELOAD) && ENABLE_PRELOAD)
+# define RPMALLOC_ATTRIB_MALLOC
+# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
+# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size)
+# else
+# define RPMALLOC_ATTRIB_MALLOC __attribute__((__malloc__))
+# define RPMALLOC_ATTRIB_ALLOC_SIZE(size) __attribute__((alloc_size(size)))
+# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) __attribute__((alloc_size(count, size)))
+# endif
+# define RPMALLOC_CDECL
+#elif defined(_MSC_VER)
+# define RPMALLOC_EXPORT
+# define RPMALLOC_ALLOCATOR __declspec(allocator) __declspec(restrict)
+# define RPMALLOC_ATTRIB_MALLOC
+# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
+# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)
+# define RPMALLOC_CDECL __cdecl
+#else
+# define RPMALLOC_EXPORT
+# define RPMALLOC_ALLOCATOR
+# define RPMALLOC_ATTRIB_MALLOC
+# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
+# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)
+# define RPMALLOC_CDECL
+#endif
+
+//! Define RPMALLOC_CONFIGURABLE to enable configuring sizes. Will introduce
+// a very small overhead due to some size calculations not being compile time constants
+#ifndef RPMALLOC_CONFIGURABLE
+#define RPMALLOC_CONFIGURABLE 0
+#endif
+
+//! Define RPMALLOC_FIRST_CLASS_HEAPS to enable heap based API (rpmalloc_heap_* functions).
+// Will introduce a very small overhead to track fully allocated spans in heaps
+#ifndef RPMALLOC_FIRST_CLASS_HEAPS
+#define RPMALLOC_FIRST_CLASS_HEAPS 0
+#endif
+
+//! Flag to rpaligned_realloc to not preserve content in reallocation
+#define RPMALLOC_NO_PRESERVE 1
+//! Flag to rpaligned_realloc to fail and return null pointer if grow cannot be done in-place,
+// in which case the original pointer is still valid (just like a call to realloc which failes to allocate
+// a new block).
+#define RPMALLOC_GROW_OR_FAIL 2
+
+typedef struct rpmalloc_global_statistics_t {
+ //! Current amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
+ size_t mapped;
+ //! Peak amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
+ size_t mapped_peak;
+ //! Current amount of memory in global caches for small and medium sizes (<32KiB)
+ size_t cached;
+ //! Current amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
+ size_t huge_alloc;
+ //! Peak amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
+ size_t huge_alloc_peak;
+ //! Total amount of memory mapped since initialization (only if ENABLE_STATISTICS=1)
+ size_t mapped_total;
+ //! Total amount of memory unmapped since initialization (only if ENABLE_STATISTICS=1)
+ size_t unmapped_total;
+} rpmalloc_global_statistics_t;
+
+typedef struct rpmalloc_thread_statistics_t {
+ //! Current number of bytes available in thread size class caches for small and medium sizes (<32KiB)
+ size_t sizecache;
+ //! Current number of bytes available in thread span caches for small and medium sizes (<32KiB)
+ size_t spancache;
+ //! Total number of bytes transitioned from thread cache to global cache (only if ENABLE_STATISTICS=1)
+ size_t thread_to_global;
+ //! Total number of bytes transitioned from global cache to thread cache (only if ENABLE_STATISTICS=1)
+ size_t global_to_thread;
+ //! Per span count statistics (only if ENABLE_STATISTICS=1)
+ struct {
+ //! Currently used number of spans
+ size_t current;
+ //! High water mark of spans used
+ size_t peak;
+ //! Number of spans transitioned to global cache
+ size_t to_global;
+ //! Number of spans transitioned from global cache
+ size_t from_global;
+ //! Number of spans transitioned to thread cache
+ size_t to_cache;
+ //! Number of spans transitioned from thread cache
+ size_t from_cache;
+ //! Number of spans transitioned to reserved state
+ size_t to_reserved;
+ //! Number of spans transitioned from reserved state
+ size_t from_reserved;
+ //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
+ size_t map_calls;
+ } span_use[64];
+ //! Per size class statistics (only if ENABLE_STATISTICS=1)
+ struct {
+ //! Current number of allocations
+ size_t alloc_current;
+ //! Peak number of allocations
+ size_t alloc_peak;
+ //! Total number of allocations
+ size_t alloc_total;
+ //! Total number of frees
+ size_t free_total;
+ //! Number of spans transitioned to cache
+ size_t spans_to_cache;
+ //! Number of spans transitioned from cache
+ size_t spans_from_cache;
+ //! Number of spans transitioned from reserved state
+ size_t spans_from_reserved;
+ //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
+ size_t map_calls;
+ } size_use[128];
+} rpmalloc_thread_statistics_t;
+
+typedef struct rpmalloc_config_t {
+ //! Map memory pages for the given number of bytes. The returned address MUST be
+ // aligned to the rpmalloc span size, which will always be a power of two.
+ // Optionally the function can store an alignment offset in the offset variable
+ // in case it performs alignment and the returned pointer is offset from the
+ // actual start of the memory region due to this alignment. The alignment offset
+ // will be passed to the memory unmap function. The alignment offset MUST NOT be
+ // larger than 65535 (storable in an uint16_t), if it is you must use natural
+ // alignment to shift it into 16 bits. If you set a memory_map function, you
+ // must also set a memory_unmap function or else the default implementation will
+ // be used for both. This function must be thread safe, it can be called by
+ // multiple threads simultaneously.
+ void* (*memory_map)(size_t size, size_t* offset);
+ //! Unmap the memory pages starting at address and spanning the given number of bytes.
+ // If release is set to non-zero, the unmap is for an entire span range as returned by
+ // a previous call to memory_map and that the entire range should be released. The
+ // release argument holds the size of the entire span range. If release is set to 0,
+ // the unmap is a partial decommit of a subset of the mapped memory range.
+ // If you set a memory_unmap function, you must also set a memory_map function or
+ // else the default implementation will be used for both. This function must be thread
+ // safe, it can be called by multiple threads simultaneously.
+ void (*memory_unmap)(void* address, size_t size, size_t offset, size_t release);
+ //! Called when an assert fails, if asserts are enabled. Will use the standard assert()
+ // if this is not set.
+ void (*error_callback)(const char* message);
+ //! Called when a call to map memory pages fails (out of memory). If this callback is
+ // not set or returns zero the library will return a null pointer in the allocation
+ // call. If this callback returns non-zero the map call will be retried. The argument
+ // passed is the number of bytes that was requested in the map call. Only used if
+ // the default system memory map function is used (memory_map callback is not set).
+ int (*map_fail_callback)(size_t size);
+ //! Size of memory pages. The page size MUST be a power of two. All memory mapping
+ // requests to memory_map will be made with size set to a multiple of the page size.
+ // Used if RPMALLOC_CONFIGURABLE is defined to 1, otherwise system page size is used.
+ size_t page_size;
+ //! Size of a span of memory blocks. MUST be a power of two, and in [4096,262144]
+ // range (unless 0 - set to 0 to use the default span size). Used if RPMALLOC_CONFIGURABLE
+ // is defined to 1.
+ size_t span_size;
+ //! Number of spans to map at each request to map new virtual memory blocks. This can
+ // be used to minimize the system call overhead at the cost of virtual memory address
+ // space. The extra mapped pages will not be written until actually used, so physical
+ // committed memory should not be affected in the default implementation. Will be
+ // aligned to a multiple of spans that match memory page size in case of huge pages.
+ size_t span_map_count;
+ //! Enable use of large/huge pages. If this flag is set to non-zero and page size is
+ // zero, the allocator will try to enable huge pages and auto detect the configuration.
+ // If this is set to non-zero and page_size is also non-zero, the allocator will
+ // assume huge pages have been configured and enabled prior to initializing the
+ // allocator.
+ // For Windows, see https://docs.microsoft.com/en-us/windows/desktop/memory/large-page-support
+ // For Linux, see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
+ int enable_huge_pages;
+ //! Respectively allocated pages and huge allocated pages names for systems
+ // supporting it to be able to distinguish among anonymous regions.
+ const char *page_name;
+ const char *huge_page_name;
+} rpmalloc_config_t;
+
+//! Initialize allocator with default configuration
+RPMALLOC_EXPORT int
+rpmalloc_initialize(void);
+
+//! Initialize allocator with given configuration
+RPMALLOC_EXPORT int
+rpmalloc_initialize_config(const rpmalloc_config_t* config);
+
+//! Get allocator configuration
+RPMALLOC_EXPORT const rpmalloc_config_t*
+rpmalloc_config(void);
+
+//! Finalize allocator
+RPMALLOC_EXPORT void
+rpmalloc_finalize(void);
+
+//! Initialize allocator for calling thread
+RPMALLOC_EXPORT void
+rpmalloc_thread_initialize(void);
+
+//! Finalize allocator for calling thread
+RPMALLOC_EXPORT void
+rpmalloc_thread_finalize(int release_caches);
+
+//! Perform deferred deallocations pending for the calling thread heap
+RPMALLOC_EXPORT void
+rpmalloc_thread_collect(void);
+
+//! Query if allocator is initialized for calling thread
+RPMALLOC_EXPORT int
+rpmalloc_is_thread_initialized(void);
+
+//! Get per-thread statistics
+RPMALLOC_EXPORT void
+rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats);
+
+//! Get global statistics
+RPMALLOC_EXPORT void
+rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats);
+
+//! Dump all statistics in human readable format to file (should be a FILE*)
+RPMALLOC_EXPORT void
+rpmalloc_dump_statistics(void* file);
+
+//! Allocate a memory block of at least the given size
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1);
+
+//! Free the given memory block
+RPMALLOC_EXPORT void
+rpfree(void* ptr);
+
+//! Allocate a memory block of at least the given size and zero initialize it
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpcalloc(size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2);
+
+//! Reallocate the given block to at least the given size
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rprealloc(void* ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+//! Reallocate the given block to at least the given size and alignment,
+// with optional control flags (see RPMALLOC_NO_PRESERVE).
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
+
+//! Allocate a memory block of at least the given size and alignment.
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+//! Allocate a memory block of at least the given size and alignment, and zero initialize it.
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpaligned_calloc(size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
+
+//! Allocate a memory block of at least the given size and alignment.
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+//! Allocate a memory block of at least the given size and alignment.
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT int
+rpposix_memalign(void** memptr, size_t alignment, size_t size);
+
+//! Query the usable size of the given memory block (from given pointer to the end of block)
+RPMALLOC_EXPORT size_t
+rpmalloc_usable_size(void* ptr);
+
+//! Dummy empty function for forcing linker symbol inclusion
+RPMALLOC_EXPORT void
+rpmalloc_linker_reference(void);
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+
+//! Heap type
+typedef struct heap_t rpmalloc_heap_t;
+
+//! Acquire a new heap. Will reuse existing released heaps or allocate memory for a new heap
+// if none available. Heap API is implemented with the strict assumption that only one single
+// thread will call heap functions for a given heap at any given time, no functions are thread safe.
+RPMALLOC_EXPORT rpmalloc_heap_t*
+rpmalloc_heap_acquire(void);
+
+//! Release a heap (does NOT free the memory allocated by the heap, use rpmalloc_heap_free_all before destroying the heap).
+// Releasing a heap will enable it to be reused by other threads. Safe to pass a null pointer.
+RPMALLOC_EXPORT void
+rpmalloc_heap_release(rpmalloc_heap_t* heap);
+
+//! Allocate a memory block of at least the given size using the given heap.
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+//! Allocate a memory block of at least the given size using the given heap. The returned
+// block will have the requested alignment. Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB).
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
+
+//! Allocate a memory block of at least the given size using the given heap and zero initialize it.
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
+
+//! Allocate a memory block of at least the given size using the given heap and zero initialize it. The returned
+// block will have the requested alignment. Alignment must either be zero, or a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB).
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
+
+//! Reallocate the given block to at least the given size. The memory block MUST be allocated
+// by the same heap given to this function.
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
+
+//! Reallocate the given block to at least the given size. The memory block MUST be allocated
+// by the same heap given to this function. The returned block will have the requested alignment.
+// Alignment must be either zero, or a power of two and a multiple of sizeof(void*), and should ideally be
+// less than memory page size. A caveat of rpmalloc internals is that this must also be strictly less than
+// the span size (default 64KiB).
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(4);
+
+//! Free the given memory block from the given heap. The memory block MUST be allocated
+// by the same heap given to this function.
+RPMALLOC_EXPORT void
+rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr);
+
+//! Free all memory allocated by the heap
+RPMALLOC_EXPORT void
+rpmalloc_heap_free_all(rpmalloc_heap_t* heap);
+
+//! Set the given heap as the current heap for the calling thread. A heap MUST only be current heap
+// for a single thread, a heap can never be shared between multiple threads. The previous
+// current heap for the calling thread is released to be reused by other threads.
+RPMALLOC_EXPORT void
+rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap);
+
+//! Returns which heap the given pointer is allocated on
+RPMALLOC_EXPORT rpmalloc_heap_t*
+rpmalloc_get_heap_for_ptr(void* ptr);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/engine/split/3rd_rpmalloci.c b/engine/split/3rd_rpmalloci.c
new file mode 100644
index 0000000..8724288
--- /dev/null
+++ b/engine/split/3rd_rpmalloci.c
@@ -0,0 +1,488 @@
+/* malloc.c - Memory allocator - Public Domain - 2016 Mattias Jansson
+ *
+ * This library provides a cross-platform lock free thread caching malloc implementation in C11.
+ * The latest source code is always available at
+ *
+ * https://github.com/mjansson/rpmalloc
+ *
+ * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
+ *
+ */
+
+//
+// This file provides overrides for the standard library malloc entry points for C and new/delete operators for C++
+// It also provides automatic initialization/finalization of process and threads
+//
+#if defined(__TINYC__)
+#include
+#endif
+
+#ifndef ARCH_64BIT
+# if defined(__LLP64__) || defined(__LP64__) || defined(_WIN64)
+# define ARCH_64BIT 1
+typedef struct { int pass_static_assert : sizeof(size_t) == 8; } static_assert_data_type_size_mismatch1; //< @r-lyeh
+typedef struct { int pass_static_assert : sizeof(void*) == 8; } static_assert_data_type_size_mismatch2; //< @r-lyeh
+# else
+# define ARCH_64BIT 0
+typedef struct { int pass_static_assert : sizeof(size_t) == 4; } static_assert_data_type_size_mismatch1; //< @r-lyeh
+typedef struct { int pass_static_assert : sizeof(void*) == 4; } static_assert_data_type_size_mismatch2; //< @r-lyeh
+# endif
+#endif
+
+#if (defined(__GNUC__) || defined(__clang__))
+#pragma GCC visibility push(default)
+#endif
+
+#define USE_IMPLEMENT 1
+#define USE_INTERPOSE 0
+#define USE_ALIAS 0
+
+#if defined(__APPLE__)
+#undef USE_INTERPOSE
+#define USE_INTERPOSE 1
+
+typedef struct interpose_t {
+ void* new_func;
+ void* orig_func;
+} interpose_t;
+
+#define MAC_INTERPOSE_PAIR(newf, oldf) { (void*)newf, (void*)oldf }
+#define MAC_INTERPOSE_SINGLE(newf, oldf) \
+__attribute__((used)) static const interpose_t macinterpose##newf##oldf \
+__attribute__ ((section("__DATA, __interpose"))) = MAC_INTERPOSE_PAIR(newf, oldf)
+
+#endif
+
+#if !defined(_WIN32) && !defined(__APPLE__)
+#undef USE_IMPLEMENT
+#undef USE_ALIAS
+#define USE_IMPLEMENT 0
+#define USE_ALIAS 1
+#endif
+
+#ifdef _MSC_VER
+#pragma warning (disable : 4100)
+#undef malloc
+#undef free
+#undef calloc
+#define RPMALLOC_RESTRICT __declspec(restrict)
+#else
+#define RPMALLOC_RESTRICT
+#endif
+
+#if ENABLE_OVERRIDE
+
+typedef struct rp_nothrow_t { int __dummy; } rp_nothrow_t;
+
+#if USE_IMPLEMENT
+
+extern inline RPMALLOC_RESTRICT void* RPMALLOC_CDECL malloc(size_t size) { return rpmalloc(size); }
+extern inline RPMALLOC_RESTRICT void* RPMALLOC_CDECL calloc(size_t count, size_t size) { return rpcalloc(count, size); }
+extern inline RPMALLOC_RESTRICT void* RPMALLOC_CDECL realloc(void* ptr, size_t size) { return rprealloc(ptr, size); }
+extern inline void* RPMALLOC_CDECL reallocf(void* ptr, size_t size) { return rprealloc(ptr, size); }
+extern inline void* RPMALLOC_CDECL aligned_alloc(size_t alignment, size_t size) { return rpaligned_alloc(alignment, size); }
+extern inline void* RPMALLOC_CDECL memalign(size_t alignment, size_t size) { return rpmemalign(alignment, size); }
+extern inline int RPMALLOC_CDECL posix_memalign(void** memptr, size_t alignment, size_t size) { return rpposix_memalign(memptr, alignment, size); }
+extern inline void RPMALLOC_CDECL free(void* ptr) { rpfree(ptr); }
+extern inline void RPMALLOC_CDECL cfree(void* ptr) { rpfree(ptr); }
+extern inline size_t RPMALLOC_CDECL malloc_usable_size(void* ptr) { return rpmalloc_usable_size(ptr); }
+extern inline size_t RPMALLOC_CDECL malloc_size(void* ptr) { return rpmalloc_usable_size(ptr); }
+
+#ifdef _WIN32
+// For Windows, #include in one source file to get the C++ operator overrides implemented in your module
+#else
+// Overload the C++ operators using the mangled names (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling)
+// operators delete and delete[]
+#define RPDEFVIS __attribute__((visibility("default")))
+extern void _ZdlPv(void* p); void RPDEFVIS _ZdlPv(void* p) { rpfree(p); }
+extern void _ZdaPv(void* p); void RPDEFVIS _ZdaPv(void* p) { rpfree(p); }
+#if ARCH_64BIT
+// 64-bit operators new and new[], normal and aligned
+extern void* _Znwm(uint64_t size); void* RPDEFVIS _Znwm(uint64_t size) { return rpmalloc(size); }
+extern void* _Znam(uint64_t size); void* RPDEFVIS _Znam(uint64_t size) { return rpmalloc(size); }
+extern void* _Znwmm(uint64_t size, uint64_t align); void* RPDEFVIS _Znwmm(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
+extern void* _Znamm(uint64_t size, uint64_t align); void* RPDEFVIS _Znamm(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
+extern void* _ZnwmSt11align_val_t(uint64_t size, uint64_t align); void* RPDEFVIS _ZnwmSt11align_val_t(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
+extern void* _ZnamSt11align_val_t(uint64_t size, uint64_t align); void* RPDEFVIS _ZnamSt11align_val_t(uint64_t size, uint64_t align) { return rpaligned_alloc(align, size); }
+extern void* _ZnwmRKSt9nothrow_t(uint64_t size, rp_nothrow_t t); void* RPDEFVIS _ZnwmRKSt9nothrow_t(uint64_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
+extern void* _ZnamRKSt9nothrow_t(uint64_t size, rp_nothrow_t t); void* RPDEFVIS _ZnamRKSt9nothrow_t(uint64_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
+extern void* _ZnwmSt11align_val_tRKSt9nothrow_t(uint64_t size, uint64_t align, rp_nothrow_t t); void* RPDEFVIS _ZnwmSt11align_val_tRKSt9nothrow_t(uint64_t size, uint64_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
+extern void* _ZnamSt11align_val_tRKSt9nothrow_t(uint64_t size, uint64_t align, rp_nothrow_t t); void* RPDEFVIS _ZnamSt11align_val_tRKSt9nothrow_t(uint64_t size, uint64_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
+// 64-bit operators sized delete and delete[], normal and aligned
+extern void _ZdlPvm(void* p, uint64_t size); void RPDEFVIS _ZdlPvm(void* p, uint64_t size) { rpfree(p); (void)sizeof(size); }
+extern void _ZdaPvm(void* p, uint64_t size); void RPDEFVIS _ZdaPvm(void* p, uint64_t size) { rpfree(p); (void)sizeof(size); }
+extern void _ZdlPvSt11align_val_t(void* p, uint64_t align); void RPDEFVIS _ZdlPvSt11align_val_t(void* p, uint64_t align) { rpfree(p); (void)sizeof(align); }
+extern void _ZdaPvSt11align_val_t(void* p, uint64_t align); void RPDEFVIS _ZdaPvSt11align_val_t(void* p, uint64_t align) { rpfree(p); (void)sizeof(align); }
+extern void _ZdlPvmSt11align_val_t(void* p, uint64_t size, uint64_t align); void RPDEFVIS _ZdlPvmSt11align_val_t(void* p, uint64_t size, uint64_t align) { rpfree(p); (void)sizeof(size); (void)sizeof(align); }
+extern void _ZdaPvmSt11align_val_t(void* p, uint64_t size, uint64_t align); void RPDEFVIS _ZdaPvmSt11align_val_t(void* p, uint64_t size, uint64_t align) { rpfree(p); (void)sizeof(size); (void)sizeof(align); }
+#else
+// 32-bit operators new and new[], normal and aligned
+extern void* _Znwj(uint32_t size); void* RPDEFVIS _Znwj(uint32_t size) { return rpmalloc(size); }
+extern void* _Znaj(uint32_t size); void* RPDEFVIS _Znaj(uint32_t size) { return rpmalloc(size); }
+extern void* _Znwjj(uint32_t size, uint32_t align); void* RPDEFVIS _Znwjj(uint32_t size, uint32_t align) { return rpaligned_alloc(align, size); }
+extern void* _Znajj(uint32_t size, uint32_t align); void* RPDEFVIS _Znajj(uint32_t size, uint32_t align) { return rpaligned_alloc(align, size); }
+extern void* _ZnwjSt11align_val_t(size_t size, size_t align); void* RPDEFVIS _ZnwjSt11align_val_t(size_t size, size_t align) { return rpaligned_alloc(align, size); }
+extern void* _ZnajSt11align_val_t(size_t size, size_t align); void* RPDEFVIS _ZnajSt11align_val_t(size_t size, size_t align) { return rpaligned_alloc(align, size); }
+extern void* _ZnwjRKSt9nothrow_t(size_t size, rp_nothrow_t t); void* RPDEFVIS _ZnwjRKSt9nothrow_t(size_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
+extern void* _ZnajRKSt9nothrow_t(size_t size, rp_nothrow_t t); void* RPDEFVIS _ZnajRKSt9nothrow_t(size_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
+extern void* _ZnwjSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t); void* RPDEFVIS _ZnwjSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
+extern void* _ZnajSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t); void* RPDEFVIS _ZnajSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
+// 32-bit operators sized delete and delete[], normal and aligned
+extern void _ZdlPvj(void* p, uint64_t size); void RPDEFVIS _ZdlPvj(void* p, uint64_t size) { rpfree(p); (void)sizeof(size); }
+extern void _ZdaPvj(void* p, uint64_t size); void RPDEFVIS _ZdaPvj(void* p, uint64_t size) { rpfree(p); (void)sizeof(size); }
+extern void _ZdlPvSt11align_val_t(void* p, uint32_t align); void RPDEFVIS _ZdlPvSt11align_val_t(void* p, uint64_t a) { rpfree(p); (void)sizeof(align); }
+extern void _ZdaPvSt11align_val_t(void* p, uint32_t align); void RPDEFVIS _ZdaPvSt11align_val_t(void* p, uint64_t a) { rpfree(p); (void)sizeof(align); }
+extern void _ZdlPvjSt11align_val_t(void* p, uint32_t size, uint32_t align); void RPDEFVIS _ZdlPvjSt11align_val_t(void* p, uint64_t size, uint64_t align) { rpfree(p); (void)sizeof(size); (void)sizeof(a); }
+extern void _ZdaPvjSt11align_val_t(void* p, uint32_t size, uint32_t align); void RPDEFVIS _ZdaPvjSt11align_val_t(void* p, uint64_t size, uint64_t align) { rpfree(p); (void)sizeof(size); (void)sizeof(a); }
+#endif
+#endif
+#endif
+
+#if USE_INTERPOSE || USE_ALIAS
+
+static void* rpmalloc_nothrow(size_t size, rp_nothrow_t t) { (void)sizeof(t); return rpmalloc(size); }
+static void* rpaligned_alloc_reverse(size_t size, size_t align) { return rpaligned_alloc(align, size); }
+static void* rpaligned_alloc_reverse_nothrow(size_t size, size_t align, rp_nothrow_t t) { (void)sizeof(t); return rpaligned_alloc(align, size); }
+static void rpfree_size(void* p, size_t size) { (void)sizeof(size); rpfree(p); }
+static void rpfree_aligned(void* p, size_t align) { (void)sizeof(align); rpfree(p); }
+static void rpfree_size_aligned(void* p, size_t size, size_t align) { (void)sizeof(size); (void)sizeof(align); rpfree(p); }
+
+#endif
+
+#if USE_INTERPOSE
+
+__attribute__((used)) static const interpose_t macinterpose_malloc[]
+__attribute__ ((section("__DATA, __interpose"))) = {
+ //new and new[]
+ MAC_INTERPOSE_PAIR(rpmalloc, _Znwm),
+ MAC_INTERPOSE_PAIR(rpmalloc, _Znam),
+ MAC_INTERPOSE_PAIR(rpaligned_alloc_reverse, _Znwmm),
+ MAC_INTERPOSE_PAIR(rpaligned_alloc_reverse, _Znamm),
+ MAC_INTERPOSE_PAIR(rpmalloc_nothrow, _ZnwmRKSt9nothrow_t),
+ MAC_INTERPOSE_PAIR(rpmalloc_nothrow, _ZnamRKSt9nothrow_t),
+ MAC_INTERPOSE_PAIR(rpaligned_alloc_reverse, _ZnwmSt11align_val_t),
+ MAC_INTERPOSE_PAIR(rpaligned_alloc_reverse, _ZnamSt11align_val_t),
+ MAC_INTERPOSE_PAIR(rpaligned_alloc_reverse_nothrow, _ZnwmSt11align_val_tRKSt9nothrow_t),
+ MAC_INTERPOSE_PAIR(rpaligned_alloc_reverse_nothrow, _ZnamSt11align_val_tRKSt9nothrow_t),
+ //delete and delete[]
+ MAC_INTERPOSE_PAIR(rpfree, _ZdlPv),
+ MAC_INTERPOSE_PAIR(rpfree, _ZdaPv),
+ MAC_INTERPOSE_PAIR(rpfree_size, _ZdlPvm),
+ MAC_INTERPOSE_PAIR(rpfree_size, _ZdaPvm),
+ MAC_INTERPOSE_PAIR(rpfree_aligned, _ZdlPvSt11align_val_t),
+ MAC_INTERPOSE_PAIR(rpfree_aligned, _ZdaPvSt11align_val_t),
+ MAC_INTERPOSE_PAIR(rpfree_size_aligned, _ZdlPvmSt11align_val_t),
+ MAC_INTERPOSE_PAIR(rpfree_size_aligned, _ZdaPvmSt11align_val_t),
+ //libc entry points
+ MAC_INTERPOSE_PAIR(rpmalloc, malloc),
+ MAC_INTERPOSE_PAIR(rpmalloc, calloc),
+ MAC_INTERPOSE_PAIR(rprealloc, realloc),
+ MAC_INTERPOSE_PAIR(rprealloc, reallocf),
+#if defined(__MAC_10_15) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_15
+ MAC_INTERPOSE_PAIR(rpaligned_alloc, aligned_alloc),
+#endif
+ MAC_INTERPOSE_PAIR(rpmemalign, memalign),
+ MAC_INTERPOSE_PAIR(rpposix_memalign, posix_memalign),
+ MAC_INTERPOSE_PAIR(rpfree, free),
+ MAC_INTERPOSE_PAIR(rpfree, cfree),
+ MAC_INTERPOSE_PAIR(rpmalloc_usable_size, malloc_usable_size),
+ MAC_INTERPOSE_PAIR(rpmalloc_usable_size, malloc_size)
+};
+
+#endif
+
+#if USE_ALIAS
+
+#define RPALIAS(fn) __attribute__((alias(#fn), used, visibility("default")));
+
+// Alias the C++ operators using the mangled names (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling)
+
+// operators delete and delete[]
+void _ZdlPv(void* p) RPALIAS(rpfree)
+void _ZdaPv(void* p) RPALIAS(rpfree)
+
+#if ARCH_64BIT
+// 64-bit operators new and new[], normal and aligned
+void* _Znwm(uint64_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1) RPALIAS(rpmalloc)
+void* _Znam(uint64_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1) RPALIAS(rpmalloc)
+void* _Znwmm(uint64_t size, uint64_t align) RPALIAS(rpaligned_alloc_reverse)
+void* _Znamm(uint64_t size, uint64_t align) RPALIAS(rpaligned_alloc_reverse)
+void* _ZnwmSt11align_val_t(size_t size, size_t align) RPALIAS(rpaligned_alloc_reverse)
+void* _ZnamSt11align_val_t(size_t size, size_t align) RPALIAS(rpaligned_alloc_reverse)
+void* _ZnwmRKSt9nothrow_t(size_t size, rp_nothrow_t t) RPALIAS(rpmalloc_nothrow)
+void* _ZnamRKSt9nothrow_t(size_t size, rp_nothrow_t t) RPALIAS(rpmalloc_nothrow)
+void* _ZnwmSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) RPALIAS(rpaligned_alloc_reverse_nothrow)
+void* _ZnamSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) RPALIAS(rpaligned_alloc_reverse_nothrow)
+// 64-bit operators delete and delete[], sized and aligned
+void _ZdlPvm(void* p, size_t n) RPALIAS(rpfree_size)
+void _ZdaPvm(void* p, size_t n) RPALIAS(rpfree_size)
+void _ZdlPvSt11align_val_t(void* p, size_t a) RPALIAS(rpfree_aligned)
+void _ZdaPvSt11align_val_t(void* p, size_t a) RPALIAS(rpfree_aligned)
+void _ZdlPvmSt11align_val_t(void* p, size_t n, size_t a) RPALIAS(rpfree_size_aligned)
+void _ZdaPvmSt11align_val_t(void* p, size_t n, size_t a) RPALIAS(rpfree_size_aligned)
+#else
+// 32-bit operators new and new[], normal and aligned
+void* _Znwj(uint32_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1) RPALIAS(rpmalloc)
+void* _Znaj(uint32_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1) RPALIAS(rpmalloc)
+void* _Znwjj(uint32_t size, uint32_t align) RPALIAS(rpaligned_alloc_reverse)
+void* _Znajj(uint32_t size, uint32_t align) RPALIAS(rpaligned_alloc_reverse)
+void* _ZnwjSt11align_val_t(size_t size, size_t align) RPALIAS(rpaligned_alloc_reverse)
+void* _ZnajSt11align_val_t(size_t size, size_t align) RPALIAS(rpaligned_alloc_reverse)
+void* _ZnwjRKSt9nothrow_t(size_t size, rp_nothrow_t t) RPALIAS(rpmalloc_nothrow)
+void* _ZnajRKSt9nothrow_t(size_t size, rp_nothrow_t t) RPALIAS(rpmalloc_nothrow)
+void* _ZnwjSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) RPALIAS(rpaligned_alloc_reverse_nothrow)
+void* _ZnajSt11align_val_tRKSt9nothrow_t(size_t size, size_t align, rp_nothrow_t t) RPALIAS(rpaligned_alloc_reverse_nothrow)
+// 32-bit operators delete and delete[], sized and aligned
+void _ZdlPvj(void* p, size_t n) RPALIAS(rpfree_size)
+void _ZdaPvj(void* p, size_t n) RPALIAS(rpfree_size)
+void _ZdlPvSt11align_val_t(void* p, size_t a) RPALIAS(rpfree_aligned)
+void _ZdaPvSt11align_val_t(void* p, size_t a) RPALIAS(rpfree_aligned)
+void _ZdlPvjSt11align_val_t(void* p, size_t n, size_t a) RPALIAS(rpfree_size_aligned)
+void _ZdaPvjSt11align_val_t(void* p, size_t n, size_t a) RPALIAS(rpfree_size_aligned)
+#endif
+
+void* malloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1) RPALIAS(rpmalloc)
+void* calloc(size_t count, size_t size) RPALIAS(rpcalloc)
+void* realloc(void* ptr, size_t size) RPALIAS(rprealloc)
+void* reallocf(void* ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2) RPALIAS(rprealloc)
+void* aligned_alloc(size_t alignment, size_t size) RPALIAS(rpaligned_alloc)
+void* memalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2) RPALIAS(rpmemalign)
+int posix_memalign(void** memptr, size_t alignment, size_t size) RPALIAS(rpposix_memalign)
+void free(void* ptr) RPALIAS(rpfree)
+void cfree(void* ptr) RPALIAS(rpfree)
+#if defined(__ANDROID__) || defined(__FreeBSD__)
+size_t malloc_usable_size(const void* ptr) RPALIAS(rpmalloc_usable_size)
+#else
+size_t malloc_usable_size(void* ptr) RPALIAS(rpmalloc_usable_size)
+#endif
+size_t malloc_size(void* ptr) RPALIAS(rpmalloc_usable_size)
+
+#endif
+
+static inline size_t
+_rpmalloc_page_size(void) {
+ return _memory_page_size;
+}
+
+extern void* RPMALLOC_CDECL
+reallocarray(void* ptr, size_t count, size_t size) {
+ size_t total;
+#if ENABLE_VALIDATE_ARGS
+#ifdef _MSC_VER
+ int err = SizeTMult(count, size, &total);
+ if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#else
+ int err = __builtin_umull_overflow(count, size, &total);
+ if (err || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+#else
+ total = count * size;
+#endif
+ return realloc(ptr, total);
+}
+
+extern inline void* RPMALLOC_CDECL
+valloc(size_t size) {
+ get_thread_heap();
+ return rpaligned_alloc(_rpmalloc_page_size(), size);
+}
+
+extern inline void* RPMALLOC_CDECL
+pvalloc(size_t size) {
+ get_thread_heap();
+ const size_t page_size = _rpmalloc_page_size();
+ const size_t aligned_size = ((size + page_size - 1) / page_size) * page_size;
+#if ENABLE_VALIDATE_ARGS
+ if (aligned_size < size) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ return rpaligned_alloc(_rpmalloc_page_size(), aligned_size);
+}
+
+#endif // ENABLE_OVERRIDE
+
+#if ENABLE_PRELOAD
+
+#ifdef _WIN32
+
+#if defined(BUILD_DYNAMIC_LINK) && BUILD_DYNAMIC_LINK
+
+extern __declspec(dllexport) BOOL WINAPI
+DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved);
+
+extern __declspec(dllexport) BOOL WINAPI
+DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
+ (void)sizeof(reserved);
+ (void)sizeof(instance);
+ if (reason == DLL_PROCESS_ATTACH)
+ rpmalloc_initialize();
+ else if (reason == DLL_PROCESS_DETACH)
+ rpmalloc_finalize();
+ else if (reason == DLL_THREAD_ATTACH)
+ rpmalloc_thread_initialize();
+ else if (reason == DLL_THREAD_DETACH)
+ rpmalloc_thread_finalize(1);
+ return TRUE;
+}
+
+//end BUILD_DYNAMIC_LINK
+#else
+
+extern void
+_global_rpmalloc_init(void) {
+ rpmalloc_set_main_thread();
+ rpmalloc_initialize();
+}
+
+#if defined(__clang__) || defined(__GNUC__)
+
+static void __attribute__((constructor))
+initializer(void) {
+ _global_rpmalloc_init();
+}
+
+#elif defined(_MSC_VER)
+
+#pragma section(".CRT$XIB",read)
+__declspec(allocate(".CRT$XIB")) void (*_rpmalloc_module_init)(void) = _global_rpmalloc_init;
+#pragma comment(linker, "/include:_rpmalloc_module_init")
+
+#endif
+
+//end !BUILD_DYNAMIC_LINK
+#endif
+
+#else
+
+#include
+#include
+#include
+#include
+
+extern void
+rpmalloc_set_main_thread(void);
+
+static pthread_key_t destructor_key;
+
+static void
+thread_destructor(void*);
+
+static void __attribute__((constructor))
+initializer(void) {
+ rpmalloc_set_main_thread();
+ rpmalloc_initialize();
+ pthread_key_create(&destructor_key, thread_destructor);
+}
+
+static void __attribute__((destructor))
+finalizer(void) {
+ rpmalloc_finalize();
+}
+
+typedef struct {
+ void* (*real_start)(void*);
+ void* real_arg;
+} thread_starter_arg;
+
+static void*
+thread_starter(void* argptr) {
+ thread_starter_arg* arg = argptr;
+ void* (*real_start)(void*) = arg->real_start;
+ void* real_arg = arg->real_arg;
+ rpmalloc_thread_initialize();
+ rpfree(argptr);
+ pthread_setspecific(destructor_key, (void*)1);
+ return (*real_start)(real_arg);
+}
+
+static void
+thread_destructor(void* value) {
+ (void)sizeof(value);
+ rpmalloc_thread_finalize(1);
+}
+
+#ifdef __APPLE__
+
+static int
+pthread_create_proxy(pthread_t* thread,
+ const pthread_attr_t* attr,
+ void* (*start_routine)(void*),
+ void* arg) {
+ rpmalloc_initialize();
+ thread_starter_arg* starter_arg = rpmalloc(sizeof(thread_starter_arg));
+ starter_arg->real_start = start_routine;
+ starter_arg->real_arg = arg;
+ return pthread_create(thread, attr, thread_starter, starter_arg);
+}
+
+MAC_INTERPOSE_SINGLE(pthread_create_proxy, pthread_create);
+
+#else
+
+#include
+
+int
+pthread_create(pthread_t* thread,
+ const pthread_attr_t* attr,
+ void* (*start_routine)(void*),
+ void* arg) {
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
+ defined(__APPLE__) || defined(__HAIKU__)
+ char fname[] = "pthread_create";
+#else
+ char fname[] = "_pthread_create";
+#endif
+ void* real_pthread_create = dlsym(RTLD_NEXT, fname);
+ rpmalloc_thread_initialize();
+ thread_starter_arg* starter_arg = rpmalloc(sizeof(thread_starter_arg));
+ starter_arg->real_start = start_routine;
+ starter_arg->real_arg = arg;
+ return (*(int (*)(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*))real_pthread_create)(thread, attr, thread_starter, starter_arg);
+}
+
+#endif
+
+#endif
+
+#endif
+
+#if ENABLE_OVERRIDE
+
+#if defined(__GLIBC__) && defined(__linux__)
+
+void* __libc_malloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1) RPALIAS(rpmalloc)
+void* __libc_calloc(size_t count, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2) RPALIAS(rpcalloc)
+void* __libc_realloc(void* p, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2) RPALIAS(rprealloc)
+void __libc_free(void* p) RPALIAS(rpfree)
+void __libc_cfree(void* p) RPALIAS(rpfree)
+void* __libc_memalign(size_t align, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2) RPALIAS(rpmemalign)
+int __posix_memalign(void** p, size_t align, size_t size) RPALIAS(rpposix_memalign)
+
+extern void* __libc_valloc(size_t size);
+extern void* __libc_pvalloc(size_t size);
+
+void*
+__libc_valloc(size_t size) {
+ return valloc(size);
+}
+
+void*
+__libc_pvalloc(size_t size) {
+ return pvalloc(size);
+}
+
+#endif
+
+#endif
+
+#if (defined(__GNUC__) || defined(__clang__))
+#pragma GCC visibility pop
+#endif
diff --git a/engine/split/v4k.c.inl b/engine/split/v4k.c.inl
index 0b980be..291e241 100644
--- a/engine/split/v4k.c.inl
+++ b/engine/split/v4k.c.inl
@@ -148,6 +148,8 @@
{{FILE:v4k_scene.c}}
+{{FILE:v4k_sprite.c}}
+
{{FILE:v4k_system.c}}
{{FILE:v4k_time.c}}
@@ -162,10 +164,17 @@
{{FILE:v4k_ai.c}}
-{{FILE:v4k_editor.c}}
-
-// editor is last in place, so it can use all internals from above headers
+{{FILE:v4k_editor0.c}}
{{FILE:v4k_main.c}}
+// editor is last in place, so it can use all internals from above headers
+{{FILE:v4k_editor.c}}
+{{FILE:v4k_editor_scene.h}}
+{{FILE:v4k_editor_browser.h}}
+{{FILE:v4k_editor_timeline.h}}
+{{FILE:v4k_editor_console.h}}
+{{FILE:v4k_editor_nodes.h}}
+{{FILE:v4k_editor_script.h}}
+
{{FILE:v4k_end.c}}
diff --git a/engine/split/v4k.h.inl b/engine/split/v4k.h.inl
index 2fb6359..5887804 100644
--- a/engine/split/v4k.h.inl
+++ b/engine/split/v4k.h.inl
@@ -116,8 +116,6 @@ extern "C" {
{{FILE:v4k_extend.h}}
-{{FILE:v4k_editor.h}}
-
{{FILE:v4k_file.h}}
{{FILE:v4k_font.h}}
@@ -144,6 +142,8 @@ extern "C" {
{{FILE:v4k_scene.h}}
+{{FILE:v4k_sprite.h}}
+
{{FILE:v4k_string.h}}
{{FILE:v4k_system.h}}
@@ -158,6 +158,10 @@ extern "C" {
// ----
+{{FILE:v4k_editor.h}}
+
+// ----
+
#if is(cpp)
} // extern "C"
#endif
diff --git a/engine/split/v4k.x.inl b/engine/split/v4k.x.inl
index 2516ef4..0e2c85d 100644
--- a/engine/split/v4k.x.inl
+++ b/engine/split/v4k.x.inl
@@ -184,6 +184,16 @@ static char *ui_filter = 0;
{{FILE:3rd_eval.h}}
{{FILE:3rd_luadebugger.h}}
{{FILE:3rd_base64.h}}
+
+#if ENABLE_RPMALLOC
+{{FILE:3rd_rpmalloc.h}}
+{{FILE:3rd_rpmalloc.c}}
+//{{FILE: 3rd_rpmalloci.c}}
+#define SYS_MEM_INIT() rpmalloc_initialize()
+#define SYS_MEM_REALLOC rprealloc
+#define SYS_MEM_SIZE rpmalloc_usable_size
+#endif
+
//#define SQLITE_OMIT_LOAD_EXTENSION
//#define SQLITE_CORE 1
//#define SQLITE_DEBUG 1
@@ -197,4 +207,13 @@ static char *ui_filter = 0;
//#undef rehash
//#undef NB
//#undef threadid
+
+// editor
+{{FILE:3rd_icon_mdi.h}}
+// editor_script
+#define GLEQ_IMPLEMENTATION
+{{FILE:3rd_lite_sys_gleq.h}}
+{{FILE:3rd_lite_sys.h}}
+{{FILE:3rd_lite.h}}
+
#endif // V4K_3RD
diff --git a/engine/split/v4k_cook.c b/engine/split/v4k_cook.c
index f2dd7e1..db9288f 100644
--- a/engine/split/v4k_cook.c
+++ b/engine/split/v4k_cook.c
@@ -11,7 +11,7 @@
const char *ART = "art/";
const char *TOOLS = "tools/bin/";
-const char *EDITOR = "tools/editor/";
+const char *EDITOR = "tools/";
const char *COOK_INI = "tools/cook.ini";
static unsigned ART_SKIP_ROOT; // number of chars to skip the base root in ART folder
@@ -508,11 +508,14 @@ int cook(void *userdata) {
fclose(in);
}
+// if(array_count(uncooked))
+// PRINTF("cook_jobs[%d]=%d\n", job->threadid, array_count(uncooked));
+
// generate cook metrics. you usually do `game.exe --cook-stats && (type *.csv | sort /R > cook.csv)`
static __thread FILE *statsfile = 0;
if(flag("--cook-stats"))
fseek(statsfile = fopen(va("cook%d.csv",job->threadid), "a+t"), 0L, SEEK_END);
- if(statsfile && ftell(statsfile) == 0) fprintf(statsfile,"%10s,%10s,%10s,%10s,%10s, %s\n","+total_ms","gen_ms","exe_ms","zip_ms","pass","file");
+ if(statsfile && !job->threadid && ftell(statsfile) == 0) fprintf(statsfile,"%10s,%10s,%10s,%10s,%10s, %s\n","+total_ms","gen_ms","exe_ms","zip_ms","pass","file");
// added or changed files
for( int i = 0, end = array_count(uncooked); i < end && !cook_cancelling; ++i ) {
@@ -825,10 +828,8 @@ void cook_stop() {
int cook_progress() {
int count = 0, sum = 0;
for( int i = 0, end = cook_jobs(); i < end; ++i ) {
-// if( jobs[i].progress >= 0 ) {
sum += jobs[i].progress;
++count;
-// }
}
return cook_jobs() ? sum / (count+!count) : 100;
}
diff --git a/engine/split/v4k_editor.c b/engine/split/v4k_editor.c
index 21e812c..62d80ff 100644
--- a/engine/split/v4k_editor.c
+++ b/engine/split/v4k_editor.c
@@ -1,679 +1,741 @@
-// editing:
-// nope > functions: add/rem property
+// ## Editor long-term plan
+// - editor = tree of nodes. levels and objects are nodes, and their widgets are also nodes
+// - you can perform actions on nodes, with or without descendants, top-bottom or bottom-top
+// - these operations include load/save, undo/redo, reset, play/render, ddraw, etc
+// - nodes are saved to disk as a filesystem layout: parents are folders, and leafs are files
+// - network replication can be done by external tools by comparing the filesystems and by sending the resulting diff zipped
+//
+// ## Editor roadmap
+// - Gizmos?, scene tree, property editor?, load/save?, undo/redo?, copy/paste, on/off (vis,tick,ddraw,log), vcs.
+// - Scenenode pass: node singleton display, node console, node labels, node outlines?.
+// - Render pass: billboards?, materials, un/lit, cast shadows, wireframe, skybox?/mie?, fog/atmosphere
+// - Level pass: volumes, triggers, platforms, level streaming, collide?, physics
+// - Edit pass: Procedural content, brushes, noise and CSG.
+// - GUI pass: timeline and data tracks, node graphs.
-#define ICON_PLAY ICON_MD_PLAY_ARROW
-#define ICON_PAUSE ICON_MD_PAUSE
-#define ICON_STOP ICON_MD_STOP
-#define ICON_CANCEL ICON_MD_CLOSE
+// ## Alt plan
+// editor is a database + window/tile manager + ui toolkit; all network driven.
+// to be precise, editor is a dumb app and ...
+// - does not know a thing about what it stores.
+// - does not know how to render the game graphics.
+// - does not know how to run the game logic.
+//
+// the editor will create a canvas for your game to render.
+// your game will be responsible to tick the logic and render the window inside the editor.
+//
+// that being said, editor...
+// - can store datas hierarchically.
+// - can perform diffs and merges, and version the datas into repositories.
+// - can be instructed to render UI on top of game and window views.
+// - can download new .natvis and plugins quickly.
+// - can dump whole project in a filesystem form (zip).
-#define ICON_WARNING ICON_MD_WARNING
-#define ICON_BROWSER ICON_MD_FOLDER_SPECIAL
-#define ICON_OUTLINER ICON_MD_VIEW_IN_AR
-#define ICON_BUILD ICON_MD_BUILD
-#define ICON_SCREENSHOT ICON_MD_PHOTO_CAMERA
-#define ICON_CAMERA_ON ICON_MD_VIDEOCAM
-#define ICON_CAMERA_OFF ICON_MD_VIDEOCAM_OFF
-#define ICON_GAMEPAD_ON ICON_MD_VIDEOGAME_ASSET
-#define ICON_GAMEPAD_OFF ICON_MD_VIDEOGAME_ASSET_OFF
-#define ICON_AUDIO_ON ICON_MD_VOLUME_UP
-#define ICON_AUDIO_OFF ICON_MD_VOLUME_OFF
-#define ICON_WINDOWED ICON_MD_FULLSCREEN_EXIT
-#define ICON_FULLSCREEN ICON_MD_FULLSCREEN
-#define ICON_LIGHTS_ON ICON_MD_LIGHTBULB
-#define ICON_LIGHTS_OFF ICON_MD_LIGHTBULB_OUTLINE
-#define ICON_RENDER_BASIC ICON_MD_IMAGE_SEARCH
-#define ICON_RENDER_FULL ICON_MD_INSERT_PHOTO
+// - editor reflects database contents up-to-date.
+// - database can be queried and modified via OSC(UDP) commands.
-#define ICON_SIGNAL ICON_MD_SIGNAL_CELLULAR_ALT
-#define ICON_DISK ICON_MD_STORAGE
-#define ICON_RATE ICON_MD_SPEED
+// editor database uses one table, and stores two kind of payload types:
+// - classes: defines typename and dna. class names are prefixed by '@'
+// - instances: defines typename and datas. instance names are as-is, not prefixed.
+//
+// every save contains 5Ws: what, who, when, where, how,
+// every save can be diffed/merged.
-#define ICON_CLOCK ICON_MD_TODAY
-#define ICON_CHRONO ICON_MD_TIMELAPSE
+// ----------------------------------------------------------------------------
-#define ICON_SETTINGS ICON_MD_SETTINGS
-#define ICON_LANGUAGE ICON_MD_G_TRANSLATE
-#define ICON_PERSONA ICON_MD_FACE
-#define ICON_SOCIAL ICON_MD_MESSAGE
-#define ICON_GAME ICON_MD_ROCKET_LAUNCH
-#define ICON_KEYBOARD ICON_MD_KEYBOARD
-#define ICON_MOUSE ICON_MD_MOUSE
-#define ICON_GAMEPAD ICON_MD_GAMEPAD
-#define ICON_MONITOR ICON_MD_MONITOR
-#define ICON_WIFI ICON_MD_WIFI
-#define ICON_BUDGET ICON_MD_SAVINGS
-#define ICON_NEW_FOLDER ICON_MD_CREATE_NEW_FOLDER
-#define ICON_PLUGIN ICON_MD_EXTENSION
-#define ICON_RESTART ICON_MD_REPLAY
-#define ICON_QUIT ICON_MD_CLOSE
+#define EDITOR_VERSION "2023.10"
-#define ICON_POWER ICON_MD_BOLT // ICON_MD_POWER
-#define ICON_BATTERY_CHARGING ICON_MD_BATTERY_CHARGING_FULL
-#define ICON_BATTERY_LEVELS \
- ICON_MD_BATTERY_ALERT, \
- ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, \
- ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR, \
- ICON_MD_BATTERY_4_BAR,ICON_MD_BATTERY_5_BAR, \
- ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL
+// ----------------------------------------------------------------------------
-char *editor_path(const char *path) {
- return va("%s/%s", EDITOR, path);
+typedef struct editor_bind_t {
+ const char *command;
+ const char *bindings;
+ void (*fn)();
+} editor_bind_t;
+
+array(editor_bind_t) editor_binds;
+
+#define EDITOR_BIND(CMD,KEYS,...) void macro(editor_bind_##CMD##_fn_)() { __VA_ARGS__ }; AUTORUN { array_push(editor_binds, ((editor_bind_t){#CMD,KEYS,macro(editor_bind_##CMD##_fn_)}) ); }
+
+// ----------------------------------------------------------------------------
+
+typedef void (*editor_no_property)(void *);
+array(void*) editor_persist_kv;
+array(editor_no_property) editor_no_properties;
+
+#define EDITOR_PROPERTY(property_name,T,defaults) \
+typedef map(void*,T) editor_##property_name##_map_t; \
+editor_##property_name##_map_t *editor_##property_name##_map() { \
+ static editor_##property_name##_map_t map = 0; do_once map_init_ptr(map); \
+ return ↦ \
+} \
+T editor_##property_name(const void *obj) { \
+ return *map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) defaults)); \
+} \
+void editor_set##property_name(const void *obj, T value) { \
+ *map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) value)) = ((T) value); \
+} \
+void editor_alt##property_name(const void *obj) { \
+ T* found = map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) defaults)); \
+ *found = (T)(uintptr_t)!(*found); \
+} \
+void editor_no##property_name(void *obj) { \
+ T* found = map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) defaults)); \
+ map_erase(*editor_##property_name##_map(), (void*)obj); \
+} \
+AUTORUN { array_push(editor_persist_kv, #T); array_push(editor_persist_kv, editor_##property_name##_map()); array_push(editor_no_properties, editor_no##property_name); }
+
+EDITOR_PROPERTY(open, int, 0); // whether object is tree opened in tree editor
+EDITOR_PROPERTY(selected, int, 0); // whether object is displaying a contextual popup or not
+EDITOR_PROPERTY(changed, int, 0); // whether object is displaying a contextual popup or not
+EDITOR_PROPERTY(popup, int, 0); // whether object is displaying a contextual popup or not
+EDITOR_PROPERTY(visible, int, 0);
+EDITOR_PROPERTY(script, int, 0);
+EDITOR_PROPERTY(event, int, 0);
+EDITOR_PROPERTY(iconinstance, char*, 0);
+EDITOR_PROPERTY(iconclass, char*, 0);
+EDITOR_PROPERTY(treeoffsety, int, 0);
+// new prop: breakpoint: request to break on any given node
+// new prop: persist: objects with this property will be saved on disk
+
+void editor_destroy_properties(void *o) {
+ for each_array(editor_no_properties,editor_no_property,fn) {
+ fn(o);
+ }
}
-vec3 editor_pick(float mouse_x, float mouse_y) {
-#if 0
- // unproject 2d coord as 3d coord
- camera_t *camera = camera_get_active();
- vec3 out, xyd = vec3(mouse_x,window_height()-mouse_y,1); // usually x:mouse_x,y:window_height()-mouse_y,d:0=znear/1=zfar
- mat44 mvp, model; identity44(model); multiply44x3(mvp, camera->proj, camera->view, model);
- bool ok = unproject44(&out, xyd, vec4(0,0,window_width(),window_height()), mvp);
- return out;
-#else
- // unproject 2d coord as 3d coord
- vec2 dpi = ifdef(osx, window_dpi(), vec2(1,1));
- camera_t *camera = camera_get_active();
- float x = (2.0f * mouse_x) / (dpi.x * window_width()) - 1.0f;
- float y = 1.0f - (2.0f * mouse_y) / (dpi.y * window_height());
- float z = 1.0f;
- vec3 ray_nds = vec3(x, y, z);
- vec4 ray_clip = vec4(ray_nds.x, ray_nds.y, -1.0, 1.0);
- mat44 inv_proj; invert44(inv_proj, camera->proj);
- mat44 inv_view; invert44(inv_view, camera->view);
- vec4 p = transform444(inv_proj, ray_clip);
- vec4 eye = vec4(p.x, p.y, -1.0, 0.0);
- vec4 wld = norm4(transform444(inv_view, eye));
- return vec3(wld.x, wld.y, wld.z);
-#endif
+void editor_load_on_boot(void) {
+}
+void editor_save_on_quit(void) {
+}
+AUTORUN {
+ editor_load_on_boot();
+ (atexit)(editor_save_on_quit);
}
-#if 0
-int editor_ui_bits8(const char *label, uint8_t *enabled) { // @to deprecate
- int clicked = 0;
- uint8_t copy = *enabled;
+// ----------------------------------------------------------------------------
- // @fixme: better way to retrieve widget width? nk_layout_row_dynamic() seems excessive
- nk_layout_row_dynamic(ui_ctx, 1, 1);
- struct nk_rect bounds = nk_widget_bounds(ui_ctx);
+typedef int(*subeditor)(int mode);
- // actual widget: label + 8 checkboxes
- enum { HEIGHT = 18, BITS = 8, SPAN = 118 }; // bits widget below needs at least 118px wide
- nk_layout_row_begin(ui_ctx, NK_STATIC, HEIGHT, 1+BITS);
+struct editor_t {
+ // time
+ unsigned frame;
+ double t, dt, slomo;
+ // controls
+ int transparent;
+ int attached;
+ int active; // focus? does_grabinput instead?
+ int key;
+ vec2 mouse; // 2d coord for ray/picking
+ bool gamepad; // mask instead? |1|2|4|8
+ int hz_high, hz_medium, hz_low;
+ int filter;
+ bool battery; // battery mode: low fps
+ bool unlit;
+ bool ddraw;
+ // event root nodes
+ obj* root;
+ obj* on_init;
+ obj* on_tick;
+ obj* on_draw;
+ obj* on_edit;
+ obj* on_quit;
+ // all of them (hierarchical)
+ array(obj*) objs; // @todo:set() world?
+ // all of them (flat)
+ set(obj*) world;
+ //
+ array(char*) cmds;
+ // subeditors
+ array(subeditor) subeditors;
+} editor = {
+ .active = 1,
+ .gamepad = 1,
+ .hz_high = 60, .hz_medium = 18, .hz_low = 5,
+};
- int offset = bounds.w > SPAN ? bounds.w - SPAN : 0;
- nk_layout_row_push(ui_ctx, offset);
- if( ui_label_(label, NK_TEXT_LEFT) ) clicked = 1<<31;
+enum {
+ EDITOR_PANEL,
+ EDITOR_WINDOW,
+ EDITOR_WINDOW_NK,
+ EDITOR_WINDOW_NK_SMALL,
+};
- for( int i = 0; i < BITS; ++i ) {
- nk_layout_row_push(ui_ctx, 10);
- // bit
- int val = (*enabled >> i) & 1;
- int chg = nk_checkbox_label(ui_ctx, "", &val);
- *enabled = (*enabled & ~(1 << i)) | ((!!val) << i);
- // tooltip
- struct nk_rect bb = { offset + 10 + i * 14, bounds.y, 14, HEIGHT }; // 10:padding,14:width
- if (nk_input_is_mouse_hovering_rect(&ui_ctx->input, bb) && !ui_popups()) {
- const char *tips[BITS] = {"Init","Tick","Draw","Quit","","","",""};
- if(tips[i][0]) nk_tooltipf(ui_ctx, "%s", tips[i]);
- }
- }
+int editor_begin(const char *title, int mode) {
+ if( mode == 0 ) return ui_panel(title, PANEL_OPEN);
+ if( mode == 1 ) return ui_window(title, 0);
- nk_layout_row_end(ui_ctx);
- return clicked | (copy ^ *enabled);
-}
-#endif
+ int ww = window_width(), w = ww * 0.66;
+ int hh = window_height(), h = hh * 0.66;
+ struct nk_rect position = { (ww-w)/2,(hh-h)/2, w,h };
+ nk_flags win_flags = NK_WINDOW_TITLE | NK_WINDOW_BORDER |
+ NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE |
+ NK_WINDOW_CLOSABLE | NK_WINDOW_MINIMIZABLE |
+ // NK_WINDOW_SCALE_LEFT|NK_WINDOW_SCALE_TOP| //< @fixme: move this logic into nuklear
+ // NK_WINDOW_MAXIMIZABLE | NK_WINDOW_PINNABLE |
+ 0; // NK_WINDOW_SCROLL_AUTO_HIDE;
-typedef union engine_var {
- int i;
- float f;
- char *s;
-} engine_var;
-static map(char*,engine_var) engine_vars;
-float *engine_getf(const char *key) {
- if(!engine_vars) map_init_str(engine_vars);
- engine_var *found = map_find_or_add(engine_vars, (char*)key, ((engine_var){0}) );
- return &found->f;
-}
-int *engine_geti(const char *key) {
- if(!engine_vars) map_init_str(engine_vars);
- engine_var *found = map_find_or_add(engine_vars, (char*)key, ((engine_var){0}) );
- return &found->i;
-}
-char **engine_gets(const char *key) {
- if(!engine_vars) map_init_str(engine_vars);
- engine_var *found = map_find_or_add(engine_vars, (char*)key, ((engine_var){0}) );
- if(!found->s) found->s = stringf("%s","");
- return &found->s;
-}
-
-int engine_send(const char *cmd, const char *optional_value) {
- unsigned *gamepads = engine_geti("gamepads"); // 0 off, mask gamepad1(1), gamepad2(2), gamepad3(4), gamepad4(8)...
- unsigned *renders = engine_geti("renders"); // 0 off, mask: 1=lit, 2=ddraw, 3=whiteboxes
- float *speed = engine_getf("speed"); // <0 num of frames to advance, 0 paused, [0..1] slomo, 1 play regular speed, >1 fast-forward (x2/x4/x8)
- unsigned *powersave = engine_geti("powersave");
-
- char *name;
- /**/ if( !strcmp(cmd, "key_quit" )) record_stop(), exit(0);
- else if( !strcmp(cmd, "key_stop" )) window_pause(1);
- else if( !strcmp(cmd, "key_mute" )) audio_volume_master( 1 ^ !!audio_volume_master(-1) );
- else if( !strcmp(cmd, "key_pause" )) window_pause( window_has_pause() ^ 1 );
- else if( !strcmp(cmd, "key_reload" )) window_reload();
- else if( !strcmp(cmd, "key_battery" )) *powersave = optional_value ? !!atoi(optional_value) : *powersave ^ 1;
- else if( !strcmp(cmd, "key_browser" )) ui_show("File Browser", ui_visible("File Browser") ^ true);
- else if( !strcmp(cmd, "key_outliner" )) ui_show("Outliner", ui_visible("Outliner") ^ true);
- else if( !strcmp(cmd, "key_record" )) if(record_active()) record_stop(), ui_notify(va("Video recorded"), date_string()); else
- app_beep(), name = file_counter(va("%s.mp4",app_name())), window_record(name);
- else if( !strcmp(cmd, "key_screenshot" )) name = file_counter(va("%s.png",app_name())), window_screenshot(name), ui_notify(va("Screenshot: %s", name), date_string());
- else if( !strcmp(cmd, "key_profiler" )) ui_show("Profiler", profiler_enable(ui_visible("Profiler") ^ true));
- else if( !strcmp(cmd, "key_fullscreen" )) record_stop(), window_fullscreen( window_has_fullscreen() ^ 1 ); // framebuffer resizing corrupts video stream, so stop any recording beforehand
- else if( !strcmp(cmd, "key_gamepad" )) *gamepads = (*gamepads & ~1u) | ((*gamepads & 1) ^ 1);
- else if( !strcmp(cmd, "key_lit" )) *renders = (*renders & ~1u) | ((*renders & 1) ^ 1);
- else if( !strcmp(cmd, "key_ddraw" )) *renders = (*renders & ~2u) | ((*renders & 2) ^ 2);
- else alert(va("editor could not handle `%s` command.", cmd));
-
- return 0;
-}
-
-int engine_tick() {
- enum { engine_hz = 60 };
- enum { engine_hz_mid = 18 };
- enum { engine_hz_low = 5 };
- if( *engine_geti("powersave") ) {
- // adaptive framerate
- int app_on_background = !window_has_focus();
- int hz = app_on_background ? engine_hz_low : engine_hz_mid;
- window_fps_lock( hz < 5 ? 5 : hz );
- } else {
- // window_fps_lock( editor_hz );
+ if( mode == 3 ) {
+ mode = 2, position.x = input(MOUSE_X), position.w = w/3, win_flags =
+ NK_WINDOW_TITLE|NK_WINDOW_CLOSABLE|
+ NK_WINDOW_SCALABLE|NK_WINDOW_MOVABLE| //< nuklear requires these two to `remember` popup rects
+ 0;
}
+ if( mode == 2 || mode == 3 )
+ if (nk_begin(ui_ctx, title, position, win_flags))
+ return 1;
+ else
+ return nk_end(ui_ctx), 0;
+
+ return 0;
+}
+int editor_end(int mode) {
+ if( mode == 0 ) return ui_panel_end();
+ if( mode == 1 ) return ui_window_end();
+ if( mode == 2 ) nk_end(ui_ctx);
+ if( mode == 3 ) nk_end(ui_ctx);
return 0;
}
-int ui_debug() {
- static int time_factor = 0;
- static int playing = 0;
- static int paused = 0;
- int advance_frame = 0;
+#if 0 // deprecate
+bool editor_active() {
+ return ui_hover() || ui_active() || gizmo_active() ? editor.active : 0;
+}
+#endif
-#if 0
- static int do_filter = 0;
- static int do_profile = 0;
- static int do_extra = 0;
+int editor_filter() {
+ if( editor.filter ) {
+ if (nk_begin(ui_ctx, "Filter", nk_rect(window_width()-window_width()*0.33,32, window_width()*0.33, 40),
+ NK_WINDOW_NO_SCROLLBAR)) {
- char *EDITOR_TOOLBAR_ICONS = va("%s;%s;%s;%s;%s;%s;%s;%s",
- do_filter ? ICON_MD_CLOSE : ICON_MD_SEARCH,
- ICON_MD_PLAY_ARROW,
- paused ? ICON_MD_SKIP_NEXT : ICON_MD_PAUSE,
- ICON_MD_FAST_FORWARD,
- ICON_MD_STOP,
- ICON_MD_REPLAY,
- ICON_MD_FACE,
- ICON_MD_MENU
- );
-
- if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1;
- int choice = ui_toolbar(EDITOR_TOOLBAR_ICONS);
- if( choice == 1 ) do_filter ^= 1, do_profile = 0, do_extra = 0;
- if( choice == 2 ) playing = 1, paused = 0;
- if( choice == 3 ) advance_frame = !!paused, paused = 1;
- if( choice == 4 ) paused = 0, time_factor = (++time_factor) % 4;
- if( choice == 5 ) playing = 0, paused = 0, advance_frame = 0, time_factor = 0;
- if( choice == 6 ) window_reload();
- if( choice == 7 ) do_filter = 0, do_profile ^= 1, do_extra = 0;
- if( choice == 8 ) do_filter = 0, do_profile = 0, do_extra ^= 1;
-
- if( do_filter ) {
char *bak = ui_filter; ui_filter = 0;
ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &bak);
ui_filter = bak;
- if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon)
- do_filter = 0;
- }
- } else {
- if( ui_filter ) ui_filter[0] = '\0';
- }
- char *filter_mask = ui_filter && ui_filter[0] ? va("*%s*", ui_filter) : "*";
- static char *username = 0;
- static char *userpass = 0;
- if( do_profile ) {
- ui_string(ICON_MD_FACE " Username", &username);
- ui_string(ICON_MD_FACE " Password", &userpass);
+ if( input(KEY_ESC) || ( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 )) {
+ if( ui_filter ) ui_filter[0] = '\0';
+ editor.filter = 0;
+ }
+ }
+ nk_end(ui_ctx);
}
- if( do_extra ) {
- int choice2 = ui_label2_toolbar(NULL,
- ICON_MD_VIEW_IN_AR
- ICON_MD_MESSAGE
- ICON_MD_TIPS_AND_UPDATES ICON_MD_LIGHTBULB ICON_MD_LIGHTBULB_OUTLINE
- ICON_MD_IMAGE_SEARCH ICON_MD_INSERT_PHOTO
- ICON_MD_VIDEOGAME_ASSET ICON_MD_VIDEOGAME_ASSET_OFF
-
- ICON_MD_VOLUME_UP ICON_MD_VOLUME_OFF // audio_volume_master(-1) > 0
-
- ICON_MD_TROUBLESHOOT ICON_MD_SCHEMA ICON_MD_MENU
- );
+ return editor.filter;
}
-#endif
- int open = 0, clicked_or_toggled = 0;
+static
+int editor_select_(void *o, const char *mask) {
+ int matches = 0;
+ int off = mask[0] == '!', inv = mask[0] == '~';
+ int match = strmatchi(obj_type(o), mask+off+inv) || strmatchi(obj_name(o), mask+off+inv);
+ if( match ) {
+ editor_setselected(o, inv ? editor_selected(o) ^ 1 : !off);
+ ++matches;
+ }
+ for each_objchild(o, obj*, oo) {
+ matches += editor_select_(oo, mask);
+ }
+ return matches;
+}
+void editor_select(const char *mask) {
+ for each_array( editor.objs, obj*, o )
+ editor_select_(o, mask);
+}
+void editor_unselect() { // same than editor_select("!**");
+ for each_map_ptr(*editor_selected_map(), void*,o, int, k) {
+ if( *k ) *k = 0;
+ }
+ }
+void editor_select_aabb(aabb box) {
+ int is_inv = input_held(KEY_CTRL);
+ int is_add = input_held(KEY_SHIFT);
+ if( !is_inv && !is_add ) editor_unselect();
- #define EDITOR_UI_COLLAPSE(f,...) \
- for( int macro(p) = (open = ui_collapse(f,__VA_ARGS__)), macro(dummy) = (clicked_or_toggled = ui_collapse_clicked()); macro(p); ui_collapse_end(), macro(p) = 0)
-
- EDITOR_UI_COLLAPSE(ICON_MD_VIEW_QUILT " Windows", "Debug.Windows") {
- int choice = ui_toolbar(ICON_MD_RECYCLING "@Reset layout;" ICON_MD_SAVE_AS "@Save layout");
- if( choice == 1 ) ui_layout_all_reset("*");
- if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*");
-
- for each_map_ptr_sorted(ui_windows, char*, k, unsigned, v) {
- bool visible = ui_visible(*k);
- if( ui_bool( *k, &visible ) ) {
- ui_show( *k, ui_visible(*k) ^ true );
+ aabb item = {0};
+ for each_set_ptr( editor.world, obj*, o ) {
+ if( obj_hasmethod(*o,aabb) && obj_aabb(*o, &item) ) {
+ if( aabb_test_aabb(item, box) ) {
+ if( is_inv )
+ editor_altselected(*o);
+ else
+ editor_setselected(*o, 1);
}
}
}
+}
- EDITOR_UI_COLLAPSE(ICON_MD_BUG_REPORT " Bugs 0", "Debug.Bugs") {
- // @todo. parse /bugs.ini, includes saved screenshots & videos.
- // @todo. screenshot include parseable level, position screen markers (same info as /bugs.ini)
+static obj* active_ = 0;
+static void editor_selectgroup_(obj *o, obj *first, obj *last) {
+ // printf("%s (looking for %s in [%s..%s])\n", obj_name(o), active_ ? obj_name(active_) : "", obj_name(first), obj_name(last));
+ if( !active_ ) if( o == first || o == last ) active_ = o == first ? last : first;
+ if( active_ ) editor_setselected(o, 1);
+ if( o == active_ ) active_ = 0;
+ for each_objchild(o, obj*, oo) {
+ editor_selectgroup_(oo, first, last);
}
-
-
- // Art and bookmarks
- EDITOR_UI_COLLAPSE(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art") {
- bool inlined = true;
- const char *file = 0;
- if( ui_browse(&file, &inlined) ) {
- const char *sep = ifdef(win32, "\"", "'");
- app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep));
- }
- }
- EDITOR_UI_COLLAPSE(ICON_MD_BOOKMARK " Bookmarks", "Debug.Bookmarks") { /* @todo */ }
-
-
- // E,C,S,W
- EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Scene", "Debug.Scene") {
- EDITOR_UI_COLLAPSE(ICON_MD_BUBBLE_CHART/*ICON_MD_SCATTER_PLOT*/ " Entities", "Debug.Entities") { /* @todo */ }
- EDITOR_UI_COLLAPSE(ICON_MD_TUNE " Components", "Debug.Components") { /* @todo */ }
- EDITOR_UI_COLLAPSE(ICON_MD_PRECISION_MANUFACTURING " Systems", "Debug.Systems") { /* @todo */ }
- EDITOR_UI_COLLAPSE(ICON_MD_PUBLIC " Levels", "Debug.Levels") {
- //node_edit(editor.edit.down,&editor.edit);
- }
-
- //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Init", "Debug.HierarchyInit") { /* @todo */ }
- //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Draw", "Debug.HierarchyDraw") { /* @todo */ }
- //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Tick", "Debug.HierarchyTick") { /* @todo */ }
- //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Edit", "Debug.HierarchyEdit") { /* @todo */ }
- //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Quit", "Debug.HierarchyQuit") { /* @todo */ }
-
- // node_edit(&editor.init,&editor.init);
- // node_edit(&editor.draw,&editor.draw);
- // node_edit(&editor.tick,&editor.tick);
- // node_edit(&editor.edit,&editor.edit);
- // node_edit(&editor.quit,&editor.quit);
- }
-
- EDITOR_UI_COLLAPSE(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI") {
- // @todo
- }
- EDITOR_UI_COLLAPSE(ICON_MD_VOLUME_UP " Audio", "Debug.Audio") {
- ui_audio();
- }
- EDITOR_UI_COLLAPSE(ICON_MD_VIDEOCAM " Camera", "Debug.Camera") {
- ui_camera( camera_get_active() );
- }
- EDITOR_UI_COLLAPSE(ICON_MD_MONITOR " Display", "Debug.Display") {
- // @todo: fps lock, fps target, aspect ratio, fullscreen
- char *text = va("%s;%s;%s",
- window_has_fullscreen() ? ICON_MD_FULLSCREEN_EXIT : ICON_MD_FULLSCREEN,
- ICON_MD_PHOTO_CAMERA,
- record_active() ? ICON_MD_VIDEOCAM_OFF : ICON_MD_VIDEOCAM
- );
-
- int choice = ui_toolbar(text);
- if( choice == 1 ) engine_send("key_fullscreen",0);
- if( choice == 2 ) engine_send("key_screenshot",0);
- if( choice == 3 ) engine_send("key_record",0);
- }
- EDITOR_UI_COLLAPSE(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard") {
- ui_keyboard();
- }
- EDITOR_UI_COLLAPSE(ICON_MD_MOUSE " Mouse", "Debug.Mouse") {
- ui_mouse();
- }
- EDITOR_UI_COLLAPSE(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads") {
- for( int q = 0; q < 4; ++q ) {
- for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) {
- ui_gamepad(q);
+}
+void editor_selectgroup(obj *first, obj *last) {
+ if( last ) {
+ if( !first ) first = array_count(editor.objs) ? editor.objs[0] : NULL;
+ if( !first ) editor_setselected(last, 1);
+ else {
+ active_ = 0;
+ for each_array(editor.objs,obj*,o) {
+ editor_selectgroup_(o, first, last);
}
}
- }
-
-
- EDITOR_UI_COLLAPSE(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts") {
- // @todo
- }
- EDITOR_UI_COLLAPSE(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders") {
- ui_shaders();
- }
- EDITOR_UI_COLLAPSE(ICON_MD_MOVIE " FXs", "Debug.FXs") {
- ui_fxs();
- }
-
-
- EDITOR_UI_COLLAPSE(ICON_MD_SAVINGS " Budgets", "Debug.Budgets") {
- // @todo. // mem,fps,gfx,net,hdd,... also logging
- }
- EDITOR_UI_COLLAPSE(ICON_MD_WIFI/*ICON_MD_SIGNAL_CELLULAR_ALT*/ " Network 0/0 KiB", "Debug.Network") {
- // @todo
- // SIGNAL_CELLULAR_1_BAR SIGNAL_CELLULAR_2_BAR
- }
- EDITOR_UI_COLLAPSE(va(ICON_MD_SPEED " Profiler %5.2f/%dfps", window_fps(), (int)window_fps_target()), "Debug.Profiler") {
- ui_profiler();
- }
- EDITOR_UI_COLLAPSE(va(ICON_MD_STORAGE " Storage %s", xstats()), "Debug.Storage") {
- // @todo
- }
-
-
-
- // logic: either plug icon (power saving off) or one of the following ones (power saving on):
- // if 0% batt (no batt): battery alert
- // if discharging: battery levels [alert,0..6,full]
- // if charging: battery charging
- int battery_read = app_battery();
- int battery_level = abs(battery_read);
- int battery_discharging = battery_read < 0 && battery_level < 100;
- const char *power_icon_label = ICON_MD_POWER " Power";
- if( battery_level ) {
- const char *battery_levels[9] = { // @todo: remap [7%..100%] -> [0..1] ?
- ICON_MD_BATTERY_ALERT,ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR,
- ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR,ICON_MD_BATTERY_4_BAR,
- ICON_MD_BATTERY_5_BAR,ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL,
- };
- power_icon_label = (const char*)va("%s Power %d%%",
- battery_discharging ? battery_levels[(int)((9-1)*clampf(battery_level/100.f,0,1))] : ICON_MD_BATTERY_CHARGING_FULL,
- battery_level);
- }
-
- EDITOR_UI_COLLAPSE(power_icon_label, "Debug.Power") {
- int choice = ui_toolbar( ICON_MD_POWER ";" ICON_MD_BOLT );
- if( choice == 1 ) engine_send("key_battery","0");
- if( choice == 2 ) engine_send("key_battery","1");
- }
-
- EDITOR_UI_COLLAPSE(ICON_MD_WATER " Reflection", "Debug.Reflect") {
- ui_reflect("*");
- }
-
- EDITOR_UI_COLLAPSE(ICON_MD_EXTENSION " Plugins", "Debug.Plugins") {
- // @todo. include VCS
- EDITOR_UI_COLLAPSE(ICON_MD_BUILD " Cook", "Debug.Cook") {
- // @todo
}
}
+static obj *find_any_selected_(obj *o) {
+ if( editor_selected(o) ) return o;
+ for each_objchild(o,obj*,oo) {
+ obj *ooo = find_any_selected_(oo);
+ if( ooo )
+ return ooo;
+ }
+ return 0;
+}
+void* editor_first_selected() {
+ for each_array(editor.objs,obj*,o) {
+ obj *oo = find_any_selected_(o);
+ // if( oo ) printf("1st found: %s\n", obj_name(oo));
+ if( oo ) return oo;
+}
return 0;
}
-static int gizmo__mode;
-static int gizmo__active;
-static int gizmo__hover;
-bool gizmo_active() {
- return gizmo__active;
+static obj *find_last_selected_(obj *o) {
+ void *last = 0;
+ if( editor_selected(o) ) last = o;
+ for each_objchild(o,obj*,oo) {
+ obj *ooo = find_last_selected_(oo);
+ if( ooo )
+ last = ooo;
}
-bool gizmo_hover() {
- return gizmo__hover;
+ return last;
}
-int gizmo(vec3 *pos, vec3 *rot, vec3 *sca) {
-#if 0
- ddraw_flush();
- mat44 copy; copy44(copy, camera_get_active()->view);
- if( 1 ) {
- float *mv = camera_get_active()->view;
- float d = sqrt(mv[4*0+0] * mv[4*0+0] + mv[4*1+1] * mv[4*1+1] + mv[4*2+2] * mv[4*2+2]);
- if(4) mv[4*0+0] = d, mv[4*0+1] = 0, mv[4*0+2] = 0;
- if(2) mv[4*1+0] = 0, mv[4*1+1] = d, mv[4*1+2] = 0;
- if(1) mv[4*2+0] = 0, mv[4*2+1] = 0, mv[4*2+2] = d;
+void* editor_last_selected() {
+ void *last = 0;
+ for each_array(editor.objs,obj*,o) {
+ obj *oo = find_last_selected_(o);
+ // if( oo ) printf("last found: %s\n", obj_name(oo));
+ if( oo ) last = oo;
+}
+ return last;
+}
+
+// ----------------------------------------------------------------------------------------
+
+void editor_addtoworld(obj *o) {
+ set_find_or_add(editor.world, o);
+ for each_objchild(o, obj*, oo) {
+ editor_addtoworld(oo);
+}
+}
+
+void editor_watch(const void *o) {
+ array_push(editor.objs, (obj*)o);
+ obj_push(o); // save state
+
+ editor_addtoworld((obj*)o);
+}
+void* editor_spawn(const char *ini) { // deprecate?
+ obj *o = obj_make(ini);
+ editor_watch(o);
+ return o;
+}
+void editor_spawn1() {
+ obj *selected = editor_first_selected();
+ obj *o = selected ? obj_make(obj_saveini(selected)) : obj_new(obj);
+ if( selected ) obj_attach(selected, o), editor_setopen(selected, 1);
+ else
+ editor_watch(o);
+
+ editor_unselect();
+ editor_setselected(o, 1);
+}
+
+typedef set(obj*) set_objp_t;
+static
+void editor_glob_recurse(set_objp_t*list, obj *o) {
+ set_find_or_add(*list, o);
+ for each_objchild(o,obj*,oo) {
+ editor_glob_recurse(list, oo);
}
-#endif
-
- ddraw_color_push(dd_color);
- ddraw_ontop_push(1);
-
- int enabled = !ui_active() && !ui_hover();
- vec3 mouse = enabled ? vec3(input(MOUSE_X),input(MOUSE_Y),input_down(MOUSE_L)) : vec3(0,0,0); // x,y,l
- vec3 from = camera_get_active()->position;
- vec3 to = editor_pick(mouse.x, mouse.y);
- ray r = ray(from, to);
-
- static vec3 src3, hit3, off3; static vec2 src2;
- #define on_gizmo_dragged(X,Y,Z,COLOR,DRAWCMD, ...) do { \
- vec3 dir = vec3(X,Y,Z); \
- line axis = {add3(*pos, scale3(dir,100)), add3(*pos, scale3(dir,-100))}; \
- plane ground = { vec3(0,0,0), vec3(Y?1:0,Y?0:1,0) }; \
- vec3 unit = vec3(X+(1.0-X)*0.3,Y+(1.0-Y)*0.3,Z+(1.0-Z)*0.3); \
- aabb arrow = { sub3(*pos,unit), add3(*pos,unit) }; \
- hit *hit_arrow = ray_hit_aabb(r, arrow), *hit_ground = ray_hit_plane(r, ground); \
- ddraw_color( hit_arrow || gizmo__active == (X*4+Y*2+Z) ? gizmo__hover = 1, YELLOW : COLOR ); \
- DRAWCMD; \
- if( !gizmo__active && hit_arrow && mouse.z ) src2 = vec2(mouse.x,mouse.y), src3 = *pos, hit3 = hit_ground->p, off3 = mul3(sub3(src3,hit3),vec3(X,Y,Z)), gizmo__active = X*4+Y*2+Z; \
- if( (gizmo__active && gizmo__active==(X*4+Y*2+Z)) || (!gizmo__active && hit_arrow) ) { ddraw_color( COLOR ); ( 1 ? ddraw_line : ddraw_line_dashed)(axis.a, axis.b); } \
- if( gizmo__active == (X*4+Y*2+Z) && hit_ground ) {{ __VA_ARGS__ }; modified = 1; gizmo__active *= !!input(MOUSE_L); } \
- } while(0)
- #define gizmo_translate(X,Y,Z,COLOR) \
- on_gizmo_dragged(X,Y,Z,COLOR, ddraw_arrow(*pos,add3(*pos,vec3(X,Y,Z))), { \
- *pos = add3(line_closest_point(axis, hit_ground->p), off3); \
- } )
- #define gizmo_scale(X,Y,Z,COLOR) \
- on_gizmo_dragged(X,Y,Z,COLOR, (ddraw_line(*pos,add3(*pos,vec3(X,Y,Z))),ddraw_sphere(add3(*pos,vec3(X-0.1*X,Y-0.1*Y,Z-0.1*Z)),0.1)), { /*ddraw_aabb(arrow.min,arrow.max)*/ \
- int component = (X*1+Y*2+Z*3)-1; \
- float mag = len2(sub2(vec2(mouse.x, mouse.y), src2)); \
- float magx = (mouse.x - src2.x) * (mouse.x - src2.x); \
- float magy = (mouse.y - src2.y) * (mouse.y - src2.y); \
- float sgn = (magx > magy ? mouse.x > src2.x : mouse.y > src2.y) ? 1 : -1; \
- sca->v3[component] -= sgn * mag * 0.01; \
- src2 = vec2(mouse.x, mouse.y); \
- } )
- #define gizmo_rotate(X,Y,Z,COLOR) do { \
- vec3 dir = vec3(X,Y,Z); \
- line axis = {add3(*pos, scale3(dir,100)), add3(*pos, scale3(dir,-100))}; \
- plane ground = { vec3(0,0,0), vec3(0,1,0) }; \
- vec3 unit = vec3(X+(1.0-X)*0.3,Y+(1.0-Y)*0.3,Z+(1.0-Z)*0.3); \
- aabb arrow = { sub3(*pos,unit), add3(*pos,unit) }; \
- hit *hit_arrow = ray_hit_aabb(r, arrow), *hit_ground = ray_hit_plane(r, ground); \
- int hover = (hit_arrow ? (X*4+Y*2+Z) : 0); \
- if( gizmo__active == (X*4+Y*2+Z) ) { ddraw_color(gizmo__active ? gizmo__hover = 1, YELLOW : WHITE); ddraw_circle(*pos, vec3(X,Y,Z), 1); } \
- else if( !gizmo__active && hover == (X*4+Y*2+Z) ) { gizmo__hover = 1; ddraw_color(COLOR); ddraw_circle(*pos, vec3(X,Y,Z), 1); } \
- else if( !gizmo__active ) { ddraw_color(WHITE); ddraw_circle(*pos, vec3(X,Y,Z), 1); } \
- if( !gizmo__active && hit_arrow && mouse.z ) src2 = vec2(mouse.x,mouse.y), gizmo__active = hover; \
- if( (!gizmo__active && hover == (X*4+Y*2+Z)) || gizmo__active == (X*4+Y*2+Z) ) { gizmo__hover = 1; ddraw_color( COLOR ); ( 1 ? ddraw_line_thin : ddraw_line_dashed)(axis.a, axis.b); } \
- if( gizmo__active && gizmo__active == (X*4+Y*2+Z) && hit_ground && enabled ) { \
- int component = (Y*1+X*2+Z*3)-1; /*pitch,yaw,roll*/ \
- float mag = len2(sub2(vec2(mouse.x, mouse.y), src2)); \
- float magx = (mouse.x - src2.x) * (mouse.x - src2.x); \
- float magy = (mouse.y - src2.y) * (mouse.y - src2.y); \
- float sgn = (magx > magy ? mouse.x > src2.x : mouse.y > src2.y) ? 1 : -1; \
- rot->v3[component] += sgn * mag; \
- /*rot->v3[component] = clampf(rot->v3[component], -360, +360);*/ \
- src2 = vec2(mouse.x, mouse.y); \
- \
- } \
- gizmo__active *= enabled && !!input(MOUSE_L); \
- } while(0)
-
- gizmo__hover = 0;
-
- int modified = 0;
- if(enabled && input_down(KEY_SPACE)) gizmo__active = 0, gizmo__mode = (gizmo__mode + 1) % 3;
- if(gizmo__mode == 0) gizmo_translate(1,0,0, RED);
- if(gizmo__mode == 0) gizmo_translate(0,1,0, GREEN);
- if(gizmo__mode == 0) gizmo_translate(0,0,1, BLUE);
- if(gizmo__mode == 1) gizmo_scale(1,0,0, RED);
- if(gizmo__mode == 1) gizmo_scale(0,1,0, GREEN);
- if(gizmo__mode == 1) gizmo_scale(0,0,1, BLUE);
- if(gizmo__mode == 2) gizmo_rotate(1,0,0, RED);
- if(gizmo__mode == 2) gizmo_rotate(0,1,0, GREEN);
- if(gizmo__mode == 2) gizmo_rotate(0,0,1, BLUE);
-
-#if 0
- ddraw_flush();
- copy44(camera_get_active()->view, copy);
-#endif
-
- ddraw_ontop_pop();
- ddraw_color_pop();
-
- return modified;
}
-
-// -- localization kit
-
-static const char *kit_lang = "enUS", *kit_langs =
- "enUS,enGB,"
- "frFR,"
- "esES,esAR,esMX,"
- "deDE,deCH,deAT,"
- "itIT,itCH,"
- "ptBR,ptPT,"
- "zhCN,zhSG,zhTW,zhHK,zhMO,"
- "ruRU,elGR,trTR,daDK,noNB,svSE,nlNL,plPL,fiFI,jaJP,"
- "koKR,csCZ,huHU,roRO,thTH,bgBG,heIL"
-;
-
-static map(char*,char*) kit_ids;
-static map(char*,char*) kit_vars;
-
-#ifndef KIT_FMT_ID2
-#define KIT_FMT_ID2 "%s.%s"
-#endif
-
-void kit_init() {
- do_once map_init(kit_ids, less_str, hash_str);
- do_once map_init(kit_vars, less_str, hash_str);
-}
-
-void kit_insert( const char *id, const char *translation) {
- char *id2 = va(KIT_FMT_ID2, kit_lang, id);
-
- char **found = map_find_or_add_allocated_key(kit_ids, STRDUP(id2), NULL);
- if(*found) FREE(*found);
- *found = STRDUP(translation);
-}
-
-bool kit_merge( const char *filename ) {
- // @todo: xlsx2ini
- return false;
-}
-
-void kit_clear() {
- map_clear(kit_ids);
-}
-
-bool kit_load( const char *filename ) {
- return kit_clear(), kit_merge( filename );
-}
-
-void kit_set( const char *key, const char *value ) {
- value = value && value[0] ? value : "";
-
- char **found = map_find_or_add_allocated_key(kit_vars, STRDUP(key), NULL );
- if(*found) FREE(*found);
- *found = STRDUP(value);
-}
-
-void kit_reset() {
- map_clear(kit_vars);
-}
-
-char *kit_translate2( const char *id, const char *lang ) {
- char *id2 = va(KIT_FMT_ID2, lang, id);
-
- char **found = map_find(kit_ids, id2);
-
- // return original [[ID]] if no translation is found
- if( !found ) return va("[[%s]]", id);
-
- // return translation if no {{moustaches}} are found
- if( !strstr(*found, "{{") ) return *found;
-
- // else replace all found {{moustaches}} with context vars
- {
- // make room
- static __thread char *results[16] = {0};
- static __thread unsigned counter = 0; counter = (counter+1) % 16;
-
- char *buffer = results[ counter ];
- if( buffer ) FREE(buffer), buffer = 0;
-
- // iterate moustaches
- const char *begin, *end, *text = *found;
- while( NULL != (begin = strstr(text, "{{")) ) {
- end = strstr(begin+2, "}}");
- if( end ) {
- char *var = va("%.*s", (int)(end - (begin+2)), begin+2);
- char **found_var = map_find(kit_vars, var);
-
- if( found_var && 0[*found_var] ) {
- strcatf(&buffer, "%.*s%s", (int)(begin - text), text, *found_var);
- } else {
- strcatf(&buffer, "%.*s{{%s}}", (int)(begin - text), text, var);
- }
-
- text = end+2;
- } else {
- strcatf(&buffer, "%.*s", (int)(begin - text), text);
-
- text = begin+2;
+void editor_destroy_selected() {
+ set_objp_t list = 0;
+ set_init_ptr(list);
+ for each_map_ptr(*editor_selected_map(), obj*,o, int,selected) {
+ if( *selected ) { editor_glob_recurse(&list, *o); }
+ }
+ for each_set(list, obj*, o) {
+ obj_detach(o);
+ }
+ for each_set(list, obj*, o) {
+ // printf("deleting %p %s\n", o, obj_name(o));
+ // remove from watched items
+ for (int i = 0, end = array_count(editor.objs); i < end; ++i) {
+ if (editor.objs[i] == o) {
+ editor.objs[i] = 0;
+ array_erase_slow(editor.objs, i);
+ --end;
+ --i;
}
}
+ // delete from world
+ set_erase(editor.world, o);
+ // delete properties + obj
+ editor_destroy_properties(o);
+ obj_free(o);
+ }
+ set_free(list);
+}
+void editor_inspect(obj *o) {
+ ui_section(va("%s (%s)", obj_type(o), obj_name(o)));
- strcatf(&buffer, "%s", text);
- return buffer;
+ if( obj_hasmethod(o, menu) ) {
+ obj_menu(o);
+ }
+
+ for each_objmember(o,TYPE,NAME,PTR) {
+ if( !editor_changed(PTR) ) {
+ obj_push(o);
+ }
+ ui_label_icon_highlight = editor_changed(PTR); // @hack: remove ui_label_icon_highlight hack
+ char *label = va(ICON_MD_UNDO "%s", NAME);
+ int changed = 0;
+ /**/ if( !strcmp(TYPE,"float") ) changed = ui_float(label, PTR);
+ else if( !strcmp(TYPE,"int") ) changed = ui_int(label, PTR);
+ else if( !strcmp(TYPE,"vec2") ) changed = ui_float2(label, PTR);
+ else if( !strcmp(TYPE,"vec3") ) changed = ui_float3(label, PTR);
+ else if( !strcmp(TYPE,"vec4") ) changed = ui_float4(label, PTR);
+ else if( !strcmp(TYPE,"rgb") ) changed = ui_color3(label, PTR);
+ else if( !strcmp(TYPE,"rgba") ) changed = ui_color4(label, PTR);
+ else if( !strcmp(TYPE,"color") ) changed = ui_color4f(label, PTR);
+ else if( !strcmp(TYPE,"color3f") ) changed = ui_color3f(label, PTR);
+ else if( !strcmp(TYPE,"color4f") ) changed = ui_color4f(label, PTR);
+ else if( !strcmp(TYPE,"char*") ) changed = ui_string(label, PTR);
+ else ui_label2(label, va("(%s)", TYPE)); // INFO instead of (TYPE)?
+ if( changed ) {
+ editor_setchanged(PTR, 1);
+ }
+ if( ui_label_icon_highlight )
+ if( ui_label_icon_clicked_L.x >= 6 && ui_label_icon_clicked_L.x <= 26 ) { // @hack: if clicked on UNDO icon (1st icon)
+ editor_setchanged(PTR, 0);
+ }
+ if( !editor_changed(PTR) ) {
+ obj_pop(o);
+ }
}
}
-char *kit_translate( const char *id ) {
- return kit_translate2( id, kit_lang );
-}
+// ----------------------------------------------------------------------------------------
+// tty
-void kit_locale( const char *lang ) {
- kit_lang = STRDUP(lang); // @leak
-}
-
-void kit_dump_state( FILE *fp ) {
- for each_map(kit_ids, char *, k, char *, v) {
- fprintf(fp, "[ID ] %s=%s\n", k, v);
+static thread_mutex_t *console_lock;
+static array(char*) editor_jobs;
+int editor_send(const char *cmd) { // return job-id
+ int skip = strspn(cmd, " \t\r\n");
+ char *buf = STRDUP(cmd + skip);
+ strswap(buf, "\r\n", "");
+ int jobid;
+ do_threadlock(console_lock) {
+ array_push(editor_jobs, buf);
+ jobid = array_count(editor_jobs) - 1;
}
- for each_map(kit_vars, char *, k, char *, v) {
- fprintf(fp, "[VAR] %s=%s\n", k, v);
+ return jobid;
+}
+const char* editor_recv(int jobid, double timeout_ss) {
+ char *answer = 0;
+
+ while(!answer && timeout_ss >= 0 ) {
+ do_threadlock(console_lock) {
+ if( editor_jobs[jobid][0] == '\0' )
+ answer = editor_jobs[jobid];
+ }
+ timeout_ss -= 0.1;
+ if( timeout_ss > 0 ) sleep_ms(100); // thread_yield()
+ }
+
+ return answer + 1;
+}
+
+// plain and ctrl keys
+EDITOR_BIND(play, "down(F5)", { window_pause(0); /* if(!editor.slomo) editor.active = 0; */ editor.slomo = 1; } );
+EDITOR_BIND(stop, "down(ESC)", { if(editor.t > 0) { window_pause(1), editor.frame = 0, editor.t = 0, editor.dt = 0, editor.slomo = 0, editor.active = 1; editor_select("**"); editor_destroy_selected(); }} );
+EDITOR_BIND(eject, "down(F1)", { /*window_pause(!editor.active); editor.slomo = !!editor.active;*/ editor.active ^= 1; } );
+EDITOR_BIND(pause, "(held(CTRL) & down(P)) | down(PAUSE)", { window_pause( window_has_pause() ^ 1 ); } );
+EDITOR_BIND(frame, "held(CTRL) & down(LEFT)", { window_pause(1); editor.frame++, editor.t += (editor.dt = 1/60.f); } );
+EDITOR_BIND(slomo, "held(CTRL) & down(RIGHT)", { window_pause(0); editor.slomo = maxf(fmod(editor.slomo * 2, 16), 0.125); } );
+EDITOR_BIND(reload, "held(CTRL) & down(F5)", { window_reload(); } );
+EDITOR_BIND(filter, "held(CTRL) & down(F)", { editor.filter ^= 1; } );
+
+// alt keys
+EDITOR_BIND(quit, "held(ALT) & down(F4)", { record_stop(), exit(0); } );
+EDITOR_BIND(mute, "held(ALT) & down(M)", { audio_volume_master( 1 ^ !!audio_volume_master(-1) ); } );
+EDITOR_BIND(gamepad, "held(ALT) & down(G)", { editor.gamepad ^= 1; } );
+EDITOR_BIND(transparent, "held(ALT) & down(T)", { editor.transparent ^= 1; } );
+EDITOR_BIND(record, "held(ALT) & down(Z)", { if(record_active()) record_stop(), ui_notify(va("Video recorded"), date_string()); else { char *name = file_counter(va("%s.mp4",app_name())); app_beep(), window_record(name); } } );
+EDITOR_BIND(screenshot, "held(ALT) & down(S)", { char *name = file_counter(va("%s.png",app_name())); window_screenshot(name), ui_notify(va("Screenshot: %s", name), date_string()); } );
+EDITOR_BIND(battery, "held(ALT) & down(B)", { editor.battery ^= 1; } );
+EDITOR_BIND(outliner, "held(ALT) & down(O)", { ui_show("Outliner", ui_visible("Outliner") ^ true); } );
+EDITOR_BIND(profiler, "held(ALT) & down(P)", { ui_show("Profiler", profiler_enable(ui_visible("Profiler") ^ true)); } );
+EDITOR_BIND(fullscreen, "(held(ALT)&down(ENTER))|down(F11)",{ record_stop(), window_fullscreen( window_has_fullscreen() ^ 1 ); } ); // close any recording before framebuffer resizing, which would corrupt video stream
+EDITOR_BIND(unlit, "held(ALT) & down(U)", { editor.unlit ^= 1; } );
+EDITOR_BIND(ddraw, "held(ALT) & down(D)", { editor.ddraw ^= 1; } );
+
+void editor_pump() {
+ for each_array(editor_binds,editor_bind_t,b) {
+ if( input_eval(b.bindings) ) {
+ editor_send(b.command);
+ }
+ }
+
+ do_threadlock(console_lock) {
+ for each_array_ptr(editor_jobs,char*,cmd) {
+ if( (*cmd)[0] ) {
+ int found = 0;
+ for each_array(editor_binds,editor_bind_t,b) {
+ if( !strcmpi(b.command, *cmd)) {
+ b.fn();
+ found = 1;
+ break;
+ }
+ }
+
+ if( !found ) {
+ // alert(va("Editor: could not handle `%s` command.", *cmd));
+ (*cmd)[0] = '\0'; strcatf(&(*cmd), "\1%s\n", "Err\n"); (*cmd)[0] = '\0';
+ }
+
+ if( (*cmd)[0] ) {
+ (*cmd)[0] = '\0'; strcatf(&(*cmd), "\1%s\n", "Ok\n"); (*cmd)[0] = '\0';
+ }
+ }
+ }
}
}
-/*
-int main() {
- kit_init();
+// ----------------------------------------------------------------------------------------
- kit_locale("enUS");
- kit_insert("HELLO_PLAYERS", "Hi {{PLAYER1}} and {{PLAYER2}}!");
- kit_insert("GREET_PLAYERS", "Nice to meet you.");
-
- kit_locale("esES");
- kit_insert("HELLO_PLAYERS", "Hola {{PLAYER1}} y {{PLAYER2}}!");
- kit_insert("GREET_PLAYERS", "Un placer conoceros.");
-
- kit_locale("enUS");
- printf("%s %s\n", kit_translate("HELLO_PLAYERS"), kit_translate("GREET_PLAYERS")); // Hi {{PLAYER1}} and {{PLAYER2}}! Nice to meet you.
-
- kit_locale("esES");
- kit_set("PLAYER1", "John");
- kit_set("PLAYER2", "Karl");
- printf("%s %s\n", kit_translate("HELLO_PLAYERS"), kit_translate("GREET_PLAYERS")); // Hola John y Karl! Un placer conoceros.
-
- assert( 0 == strcmp(kit_translate("NON_EXISTING"), "[[NON_EXISTING]]")); // [[NON_EXISTING]]
- assert(~puts("Ok"));
+void editor_symbol(int x, int y, const char *sym) {
+ #define FONT_SYMBOLS FONT_FACE2
+ #define FONT_WHITE FONT_COLOR1
+ #define FONT_YELLOW FONT_COLOR2
+ #define FONT_ORANGE FONT_COLOR3
+ #define FONT_CYAN FONT_COLOR4
+ // style: atlas size, unicode ranges and 6 font faces max
+ do_once font_face(FONT_SYMBOLS, "MaterialIconsSharp-Regular.otf", 24.f, FONT_EM|FONT_2048);
+ // style: 10 colors max
+ do_once font_color(FONT_WHITE, WHITE);
+ do_once font_color(FONT_YELLOW, YELLOW);
+ do_once font_color(FONT_CYAN, CYAN);
+ do_once font_color(FONT_ORANGE, ORANGE);
+ font_goto(x,y);
+ font_print(va(FONT_SYMBOLS FONT_WHITE FONT_H1 "%s", sym));
+}
+
+void editor_frame( void (*game)(unsigned, float, double) ) {
+ do_once {
+ set_init_ptr(editor.world);
+ //set_init_ptr(editor.selection);
+ profiler_enable( false );
+
+ window_pause( true );
+ window_cursor_shape(CURSOR_SW_AUTO);
+ editor.hz_high = window_fps_target();
+
+ fx_load("editorOutline.fs");
+ fx_enable(0, 1);
+
+ obj_setname(editor.root = obj_new(obj), "Signals");
+ obj_setname(editor.on_init = obj_new(obj), "onInit");
+ obj_setname(editor.on_tick = obj_new(obj), "onTick");
+ obj_setname(editor.on_draw = obj_new(obj), "onDraw");
+ obj_setname(editor.on_edit = obj_new(obj), "onEdit");
+ obj_setname(editor.on_quit = obj_new(obj), "onQuit");
+
+ obj_attach(editor.root, editor.on_init);
+ obj_attach(editor.root, editor.on_tick);
+ obj_attach(editor.root, editor.on_draw);
+ obj_attach(editor.root, editor.on_edit);
+ obj_attach(editor.root, editor.on_quit);
+
+ editor_seticoninstance(editor.root, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_init, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_tick, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_draw, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_edit, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_quit, ICON_MDI_SIGNAL_VARIANT);
+
+ editor_seticonclass(obj_type(editor.root), ICON_MDI_CUBE_OUTLINE);
+ }
+
+ // game tick
+ game(editor.frame, editor.dt, editor.t);
+
+ // timing
+ editor.dt = clampf(window_delta(), 0, 1/60.f) * !window_has_pause() * editor.slomo;
+ editor.t += editor.dt;
+ editor.frame += !window_has_pause();
+ editor.frame += !editor.frame;
+
+ // process inputs & messages
+ editor_pump();
+
+ // adaptive framerate
+ int app_on_background = !window_has_focus();
+ int hz = app_on_background ? editor.hz_low : editor.battery ? editor.hz_medium : editor.hz_high;
+ window_fps_lock( hz < 5 ? 5 : hz );
+
+ // draw menubar
+ static int stats_mode = 1;
+ static double last_fps = 0; if(!window_has_pause()) last_fps = window_fps();
+ const char *STATS = va("x%4.3f %03d.%03dss %02dF %s",
+ editor.slomo, (int)editor.t, (int)(1000 * (editor.t - (int)editor.t)),
+ (editor.frame-1) % ((int)window_fps_target() + !(int)window_fps_target()),
+ stats_mode == 1 ? va("%5.2f/%dfps", last_fps, (int)window_fps_target()) : stats_mode == 0 ? "0/0 KiB" : xstats());
+ const char *ICON_PL4Y = window_has_pause() ? ICON_MDI_PLAY : ICON_MDI_PAUSE;
+ const char *ICON_SKIP = window_has_pause() ? ICON_MDI_STEP_FORWARD/*ICON_MDI_SKIP_NEXT*/ : ICON_MDI_FAST_FORWARD;
+
+ int is_borderless = !glfwGetWindowAttrib(window, GLFW_DECORATED);
+ int ingame = !editor.active;
+ static double clicked_titlebar = 0;
+ UI_MENU(14+is_borderless, \
+ if(ingame) ui_disable(); \
+ UI_MENU_ITEM(ICON_MDI_FILE_TREE, editor_send("scene")) \
+ if(ingame) ui_enable(); \
+ UI_MENU_ITEM(ICON_PL4Y, if(editor.t == 0) editor_send("eject"); editor_send(window_has_pause() ? "play" : "pause")) \
+ UI_MENU_ITEM(ICON_SKIP, editor_send(window_has_pause() ? "frame" : "slomo")) \
+ UI_MENU_ITEM(ICON_MDI_STOP, editor_send("stop")) \
+ UI_MENU_ITEM(ICON_MDI_EJECT, editor_send("eject")) \
+ UI_MENU_ITEM(STATS, stats_mode = (++stats_mode) % 3) \
+ UI_MENU_ALIGN_RIGHT(32+32+32+32+32+32+34 + 32*is_borderless, clicked_titlebar = time_ms()) \
+ if(ingame) ui_disable(); \
+ UI_MENU_ITEM(ICON_MD_FOLDER_SPECIAL, editor_send("browser")) \
+ UI_MENU_ITEM(ICON_MDI_SCRIPT_TEXT, editor_send("script")) \
+ UI_MENU_ITEM(ICON_MDI_CHART_TIMELINE, editor_send("timeline")) \
+ UI_MENU_ITEM(ICON_MDI_CONSOLE, editor_send("console")) \
+ UI_MENU_ITEM(ICON_MDI_GRAPH, editor_send("nodes")) \
+ UI_MENU_ITEM(ICON_MD_SEARCH, editor_send("filter")) \
+ UI_MENU_POPUP(ICON_MD_SETTINGS, vec2(0.33,1.00), ui_debug()) \
+ if(ingame) ui_enable(); \
+ UI_MENU_ITEM(ICON_MD_CLOSE, editor_send("quit")) \
+ );
+
+ if( is_borderless ) {
+ static vec3 drag = {0};
+ if( clicked_titlebar ) {
+ static double clicks = 0;
+ if( input_up(MOUSE_L) ) ++clicks;
+ if( input_up(MOUSE_L) && clicks == 2 ) window_visible(false), window_maximize( window_has_maximize() ^ 1 ), window_visible(true);
+ if( (time_ms() - clicked_titlebar) > 400 ) clicks = 0, clicked_titlebar = 0;
+
+ if( input_down(MOUSE_L) ) drag = vec3(input(MOUSE_X), input(MOUSE_Y), 1);
+ }
+ if( drag.z *= !input_up(MOUSE_L) ) {
+ int wx = 0, wy = 0;
+ glfwGetWindowPos(window_handle(), &wx, &wy);
+ glfwSetWindowPos(window_handle(), wx + input(MOUSE_X) - drag.x, wy + input(MOUSE_Y) - drag.y);
+ }
+ }
+
+ if( !editor.active ) return;
+
+ // draw edit view (gizmos, position markers, etc).
+ for each_set_ptr(editor.world,obj*,o) {
+ if( obj_hasmethod(*o,edit) ) {
+ obj_edit(*o);
+ }
+}
+
+ // draw silhouettes
+ sprite_flush();
+ fx_begin();
+ for each_map_ptr(*editor_selected_map(),void*,o,int,selected) {
+ if( !*selected ) continue;
+ if( obj_hasmethod(*o,draw) ) {
+ obj_draw(*o);
+ }
+ if( obj_hasmethod(*o,edit) ) {
+ obj_edit(*o);
+}
+}
+ sprite_flush();
+ fx_end();
+
+ // draw box selection
+ if( !ui_active() ) { //< check that we're not moving a window
+ static vec2 from = {0}, to = {0};
+ if( input_down(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y)), from = to;
+ if( input(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y));
+ if( len2sq(sub2(from,to)) > 0 ) {
+ vec2 a = min2(from, to), b = max2(from, to);
+ ddraw_push_2d();
+ ddraw_color_push(YELLOW);
+ ddraw_line( vec3(a.x,a.y,0),vec3(b.x-1,a.y,0) );
+ ddraw_line( vec3(b.x,a.y,0),vec3(b.x,b.y-1,0) );
+ ddraw_line( vec3(b.x,b.y,0),vec3(a.x-1,b.y,0) );
+ ddraw_line( vec3(a.x,b.y,0),vec3(a.x,a.y-1,0) );
+ ddraw_color_pop();
+ ddraw_pop_2d();
+ }
+ if( input_up(MOUSE_L) ) {
+ vec2 a = min2(from, to), b = max2(from, to);
+ from = to = vec2(0,0);
+
+ editor_select_aabb(aabb(vec3(a.x,a.y,0),vec3(b.x,b.y,0)));
+ }
+ }
+
+ // draw mouse aabb
+ aabb mouse = { vec3(input(MOUSE_X),input(MOUSE_Y),0), vec3(input(MOUSE_X),input(MOUSE_Y),1)};
+ if( 1 ) {
+ ddraw_color_push(YELLOW);
+ ddraw_push_2d();
+ ddraw_aabb(mouse.min, mouse.max);
+ ddraw_pop_2d();
+ ddraw_color_pop();
+ }
+
+ // tick mouse aabb selection and contextual tab (RMB)
+ aabb box = {0};
+ for each_set(editor.world,obj*,o) {
+ if( !obj_hasmethod(o, aabb) ) continue;
+ if( !obj_aabb(o, &box) ) continue;
+
+ // trigger contextual inspector
+ if( input_down(MOUSE_R) ) {
+ int is_selected = editor_selected(o);
+ editor_setpopup(o, is_selected);
+ }
+
+ // draw contextual inspector
+ if( editor_popup(o) ) {
+ if( editor_begin(va("%s (%s)", obj_name(o), obj_type(o)),EDITOR_WINDOW_NK_SMALL) ) {
+ ui_label2(obj_name(o), obj_type(o));
+ editor_inspect(o);
+ editor_end(EDITOR_WINDOW_NK_SMALL);
+ } else {
+ editor_setpopup(o, 0);
+ }
+ }
+}
+
+
+ // draw subeditors
+ static int preferred_window_mode = EDITOR_WINDOW;
+ static struct nk_color bak, *on = 0; do_once bak = ui_ctx->style.window.fixed_background.data.color; // ui_ctx->style.window.fixed_background.data.color = !!(on = (on ? NULL : &bak)) ? AS_NKCOLOR(0) : bak; };
+ if( editor.transparent ) ui_ctx->style.window.fixed_background.data.color = AS_NKCOLOR(0);
+ for each_array(editor.subeditors, subeditor, fn) {
+ fn(preferred_window_mode);
+ }
+ ui_ctx->style.window.fixed_background.data.color = bak;
+
+ // draw ui filter (note: render at end-of-frame, so it's hopefully on-top)
+ editor_filter();
}
-*/
diff --git a/engine/split/v4k_editor.h b/engine/split/v4k_editor.h
index 4aa5356..d1f5bd4 100644
--- a/engine/split/v4k_editor.h
+++ b/engine/split/v4k_editor.h
@@ -1,8 +1,8 @@
// -----------------------------------------------------------------------------
// in-game editor
// - rlyeh, public domain.
-//
-// @todo: merge editor1.c and editor3.c internals into this api
+
+API int editor_send(const char *command);
//API void editor();
//API bool editor_active();
@@ -26,19 +26,3 @@ API char* dialog_save();
API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca);
API bool gizmo_active();
API bool gizmo_hover();
-
-// localization kit (I18N, L10N)
-
-API bool kit_load( const char *filename ); // load translations file (xlsx)
-API bool kit_merge( const char *filename ); // merge translations file into existing context
-API void kit_insert( const char *id, const char *translation ); // insert single translation unit
-API void kit_clear(); // delete all translations
-
-API void kit_set( const char *variable, const char *value ); // set context variable
-API void kit_reset(); // reset all variables in context
-API void kit_dump_state( FILE *fp ); // debug
-
-API char* kit_translate2( const char *id, const char *langcode_iso639_1 ); // perform a translation given explicit locale
-
-API void kit_locale( const char *langcode_iso639_1 ); // set current locale: enUS, ptBR, esES, ...
-API char* kit_translate( const char *id ); // perform a translation, given current locale
diff --git a/engine/split/v4k_editor0.c b/engine/split/v4k_editor0.c
new file mode 100644
index 0000000..08289a3
--- /dev/null
+++ b/engine/split/v4k_editor0.c
@@ -0,0 +1,532 @@
+// editing:
+// nope > functions: add/rem property
+
+#define ICON_PLAY ICON_MD_PLAY_ARROW
+#define ICON_PAUSE ICON_MD_PAUSE
+#define ICON_STOP ICON_MD_STOP
+#define ICON_CANCEL ICON_MD_CLOSE
+
+#define ICON_WARNING ICON_MD_WARNING
+#define ICON_BROWSER ICON_MD_FOLDER_SPECIAL
+#define ICON_OUTLINER ICON_MD_VIEW_IN_AR
+#define ICON_BUILD ICON_MD_BUILD
+#define ICON_SCREENSHOT ICON_MD_PHOTO_CAMERA
+#define ICON_CAMERA_ON ICON_MD_VIDEOCAM
+#define ICON_CAMERA_OFF ICON_MD_VIDEOCAM_OFF
+#define ICON_GAMEPAD_ON ICON_MD_VIDEOGAME_ASSET
+#define ICON_GAMEPAD_OFF ICON_MD_VIDEOGAME_ASSET_OFF
+#define ICON_AUDIO_ON ICON_MD_VOLUME_UP
+#define ICON_AUDIO_OFF ICON_MD_VOLUME_OFF
+#define ICON_WINDOWED ICON_MD_FULLSCREEN_EXIT
+#define ICON_FULLSCREEN ICON_MD_FULLSCREEN
+#define ICON_LIGHTS_ON ICON_MD_LIGHTBULB
+#define ICON_LIGHTS_OFF ICON_MD_LIGHTBULB_OUTLINE
+#define ICON_RENDER_BASIC ICON_MD_IMAGE_SEARCH
+#define ICON_RENDER_FULL ICON_MD_INSERT_PHOTO
+
+#define ICON_SIGNAL ICON_MD_SIGNAL_CELLULAR_ALT
+#define ICON_DISK ICON_MD_STORAGE
+#define ICON_RATE ICON_MD_SPEED
+
+#define ICON_CLOCK ICON_MD_TODAY
+#define ICON_CHRONO ICON_MD_TIMELAPSE
+
+#define ICON_SETTINGS ICON_MD_SETTINGS
+#define ICON_LANGUAGE ICON_MD_G_TRANSLATE
+#define ICON_PERSONA ICON_MD_FACE
+#define ICON_SOCIAL ICON_MD_MESSAGE
+#define ICON_GAME ICON_MD_ROCKET_LAUNCH
+#define ICON_KEYBOARD ICON_MD_KEYBOARD
+#define ICON_MOUSE ICON_MD_MOUSE
+#define ICON_GAMEPAD ICON_MD_GAMEPAD
+#define ICON_MONITOR ICON_MD_MONITOR
+#define ICON_WIFI ICON_MD_WIFI
+#define ICON_BUDGET ICON_MD_SAVINGS
+#define ICON_NEW_FOLDER ICON_MD_CREATE_NEW_FOLDER
+#define ICON_PLUGIN ICON_MD_EXTENSION
+#define ICON_RESTART ICON_MD_REPLAY
+#define ICON_QUIT ICON_MD_CLOSE
+
+#define ICON_POWER ICON_MD_BOLT // ICON_MD_POWER
+#define ICON_BATTERY_CHARGING ICON_MD_BATTERY_CHARGING_FULL
+#define ICON_BATTERY_LEVELS \
+ ICON_MD_BATTERY_ALERT, \
+ ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, \
+ ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR, \
+ ICON_MD_BATTERY_4_BAR,ICON_MD_BATTERY_5_BAR, \
+ ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL
+
+char *editor_path(const char *path) {
+ return va("%s/%s", EDITOR, path);
+}
+
+vec3 editor_pick(float mouse_x, float mouse_y) {
+#if 0
+ // unproject 2d coord as 3d coord
+ camera_t *camera = camera_get_active();
+ vec3 out, xyd = vec3(mouse_x,window_height()-mouse_y,1); // usually x:mouse_x,y:window_height()-mouse_y,d:0=znear/1=zfar
+ mat44 mvp, model; identity44(model); multiply44x3(mvp, camera->proj, camera->view, model);
+ bool ok = unproject44(&out, xyd, vec4(0,0,window_width(),window_height()), mvp);
+ return out;
+#else
+ // unproject 2d coord as 3d coord
+ vec2 dpi = ifdef(osx, window_dpi(), vec2(1,1));
+ camera_t *camera = camera_get_active();
+ float x = (2.0f * mouse_x) / (dpi.x * window_width()) - 1.0f;
+ float y = 1.0f - (2.0f * mouse_y) / (dpi.y * window_height());
+ float z = 1.0f;
+ vec3 ray_nds = vec3(x, y, z);
+ vec4 ray_clip = vec4(ray_nds.x, ray_nds.y, -1.0, 1.0);
+ mat44 inv_proj; invert44(inv_proj, camera->proj);
+ mat44 inv_view; invert44(inv_view, camera->view);
+ vec4 p = transform444(inv_proj, ray_clip);
+ vec4 eye = vec4(p.x, p.y, -1.0, 0.0);
+ vec4 wld = norm4(transform444(inv_view, eye));
+ return vec3(wld.x, wld.y, wld.z);
+#endif
+}
+
+#if 0
+int editor_ui_bits8(const char *label, uint8_t *enabled) { // @to deprecate
+ int clicked = 0;
+ uint8_t copy = *enabled;
+
+ // @fixme: better way to retrieve widget width? nk_layout_row_dynamic() seems excessive
+ nk_layout_row_dynamic(ui_ctx, 1, 1);
+ struct nk_rect bounds = nk_widget_bounds(ui_ctx);
+
+ // actual widget: label + 8 checkboxes
+ enum { HEIGHT = 18, BITS = 8, SPAN = 118 }; // bits widget below needs at least 118px wide
+ nk_layout_row_begin(ui_ctx, NK_STATIC, HEIGHT, 1+BITS);
+
+ int offset = bounds.w > SPAN ? bounds.w - SPAN : 0;
+ nk_layout_row_push(ui_ctx, offset);
+ if( ui_label_(label, NK_TEXT_LEFT) ) clicked = 1<<31;
+
+ for( int i = 0; i < BITS; ++i ) {
+ nk_layout_row_push(ui_ctx, 10);
+ // bit
+ int val = (*enabled >> i) & 1;
+ int chg = nk_checkbox_label(ui_ctx, "", &val);
+ *enabled = (*enabled & ~(1 << i)) | ((!!val) << i);
+ // tooltip
+ struct nk_rect bb = { offset + 10 + i * 14, bounds.y, 14, HEIGHT }; // 10:padding,14:width
+ if (nk_input_is_mouse_hovering_rect(&ui_ctx->input, bb) && !ui_popups()) {
+ const char *tips[BITS] = {"Init","Tick","Draw","Quit","","","",""};
+ if(tips[i][0]) nk_tooltipf(ui_ctx, "%s", tips[i]);
+ }
+ }
+
+ nk_layout_row_end(ui_ctx);
+ return clicked | (copy ^ *enabled);
+}
+#endif
+
+
+typedef union engine_var {
+ int i;
+ float f;
+ char *s;
+} engine_var;
+static map(char*,engine_var) engine_vars;
+float *engine_getf(const char *key) {
+ if(!engine_vars) map_init_str(engine_vars);
+ engine_var *found = map_find_or_add(engine_vars, (char*)key, ((engine_var){0}) );
+ return &found->f;
+}
+int *engine_geti(const char *key) {
+ if(!engine_vars) map_init_str(engine_vars);
+ engine_var *found = map_find_or_add(engine_vars, (char*)key, ((engine_var){0}) );
+ return &found->i;
+}
+char **engine_gets(const char *key) {
+ if(!engine_vars) map_init_str(engine_vars);
+ engine_var *found = map_find_or_add(engine_vars, (char*)key, ((engine_var){0}) );
+ if(!found->s) found->s = stringf("%s","");
+ return &found->s;
+}
+
+int engine_send(const char *cmd, const char *optional_value) {
+ unsigned *gamepads = engine_geti("gamepads"); // 0 off, mask gamepad1(1), gamepad2(2), gamepad3(4), gamepad4(8)...
+ unsigned *renders = engine_geti("renders"); // 0 off, mask: 1=lit, 2=ddraw, 3=whiteboxes
+ float *speed = engine_getf("speed"); // <0 num of frames to advance, 0 paused, [0..1] slomo, 1 play regular speed, >1 fast-forward (x2/x4/x8)
+ unsigned *powersave = engine_geti("powersave");
+
+ char *name;
+ /**/ if( !strcmp(cmd, "key_quit" )) record_stop(), exit(0);
+ else if( !strcmp(cmd, "key_stop" )) window_pause(1);
+ else if( !strcmp(cmd, "key_mute" )) audio_volume_master( 1 ^ !!audio_volume_master(-1) );
+ else if( !strcmp(cmd, "key_pause" )) window_pause( window_has_pause() ^ 1 );
+ else if( !strcmp(cmd, "key_reload" )) window_reload();
+ else if( !strcmp(cmd, "key_battery" )) *powersave = optional_value ? !!atoi(optional_value) : *powersave ^ 1;
+ else if( !strcmp(cmd, "key_browser" )) ui_show("File Browser", ui_visible("File Browser") ^ true);
+ else if( !strcmp(cmd, "key_outliner" )) ui_show("Outliner", ui_visible("Outliner") ^ true);
+ else if( !strcmp(cmd, "key_record" )) if(record_active()) record_stop(), ui_notify(va("Video recorded"), date_string()); else
+ app_beep(), name = file_counter(va("%s.mp4",app_name())), window_record(name);
+ else if( !strcmp(cmd, "key_screenshot" )) name = file_counter(va("%s.png",app_name())), window_screenshot(name), ui_notify(va("Screenshot: %s", name), date_string());
+ else if( !strcmp(cmd, "key_profiler" )) ui_show("Profiler", profiler_enable(ui_visible("Profiler") ^ true));
+ else if( !strcmp(cmd, "key_fullscreen" )) record_stop(), window_fullscreen( window_has_fullscreen() ^ 1 ); // framebuffer resizing corrupts video stream, so stop any recording beforehand
+ else if( !strcmp(cmd, "key_gamepad" )) *gamepads = (*gamepads & ~1u) | ((*gamepads & 1) ^ 1);
+ else if( !strcmp(cmd, "key_lit" )) *renders = (*renders & ~1u) | ((*renders & 1) ^ 1);
+ else if( !strcmp(cmd, "key_ddraw" )) *renders = (*renders & ~2u) | ((*renders & 2) ^ 2);
+ else alert(va("editor could not handle `%s` command.", cmd));
+
+ return 0;
+}
+
+int engine_tick() {
+ enum { engine_hz = 60 };
+ enum { engine_hz_mid = 18 };
+ enum { engine_hz_low = 5 };
+ if( *engine_geti("powersave") ) {
+ // adaptive framerate
+ int app_on_background = !window_has_focus();
+ int hz = app_on_background ? engine_hz_low : engine_hz_mid;
+ window_fps_lock( hz < 5 ? 5 : hz );
+ } else {
+ // window_fps_lock( editor_hz );
+ }
+
+ return 0;
+}
+
+int ui_debug() {
+ static int time_factor = 0;
+ static int playing = 0;
+ static int paused = 0;
+ int advance_frame = 0;
+
+#if 0
+ static int do_filter = 0;
+ static int do_profile = 0;
+ static int do_extra = 0;
+
+ char *EDITOR_TOOLBAR_ICONS = va("%s;%s;%s;%s;%s;%s;%s;%s",
+ do_filter ? ICON_MD_CLOSE : ICON_MD_SEARCH,
+ ICON_MD_PLAY_ARROW,
+ paused ? ICON_MD_SKIP_NEXT : ICON_MD_PAUSE,
+ ICON_MD_FAST_FORWARD,
+ ICON_MD_STOP,
+ ICON_MD_REPLAY,
+ ICON_MD_FACE,
+ ICON_MD_MENU
+ );
+
+ if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1;
+ int choice = ui_toolbar(EDITOR_TOOLBAR_ICONS);
+ if( choice == 1 ) do_filter ^= 1, do_profile = 0, do_extra = 0;
+ if( choice == 2 ) playing = 1, paused = 0;
+ if( choice == 3 ) advance_frame = !!paused, paused = 1;
+ if( choice == 4 ) paused = 0, time_factor = (++time_factor) % 4;
+ if( choice == 5 ) playing = 0, paused = 0, advance_frame = 0, time_factor = 0;
+ if( choice == 6 ) window_reload();
+ if( choice == 7 ) do_filter = 0, do_profile ^= 1, do_extra = 0;
+ if( choice == 8 ) do_filter = 0, do_profile = 0, do_extra ^= 1;
+
+ if( do_filter ) {
+ char *bak = ui_filter; ui_filter = 0;
+ ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &bak);
+ ui_filter = bak;
+ if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon)
+ do_filter = 0;
+ }
+ } else {
+ if( ui_filter ) ui_filter[0] = '\0';
+ }
+ char *filter_mask = ui_filter && ui_filter[0] ? va("*%s*", ui_filter) : "*";
+
+ static char *username = 0;
+ static char *userpass = 0;
+ if( do_profile ) {
+ ui_string(ICON_MD_FACE " Username", &username);
+ ui_string(ICON_MD_FACE " Password", &userpass);
+ }
+
+ if( do_extra ) {
+ int choice2 = ui_label2_toolbar(NULL,
+ ICON_MD_VIEW_IN_AR
+ ICON_MD_MESSAGE
+ ICON_MD_TIPS_AND_UPDATES ICON_MD_LIGHTBULB ICON_MD_LIGHTBULB_OUTLINE
+ ICON_MD_IMAGE_SEARCH ICON_MD_INSERT_PHOTO
+ ICON_MD_VIDEOGAME_ASSET ICON_MD_VIDEOGAME_ASSET_OFF
+
+ ICON_MD_VOLUME_UP ICON_MD_VOLUME_OFF // audio_volume_master(-1) > 0
+
+ ICON_MD_TROUBLESHOOT ICON_MD_SCHEMA ICON_MD_MENU
+ );
+ }
+#endif
+
+ int open = 0, clicked_or_toggled = 0;
+
+
+ #define EDITOR_UI_COLLAPSE(f,...) \
+ for( int macro(p) = (open = ui_collapse(f,__VA_ARGS__)), macro(dummy) = (clicked_or_toggled = ui_collapse_clicked()); macro(p); ui_collapse_end(), macro(p) = 0)
+
+ EDITOR_UI_COLLAPSE(ICON_MD_VIEW_QUILT " Windows", "Debug.Windows") {
+ int choice = ui_toolbar(ICON_MD_RECYCLING "@Reset layout;" ICON_MD_SAVE_AS "@Save layout");
+ if( choice == 1 ) ui_layout_all_reset("*");
+ if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*");
+
+ for each_map_ptr_sorted(ui_windows, char*, k, unsigned, v) {
+ bool visible = ui_visible(*k);
+ if( ui_bool( *k, &visible ) ) {
+ ui_show( *k, ui_visible(*k) ^ true );
+ }
+ }
+ }
+
+ EDITOR_UI_COLLAPSE(ICON_MD_BUG_REPORT " Bugs 0", "Debug.Bugs") {
+ // @todo. parse /bugs.ini, includes saved screenshots & videos.
+ // @todo. screenshot include parseable level, position screen markers (same info as /bugs.ini)
+ }
+
+
+ // Art and bookmarks
+ EDITOR_UI_COLLAPSE(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art") {
+ bool inlined = true;
+ const char *file = 0;
+ if( ui_browse(&file, &inlined) ) {
+ const char *sep = ifdef(win32, "\"", "'");
+ app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep));
+ }
+ }
+ EDITOR_UI_COLLAPSE(ICON_MD_BOOKMARK " Bookmarks", "Debug.Bookmarks") { /* @todo */ }
+
+
+ // E,C,S,W
+ EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Scene", "Debug.Scene") {
+ EDITOR_UI_COLLAPSE(ICON_MD_BUBBLE_CHART/*ICON_MD_SCATTER_PLOT*/ " Entities", "Debug.Entities") { /* @todo */ }
+ EDITOR_UI_COLLAPSE(ICON_MD_TUNE " Components", "Debug.Components") { /* @todo */ }
+ EDITOR_UI_COLLAPSE(ICON_MD_PRECISION_MANUFACTURING " Systems", "Debug.Systems") { /* @todo */ }
+ EDITOR_UI_COLLAPSE(ICON_MD_PUBLIC " Levels", "Debug.Levels") {
+ //node_edit(editor.edit.down,&editor.edit);
+ }
+
+ //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Init", "Debug.HierarchyInit") { /* @todo */ }
+ //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Draw", "Debug.HierarchyDraw") { /* @todo */ }
+ //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Tick", "Debug.HierarchyTick") { /* @todo */ }
+ //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Edit", "Debug.HierarchyEdit") { /* @todo */ }
+ //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Quit", "Debug.HierarchyQuit") { /* @todo */ }
+
+ // node_edit(&editor.init,&editor.init);
+ // node_edit(&editor.draw,&editor.draw);
+ // node_edit(&editor.tick,&editor.tick);
+ // node_edit(&editor.edit,&editor.edit);
+ // node_edit(&editor.quit,&editor.quit);
+ }
+
+ EDITOR_UI_COLLAPSE(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI") {
+ // @todo
+ }
+ EDITOR_UI_COLLAPSE(ICON_MD_VOLUME_UP " Audio", "Debug.Audio") {
+ ui_audio();
+ }
+ EDITOR_UI_COLLAPSE(ICON_MD_VIDEOCAM " Camera", "Debug.Camera") {
+ ui_camera( camera_get_active() );
+ }
+ EDITOR_UI_COLLAPSE(ICON_MD_MONITOR " Display", "Debug.Display") {
+ // @todo: fps lock, fps target, aspect ratio, fullscreen
+ char *text = va("%s;%s;%s",
+ window_has_fullscreen() ? ICON_MD_FULLSCREEN_EXIT : ICON_MD_FULLSCREEN,
+ ICON_MD_PHOTO_CAMERA,
+ record_active() ? ICON_MD_VIDEOCAM_OFF : ICON_MD_VIDEOCAM
+ );
+
+ int choice = ui_toolbar(text);
+ if( choice == 1 ) engine_send("key_fullscreen",0);
+ if( choice == 2 ) engine_send("key_screenshot",0);
+ if( choice == 3 ) engine_send("key_record",0);
+ }
+ EDITOR_UI_COLLAPSE(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard") {
+ ui_keyboard();
+ }
+ EDITOR_UI_COLLAPSE(ICON_MD_MOUSE " Mouse", "Debug.Mouse") {
+ ui_mouse();
+ }
+ EDITOR_UI_COLLAPSE(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads") {
+ for( int q = 0; q < 4; ++q ) {
+ for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) {
+ ui_gamepad(q);
+ }
+ }
+ }
+
+
+ EDITOR_UI_COLLAPSE(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts") {
+ // @todo
+ }
+ EDITOR_UI_COLLAPSE(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders") {
+ ui_shaders();
+ }
+ EDITOR_UI_COLLAPSE(ICON_MD_MOVIE " FXs", "Debug.FXs") {
+ ui_fxs();
+ }
+
+
+ EDITOR_UI_COLLAPSE(ICON_MD_SAVINGS " Budgets", "Debug.Budgets") {
+ // @todo. // mem,fps,gfx,net,hdd,... also logging
+ }
+ EDITOR_UI_COLLAPSE(ICON_MD_WIFI/*ICON_MD_SIGNAL_CELLULAR_ALT*/ " Network 0/0 KiB", "Debug.Network") {
+ // @todo
+ // SIGNAL_CELLULAR_1_BAR SIGNAL_CELLULAR_2_BAR
+ }
+ EDITOR_UI_COLLAPSE(va(ICON_MD_SPEED " Profiler %5.2f/%dfps", window_fps(), (int)window_fps_target()), "Debug.Profiler") {
+ ui_profiler();
+ }
+ EDITOR_UI_COLLAPSE(va(ICON_MD_STORAGE " Storage %s", xstats()), "Debug.Storage") {
+ // @todo
+ }
+
+
+
+ // logic: either plug icon (power saving off) or one of the following ones (power saving on):
+ // if 0% batt (no batt): battery alert
+ // if discharging: battery levels [alert,0..6,full]
+ // if charging: battery charging
+ int battery_read = app_battery();
+ int battery_level = abs(battery_read);
+ int battery_discharging = battery_read < 0 && battery_level < 100;
+ const char *power_icon_label = ICON_MD_POWER " Power";
+ if( battery_level ) {
+ const char *battery_levels[9] = { // @todo: remap [7%..100%] -> [0..1] ?
+ ICON_MD_BATTERY_ALERT,ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR,
+ ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR,ICON_MD_BATTERY_4_BAR,
+ ICON_MD_BATTERY_5_BAR,ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL,
+ };
+ power_icon_label = (const char*)va("%s Power %d%%",
+ battery_discharging ? battery_levels[(int)((9-1)*clampf(battery_level/100.f,0,1))] : ICON_MD_BATTERY_CHARGING_FULL,
+ battery_level);
+ }
+
+ EDITOR_UI_COLLAPSE(power_icon_label, "Debug.Power") {
+ int choice = ui_toolbar( ICON_MD_POWER ";" ICON_MD_BOLT );
+ if( choice == 1 ) engine_send("key_battery","0");
+ if( choice == 2 ) engine_send("key_battery","1");
+ }
+
+ EDITOR_UI_COLLAPSE(ICON_MD_WATER " Reflection", "Debug.Reflect") {
+ ui_reflect("*");
+ }
+
+ EDITOR_UI_COLLAPSE(ICON_MD_EXTENSION " Plugins", "Debug.Plugins") {
+ // @todo. include VCS
+ EDITOR_UI_COLLAPSE(ICON_MD_BUILD " Cook", "Debug.Cook") {
+ // @todo
+ }
+ }
+
+ return 0;
+}
+
+static int gizmo__mode;
+static int gizmo__active;
+static int gizmo__hover;
+bool gizmo_active() {
+ return gizmo__active;
+}
+bool gizmo_hover() {
+ return gizmo__hover;
+}
+int gizmo(vec3 *pos, vec3 *rot, vec3 *sca) {
+#if 0
+ ddraw_flush();
+ mat44 copy; copy44(copy, camera_get_active()->view);
+ if( 1 ) {
+ float *mv = camera_get_active()->view;
+ float d = sqrt(mv[4*0+0] * mv[4*0+0] + mv[4*1+1] * mv[4*1+1] + mv[4*2+2] * mv[4*2+2]);
+ if(4) mv[4*0+0] = d, mv[4*0+1] = 0, mv[4*0+2] = 0;
+ if(2) mv[4*1+0] = 0, mv[4*1+1] = d, mv[4*1+2] = 0;
+ if(1) mv[4*2+0] = 0, mv[4*2+1] = 0, mv[4*2+2] = d;
+ }
+#endif
+
+ ddraw_color_push(dd_color);
+ ddraw_ontop_push(1);
+
+ int enabled = !ui_active() && !ui_hover();
+ vec3 mouse = enabled ? vec3(input(MOUSE_X),input(MOUSE_Y),input_down(MOUSE_L)) : vec3(0,0,0); // x,y,l
+ vec3 from = camera_get_active()->position;
+ vec3 to = editor_pick(mouse.x, mouse.y);
+ ray r = ray(from, to);
+
+ static vec3 src3, hit3, off3; static vec2 src2;
+ #define on_gizmo_dragged(X,Y,Z,COLOR,DRAWCMD, ...) do { \
+ vec3 dir = vec3(X,Y,Z); \
+ line axis = {add3(*pos, scale3(dir,100)), add3(*pos, scale3(dir,-100))}; \
+ plane ground = { vec3(0,0,0), vec3(Y?1:0,Y?0:1,0) }; \
+ vec3 unit = vec3(X+(1.0-X)*0.3,Y+(1.0-Y)*0.3,Z+(1.0-Z)*0.3); \
+ aabb arrow = { sub3(*pos,unit), add3(*pos,unit) }; \
+ hit *hit_arrow = ray_hit_aabb(r, arrow), *hit_ground = ray_hit_plane(r, ground); \
+ ddraw_color( hit_arrow || gizmo__active == (X*4+Y*2+Z) ? gizmo__hover = 1, YELLOW : COLOR ); \
+ DRAWCMD; \
+ if( !gizmo__active && hit_arrow && mouse.z ) src2 = vec2(mouse.x,mouse.y), src3 = *pos, hit3 = hit_ground->p, off3 = mul3(sub3(src3,hit3),vec3(X,Y,Z)), gizmo__active = X*4+Y*2+Z; \
+ if( (gizmo__active && gizmo__active==(X*4+Y*2+Z)) || (!gizmo__active && hit_arrow) ) { ddraw_color( COLOR ); ( 1 ? ddraw_line : ddraw_line_dashed)(axis.a, axis.b); } \
+ if( gizmo__active == (X*4+Y*2+Z) && hit_ground ) {{ __VA_ARGS__ }; modified = 1; gizmo__active *= !!input(MOUSE_L); } \
+ } while(0)
+ #define gizmo_translate(X,Y,Z,COLOR) \
+ on_gizmo_dragged(X,Y,Z,COLOR, ddraw_arrow(*pos,add3(*pos,vec3(X,Y,Z))), { \
+ *pos = add3(line_closest_point(axis, hit_ground->p), off3); \
+ } )
+ #define gizmo_scale(X,Y,Z,COLOR) \
+ on_gizmo_dragged(X,Y,Z,COLOR, (ddraw_line(*pos,add3(*pos,vec3(X,Y,Z))),ddraw_sphere(add3(*pos,vec3(X-0.1*X,Y-0.1*Y,Z-0.1*Z)),0.1)), { /*ddraw_aabb(arrow.min,arrow.max)*/ \
+ int component = (X*1+Y*2+Z*3)-1; \
+ float mag = len2(sub2(vec2(mouse.x, mouse.y), src2)); \
+ float magx = (mouse.x - src2.x) * (mouse.x - src2.x); \
+ float magy = (mouse.y - src2.y) * (mouse.y - src2.y); \
+ float sgn = (magx > magy ? mouse.x > src2.x : mouse.y > src2.y) ? 1 : -1; \
+ sca->v3[component] -= sgn * mag * 0.01; \
+ src2 = vec2(mouse.x, mouse.y); \
+ } )
+ #define gizmo_rotate(X,Y,Z,COLOR) do { \
+ vec3 dir = vec3(X,Y,Z); \
+ line axis = {add3(*pos, scale3(dir,100)), add3(*pos, scale3(dir,-100))}; \
+ plane ground = { vec3(0,0,0), vec3(0,1,0) }; \
+ vec3 unit = vec3(X+(1.0-X)*0.3,Y+(1.0-Y)*0.3,Z+(1.0-Z)*0.3); \
+ aabb arrow = { sub3(*pos,unit), add3(*pos,unit) }; \
+ hit *hit_arrow = ray_hit_aabb(r, arrow), *hit_ground = ray_hit_plane(r, ground); \
+ int hover = (hit_arrow ? (X*4+Y*2+Z) : 0); \
+ if( gizmo__active == (X*4+Y*2+Z) ) { ddraw_color(gizmo__active ? gizmo__hover = 1, YELLOW : WHITE); ddraw_circle(*pos, vec3(X,Y,Z), 1); } \
+ else if( !gizmo__active && hover == (X*4+Y*2+Z) ) { gizmo__hover = 1; ddraw_color(COLOR); ddraw_circle(*pos, vec3(X,Y,Z), 1); } \
+ else if( !gizmo__active ) { ddraw_color(WHITE); ddraw_circle(*pos, vec3(X,Y,Z), 1); } \
+ if( !gizmo__active && hit_arrow && mouse.z ) src2 = vec2(mouse.x,mouse.y), gizmo__active = hover; \
+ if( (!gizmo__active && hover == (X*4+Y*2+Z)) || gizmo__active == (X*4+Y*2+Z) ) { gizmo__hover = 1; ddraw_color( COLOR ); ( 1 ? ddraw_line_thin : ddraw_line_dashed)(axis.a, axis.b); } \
+ if( gizmo__active && gizmo__active == (X*4+Y*2+Z) && hit_ground && enabled ) { \
+ int component = (Y*1+X*2+Z*3)-1; /*pitch,yaw,roll*/ \
+ float mag = len2(sub2(vec2(mouse.x, mouse.y), src2)); \
+ float magx = (mouse.x - src2.x) * (mouse.x - src2.x); \
+ float magy = (mouse.y - src2.y) * (mouse.y - src2.y); \
+ float sgn = (magx > magy ? mouse.x > src2.x : mouse.y > src2.y) ? 1 : -1; \
+ rot->v3[component] += sgn * mag; \
+ /*rot->v3[component] = clampf(rot->v3[component], -360, +360);*/ \
+ src2 = vec2(mouse.x, mouse.y); \
+ \
+ } \
+ gizmo__active *= enabled && !!input(MOUSE_L); \
+ } while(0)
+
+ gizmo__hover = 0;
+
+ int modified = 0;
+ if(enabled && input_down(KEY_SPACE)) gizmo__active = 0, gizmo__mode = (gizmo__mode + 1) % 3;
+ if(gizmo__mode == 0) gizmo_translate(1,0,0, RED);
+ if(gizmo__mode == 0) gizmo_translate(0,1,0, GREEN);
+ if(gizmo__mode == 0) gizmo_translate(0,0,1, BLUE);
+ if(gizmo__mode == 1) gizmo_scale(1,0,0, RED);
+ if(gizmo__mode == 1) gizmo_scale(0,1,0, GREEN);
+ if(gizmo__mode == 1) gizmo_scale(0,0,1, BLUE);
+ if(gizmo__mode == 2) gizmo_rotate(1,0,0, RED);
+ if(gizmo__mode == 2) gizmo_rotate(0,1,0, GREEN);
+ if(gizmo__mode == 2) gizmo_rotate(0,0,1, BLUE);
+
+#if 0
+ ddraw_flush();
+ copy44(camera_get_active()->view, copy);
+#endif
+
+ ddraw_ontop_pop();
+ ddraw_color_pop();
+
+ return modified;
+}
+
diff --git a/tools/editor/v4k_editor2_browser.h b/engine/split/v4k_editor_browser.h
similarity index 100%
rename from tools/editor/v4k_editor2_browser.h
rename to engine/split/v4k_editor_browser.h
diff --git a/tools/editor/v4k_editor4_console.h b/engine/split/v4k_editor_console.h
similarity index 100%
rename from tools/editor/v4k_editor4_console.h
rename to engine/split/v4k_editor_console.h
diff --git a/tools/editor/v4k_editor5_nodes.h b/engine/split/v4k_editor_nodes.h
similarity index 100%
rename from tools/editor/v4k_editor5_nodes.h
rename to engine/split/v4k_editor_nodes.h
diff --git a/tools/editor/v4k_editor1_scene.h b/engine/split/v4k_editor_scene.h
similarity index 99%
rename from tools/editor/v4k_editor1_scene.h
rename to engine/split/v4k_editor_scene.h
index 2d9a590..4528b3d 100644
--- a/tools/editor/v4k_editor1_scene.h
+++ b/engine/split/v4k_editor_scene.h
@@ -92,8 +92,6 @@ void editor_scene_(obj *o, unsigned flags) {
}
if( ui_contextual() ) {
- API int editor_send(const char *);
-
int choice = ui_label(ICON_MD_BOOKMARK_ADDED "Toggle bookmarks (CTRL+B)");
if( choice & 1 ) editor_send("bookmark");
diff --git a/tools/editor/v4k_editor6_script.h b/engine/split/v4k_editor_script.h
similarity index 74%
rename from tools/editor/v4k_editor6_script.h
rename to engine/split/v4k_editor_script.h
index c63c927..f7e2482 100644
--- a/tools/editor/v4k_editor6_script.h
+++ b/engine/split/v4k_editor_script.h
@@ -1,24 +1,3 @@
-// lite {
-#define f_gc f_gc2
-#define clip clip2
-#define GLEQ_IMPLEMENTATION
-#include "3rd_lite_sys_gleq.h"
-#include "3rd_lite_sys.h"
-#include "3rd_lite.h"
-// }
-
-TODO("new: integrate with Art/ browser")
-TODO("bug: lite key bindings are being sent to editor")
-TODO("bug: not sending quit signal to lite neither at window close nor editor close (see: temporary files)")
-TODO("bug: missing search results window")
-TODO("bug: missing code completions popup")
-// TODO("eval: https://github.com/drmargarido/linters")
-// TODO("eval: https://github.com/monolifed/theme16")
-// TODO("eval: https://github.com/vincens2005/lite-formatters")
-// https://github.com/takase1121/lite-xl-img
-// https://github.com/takase1121/lite-xl-finder
-// https://github.com/rxi/lite/commit/236a585756cb9fa70130eee6c9a604780aced424 > suru.png
-// https://github.com/rxi/lite/commit/f90b00748e1fe1cd2340aaa06d2526a1b2ea54ec
int ui_texture_fit(texture_t t, struct nk_rect bounds) {
// allocate complete window space
diff --git a/tools/editor/v4k_editor3_timeline.h b/engine/split/v4k_editor_timeline.h
similarity index 100%
rename from tools/editor/v4k_editor3_timeline.h
rename to engine/split/v4k_editor_timeline.h
diff --git a/engine/split/v4k_file.c b/engine/split/v4k_file.c
index 517c4f9..824e95c 100644
--- a/engine/split/v4k_file.c
+++ b/engine/split/v4k_file.c
@@ -884,7 +884,7 @@ if( found && *found == 0 ) {
char *cmd = va("%scook" ifdef(osx,".osx",ifdef(linux,".linux",".exe"))" %s %s --cook-ini=%s --cook-additive --cook-jobs=1 --quiet", TOOLS, group1, group2, COOK_INI);
// cook groups
- int rc = atoi(app_exec(cmd));
+ int rc = system(cmd); // atoi(app_exec(cmd));
if(rc < 0) PANIC("cannot invoke `%scook` (return code %d)", TOOLS, rc);
vfs_reload(); // @todo: optimize me. it is waaay inefficent to reload the whole VFS layout after cooking a single asset
diff --git a/engine/split/v4k_main.c b/engine/split/v4k_main.c
index 749edf8..2e36d84 100644
--- a/engine/split/v4k_main.c
+++ b/engine/split/v4k_main.c
@@ -64,7 +64,7 @@ void v4k_init() {
ifdef(debug, trap_install());
// init panic handler
- panic_oom_reserve = SYS_REALLOC(panic_oom_reserve, 1<<20); // 1MiB
+ panic_oom_reserve = SYS_MEM_REALLOC(panic_oom_reserve, 1<<20); // 1MiB
// init glfw
glfw_init();
diff --git a/engine/split/v4k_memory.c b/engine/split/v4k_memory.c
index 2c1eb98..4a92a19 100644
--- a/engine/split/v4k_memory.c
+++ b/engine/split/v4k_memory.c
@@ -6,9 +6,10 @@ size_t dlmalloc_usable_size(void*); // __ANDROID_API__
# include
#endif
-#ifndef SYS_REALLOC
-#define SYS_REALLOC realloc
-#define SYS_MSIZE /* bsd/osx, then win32, then ems/__GLIBC__, then __ANDROID_API__ */ \
+#ifndef SYS_MEM_INIT
+#define SYS_MEM_INIT()
+#define SYS_MEM_REALLOC realloc
+#define SYS_MEM_SIZE /* bsd/osx, then win32, then ems/__GLIBC__, then __ANDROID_API__ */ \
ifdef(osx, malloc_size, ifdef(bsd, malloc_size, \
ifdef(win32, _msize, malloc_usable_size)))
#endif
@@ -18,10 +19,12 @@ size_t dlmalloc_usable_size(void*); // __ANDROID_API__
static __thread uint64_t xstats_current = 0, xstats_total = 0, xstats_allocs = 0;
void* xrealloc(void* oldptr, size_t size) {
+ static __thread int once = 0; for(;!once;once = 1) SYS_MEM_INIT();
+
// for stats
size_t oldsize = xsize(oldptr);
- void *ptr = SYS_REALLOC(oldptr, size);
+ void *ptr = SYS_MEM_REALLOC(oldptr, size);
if( !ptr && size ) {
PANIC("Not memory enough (trying to allocate %u bytes)", (unsigned)size);
}
@@ -46,7 +49,7 @@ void* xrealloc(void* oldptr, size_t size) {
return ptr;
}
size_t xsize(void* p) {
- if( p ) return SYS_MSIZE(p);
+ if( p ) return SYS_MEM_SIZE(p);
return 0;
}
char *xstats(void) {
diff --git a/engine/split/v4k_obj.h b/engine/split/v4k_obj.h
index 80f5904..40361f4 100644
--- a/engine/split/v4k_obj.h
+++ b/engine/split/v4k_obj.h
@@ -161,6 +161,7 @@ void* obj_free(void *o);
// --- syntax sugars
#define obj_extend(T,method) (obj_##method[OBJTYPE(T)] = (void*)T##_##method)
+#define obj_extend_t(T,method) (obj_##method[OBJTYPE(T##_t)] = (void*)T##_##method)
#define obj_method(method,o,...) (obj_##method[((struct obj*)(o))->objtype](o,##__VA_ARGS__)) // (obj_##method[((struct obj*)(o))->objtype]((o), ##__VA_ARGS__))
#define obj_hasmethod(o,method) (obj_typeid(o)[obj_##method])
@@ -183,6 +184,17 @@ void* obj_free(void *o);
#define EXTEND9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8)
#define EXTEND10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8), obj_extend(o,F9)
+#define EXTEND_T(...) EXPAND(EXTEND_T, __VA_ARGS__)
+#define EXTEND_T2(o,F1) obj_extend_t(o,F1)
+#define EXTEND_T3(o,F1,F2) obj_extend_t(o,F1), obj_extend_t(o,F2)
+#define EXTEND_T4(o,F1,F2,F3) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3)
+#define EXTEND_T5(o,F1,F2,F3,F4) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4)
+#define EXTEND_T6(o,F1,F2,F3,F4,F5) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5)
+#define EXTEND_T7(o,F1,F2,F3,F4,F5,F6) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6)
+#define EXTEND_T8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7)
+#define EXTEND_T9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8)
+#define EXTEND_T10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8), obj_extend_t(o,F9)
+
// --- declare vtables
API extern void (*obj_ctor[256])(); ///-
@@ -201,6 +213,8 @@ API extern int (*obj_lerp[256])(); ///-
API extern int (*obj_edit[256])(); ///-
API extern int (*obj_aabb[256])(); ///-
+API extern const char*OBJTYPES[256]; /// -
+
// ----------------------------------------------------------------------------
// core
diff --git a/engine/split/v4k_pack.h b/engine/split/v4k_pack.h
index 0ab83b0..8356140 100644
--- a/engine/split/v4k_pack.h
+++ b/engine/split/v4k_pack.h
@@ -126,25 +126,25 @@ typedef struct double2 { double x,y; } double2;
typedef struct double3 { double x,y,z; } double3;
typedef struct double4 { double x,y,z,w; } double4;
-#define byte2(x,y) M_CAST(byte2, (uint8_t)(x), (uint8_t)(y) )
-#define byte3(x,y,z) M_CAST(byte3, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z) )
-#define byte4(x,y,z,w) M_CAST(byte4, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z), (uint8_t)(w) )
+#define byte2(x,y) C_CAST(byte2, (uint8_t)(x), (uint8_t)(y) )
+#define byte3(x,y,z) C_CAST(byte3, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z) )
+#define byte4(x,y,z,w) C_CAST(byte4, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z), (uint8_t)(w) )
-#define int2(x,y) M_CAST(int2, (int)(x), (int)(y) )
-#define int3(x,y,z) M_CAST(int3, (int)(x), (int)(y), (int)(z) )
-#define int4(x,y,z,w) M_CAST(int4, (int)(x), (int)(y), (int)(z), (int)(w) )
+#define int2(x,y) C_CAST(int2, (int)(x), (int)(y) )
+#define int3(x,y,z) C_CAST(int3, (int)(x), (int)(y), (int)(z) )
+#define int4(x,y,z,w) C_CAST(int4, (int)(x), (int)(y), (int)(z), (int)(w) )
-#define uint2(x,y) M_CAST(uint2, (unsigned)(x), (unsigned)(y) )
-#define uint3(x,y,z) M_CAST(uint3, (unsigned)(x), (unsigned)(y), (unsigned)(z) )
-#define uint4(x,y,z,w) M_CAST(uint4, (unsigned)(x), (unsigned)(y), (unsigned)(z), (unsigned)(w) )
+#define uint2(x,y) C_CAST(uint2, (unsigned)(x), (unsigned)(y) )
+#define uint3(x,y,z) C_CAST(uint3, (unsigned)(x), (unsigned)(y), (unsigned)(z) )
+#define uint4(x,y,z,w) C_CAST(uint4, (unsigned)(x), (unsigned)(y), (unsigned)(z), (unsigned)(w) )
-#define float2(x,y) M_CAST(float2, (float)(x), (float)(y) )
-#define float3(x,y,z) M_CAST(float3, (float)(x), (float)(y), (float)(z) )
-#define float4(x,y,z,w) M_CAST(float4, (float)(x), (float)(y), (float)(z), (float)(w) )
+#define float2(x,y) C_CAST(float2, (float)(x), (float)(y) )
+#define float3(x,y,z) C_CAST(float3, (float)(x), (float)(y), (float)(z) )
+#define float4(x,y,z,w) C_CAST(float4, (float)(x), (float)(y), (float)(z), (float)(w) )
-#define double2(x,y) M_CAST(double2, (double)(x), (double)(y) )
-#define double3(x,y,z) M_CAST(double3, (double)(x), (double)(y), (double)(z) )
-#define double4(x,y,z,w) M_CAST(double4, (double)(x), (double)(y), (double)(z), (double)(w) )
+#define double2(x,y) C_CAST(double2, (double)(x), (double)(y) )
+#define double3(x,y,z) C_CAST(double3, (double)(x), (double)(y), (double)(z) )
+#define double4(x,y,z,w) C_CAST(double4, (double)(x), (double)(y), (double)(z), (double)(w) )
// -----------------------------------------------------------------------------
// compile-time fourcc, eightcc
diff --git a/engine/split/v4k_render.c b/engine/split/v4k_render.c
index fa9f6df..80d2db6 100644
--- a/engine/split/v4k_render.c
+++ b/engine/split/v4k_render.c
@@ -1429,1110 +1429,6 @@ void fullscreen_quad_ycbcr_flipped( texture_t textureYCbCr[3], float gamma ) {
// glDisable( GL_BLEND );
}
-// ----------------------------------------------------------------------------
-// sprites
-
-typedef struct sprite_t {
- float px, py, pz; // origin x, y, depth
- float ox, oy, cos, sin; // offset x, offset y, cos/sin of rotation degree
- float sx, sy; // scale x,y
- uint32_t rgba; // vertex color
- float cellw, cellh; // dimensions of any cell in spritesheet
-
- union {
- struct {
- int frame, ncx, ncy; // frame in a (num cellx, num celly) spritesheet
- };
- struct {
- float x, y, w, h; // normalized[0..1] within texture bounds
- };
- };
-} sprite_t;
-
-// sprite batching
-typedef struct batch_t { array(sprite_t) sprites; mesh_t mesh; int dirty; } batch_t;
-typedef map(int, batch_t) batch_group_t; // mapkey is anything that forces a flush. texture_id for now, might be texture_id+program_id soon
-
-// sprite stream
-typedef struct sprite_vertex { vec3 pos; vec2 uv; uint32_t rgba; } sprite_vertex;
-typedef struct sprite_index { GLuint triangle[3]; } sprite_index;
-
-#define sprite_vertex(...) C_CAST(sprite_vertex, __VA_ARGS__)
-#define sprite_index(...) C_CAST(sprite_index, __VA_ARGS__)
-
-// sprite impl
-static int sprite_count = 0;
-static int sprite_program = -1;
-static array(sprite_index) sprite_indices = 0;
-static array(sprite_vertex) sprite_vertices = 0;
-static batch_group_t sprite_additive_group = {0}; // (w/2,h/2) centered
-static batch_group_t sprite_translucent_group = {0}; // (w/2,h/2) centered
-static batch_group_t sprite_00_translucent_group = {0}; // (0,0) centered
-
-void sprite( texture_t texture, float position[3], float rotation, uint32_t color ) {
- float offset[2] = {0,0}, scale[2] = {1,1}, spritesheet[3] = {0,0,0};
- sprite_sheet( texture, spritesheet, position, rotation, offset, scale, 0, color, false );
-}
-
-// rect(x,y,w,h) is [0..1] normalized, z-index, pos(x,y,scalex,scaley), rotation (degrees), color (rgba)
-void sprite_rect( texture_t t, vec4 rect, float zindex, vec4 pos, float tilt_deg, unsigned tint_rgba) {
- // do not queue if either alpha or scale is zero
- if( 0 == (pos.z * pos.w * ((tint_rgba>>24) & 255)) ) return;
-
- sprite_t s = {0};
-
- s.px = pos.x, s.py = pos.y, s.pz = zindex;
- s.sx = pos.z, s.sy = pos.w;
-
- s.x = rect.x, s.y = rect.y, s.w = rect.z, s.h = rect.w;
- s.cellw = s.w * s.sx * t.w, s.cellh = s.h * s.sy * t.h;
-
- s.rgba = tint_rgba;
- s.ox = 0/*ox*/ * s.sx;
- s.oy = 0/*oy*/ * s.sy;
- if( tilt_deg ) {
- tilt_deg = (tilt_deg + 0) * ((float)C_PI / 180);
- s.cos = cosf(tilt_deg);
- s.sin = sinf(tilt_deg);
- } else {
- s.cos = 1;
- s.sin = 0;
- }
-
- batch_group_t *batches = &sprite_00_translucent_group;
- batch_t *found = map_find_or_add(*batches, t.id, (batch_t){0});
-
- array_push(found->sprites, s);
-}
-
-void sprite_sheet( texture_t texture, float spritesheet[3], float position[3], float rotation, float offset[2], float scale[2], int is_additive, uint32_t rgba, int resolution_independant) {
- const float px = position[0], py = position[1], pz = position[2];
- const float ox = offset[0], oy = offset[1], sx = scale[0], sy = scale[1];
- const float frame = spritesheet[0], xcells = spritesheet[1], ycells = spritesheet[2];
-
- if (frame < 0) return;
- if (frame > 0 && frame >= (xcells * ycells)) return;
-
- // no need to queue if alpha or scale are zero
- if( sx && sy && alpha(rgba) ) {
- vec3 bak = camera_get_active()->position;
- if( resolution_independant ) { // @todo: optimize me
- sprite_flush();
- camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
- }
-
- sprite_t s;
- s.px = px;
- s.py = py;
- s.pz = pz;
- s.frame = frame;
- s.ncx = xcells ? xcells : 1;
- s.ncy = ycells ? ycells : 1;
- s.sx = sx;
- s.sy = sy;
- s.ox = ox * sx;
- s.oy = oy * sy;
- s.cellw = (texture.x * sx / s.ncx);
- s.cellh = (texture.y * sy / s.ncy);
- s.rgba = rgba;
- s.cos = 1;
- s.sin = 0;
- if(rotation) {
- rotation = (rotation + 0) * ((float)C_PI / 180);
- s.cos = cosf(rotation);
- s.sin = sinf(rotation);
- }
-
- batch_group_t *batches = is_additive ? &sprite_additive_group : &sprite_translucent_group;
-#if 0
- batch_t *found = map_find(*batches, texture.id);
- if( !found ) found = map_insert(*batches, texture.id, (batch_t){0});
-#else
- batch_t *found = map_find_or_add(*batches, texture.id, (batch_t){0});
-#endif
-
- array_push(found->sprites, s);
-
- if( resolution_independant ) { // @todo: optimize me
- sprite_flush();
- camera_get_active()->position = bak;
- }
- }
-}
-
-static void sprite_rebuild_meshes() {
- sprite_count = 0;
-
- batch_group_t* list[] = { &sprite_additive_group, &sprite_translucent_group };
- for( int l = 0; l < countof(list); ++l) {
- for each_map_ptr(*list[l], int,_, batch_t,bt) {
-
- bt->dirty = array_count(bt->sprites) ? 1 : 0;
- if( !bt->dirty ) continue;
-
- int index = 0;
- array_clear(sprite_indices);
- array_clear(sprite_vertices);
-
- array_foreach_ptr(bt->sprites, sprite_t,it ) {
- float x0 = it->ox - it->cellw/2, x3 = x0 + it->cellw;
- float y0 = it->oy - it->cellh/2, y3 = y0;
- float x1 = x0, x2 = x3;
- float y1 = y0 + it->cellh, y2 = y1;
-
- // @todo: move this affine transform into glsl shader
- vec3 v0 = { it->px + ( x0 * it->cos - y0 * it->sin ), it->py + ( x0 * it->sin + y0 * it->cos ), it->pz };
- vec3 v1 = { it->px + ( x1 * it->cos - y1 * it->sin ), it->py + ( x1 * it->sin + y1 * it->cos ), it->pz };
- vec3 v2 = { it->px + ( x2 * it->cos - y2 * it->sin ), it->py + ( x2 * it->sin + y2 * it->cos ), it->pz };
- vec3 v3 = { it->px + ( x3 * it->cos - y3 * it->sin ), it->py + ( x3 * it->sin + y3 * it->cos ), it->pz };
-
- float cx = (1.0f / it->ncx) - 1e-9f;
- float cy = (1.0f / it->ncy) - 1e-9f;
- int idx = (int)it->frame;
- int px = idx % it->ncx;
- int py = idx / it->ncx;
-
- float ux = px * cx, uy = py * cy;
- float vx = ux + cx, vy = uy + cy;
-
- vec2 uv0 = vec2(ux, uy);
- vec2 uv1 = vec2(ux, vy);
- vec2 uv2 = vec2(vx, vy);
- vec2 uv3 = vec2(vx, uy);
-
- array_push( sprite_vertices, sprite_vertex(v0, uv0, it->rgba) ); // Vertex 0 (A)
- array_push( sprite_vertices, sprite_vertex(v1, uv1, it->rgba) ); // Vertex 1 (B)
- array_push( sprite_vertices, sprite_vertex(v2, uv2, it->rgba) ); // Vertex 2 (C)
- array_push( sprite_vertices, sprite_vertex(v3, uv3, it->rgba) ); // Vertex 3 (D)
-
- // A--B A A-B
- // quad | | becomes triangle |\ and triangle \|
- // D--C D-C C
- GLuint A = (index+0), B = (index+1), C = (index+2), D = (index+3); index += 4;
-
- array_push( sprite_indices, sprite_index(C, D, A) ); // Triangle 1
- array_push( sprite_indices, sprite_index(C, A, B) ); // Triangle 2
- }
-
- mesh_update(&bt->mesh, "p3 t2 c4B", 0,array_count(sprite_vertices),sprite_vertices, 3*array_count(sprite_indices),sprite_indices, MESH_STATIC);
-
- // clear elements from queue
- sprite_count += array_count(bt->sprites);
- array_clear(bt->sprites);
- }
- }
-
- batch_group_t* list2[] = { &sprite_00_translucent_group };
- for( int l = 0; l < countof(list2); ++l) {
- for each_map_ptr(*list2[l], int,_, batch_t,bt) {
-
- bt->dirty = array_count(bt->sprites) ? 1 : 0;
- if( !bt->dirty ) continue;
-
- int index = 0;
- array_clear(sprite_indices);
- array_clear(sprite_vertices);
-
- array_foreach_ptr(bt->sprites, sprite_t,it ) {
- float x0 = it->ox - it->cellw/2, x3 = x0 + it->cellw;
- float y0 = it->oy - it->cellh/2, y3 = y0;
- float x1 = x0, x2 = x3;
- float y1 = y0 + it->cellh, y2 = y1;
-
- // @todo: move this affine transform into glsl shader
- vec3 v0 = { it->px + ( x0 * it->cos - y0 * it->sin ), it->py + ( x0 * it->sin + y0 * it->cos ), it->pz };
- vec3 v1 = { it->px + ( x1 * it->cos - y1 * it->sin ), it->py + ( x1 * it->sin + y1 * it->cos ), it->pz };
- vec3 v2 = { it->px + ( x2 * it->cos - y2 * it->sin ), it->py + ( x2 * it->sin + y2 * it->cos ), it->pz };
- vec3 v3 = { it->px + ( x3 * it->cos - y3 * it->sin ), it->py + ( x3 * it->sin + y3 * it->cos ), it->pz };
-
- float ux = it->x, vx = ux + it->w;
- float uy = it->y, vy = uy + it->h;
-
- vec2 uv0 = vec2(ux, uy);
- vec2 uv1 = vec2(ux, vy);
- vec2 uv2 = vec2(vx, vy);
- vec2 uv3 = vec2(vx, uy);
-
- array_push( sprite_vertices, sprite_vertex(v0, uv0, it->rgba) ); // Vertex 0 (A)
- array_push( sprite_vertices, sprite_vertex(v1, uv1, it->rgba) ); // Vertex 1 (B)
- array_push( sprite_vertices, sprite_vertex(v2, uv2, it->rgba) ); // Vertex 2 (C)
- array_push( sprite_vertices, sprite_vertex(v3, uv3, it->rgba) ); // Vertex 3 (D)
-
- // A--B A A-B
- // quad | | becomes triangle |\ and triangle \|
- // D--C D-C C
- GLuint A = (index+0), B = (index+1), C = (index+2), D = (index+3); index += 4;
-
- array_push( sprite_indices, sprite_index(C, D, A) ); // Triangle 1
- array_push( sprite_indices, sprite_index(C, A, B) ); // Triangle 2
- }
-
- mesh_update(&bt->mesh, "p3 t2 c4B", 0,array_count(sprite_vertices),sprite_vertices, 3*array_count(sprite_indices),sprite_indices, MESH_STATIC);
-
- // clear elements from queue
- sprite_count += array_count(bt->sprites);
- array_clear(bt->sprites);
- }
- }
-}
-
-static void sprite_render_meshes() {
- if( map_count(sprite_additive_group) <= 0 )
- if( map_count(sprite_translucent_group) <= 0 )
- if( map_count(sprite_00_translucent_group) <= 0 )
- return;
-
- if( sprite_program < 0 ) {
- sprite_program = shader( vfs_read("shaders/vs_324_24_sprite.glsl"), vfs_read("shaders/fs_24_4_sprite.glsl"),
- "att_Position,att_TexCoord,att_Color",
- "fragColor", NULL
- );
- }
-
- // use the shader and bind the texture @ unit 0
- shader_bind(sprite_program);
- glActiveTexture(GL_TEXTURE0);
-
- // setup rendering state
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_BLEND);
- glDepthFunc(GL_LEQUAL); // try to help with zfighting
-
- // update camera
- // camera_fps(camera_get_active(), 0,0);
- vec3 pos = camera_get_active()->position;
- float zoom = absf(pos.z); if(zoom < 0.1f) zoom = 0.1f; zoom = 1.f / (zoom + !zoom);
- float width = window_width();
- float height = window_height();
-
- // set mvp in the uniform. (0,0) is center of screen.
- mat44 mvp2d;
- float zdepth_max = window_height(); // 1;
- float l = pos.x - width * zoom / 2;
- float r = pos.x + width * zoom / 2;
- float b = pos.y + height * zoom / 2;
- float t = pos.y - height * zoom / 2;
- ortho44(mvp2d, l,r,b,t, -zdepth_max, +zdepth_max);
-
- shader_mat44("u_mvp", mvp2d);
-
- // set (unit 0) in the uniform texture sampler, and render batch
- // for all additive then translucent groups
-
- if( map_count(sprite_additive_group) > 0 ) {
- glBlendFunc( GL_SRC_ALPHA, GL_ONE );
- for each_map_ptr(sprite_additive_group, int,texture_id, batch_t,bt) {
- if( bt->dirty ) {
- shader_texture_unit("u_texture", *texture_id, 0);
- mesh_render(&bt->mesh);
- }
- }
-// map_clear(sprite_additive_group);
- }
-
- if( map_count(sprite_translucent_group) > 0 ) {
- glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
- for each_map_ptr(sprite_translucent_group, int,texture_id, batch_t,bt) {
- if( bt->dirty ) {
- shader_texture_unit("u_texture", *texture_id, 0);
- mesh_render(&bt->mesh);
- }
- }
-// map_clear(sprite_translucent_group);
- }
-
- if( map_count(sprite_00_translucent_group) > 0 ) {
- glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
- for each_map_ptr(sprite_00_translucent_group, int,texture_id, batch_t,bt) {
- if( bt->dirty ) {
- shader_texture_unit("u_texture", *texture_id, 0);
- mesh_render(&bt->mesh);
- }
- }
-// map_clear(sprite_00_translucent_group);
- }
-
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_BLEND);
- glDepthFunc(GL_LESS);
- glUseProgram(0);
-}
-
-static void sprite_init() {
- do_once {
- map_init(sprite_00_translucent_group, less_int, hash_int);
- map_init(sprite_translucent_group, less_int, hash_int);
- map_init(sprite_additive_group, less_int, hash_int);
- }
-}
-
-void sprite_flush() {
- profile("Sprite.rebuild_time") {
- sprite_rebuild_meshes();
- }
- profile("Sprite.render_time") {
- sprite_render_meshes();
- }
-}
-
-// -----------------------------------------------------------------------------
-// tilemaps
-
-tilemap_t tilemap(const char *map, int blank_chr, int linefeed_chr) {
- tilemap_t t = {0};
- t.tint = ~0u; // WHITE
- t.blank_chr = blank_chr;
- for( ; *map ; ++map ) {
- if( map[0] == linefeed_chr ) ++t.rows;
- else {
- array_push(t.map, map[0]);
- ++t.cols;
- }
- }
- return t;
-}
-
-void tilemap_render_ext( tilemap_t m, tileset_t t, float zindex, float xy_zoom[3], float tilt, unsigned tint, bool is_additive ) {
- vec3 old_pos = camera_get_active()->position;
- sprite_flush();
- camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
-
- float scale[2] = {xy_zoom[2], xy_zoom[2]};
- xy_zoom[2] = zindex;
-
- float offset[2] = {0,0};
- float spritesheet[3] = {0,t.cols,t.rows}; // selected tile index and spritesheet dimensions (cols,rows)
-
- for( unsigned y = 0, c = 0; y < m.rows; ++y ) {
- for( unsigned x = 0; x < m.cols; ++x, ++c ) {
- if( m.map[c] != m.blank_chr ) {
- spritesheet[0] = m.map[c];
- sprite_sheet(t.tex, spritesheet, xy_zoom, tilt, offset, scale, is_additive, tint, false);
- }
- offset[0] += t.tile_w;
- }
- offset[0] = 0, offset[1] += t.tile_h;
- }
-
- sprite_flush();
- camera_get_active()->position = old_pos;
-}
-
-void tilemap_render( tilemap_t map, tileset_t set ) {
- map.position.x += set.tile_w;
- map.position.y += set.tile_h;
- tilemap_render_ext( map, set, map.zindex, &map.position.x, map.tilt, map.tint, map.is_additive );
-}
-
-tileset_t tileset(texture_t tex, unsigned tile_w, unsigned tile_h, unsigned cols, unsigned rows) {
- tileset_t t = {0};
- t.tex = tex;
- t.cols = cols, t.rows = rows;
- t.tile_w = tile_w, t.tile_h = tile_h;
- return t;
-}
-
-int ui_tileset( tileset_t t ) {
- ui_subimage(va("Selection #%d (%d,%d)", t.selected, t.selected % t.cols, t.selected / t.cols), t.tex.id, t.tex.w, t.tex.h, (t.selected % t.cols) * t.tile_w, (t.selected / t.cols) * t.tile_h, t.tile_w, t.tile_h);
- int choice;
- if( (choice = ui_image(0, t.tex.id, t.tex.w,t.tex.h)) ) {
- int px = ((choice / 100) / 100.f) * t.tex.w / t.tile_w;
- int py = ((choice % 100) / 100.f) * t.tex.h / t.tile_h;
- t.selected = px + py * t.cols;
- }
- // if( (choice = ui_buttons(3, "load", "save", "clear")) ) {}
- return t.selected;
-}
-
-// -----------------------------------------------------------------------------
-// tiled
-
-tiled_t tiled(const char *file_tmx) {
- tiled_t zero = {0}, ti = zero;
-
- // read file and parse json
- if( !xml_push(file_tmx) ) return zero;
-
- // sanity checks
- bool supported = !strcmp(xml_string("/map/@orientation"), "orthogonal") && !strcmp(xml_string("/map/@renderorder"), "right-down");
- if( !supported ) return xml_pop(), zero;
-
- // tileset
- const char *file_tsx = xml_string("/map/tileset/@source");
- if( !xml_push(vfs_read(file_tsx)) ) return zero;
- const char *set_src = xml_string("/tileset/image/@source");
- int set_w = xml_int("/tileset/@tilewidth");
- int set_h = xml_int("/tileset/@tileheight");
- int set_c = xml_int("/tileset/@columns");
- int set_r = xml_int("/tileset/@tilecount") / set_c;
- tileset_t set = tileset(texture(set_src,0), set_w, set_h, set_c, set_r );
- xml_pop();
-
- // actual parsing
- ti.w = xml_int("/map/@width");
- ti.h = xml_int("/map/@height");
- ti.tilew = xml_int("/map/@tilewidth");
- ti.tileh = xml_int("/map/@tileheight");
- ti.first_gid = xml_int("/map/tileset/@firstgid");
- ti.map_name = STRDUP( xml_string("/map/tileset/@source") ); // @leak
-
- for(int l = 0, layers = xml_count("/map/layer"); l < layers; ++l ) {
- if( strcmp(xml_string("/map/layer[%d]/data/@encoding",l), "base64") || strcmp(xml_string("/map/layer[%d]/data/@compression",l), "zlib") ) {
- PRINTF("Warning: layer encoding not supported: '%s' -> layer '%s'\n", file_tmx, *array_back(ti.names));
- continue;
- }
-
- int cols = xml_int("/map/layer[%d]/@width",l);
- int rows = xml_int("/map/layer[%d]/@height",l);
-
- tilemap_t tm = tilemap("", ' ', '\n');
- tm.blank_chr = ~0u; //ti.first_gid - 1;
- tm.cols = cols;
- tm.rows = rows;
- array_resize(tm.map, tm.cols * tm.rows);
- memset(tm.map, 0xFF, tm.cols * tm.rows * sizeof(int));
-
- for( int c = 0, chunks = xml_count("/map/layer[%d]/data/chunk", l); c <= chunks; ++c ) {
- int cw, ch;
- int cx, cy;
- array(char) b64 = 0;
-
- if( !chunks ) { // non-infinite mode
- b64 = xml_blob("/map/layer[%d]/data/$",l);
- cw = tm.cols, ch = tm.rows;
- cx = 0, cy = 0;
- } else { // infinite mode
- b64 = xml_blob("/map/layer[%d]/data/chunk[%d]/$",l,c);
- cw = xml_int("/map/layer[%d]/data/chunk[%d]/@width",l,c), ch = xml_int("/map/layer[%d]/data/chunk[%d]/@height",l,c); // 20x20
- cx = xml_int("/map/layer[%d]/data/chunk[%d]/@x",l,c), cy = xml_int("/map/layer[%d]/data/chunk[%d]/@y",l,c); // (-16,-32)
- cx = abs(cx), cy = abs(cy);
- }
-
- int outlen = cw * ch * 4;
- static __thread int *out = 0; out = (int *)REALLOC( 0, outlen + zexcess(COMPRESS_ZLIB) ); // @leak
- if( zdecode( out, outlen, b64, array_count(b64), COMPRESS_ZLIB ) > 0 ) {
- for( int y = 0, p = 0; y < ch; ++y ) {
- for( int x = 0; x < cw; ++x, ++p ) {
- if( out[p] >= ti.first_gid ) {
- int offset = (x + cx) + (y + cy) * tm.cols;
- if( offset >= 0 && offset < (cw * ch) )
- tm.map[ offset ] = out[ p ] - ti.first_gid;
- }
- }
- }
- }
- else {
- PRINTF("Warning: bad zlib stream: '%s' -> layer #%d -> chunk #%d\n", file_tmx, l, c);
- }
-
- array_free(b64);
- }
-
- array_push(ti.layers, tm);
- array_push(ti.names, STRDUP(xml_string("/map/layer[%d]/@name",l)));
- array_push(ti.visible, true);
- array_push(ti.sets, set);
- }
-
- xml_pop();
- return ti;
-}
-
-void tiled_render(tiled_t tmx, vec3 pos) {
- for( unsigned i = 0, end = array_count(tmx.layers); i < end; ++i ) {
- tmx.layers[i].position = pos; // add3(camera_get_active()->position, pos);
- if( tmx.parallax ) tmx.layers[i].position.x /= (3+i), tmx.layers[i].position.y /= (5+i);
- if( tmx.visible[i] ) tilemap_render(tmx.layers[i], tmx.sets[i]);
- }
-}
-
-void ui_tiled(tiled_t *t) {
- ui_label2("Loaded map", t->map_name ? t->map_name : "(none)");
- ui_label2("Map dimensions", va("%dx%d", t->w, t->h));
- ui_label2("Tile dimensions", va("%dx%d", t->tilew, t->tileh));
- ui_separator();
- ui_bool("Parallax", &t->parallax);
- ui_separator();
- ui_label2("Layers", va("%d", array_count(t->layers)));
- for( int i = 0; i < array_count(t->layers); ++i ) {
- if( ui_label2_toolbar(va("- %s (%dx%d)", t->names[i], t->layers[i].cols, t->layers[i].rows ), t->visible[i] ? "\xee\xa3\xb4" : "\xee\xa3\xb5") > 0 ) { // ICON_MD_VISIBILITY / ICON_MD_VISIBILITY_OFF
- t->visible[i] ^= true;
- }
- }
- ui_separator();
- if( ui_collapse(va("Sets: %d", array_count(t->layers)), va("%p",t))) {
- for( int i = 0; i < array_count(t->layers); ++i ) {
- if( ui_collapse(va("%d", i+1), va("%p%d",t,i)) ) {
- t->sets[i].selected = ui_tileset( t->sets[i] );
- ui_collapse_end();
- }
- }
- ui_collapse_end();
- }
-}
-
-// -----------------------------------------------------------------------------
-// spine json loader (wip)
-// - rlyeh, public domain
-//
-// [ref] http://es.esotericsoftware.com/spine-json-format
-//
-// notable misses:
-// - mesh deforms
-// - cubic beziers
-// - shears
-// - bounding boxes
-
-enum { SPINE_MAX_BONES = 64 }; // max bones
-
-typedef struct spine_bone_t {
- char *name, *parent;
- struct spine_bone_t *parent_bone;
-
- float z; // draw order usually matches bone-id. ie, zindex == bone_id .. root(0) < chest (mid) < finger(top)
-
- float len;
- float x, y, deg; // base
- float x2, y2, deg2; // accum / temporaries during bone transform time
- float x3, y3, deg3; // values from timeline
-
- unsigned rect_id;
- unsigned atlas_id;
-} spine_bone_t;
-
-typedef struct spine_slot_t {
- char *name, *bone, *attach;
-} spine_slot_t;
-
-typedef struct spine_rect_t {
- char *name;
- float x,y,w,h,sx,sy,deg;
-} spine_rect_t;
-
-typedef struct spine_skin_t {
- char *name;
- array(spine_rect_t) rects;
-} spine_skin_t;
-
-typedef struct spine_animkey_t { // offline; only during loading
- float time, curve[4]; // time is mandatory, curve is optional
- union {
- char *name; // type: attachment (mode-1)
- struct { float deg; }; // type: rotate (mode-2)
- struct { float x,y; }; // type: translate (mode-3)
- };
-} spine_animkey_t;
-
-#if 0
-typedef struct spine_pose_t { // runtime; only during playing
- unsigned frame;
- array(vec4) xform; // entry per bone. translation(x,y),rotation(z),attachment-id(w)
-} spine_pose_t;
-#endif
-
-typedef struct spine_anim_t {
- char *name;
- union {
-#if 0
- struct {
- unsigned frames;
- array(spine_pose_t) poses;
- };
-#endif
- struct {
- array(spine_animkey_t) attach_keys[SPINE_MAX_BONES];
- array(spine_animkey_t) rotate_keys[SPINE_MAX_BONES];
- array(spine_animkey_t) translate_keys[SPINE_MAX_BONES];
- };
- };
-} spine_anim_t;
-
-typedef struct spine_atlas_t {
- char *name;
- float x,y,w,h,deg;
-} spine_atlas_t;
-
-typedef struct spine_t {
- char *name;
- texture_t texture;
- unsigned skin;
- array(spine_bone_t) bones;
- array(spine_slot_t) slots;
- array(spine_skin_t) skins;
- array(spine_anim_t) anims;
- array(spine_atlas_t) atlas;
- // anim controller
- unsigned inuse;
- float time, maxtime;
- unsigned debug_atlas_id;
-} spine_t;
-
-// ---
-
-static
-void spine_convert_animkeys_to_animpose(spine_anim_t *input) {
- spine_anim_t copy = *input; // @todo
- // @leak: attach/rot/tra keys
-}
-
-static
-int find_bone_id(spine_t *s, const char *bone_name) {
- for( unsigned i = 0, end = array_count(s->bones); i < end; ++i )
- if( !strcmp(s->bones[i].name, bone_name)) return i;
- return -1;
-}
-static
-spine_bone_t *find_bone(spine_t *s, const char *bone_name) {
- int bone_id = find_bone_id(s, bone_name);
- return bone_id >= 0 ? &s->bones[bone_id] : NULL;
-}
-
-void spine_skin(spine_t *p, unsigned skin) {
- if( !p->texture.id ) return;
- if( skin >= array_count(p->skins) ) return;
-
- p->skin = skin;
-
- char *skin_name = va("%s/", p->skins[skin].name);
- int header = strlen(skin_name);
-
- for( int i = 0; i < array_count(p->atlas); ++i) {
- if(!strbeg(p->atlas[i].name, skin_name)) continue;
-
- int bone_id = find_bone_id(p, p->atlas[i].name+header );
- if( bone_id < 0 ) continue;
-
- p->bones[bone_id].atlas_id = i;
- }
-
- for( int i = 0; i < array_count(p->skins[p->skin].rects); ++i) {
- int bone_id = find_bone_id(p, p->skins[p->skin].rects[i].name );
- if( bone_id < 0 ) continue;
-
- p->bones[bone_id].rect_id = i;
- }
-}
-
-static
-bool spine_(spine_t *t, const char *file_json, const char *file_atlas, unsigned flags) {
- char *atlas = vfs_read(file_atlas);
- if(!atlas || !atlas[0]) return false;
-
- memset(t, 0, sizeof(spine_t));
-
- // goblins.png
- // size: 1024, 128
- // filter: Linear, Linear
- // pma: true
- // dagger
- // bounds: 2, 18, 26, 108
- // goblin/eyes-closed
- // bounds: 2, 4, 34, 12
- spine_atlas_t *sa = 0;
- const char *last_id = 0;
- const char *texture_name = 0;
- const char *texture_filter = 0;
- const char *texture_format = 0;
- const char *texture_repeat = 0;
- float texture_width = 0, texture_height = 0, temp;
- for each_substring(atlas, "\r\n", it) {
- it += strspn(it, " \t\f\v");
- /**/ if( strbeg(it, "pma:" ) || strbeg(it, "index:") ) {} // ignored
- else if( strbeg(it, "size:" ) ) sscanf(it+5, "%f,%f", &texture_width, &texture_height);
- else if( strbeg(it, "rotate:" ) ) { float tmp; tmp=sa->w,sa->w=sa->h,sa->h=tmp; sa->deg = 90; } // assert(val==90)
- else if( strbeg(it, "repeat:" ) ) texture_repeat = it+7; // temp string
- else if( strbeg(it, "filter:" ) ) texture_filter = it+7; // temp string
- else if( strbeg(it, "format:" ) ) texture_format = it+7; // temp string
- else if( strbeg(it, "bounds:" ) ) {
- sscanf(it+7, "%f,%f,%f,%f", &sa->x, &sa->y, &sa->w, &sa->h);
- }
- else if( !texture_name ) texture_name = va("%s", it);
- else {
- array_push(t->atlas, ((spine_atlas_t){0}) );
- sa = &t->atlas[array_count(t->atlas) - 1];
- sa->name = STRDUP(it);
- }
- }
- for( int i = 0; i < array_count(t->atlas); ++i ) {
- sa = &t->atlas[i];
- sa->x /= texture_width, sa->y /= texture_height;
- sa->w /= texture_width, sa->h /= texture_height;
- }
-
- if(!texture_name) return false;
-
- t->texture = texture(texture_name, TEXTURE_LINEAR);
-
- json_push(vfs_read(file_json)); // @fixme: json_push_from_file() ?
-
- array_resize(t->bones, json_count("/bones"));
- array_reserve(t->slots, json_count("/slots"));
- array_resize(t->skins, json_count("/skins"));
- array_resize(t->anims, json_count("/animations"));
-
- for( int i = 0, end = json_count("/bones"); i < end; ++i ) {
- spine_bone_t v = {0};
- v.name = STRDUP(json_string("/bones[%d]/name", i));
- v.parent = STRDUP(json_string("/bones[%d]/parent", i));
- v.x = json_float("/bones[%d]/x", i);
- v.y = json_float("/bones[%d]/y", i);
- v.z = i;
- v.len = json_float("/bones[%d]/length", i);
- v.deg = json_float("/bones[%d]/rotation", i);
- t->bones[i] = v;
-
- for( int j = i-1; j > 0; --j ) {
- if( strcmp(t->bones[j].name,v.parent) ) continue;
- t->bones[i].parent_bone = &t->bones[j];
- break;
- }
- }
-
- for( int i = 0, end = json_count("/slots"); i < end; ++i ) {
- spine_slot_t v = {0};
- v.name = STRDUP(json_string("/slots[%d]/name", i));
- v.bone = STRDUP(json_string("/slots[%d]/bone", i));
- v.attach = STRDUP(json_string("/slots[%d]/attachment", i));
-
- array_push(t->slots, v);
-
- // slots define draw-order. so, update draw-order/zindex in bone
- spine_bone_t *b = find_bone(t, v.name);
- if( b ) b->z = i;
- }
-
- for( int i = 0, end = json_count("/skins"); i < end; ++i ) {
- spine_skin_t v = {0};
- v.name = STRDUP(json_string("/skins[%d]/name", i));
-
- for( int j = 0, jend = json_count("/skins[%d]/attachments",i); j < jend; ++j ) // /skins/default/
- for( int k = 0, kend = json_count("/skins[%d]/attachments[%d]",i,j); k < kend; ++k ) { // /skins/default/left hand item/
- spine_rect_t r = {0};
- r.name = STRDUP(json_key("/skins[%d]/attachments[%d][%d]",i,j,k)); // stringf("%s-%s-%s", json_key("/skins[%d]",i), json_key("/skins[%d][%d]",i,j), json_key("/skins[%d][%d][%d]",i,j,k));
- r.x = json_float("/skins[%d]/attachments[%d][%d]/x",i,j,k);
- r.y = json_float("/skins[%d]/attachments[%d][%d]/y",i,j,k);
- r.sx= json_float("/skins[%d]/attachments[%d][%d]/scaleX",i,j,k); r.sx += !r.sx;
- r.sy= json_float("/skins[%d]/attachments[%d][%d]/scaleY",i,j,k); r.sy += !r.sy;
- r.w = json_float("/skins[%d]/attachments[%d][%d]/width",i,j,k);
- r.h = json_float("/skins[%d]/attachments[%d][%d]/height",i,j,k);
- r.deg = json_float("/skins[%d]/attachments[%d][%d]/rotation",i,j,k);
- array_push(v.rects, r);
- }
-
- t->skins[i] = v;
- }
-
-#if 1
- // simplify:
- // merge /skins/default into existing /skins/*, then delete /skins/default
- if( array_count(t->skins) > 1 ) {
- for( int i = 1; i < array_count(t->skins); ++i ) {
- for( int j = 0; j < array_count(t->skins[0].rects); ++j ) {
- array_push(t->skins[i].rects, t->skins[0].rects[j]);
- }
- }
- // @leak @fixme: FREE(t->skins[0])
- for( int i = 0; i < array_count(t->skins)-1; ++i ) {
- t->skins[i] = t->skins[i+1];
- }
- array_pop(t->skins);
- }
-#endif
-
- for( int i = 0, end = json_count("/animations"); i < end; ++i ) {
- int id;
- const char *name;
-
- spine_anim_t v = {0};
- v.name = STRDUP(json_key("/animations[%d]", i));
-
- // slots / attachments
-
- for( int j = 0, jend = json_count("/animations[%d]/slots",i); j < jend; ++j )
- for( int k = 0, kend = json_count("/animations[%d]/slots[%d]",i,j); k < kend; ++k ) // ids
- {
- int bone_id = find_bone_id(t, json_key("/animations[%d]/bones[%d]",i,j));
- if( bone_id < 0 ) continue;
-
- for( int l = 0, lend = json_count("/animations[%d]/slots[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
- spine_animkey_t key = {0};
-
- key.name = STRDUP(json_string("/animations[%d]/slots[%d][%d][%d]/name",i,j,k,l));
- key.time = json_float("/animations[%d]/slots[%d][%d][%d]/time",i,j,k,l);
- if( json_count("/animations[%d]/slots[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
- key.curve[0] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[0]",i,j,k,l);
- key.curve[1] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[1]",i,j,k,l);
- key.curve[2] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[2]",i,j,k,l);
- key.curve[3] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[3]",i,j,k,l);
- }
-
- // @todo: convert name to id
- // for(id = 0; t->bones[id].name && strcmp(t->bones[id].name,key.name); ++id)
- // printf("%s vs %s\n", key.name, t->bones[id].name);
-
- array_push(v.attach_keys[bone_id], key);
- }
- }
-
- // bones
-
- for( int j = 0, jend = json_count("/animations[%d]/bones",i); j < jend; ++j ) // slots or bones
- for( int k = 0, kend = json_count("/animations[%d]/bones[%d]",i,j); k < kend; ++k ) { // bone ids
- int bone_id = find_bone_id(t, json_key("/animations[%d]/bones[%d]",i,j));
- if( bone_id < 0 ) continue;
-
- // parse bones
- for( int l = 0, lend = json_count("/animations[%d]/bones[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
- const char *channel = json_key("/animations[%d]/bones[%d][%d]",i,j,k);
- int track = !strcmp(channel, "rotate") ? 1 : !strcmp(channel, "translate") ? 2 : 0;
- if( !track ) continue;
-
- spine_animkey_t key = {0};
-
- key.time = json_float("/animations[%d]/bones[%d][%d][%d]/time",i,j,k,l);
- if( json_count("/animations[%d]/bones[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
- key.curve[0] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[0]",i,j,k,l);
- key.curve[1] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[1]",i,j,k,l);
- key.curve[2] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[2]",i,j,k,l);
- key.curve[3] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[3]",i,j,k,l);
- }
-
- if( track == 1 )
- key.deg = json_float("/animations[%d]/bones[%d][%d][%d]/value",i,j,k,l), // "/angle"
- array_push(v.rotate_keys[bone_id], key);
- else
- key.x = json_float("/animations[%d]/bones[%d][%d][%d]/x",i,j,k,l),
- key.y = json_float("/animations[%d]/bones[%d][%d][%d]/y",i,j,k,l),
- array_push(v.translate_keys[bone_id], key);
- }
- }
-
- t->anims[i] = v;
- }
-
- json_pop();
-
- spine_skin(t, 0);
-
- return true;
-}
-
-spine_t* spine(const char *file_json, const char *file_atlas, unsigned flags) {
- spine_t *t = MALLOC(sizeof(spine_t));
- if( !spine_(t, file_json, file_atlas, flags) ) return FREE(t), NULL;
- return t;
-}
-
-void spine_render(spine_t *p, vec3 offset, unsigned flags) {
- if( !p->texture.id ) return;
- if( !flags ) return;
-
- ddraw_push_2d();
- // if( flags & 2 ) ddraw_line(vec3(0,0,0), vec3(window_width(),window_height(),0));
- // if( flags & 2 ) ddraw_line(vec3(window_width(),0,0), vec3(0,window_height(),0));
-
- // int already_computed[SPINE_MAX_BONES] = {0}; // @fixme: optimize: update longest chains first, then remnant branches
-
- for( int i = 1; i < array_count(p->bones); ++i ) {
- spine_bone_t *self = &p->bones[i];
- if( !self->rect_id ) continue;
-
- int num_bones = 0;
- static array(spine_bone_t*) chain = 0; array_resize(chain, 0);
- for( spine_bone_t *next = self; next ; next = next->parent_bone, ++num_bones ) {
- array_push(chain, next);
- }
-
- vec3 target = {0}, prev = {0};
- for( int j = 0, end = array_count(chain); j < end; ++j ) { // traverse from root(skipped) -> `i` bone direction
- int j_opposite = end - 1 - j;
-
- spine_bone_t *b = chain[j_opposite]; // bone
- spine_bone_t *pb = b->parent_bone; // parent bone
-
- float pb_x2 = 0, pb_y2 = 0, pb_deg2 = 0;
- if( pb ) pb_x2 = pb->x2, pb_y2 = pb->y2, pb_deg2 = pb->deg2;
-
- const float deg2rad = C_PI / 180;
- b->x2 = b->x3 + pb_x2 + b->x * cos( -pb_deg2 * deg2rad ) - b->y * sin( -pb_deg2 * deg2rad );
- b->y2 = -b->y3 + pb_y2 - b->y * cos( pb_deg2 * deg2rad ) + b->x * sin( pb_deg2 * deg2rad );
- b->deg2 = -b->deg3 + pb_deg2 - b->deg;
-
- prev = target;
- target = vec3(b->x2,b->y2,b->deg2);
- }
-
- target.z = 0;
- target = add3(target, offset);
- prev.z = 0;
- prev = add3(prev, offset);
-
- if( flags & 2 ) {
- ddraw_point( target );
- ddraw_text( target, -0.25f, self->name );
- ddraw_bone( prev, target ); // from parent to bone
- }
- if( flags & 1 ) {
- spine_atlas_t *a = &p->atlas[self->atlas_id];
- spine_rect_t *r = &p->skins[p->skin].rects[self->rect_id];
-
- vec4 rect = ptr4(&a->x);
- float zindex = self->z;
- float offsx = 0;
- float offsy = 0;
- float tilt = self->deg2 + (a->deg - r->deg);
- unsigned tint = self->atlas_id == p->debug_atlas_id ? 0xFF<<24 | 0xFF : ~0u;
-
- if( 1 ) {
- vec3 dir = vec3(r->x,r->y,0);
- dir = rotatez3(dir, self->deg2);
- offsx = dir.x * r->sx;
- offsy = dir.y * r->sy;
- }
-
- sprite_rect(p->texture, rect, zindex, add4(vec4(target.x,target.y,1,1),vec4(offsx,offsy,0,0)), tilt, tint);
- }
- }
-
- ddraw_pop_2d();
- ddraw_flush();
-}
-
-static
-void spine_animate_(spine_t *p, float *time, float *maxtime, float delta) {
- if( !p->texture.id ) return;
-
- if( delta > 1/120.f ) delta = 1/120.f;
- if( *time >= *maxtime ) *time = 0; else *time += delta;
-
- // reset root // needed?
- p->bones[0].x2 = 0;
- p->bones[0].y2 = 0;
- p->bones[0].deg2 = 0;
- p->bones[0].x3 = 0;
- p->bones[0].y3 = 0;
- p->bones[0].deg3 = 0;
-
- for( int i = 0, end = array_count(p->bones); i < end; ++i) {
- // @todo: attach channel
- // @todo: per channel: if curve == linear || curve == stepped || array_count(curve) == 4 {...}
- for each_array_ptr(p->anims[p->inuse].rotate_keys[i], spine_animkey_t, r) {
- double r0 = r->time;
- *maxtime = maxf( *maxtime, r0 );
- if( absf(*time - r0) < delta ) {
- p->bones[i].deg3 = r->deg;
- }
- }
- for each_array_ptr(p->anims[p->inuse].translate_keys[i], spine_animkey_t, r) {
- double r0 = r->time;
- *maxtime = maxf( *maxtime, r0 );
- if( absf(*time - r0) < delta ) {
- p->bones[i].x3 = r->x;
- p->bones[i].y3 = r->y;
- }
- }
- }
-}
-
-void spine_animate(spine_t *p, float delta) {
- spine_animate_(p, &p->time, &p->maxtime, delta);
-}
-
-void ui_spine(spine_t *p) {
- if( ui_collapse(va("Anims: %d", array_count(p->anims)), va("%p-a", p))) {
- for each_array_ptr(p->anims, spine_anim_t, q) {
- if(ui_slider2("", &p->time, va("%.2f/%.0f %.2f%%", p->time, p->maxtime, p->time * 100.f))) {
- spine_animate(p, 0);
- }
-
- int choice = ui_label2_toolbar(q->name, ICON_MD_PAUSE_CIRCLE " " ICON_MD_PLAY_CIRCLE);
- if( choice == 1 ) window_pause( 0 ); // play
- if( choice == 2 ) window_pause( 1 ); // pause
-
- for( int i = 0; i < SPINE_MAX_BONES; ++i ) {
- ui_separator();
- ui_label(va("Bone %d: Attachment keys", i));
- for each_array_ptr(q->attach_keys[i], spine_animkey_t, r) {
- ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %s", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->name));
- }
- ui_label(va("Bone %d: Rotate keys", i));
- for each_array_ptr(q->rotate_keys[i], spine_animkey_t, r) {
- ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %.2f deg", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->deg));
- }
- ui_label(va("Bone %d: Translate keys", i));
- for each_array_ptr(q->translate_keys[i], spine_animkey_t, r) {
- ui_label(va("%.2f [%.2f %.2f %.2f %.2f] (%.2f,%.2f)", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->x, r->y));
- }
- }
- }
- ui_collapse_end();
- }
- if( ui_collapse(va("Bones: %d", array_count(p->bones)), va("%p-b", p))) {
- for each_array_ptr(p->bones, spine_bone_t, q)
- if( ui_collapse(q->name, va("%p-b2", q)) ) {
- ui_label2("Parent:", q->parent);
- ui_label2("X:", va("%.2f", q->x));
- ui_label2("Y:", va("%.2f", q->y));
- ui_label2("Length:", va("%.2f", q->len));
- ui_label2("Rotation:", va("%.2f", q->deg));
- ui_collapse_end();
- }
- ui_collapse_end();
- }
- if( ui_collapse(va("Slots: %d", array_count(p->slots)), va("%p-s", p))) {
- for each_array_ptr(p->slots, spine_slot_t, q)
- if( ui_collapse(q->name, va("%p-s2", q)) ) {
- ui_label2("Bone:", q->bone);
- ui_label2("Attachment:", q->attach);
- ui_collapse_end();
- }
- ui_collapse_end();
- }
- if( ui_collapse(va("Skins: %d", array_count(p->skins)), va("%p-k", p))) {
- for each_array_ptr(p->skins, spine_skin_t, q)
- if( ui_collapse(q->name, va("%p-k2", q)) ) {
- for each_array_ptr(q->rects, spine_rect_t, r)
- if( ui_collapse(r->name, va("%p-k3", r)) ) {
- ui_label2("X:", va("%.2f", r->x));
- ui_label2("Y:", va("%.2f", r->y));
- ui_label2("Scale X:", va("%.2f", r->sx));
- ui_label2("Scale Y:", va("%.2f", r->sy));
- ui_label2("Width:", va("%.2f", r->w));
- ui_label2("Height:", va("%.2f", r->h));
- ui_label2("Rotation:", va("%.2f", r->deg));
- ui_collapse_end();
-
- spine_bone_t *b = find_bone(p, r->name);
- if( b ) {
- p->debug_atlas_id = b->atlas_id;
-
- static float tilt = 0;
- if( input(KEY_LCTRL) ) tilt += 60*1/60.f; else tilt = 0;
- spine_atlas_t *r = p->atlas + b->atlas_id;
- sprite_flush();
- camera_get_active()->position = vec3(0,0,2);
- vec4 rect = ptr4(&r->x); float zindex = 0; vec3 xy_zoom = vec3(0,0,0); unsigned tint = ~0u;
- sprite_rect(p->texture,
- // rect: vec4(r->x*1.0/p->texture.w,r->y*1.0/p->texture.h,(r->x+r->w)*1.0/p->texture.w,(r->y+r->h)*1.0/p->texture.h),
- ptr4(&r->x), // atlas
- 0, vec4(0,0,1,1), r->deg + tilt, tint);
- sprite_flush();
- camera_get_active()->position = vec3(+window_width()/3,window_height()/2.25,2);
- }
- }
- ui_collapse_end();
- }
- ui_collapse_end();
- }
-
- if( ui_int("Use skin", &p->skin) ) {
- p->skin = clampf(p->skin, 0, array_count(p->skins) - 1);
- spine_skin(p, p->skin);
- }
-
- if( p->texture.id ) ui_texture(0, p->texture);
-}
-
// -----------------------------------------------------------------------------
// cubemaps
diff --git a/engine/split/v4k_render.h b/engine/split/v4k_render.h
index ed42aa3..4f62d92 100644
--- a/engine/split/v4k_render.h
+++ b/engine/split/v4k_render.h
@@ -183,82 +183,6 @@ API void fullscreen_quad_rgb_flipped( texture_t texture, float gamma );
API void fullscreen_quad_ycbcr( texture_t texture_YCbCr[3], float gamma );
API void fullscreen_quad_ycbcr_flipped( texture_t texture_YCbCr[3], float gamma );
-// -----------------------------------------------------------------------------
-// sprites
-
-// texture id, position(x,y,depth sort), tint color, rotation angle
-API void sprite( texture_t texture, float position[3], float rotation /*0*/, uint32_t color /*~0u*/);
-
-// texture id, rect(x,y,w,h) is [0..1] normalized, z-index, pos(xy,scale.xy), rotation (degrees), color (rgba)
-API void sprite_rect( texture_t t, vec4 rect, float zindex, vec4 pos, float tilt_deg, unsigned tint_rgba);
-
-// texture id, sheet(frameNumber,X,Y) (frame in a X*Y spritesheet), position(x,y,depth sort), rotation angle, offset(x,y), scale(x,y), is_additive, tint color
-API void sprite_sheet( texture_t texture, float sheet[3], float position[3], float rotation, float offset[2], float scale[2], int is_additive, uint32_t rgba, int resolution_independant);
-
-API void sprite_flush();
-
-// -----------------------------------------------------------------------------
-// tilemaps
-
-typedef struct tileset_t {
- texture_t tex; // spritesheet
- unsigned tile_w, tile_h; // dimensions per tile in pixels
- unsigned cols, rows; // tileset num_cols, num_rows
- unsigned selected; // active tile (while editing)
-} tileset_t;
-
-API tileset_t tileset(texture_t tex, unsigned tile_w, unsigned tile_h, unsigned cols, unsigned rows);
-
-API int ui_tileset( tileset_t t );
-
-typedef struct tilemap_t {
- int blank_chr; // transparent tile
- unsigned cols, rows; // map dimensions (in tiles)
- array(int) map;
-
- vec3 position; // x,y,scale
- float zindex;
- float tilt;
- unsigned tint;
- bool is_additive;
-} tilemap_t;
-
-API tilemap_t tilemap(const char *map, int blank_chr, int linefeed_chr);
-API void tilemap_render( tilemap_t m, tileset_t style );
-API void tilemap_render_ext( tilemap_t m, tileset_t style, float zindex, float xy_zoom[3], float tilt, unsigned tint, bool is_additive );
-
-// -----------------------------------------------------------------------------
-// tiled maps
-
-typedef struct tiled_t {
- char *map_name;
- unsigned first_gid, tilew, tileh, w, h;
-
- bool parallax;
- vec3 position;
- array(bool) visible;
- array(tilemap_t) layers;
- array(tileset_t) sets;
- array(char*) names;
-} tiled_t;
-
-API tiled_t tiled(const char *file_tmx);
-API void tiled_render(tiled_t tmx, vec3 pos);
-
-API void ui_tiled(tiled_t *t);
-
-// -----------------------------------------------------------------------------
-// spines
-
-typedef struct spine_t spine_t;
-
-API spine_t*spine(const char *file_json, const char *file_atlas, unsigned flags);
-API void spine_skin(spine_t *p, unsigned skin);
-API void spine_render(spine_t *p, vec3 offset, unsigned flags);
-API void spine_animate(spine_t *p, float delta);
-
-API void ui_spine(spine_t *p);
-
// -----------------------------------------------------------------------------
// cubemaps
diff --git a/engine/split/v4k_sprite.c b/engine/split/v4k_sprite.c
new file mode 100644
index 0000000..ad3d181
--- /dev/null
+++ b/engine/split/v4k_sprite.c
@@ -0,0 +1,1466 @@
+// ----------------------------------------------------------------------------
+// sprites
+
+typedef struct sprite_static_t {
+ float px, py, pz; // origin x, y, depth
+ float ox, oy, cos, sin; // offset x, offset y, cos/sin of rotation degree
+ float sx, sy; // scale x,y
+ float cellw, cellh; // dimensions of any cell in spritesheet
+
+ union {
+ struct {
+ int frame, ncx, ncy; // frame in a (num cellx, num celly) spritesheet
+ };
+ struct {
+ float x, y, w, h; // normalized[0..1] within texture bounds
+ };
+ };
+
+ uint32_t rgba, flags; // vertex color and flags
+} sprite_static_t;
+
+// sprite batching
+typedef struct batch_t { array(sprite_static_t) sprites; mesh_t mesh; int dirty; } batch_t;
+typedef map(int, batch_t) batch_group_t; // mapkey is anything that forces a flush. texture_id for now, might be texture_id+program_id soon
+
+// sprite stream
+typedef struct sprite_vertex { vec3 pos; vec2 uv; uint32_t rgba; } sprite_vertex;
+typedef struct sprite_index { GLuint triangle[3]; } sprite_index;
+
+#define sprite_vertex(...) C_CAST(sprite_vertex, __VA_ARGS__)
+#define sprite_index(...) C_CAST(sprite_index, __VA_ARGS__)
+
+// sprite impl
+static int sprite_count = 0;
+static int sprite_program = -1;
+static array(sprite_index) sprite_indices = 0;
+static array(sprite_vertex) sprite_vertices = 0;
+
+// center_wh << 2 | additive << 1 | projected << 0
+static batch_group_t sprite_group[8] = {0};
+
+// rect(x,y,w,h) is [0..1] normalized, pos(xyz,z-index), scale_offset(sx,sy,offx,offy), rotation (degrees), color (rgba)
+void sprite_rect( texture_t t, vec4 rect, vec4 pos, vec4 scale_offset, float tilt_deg, unsigned tint_rgba, unsigned flags) {
+ float zindex = pos.w;
+ float scalex = scale_offset.x;
+ float scaley = scale_offset.y;
+ float offsetx = scale_offset.z;
+ float offsety = scale_offset.w;
+
+ // do not queue if either scales or alpha are zero
+ if( 0 == (scalex * scaley * ((tint_rgba>>24) & 255)) ) return;
+
+ ASSERT( (flags & SPRITE_CENTERED) == 0 );
+ if( flags & SPRITE_PROJECTED ) {
+ tilt_deg += 180, scalex = -scalex; // flip texture Y on mvp3d (same than turn 180º then flip X)
+ }
+
+ sprite_static_t s = {0};
+
+ s.px = pos.x, s.py = pos.y, s.pz = pos.z - zindex;
+ s.sx = scalex, s.sy = scaley;
+
+ s.x = rect.x, s.y = rect.y, s.w = rect.z, s.h = rect.w;
+ s.cellw = s.w * s.sx * t.w, s.cellh = s.h * s.sy * t.h;
+
+ s.rgba = tint_rgba;
+ s.flags = flags;
+
+#if 0
+ s.ox = 0/*ox*/ * s.sx;
+ s.oy = 0/*oy*/ * s.sy;
+#else
+ s.ox += offsetx * scalex;
+ s.oy += offsety * scaley;
+#endif
+
+ if( tilt_deg ) {
+ tilt_deg = (tilt_deg + 0) * ((float)C_PI / 180);
+ s.cos = cosf(tilt_deg);
+ s.sin = sinf(tilt_deg);
+ } else {
+ s.cos = 1;
+ s.sin = 0;
+ }
+
+ batch_group_t *batches = &sprite_group[ flags & 7 ];
+ batch_t *found = map_find_or_add(*batches, t.id, (batch_t){0});
+
+ array_push(found->sprites, s);
+}
+
+void sprite_sheet( texture_t texture, float spritesheet[3], float position[3], float rotation, float offset[2], float scale[2], unsigned rgba, unsigned flags) {
+ flags |= SPRITE_CENTERED;
+ ASSERT( flags & SPRITE_CENTERED );
+
+ const float px = position[0], py = position[1], pz = position[2];
+ const float ox = offset[0], oy = offset[1], sx = scale[0], sy = scale[1];
+ const float frame = spritesheet[0], xcells = spritesheet[1], ycells = spritesheet[2];
+
+ if (frame < 0) return;
+ if (frame > 0 && frame >= (xcells * ycells)) return;
+
+ // no need to queue if alpha or scale are zero
+ if( sx && sy && alpha(rgba) ) {
+ vec3 bak = camera_get_active()->position;
+ if( flags & SPRITE_RESOLUTION_INDEPENDANT ) { // @todo: optimize me
+ sprite_flush();
+ camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
+ }
+
+ sprite_static_t s;
+ s.px = px;
+ s.py = py;
+ s.pz = pz;
+ s.frame = frame;
+ s.ncx = xcells ? xcells : 1;
+ s.ncy = ycells ? ycells : 1;
+ s.sx = sx;
+ s.sy = sy;
+ s.ox = ox * sx;
+ s.oy = oy * sy;
+ s.cellw = (texture.x * sx / s.ncx);
+ s.cellh = (texture.y * sy / s.ncy);
+ s.rgba = rgba;
+ s.flags = flags;
+ s.cos = 1;
+ s.sin = 0;
+ if(rotation) {
+ rotation = (rotation + 0) * ((float)C_PI / 180);
+ s.cos = cosf(rotation);
+ s.sin = sinf(rotation);
+ }
+
+ batch_group_t *batches = &sprite_group[ flags & 7 ];
+#if 0
+ batch_t *found = map_find(*batches, texture.id);
+ if( !found ) found = map_insert(*batches, texture.id, (batch_t){0});
+#else
+ batch_t *found = map_find_or_add(*batches, texture.id, (batch_t){0});
+#endif
+
+ array_push(found->sprites, s);
+
+ if( flags & SPRITE_RESOLUTION_INDEPENDANT ) { // @todo: optimize me
+ sprite_flush();
+ camera_get_active()->position = bak;
+ }
+ }
+}
+
+void sprite( texture_t texture, float position[3], float rotation, unsigned color, unsigned flags) {
+ float offset[2] = {0,0}, scale[2] = {1,1}, spritesheet[3] = {0,0,0};
+ sprite_sheet( texture, spritesheet, position, rotation, offset, scale, color, flags );
+}
+
+static void sprite_rebuild_meshes() {
+ sprite_count = 0;
+
+ // w/2,h/2 centered
+ for( int l = countof(sprite_group) / 2; l < countof(sprite_group); ++l) {
+ for each_map_ptr(sprite_group[l], int,_, batch_t,bt) {
+
+ bt->dirty = array_count(bt->sprites) ? 1 : 0;
+ if( !bt->dirty ) continue;
+
+ int index = 0;
+ array_clear(sprite_indices);
+ array_clear(sprite_vertices);
+
+ array_foreach_ptr(bt->sprites, sprite_static_t,it ) {
+ float x0 = it->ox - it->cellw/2, x3 = x0 + it->cellw;
+ float y0 = it->oy - it->cellh/2, y3 = y0;
+ float x1 = x0, x2 = x3;
+ float y1 = y0 + it->cellh, y2 = y1;
+
+ // @todo: move this affine transform into glsl shader
+ vec3 v0 = { it->px + ( x0 * it->cos - y0 * it->sin ), it->py + ( x0 * it->sin + y0 * it->cos ), it->pz };
+ vec3 v1 = { it->px + ( x1 * it->cos - y1 * it->sin ), it->py + ( x1 * it->sin + y1 * it->cos ), it->pz };
+ vec3 v2 = { it->px + ( x2 * it->cos - y2 * it->sin ), it->py + ( x2 * it->sin + y2 * it->cos ), it->pz };
+ vec3 v3 = { it->px + ( x3 * it->cos - y3 * it->sin ), it->py + ( x3 * it->sin + y3 * it->cos ), it->pz };
+
+ float cx = (1.0f / it->ncx) - 1e-9f;
+ float cy = (1.0f / it->ncy) - 1e-9f;
+ int idx = (int)it->frame;
+ int px = idx % it->ncx;
+ int py = idx / it->ncx;
+
+ float ux = px * cx, uy = py * cy;
+ float vx = ux + cx, vy = uy + cy;
+
+ vec2 uv0 = vec2(ux, uy);
+ vec2 uv1 = vec2(ux, vy);
+ vec2 uv2 = vec2(vx, vy);
+ vec2 uv3 = vec2(vx, uy);
+
+ array_push( sprite_vertices, sprite_vertex(v0, uv0, it->rgba) ); // Vertex 0 (A)
+ array_push( sprite_vertices, sprite_vertex(v1, uv1, it->rgba) ); // Vertex 1 (B)
+ array_push( sprite_vertices, sprite_vertex(v2, uv2, it->rgba) ); // Vertex 2 (C)
+ array_push( sprite_vertices, sprite_vertex(v3, uv3, it->rgba) ); // Vertex 3 (D)
+
+ // A--B A A-B
+ // quad | | becomes triangle |\ and triangle \|
+ // D--C D-C C
+ GLuint A = (index+0), B = (index+1), C = (index+2), D = (index+3); index += 4;
+
+ array_push( sprite_indices, sprite_index(C, D, A) ); // Triangle 1
+ array_push( sprite_indices, sprite_index(C, A, B) ); // Triangle 2
+ }
+
+ mesh_update(&bt->mesh, "p3 t2 c4B", 0,array_count(sprite_vertices),sprite_vertices, 3*array_count(sprite_indices),sprite_indices, MESH_STATIC);
+
+ // clear elements from queue
+ sprite_count += array_count(bt->sprites);
+ array_clear(bt->sprites);
+ }
+ }
+
+ // (0,0) centered
+ for( int l = 0; l < countof(sprite_group) / 2; ++l) {
+ for each_map_ptr(sprite_group[l], int,_, batch_t,bt) {
+
+ bt->dirty = array_count(bt->sprites) ? 1 : 0;
+ if( !bt->dirty ) continue;
+
+ int index = 0;
+ array_clear(sprite_indices);
+ array_clear(sprite_vertices);
+
+ array_foreach_ptr(bt->sprites, sprite_static_t,it ) {
+ float x0 = it->ox - it->cellw/2, x3 = x0 + it->cellw;
+ float y0 = it->oy - it->cellh/2, y3 = y0;
+ float x1 = x0, x2 = x3;
+ float y1 = y0 + it->cellh, y2 = y1;
+
+ // @todo: move this affine transform into glsl shader
+ vec3 v0 = { it->px + ( x0 * it->cos - y0 * it->sin ), it->py + ( x0 * it->sin + y0 * it->cos ), it->pz };
+ vec3 v1 = { it->px + ( x1 * it->cos - y1 * it->sin ), it->py + ( x1 * it->sin + y1 * it->cos ), it->pz };
+ vec3 v2 = { it->px + ( x2 * it->cos - y2 * it->sin ), it->py + ( x2 * it->sin + y2 * it->cos ), it->pz };
+ vec3 v3 = { it->px + ( x3 * it->cos - y3 * it->sin ), it->py + ( x3 * it->sin + y3 * it->cos ), it->pz };
+
+ float ux = it->x, vx = ux + it->w;
+ float uy = it->y, vy = uy + it->h;
+
+ vec2 uv0 = vec2(ux, uy);
+ vec2 uv1 = vec2(ux, vy);
+ vec2 uv2 = vec2(vx, vy);
+ vec2 uv3 = vec2(vx, uy);
+
+ array_push( sprite_vertices, sprite_vertex(v0, uv0, it->rgba) ); // Vertex 0 (A)
+ array_push( sprite_vertices, sprite_vertex(v1, uv1, it->rgba) ); // Vertex 1 (B)
+ array_push( sprite_vertices, sprite_vertex(v2, uv2, it->rgba) ); // Vertex 2 (C)
+ array_push( sprite_vertices, sprite_vertex(v3, uv3, it->rgba) ); // Vertex 3 (D)
+
+ // A--B A A-B
+ // quad | | becomes triangle |\ and triangle \|
+ // D--C D-C C
+ GLuint A = (index+0), B = (index+1), C = (index+2), D = (index+3); index += 4;
+
+ array_push( sprite_indices, sprite_index(C, D, A) ); // Triangle 1
+ array_push( sprite_indices, sprite_index(C, A, B) ); // Triangle 2
+ }
+
+ mesh_update(&bt->mesh, "p3 t2 c4B", 0,array_count(sprite_vertices),sprite_vertices, 3*array_count(sprite_indices),sprite_indices, MESH_STATIC);
+
+ // clear elements from queue
+ sprite_count += array_count(bt->sprites);
+ array_clear(bt->sprites);
+ }
+ }
+}
+
+static void sprite_render_meshes_group(batch_group_t* sprites, int alpha_key, int alpha_value, float mvp[16]) {
+ if( map_count(*sprites) > 0 ) {
+ // setup shader
+ if( sprite_program < 0 ) {
+ sprite_program = shader( vfs_read("shaders/vs_324_24_sprite.glsl"), vfs_read("shaders/fs_24_4_sprite.glsl"),
+ "att_Position,att_TexCoord,att_Color",
+ "fragColor", NULL
+ );
+ }
+ shader_bind(sprite_program);
+ shader_mat44("u_mvp", mvp);
+
+ // set (unit 0) in the uniform texture sampler, and render batch
+ glActiveTexture(GL_TEXTURE0);
+ glBlendFunc( alpha_key, alpha_value );
+
+ for each_map_ptr(*sprites, int,texture_id, batch_t,bt) {
+ if( bt->dirty ) {
+ shader_texture_unit("u_texture", *texture_id, 0);
+ mesh_render(&bt->mesh);
+ }
+ }
+// map_clear(*sprites);
+ }
+}
+
+static void sprite_init() {
+ do_once for(int i = 0; i < countof(sprite_group); ++i) {
+ map_init(sprite_group[i], less_int, hash_int);
+ }
+}
+
+void sprite_flush() {
+ profile("Sprite.rebuild_time") {
+ sprite_rebuild_meshes();
+ }
+ profile("Sprite.render_time") {
+ // setup rendering state
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glDepthFunc(GL_LEQUAL); // try to help with zfighting
+
+ // 3d
+ mat44 mvp3d; multiply44x2(mvp3d, camera_get_active()->proj, camera_get_active()->view);
+ // render all additive then translucent groups
+ sprite_render_meshes_group(&sprite_group[SPRITE_PROJECTED], GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, mvp3d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_PROJECTED|SPRITE_CENTERED], GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, mvp3d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_PROJECTED|SPRITE_CENTERED|SPRITE_ADDITIVE], GL_SRC_ALPHA, GL_ONE, mvp3d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_PROJECTED|SPRITE_ADDITIVE], GL_SRC_ALPHA, GL_ONE, mvp3d );
+
+ // 2d: (0,0) is center of screen
+ mat44 mvp2d;
+ vec3 pos = camera_get_active()->position;
+ float zoom = absf(pos.z); if(zoom < 0.1f) zoom = 0.1f; zoom = 1.f / (zoom + !zoom);
+ float zdepth_max = window_height(); // 1;
+ float l = pos.x - window_width() * zoom / 2;
+ float r = pos.x + window_width() * zoom / 2;
+ float b = pos.y + window_height() * zoom / 2;
+ float t = pos.y - window_height() * zoom / 2;
+ ortho44(mvp2d, l,r,b,t, -zdepth_max, +zdepth_max);
+ // render all additive then translucent groups
+ sprite_render_meshes_group(&sprite_group[0], GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, mvp2d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_CENTERED], GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, mvp2d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_CENTERED|SPRITE_ADDITIVE], GL_SRC_ALPHA, GL_ONE, mvp2d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_ADDITIVE], GL_SRC_ALPHA, GL_ONE, mvp2d );
+
+ // restore rendering state
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDepthFunc(GL_LESS);
+ glUseProgram(0);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// tilemaps
+
+tilemap_t tilemap(const char *map, int blank_chr, int linefeed_chr) {
+ tilemap_t t = {0};
+ t.tint = ~0u; // WHITE
+ t.blank_chr = blank_chr;
+ for( ; *map ; ++map ) {
+ if( map[0] == linefeed_chr ) ++t.rows;
+ else {
+ array_push(t.map, map[0]);
+ ++t.cols;
+ }
+ }
+ return t;
+}
+
+void tilemap_render_ext( tilemap_t m, tileset_t t, float zindex, float xy_zoom[3], float tilt, unsigned tint, bool is_additive ) {
+ vec3 old_pos = camera_get_active()->position;
+ sprite_flush();
+ camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
+
+ float scale[2] = {xy_zoom[2], xy_zoom[2]};
+ xy_zoom[2] = zindex;
+
+ float offset[2] = {0,0};
+ float spritesheet[3] = {0,t.cols,t.rows}; // selected tile index and spritesheet dimensions (cols,rows)
+
+ for( unsigned y = 0, c = 0; y < m.rows; ++y ) {
+ for( unsigned x = 0; x < m.cols; ++x, ++c ) {
+ if( m.map[c] != m.blank_chr ) {
+ spritesheet[0] = m.map[c];
+ sprite_sheet(t.tex, spritesheet, xy_zoom, tilt, offset, scale, tint, is_additive ? SPRITE_ADDITIVE : 0);
+ }
+ offset[0] += t.tile_w;
+ }
+ offset[0] = 0, offset[1] += t.tile_h;
+ }
+
+ sprite_flush();
+ camera_get_active()->position = old_pos;
+}
+
+void tilemap_render( tilemap_t map, tileset_t set ) {
+ map.position.x += set.tile_w;
+ map.position.y += set.tile_h;
+ tilemap_render_ext( map, set, map.zindex, &map.position.x, map.tilt, map.tint, map.is_additive );
+}
+
+tileset_t tileset(texture_t tex, unsigned tile_w, unsigned tile_h, unsigned cols, unsigned rows) {
+ tileset_t t = {0};
+ t.tex = tex;
+ t.cols = cols, t.rows = rows;
+ t.tile_w = tile_w, t.tile_h = tile_h;
+ return t;
+}
+
+int ui_tileset( tileset_t t ) {
+ ui_subimage(va("Selection #%d (%d,%d)", t.selected, t.selected % t.cols, t.selected / t.cols), t.tex.id, t.tex.w, t.tex.h, (t.selected % t.cols) * t.tile_w, (t.selected / t.cols) * t.tile_h, t.tile_w, t.tile_h);
+ int choice;
+ if( (choice = ui_image(0, t.tex.id, t.tex.w,t.tex.h)) ) {
+ int px = ((choice / 100) / 100.f) * t.tex.w / t.tile_w;
+ int py = ((choice % 100) / 100.f) * t.tex.h / t.tile_h;
+ t.selected = px + py * t.cols;
+ }
+ // if( (choice = ui_buttons(3, "load", "save", "clear")) ) {}
+ return t.selected;
+}
+
+// -----------------------------------------------------------------------------
+// tiled
+
+tiled_t tiled(const char *file_tmx) {
+ tiled_t zero = {0}, ti = zero;
+
+ // read file and parse json
+ if( !xml_push(file_tmx) ) return zero;
+
+ // sanity checks
+ bool supported = !strcmp(xml_string("/map/@orientation"), "orthogonal") && !strcmp(xml_string("/map/@renderorder"), "right-down");
+ if( !supported ) return xml_pop(), zero;
+
+ // tileset
+ const char *file_tsx = xml_string("/map/tileset/@source");
+ if( !xml_push(vfs_read(file_tsx)) ) return zero;
+ const char *set_src = xml_string("/tileset/image/@source");
+ int set_w = xml_int("/tileset/@tilewidth");
+ int set_h = xml_int("/tileset/@tileheight");
+ int set_c = xml_int("/tileset/@columns");
+ int set_r = xml_int("/tileset/@tilecount") / set_c;
+ tileset_t set = tileset(texture(set_src,0), set_w, set_h, set_c, set_r );
+ xml_pop();
+
+ // actual parsing
+ ti.w = xml_int("/map/@width");
+ ti.h = xml_int("/map/@height");
+ ti.tilew = xml_int("/map/@tilewidth");
+ ti.tileh = xml_int("/map/@tileheight");
+ ti.first_gid = xml_int("/map/tileset/@firstgid");
+ ti.map_name = STRDUP( xml_string("/map/tileset/@source") ); // @leak
+
+ for(int l = 0, layers = xml_count("/map/layer"); l < layers; ++l ) {
+ if( strcmp(xml_string("/map/layer[%d]/data/@encoding",l), "base64") || strcmp(xml_string("/map/layer[%d]/data/@compression",l), "zlib") ) {
+ PRINTF("Warning: layer encoding not supported: '%s' -> layer '%s'\n", file_tmx, *array_back(ti.names));
+ continue;
+ }
+
+ int cols = xml_int("/map/layer[%d]/@width",l);
+ int rows = xml_int("/map/layer[%d]/@height",l);
+
+ tilemap_t tm = tilemap("", ' ', '\n');
+ tm.blank_chr = ~0u; //ti.first_gid - 1;
+ tm.cols = cols;
+ tm.rows = rows;
+ array_resize(tm.map, tm.cols * tm.rows);
+ memset(tm.map, 0xFF, tm.cols * tm.rows * sizeof(int));
+
+ for( int c = 0, chunks = xml_count("/map/layer[%d]/data/chunk", l); c <= chunks; ++c ) {
+ int cw, ch;
+ int cx, cy;
+ array(char) b64 = 0;
+
+ if( !chunks ) { // non-infinite mode
+ b64 = xml_blob("/map/layer[%d]/data/$",l);
+ cw = tm.cols, ch = tm.rows;
+ cx = 0, cy = 0;
+ } else { // infinite mode
+ b64 = xml_blob("/map/layer[%d]/data/chunk[%d]/$",l,c);
+ cw = xml_int("/map/layer[%d]/data/chunk[%d]/@width",l,c), ch = xml_int("/map/layer[%d]/data/chunk[%d]/@height",l,c); // 20x20
+ cx = xml_int("/map/layer[%d]/data/chunk[%d]/@x",l,c), cy = xml_int("/map/layer[%d]/data/chunk[%d]/@y",l,c); // (-16,-32)
+ cx = abs(cx), cy = abs(cy);
+ }
+
+ int outlen = cw * ch * 4;
+ static __thread int *out = 0; out = (int *)REALLOC( 0, outlen + zexcess(COMPRESS_ZLIB) ); // @leak
+ if( zdecode( out, outlen, b64, array_count(b64), COMPRESS_ZLIB ) > 0 ) {
+ for( int y = 0, p = 0; y < ch; ++y ) {
+ for( int x = 0; x < cw; ++x, ++p ) {
+ if( out[p] >= ti.first_gid ) {
+ int offset = (x + cx) + (y + cy) * tm.cols;
+ if( offset >= 0 && offset < (cw * ch) )
+ tm.map[ offset ] = out[ p ] - ti.first_gid;
+ }
+ }
+ }
+ }
+ else {
+ PRINTF("Warning: bad zlib stream: '%s' -> layer #%d -> chunk #%d\n", file_tmx, l, c);
+ }
+
+ array_free(b64);
+ }
+
+ array_push(ti.layers, tm);
+ array_push(ti.names, STRDUP(xml_string("/map/layer[%d]/@name",l)));
+ array_push(ti.visible, true);
+ array_push(ti.sets, set);
+ }
+
+ xml_pop();
+ return ti;
+}
+
+void tiled_render(tiled_t tmx, vec3 pos) {
+ for( unsigned i = 0, end = array_count(tmx.layers); i < end; ++i ) {
+ tmx.layers[i].position = pos; // add3(camera_get_active()->position, pos);
+ if( tmx.parallax ) tmx.layers[i].position.x /= (3+i), tmx.layers[i].position.y /= (5+i);
+ if( tmx.visible[i] ) tilemap_render(tmx.layers[i], tmx.sets[i]);
+ }
+}
+
+void ui_tiled(tiled_t *t) {
+ ui_label2("Loaded map", t->map_name ? t->map_name : "(none)");
+ ui_label2("Map dimensions", va("%dx%d", t->w, t->h));
+ ui_label2("Tile dimensions", va("%dx%d", t->tilew, t->tileh));
+ ui_separator();
+ ui_bool("Parallax", &t->parallax);
+ ui_separator();
+ ui_label2("Layers", va("%d", array_count(t->layers)));
+ for( int i = 0; i < array_count(t->layers); ++i ) {
+ if( ui_label2_toolbar(va("- %s (%dx%d)", t->names[i], t->layers[i].cols, t->layers[i].rows ), t->visible[i] ? "\xee\xa3\xb4" : "\xee\xa3\xb5") > 0 ) { // ICON_MD_VISIBILITY / ICON_MD_VISIBILITY_OFF
+ t->visible[i] ^= true;
+ }
+ }
+ ui_separator();
+ if( ui_collapse(va("Sets: %d", array_count(t->layers)), va("%p",t))) {
+ for( int i = 0; i < array_count(t->layers); ++i ) {
+ if( ui_collapse(va("%d", i+1), va("%p%d",t,i)) ) {
+ t->sets[i].selected = ui_tileset( t->sets[i] );
+ ui_collapse_end();
+ }
+ }
+ ui_collapse_end();
+ }
+}
+
+// -----------------------------------------------------------------------------
+// spine json loader (wip)
+// - rlyeh, public domain
+//
+// [ref] http://es.esotericsoftware.com/spine-json-format
+//
+// notable misses:
+// - mesh deforms
+// - cubic beziers
+// - shears
+// - bounding boxes
+
+enum { SPINE_MAX_BONES = 64 }; // max bones
+
+typedef struct spine_bone_t {
+ char *name, *parent;
+ struct spine_bone_t *parent_bone;
+
+ float z; // draw order usually matches bone-id. ie, zindex == bone_id .. root(0) < chest (mid) < finger(top)
+
+ float len;
+ float x, y, deg; // base
+ float x2, y2, deg2; // accum / temporaries during bone transform time
+ float x3, y3, deg3; // values from timeline
+
+ unsigned rect_id;
+ unsigned atlas_id;
+} spine_bone_t;
+
+typedef struct spine_slot_t {
+ char *name, *bone, *attach;
+} spine_slot_t;
+
+typedef struct spine_rect_t {
+ char *name;
+ float x,y,w,h,sx,sy,deg;
+} spine_rect_t;
+
+typedef struct spine_skin_t {
+ char *name;
+ array(spine_rect_t) rects;
+} spine_skin_t;
+
+typedef struct spine_animkey_t { // offline; only during loading
+ float time, curve[4]; // time is mandatory, curve is optional
+ union {
+ char *name; // type: attachment (mode-1)
+ struct { float deg; }; // type: rotate (mode-2)
+ struct { float x,y; }; // type: translate (mode-3)
+ };
+} spine_animkey_t;
+
+#if 0
+typedef struct spine_pose_t { // runtime; only during playing
+ unsigned frame;
+ array(vec4) xform; // entry per bone. translation(x,y),rotation(z),attachment-id(w)
+} spine_pose_t;
+#endif
+
+typedef struct spine_anim_t {
+ char *name;
+ union {
+#if 0
+ struct {
+ unsigned frames;
+ array(spine_pose_t) poses;
+ };
+#endif
+ struct {
+ array(spine_animkey_t) attach_keys[SPINE_MAX_BONES];
+ array(spine_animkey_t) rotate_keys[SPINE_MAX_BONES];
+ array(spine_animkey_t) translate_keys[SPINE_MAX_BONES];
+ };
+ };
+} spine_anim_t;
+
+typedef struct spine_atlas_t {
+ char *name;
+ float x,y,w,h,deg;
+} spine_atlas_t;
+
+typedef struct spine_t {
+ char *name;
+ texture_t texture;
+ unsigned skin;
+ array(spine_bone_t) bones;
+ array(spine_slot_t) slots;
+ array(spine_skin_t) skins;
+ array(spine_anim_t) anims;
+ array(spine_atlas_t) atlas;
+ // anim controller
+ unsigned inuse;
+ float time, maxtime;
+ unsigned debug_atlas_id;
+} spine_t;
+
+// ---
+
+static
+void spine_convert_animkeys_to_animpose(spine_anim_t *input) {
+ spine_anim_t copy = *input; // @todo
+ // @leak: attach/rot/tra keys
+}
+
+static
+int find_bone_id(spine_t *s, const char *bone_name) {
+ for( unsigned i = 0, end = array_count(s->bones); i < end; ++i )
+ if( !strcmp(s->bones[i].name, bone_name)) return i;
+ return -1;
+}
+static
+spine_bone_t *find_bone(spine_t *s, const char *bone_name) {
+ int bone_id = find_bone_id(s, bone_name);
+ return bone_id >= 0 ? &s->bones[bone_id] : NULL;
+}
+
+void spine_skin(spine_t *p, unsigned skin) {
+ if( !p->texture.id ) return;
+ if( skin >= array_count(p->skins) ) return;
+
+ p->skin = skin;
+
+ char *skin_name = va("%s/", p->skins[skin].name);
+ int header = strlen(skin_name);
+
+ for( int i = 0; i < array_count(p->atlas); ++i) {
+ if(!strbeg(p->atlas[i].name, skin_name)) continue;
+
+ int bone_id = find_bone_id(p, p->atlas[i].name+header );
+ if( bone_id < 0 ) continue;
+
+ p->bones[bone_id].atlas_id = i;
+ }
+
+ for( int i = 0; i < array_count(p->skins[p->skin].rects); ++i) {
+ int bone_id = find_bone_id(p, p->skins[p->skin].rects[i].name );
+ if( bone_id < 0 ) continue;
+
+ p->bones[bone_id].rect_id = i;
+ }
+}
+
+static
+bool spine_(spine_t *t, const char *file_json, const char *file_atlas, unsigned flags) {
+ char *atlas = vfs_read(file_atlas);
+ if(!atlas || !atlas[0]) return false;
+
+ memset(t, 0, sizeof(spine_t));
+
+ // goblins.png
+ // size: 1024, 128
+ // filter: Linear, Linear
+ // pma: true
+ // dagger
+ // bounds: 2, 18, 26, 108
+ // goblin/eyes-closed
+ // bounds: 2, 4, 34, 12
+ spine_atlas_t *sa = 0;
+ const char *last_id = 0;
+ const char *texture_name = 0;
+ const char *texture_filter = 0;
+ const char *texture_format = 0;
+ const char *texture_repeat = 0;
+ float texture_width = 0, texture_height = 0, temp;
+ for each_substring(atlas, "\r\n", it) {
+ it += strspn(it, " \t\f\v");
+ /**/ if( strbeg(it, "pma:" ) || strbeg(it, "index:") ) {} // ignored
+ else if( strbeg(it, "size:" ) ) sscanf(it+5, "%f,%f", &texture_width, &texture_height);
+ else if( strbeg(it, "rotate:" ) ) { float tmp; tmp=sa->w,sa->w=sa->h,sa->h=tmp; sa->deg = 90; } // assert(val==90)
+ else if( strbeg(it, "repeat:" ) ) texture_repeat = it+7; // temp string
+ else if( strbeg(it, "filter:" ) ) texture_filter = it+7; // temp string
+ else if( strbeg(it, "format:" ) ) texture_format = it+7; // temp string
+ else if( strbeg(it, "bounds:" ) ) {
+ sscanf(it+7, "%f,%f,%f,%f", &sa->x, &sa->y, &sa->w, &sa->h);
+ }
+ else if( !texture_name ) texture_name = va("%s", it);
+ else {
+ array_push(t->atlas, ((spine_atlas_t){0}) );
+ sa = &t->atlas[array_count(t->atlas) - 1];
+ sa->name = STRDUP(it);
+ }
+ }
+ for( int i = 0; i < array_count(t->atlas); ++i ) {
+ sa = &t->atlas[i];
+ sa->x /= texture_width, sa->y /= texture_height;
+ sa->w /= texture_width, sa->h /= texture_height;
+ }
+
+ if(!texture_name) return false;
+
+ t->texture = texture(texture_name, TEXTURE_LINEAR);
+
+ json_push(vfs_read(file_json)); // @fixme: json_push_from_file() ?
+
+ array_resize(t->bones, json_count("/bones"));
+ array_reserve(t->slots, json_count("/slots"));
+ array_resize(t->skins, json_count("/skins"));
+ array_resize(t->anims, json_count("/animations"));
+
+ for( int i = 0, end = json_count("/bones"); i < end; ++i ) {
+ spine_bone_t v = {0};
+ v.name = STRDUP(json_string("/bones[%d]/name", i));
+ v.parent = STRDUP(json_string("/bones[%d]/parent", i));
+ v.x = json_float("/bones[%d]/x", i);
+ v.y = json_float("/bones[%d]/y", i);
+ v.z = i;
+ v.len = json_float("/bones[%d]/length", i);
+ v.deg = json_float("/bones[%d]/rotation", i);
+ t->bones[i] = v;
+
+ for( int j = i-1; j > 0; --j ) {
+ if( strcmp(t->bones[j].name,v.parent) ) continue;
+ t->bones[i].parent_bone = &t->bones[j];
+ break;
+ }
+ }
+
+ for( int i = 0, end = json_count("/slots"); i < end; ++i ) {
+ spine_slot_t v = {0};
+ v.name = STRDUP(json_string("/slots[%d]/name", i));
+ v.bone = STRDUP(json_string("/slots[%d]/bone", i));
+ v.attach = STRDUP(json_string("/slots[%d]/attachment", i));
+
+ array_push(t->slots, v);
+
+ // slots define draw-order. so, update draw-order/zindex in bone
+ spine_bone_t *b = find_bone(t, v.name);
+ if( b ) b->z = i;
+ }
+
+ for( int i = 0, end = json_count("/skins"); i < end; ++i ) {
+ spine_skin_t v = {0};
+ v.name = STRDUP(json_string("/skins[%d]/name", i));
+
+ for( int j = 0, jend = json_count("/skins[%d]/attachments",i); j < jend; ++j ) // /skins/default/
+ for( int k = 0, kend = json_count("/skins[%d]/attachments[%d]",i,j); k < kend; ++k ) { // /skins/default/left hand item/
+ spine_rect_t r = {0};
+ r.name = STRDUP(json_key("/skins[%d]/attachments[%d][%d]",i,j,k)); // stringf("%s-%s-%s", json_key("/skins[%d]",i), json_key("/skins[%d][%d]",i,j), json_key("/skins[%d][%d][%d]",i,j,k));
+ r.x = json_float("/skins[%d]/attachments[%d][%d]/x",i,j,k);
+ r.y = json_float("/skins[%d]/attachments[%d][%d]/y",i,j,k);
+ r.sx= json_float("/skins[%d]/attachments[%d][%d]/scaleX",i,j,k); r.sx += !r.sx;
+ r.sy= json_float("/skins[%d]/attachments[%d][%d]/scaleY",i,j,k); r.sy += !r.sy;
+ r.w = json_float("/skins[%d]/attachments[%d][%d]/width",i,j,k);
+ r.h = json_float("/skins[%d]/attachments[%d][%d]/height",i,j,k);
+ r.deg = json_float("/skins[%d]/attachments[%d][%d]/rotation",i,j,k);
+ array_push(v.rects, r);
+ }
+
+ t->skins[i] = v;
+ }
+
+#if 1
+ // simplify:
+ // merge /skins/default into existing /skins/*, then delete /skins/default
+ if( array_count(t->skins) > 1 ) {
+ for( int i = 1; i < array_count(t->skins); ++i ) {
+ for( int j = 0; j < array_count(t->skins[0].rects); ++j ) {
+ array_push(t->skins[i].rects, t->skins[0].rects[j]);
+ }
+ }
+ // @leak @fixme: FREE(t->skins[0])
+ for( int i = 0; i < array_count(t->skins)-1; ++i ) {
+ t->skins[i] = t->skins[i+1];
+ }
+ array_pop(t->skins);
+ }
+#endif
+
+ for( int i = 0, end = json_count("/animations"); i < end; ++i ) {
+ int id;
+ const char *name;
+
+ spine_anim_t v = {0};
+ v.name = STRDUP(json_key("/animations[%d]", i));
+
+ // slots / attachments
+
+ for( int j = 0, jend = json_count("/animations[%d]/slots",i); j < jend; ++j )
+ for( int k = 0, kend = json_count("/animations[%d]/slots[%d]",i,j); k < kend; ++k ) // ids
+ {
+ int bone_id = find_bone_id(t, json_key("/animations[%d]/bones[%d]",i,j));
+ if( bone_id < 0 ) continue;
+
+ for( int l = 0, lend = json_count("/animations[%d]/slots[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
+ spine_animkey_t key = {0};
+
+ key.name = STRDUP(json_string("/animations[%d]/slots[%d][%d][%d]/name",i,j,k,l));
+ key.time = json_float("/animations[%d]/slots[%d][%d][%d]/time",i,j,k,l);
+ if( json_count("/animations[%d]/slots[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
+ key.curve[0] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[0]",i,j,k,l);
+ key.curve[1] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[1]",i,j,k,l);
+ key.curve[2] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[2]",i,j,k,l);
+ key.curve[3] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[3]",i,j,k,l);
+ }
+
+ // @todo: convert name to id
+ // for(id = 0; t->bones[id].name && strcmp(t->bones[id].name,key.name); ++id)
+ // printf("%s vs %s\n", key.name, t->bones[id].name);
+
+ array_push(v.attach_keys[bone_id], key);
+ }
+ }
+
+ // bones
+
+ for( int j = 0, jend = json_count("/animations[%d]/bones",i); j < jend; ++j ) // slots or bones
+ for( int k = 0, kend = json_count("/animations[%d]/bones[%d]",i,j); k < kend; ++k ) { // bone ids
+ int bone_id = find_bone_id(t, json_key("/animations[%d]/bones[%d]",i,j));
+ if( bone_id < 0 ) continue;
+
+ // parse bones
+ for( int l = 0, lend = json_count("/animations[%d]/bones[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
+ const char *channel = json_key("/animations[%d]/bones[%d][%d]",i,j,k);
+ int track = !strcmp(channel, "rotate") ? 1 : !strcmp(channel, "translate") ? 2 : 0;
+ if( !track ) continue;
+
+ spine_animkey_t key = {0};
+
+ key.time = json_float("/animations[%d]/bones[%d][%d][%d]/time",i,j,k,l);
+ if( json_count("/animations[%d]/bones[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
+ key.curve[0] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[0]",i,j,k,l);
+ key.curve[1] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[1]",i,j,k,l);
+ key.curve[2] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[2]",i,j,k,l);
+ key.curve[3] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[3]",i,j,k,l);
+ }
+
+ if( track == 1 )
+ key.deg = json_float("/animations[%d]/bones[%d][%d][%d]/value",i,j,k,l), // "/angle"
+ array_push(v.rotate_keys[bone_id], key);
+ else
+ key.x = json_float("/animations[%d]/bones[%d][%d][%d]/x",i,j,k,l),
+ key.y = json_float("/animations[%d]/bones[%d][%d][%d]/y",i,j,k,l),
+ array_push(v.translate_keys[bone_id], key);
+ }
+ }
+
+ t->anims[i] = v;
+ }
+
+ json_pop();
+
+ spine_skin(t, 0);
+
+ return true;
+}
+
+spine_t* spine(const char *file_json, const char *file_atlas, unsigned flags) {
+ spine_t *t = MALLOC(sizeof(spine_t));
+ if( !spine_(t, file_json, file_atlas, flags) ) return FREE(t), NULL;
+ return t;
+}
+
+void spine_render(spine_t *p, vec3 offset, unsigned flags) {
+ if( !p->texture.id ) return;
+ if( !flags ) return;
+
+ ddraw_push_2d();
+ // if( flags & 2 ) ddraw_line(vec3(0,0,0), vec3(window_width(),window_height(),0));
+ // if( flags & 2 ) ddraw_line(vec3(window_width(),0,0), vec3(0,window_height(),0));
+
+ // int already_computed[SPINE_MAX_BONES] = {0}; // @fixme: optimize: update longest chains first, then remnant branches
+
+ for( int i = 1; i < array_count(p->bones); ++i ) {
+ spine_bone_t *self = &p->bones[i];
+ if( !self->rect_id ) continue;
+
+ int num_bones = 0;
+ static array(spine_bone_t*) chain = 0; array_resize(chain, 0);
+ for( spine_bone_t *next = self; next ; next = next->parent_bone, ++num_bones ) {
+ array_push(chain, next);
+ }
+
+ vec3 target = {0}, prev = {0};
+ for( int j = 0, end = array_count(chain); j < end; ++j ) { // traverse from root(skipped) -> `i` bone direction
+ int j_opposite = end - 1 - j;
+
+ spine_bone_t *b = chain[j_opposite]; // bone
+ spine_bone_t *pb = b->parent_bone; // parent bone
+
+ float pb_x2 = 0, pb_y2 = 0, pb_deg2 = 0;
+ if( pb ) pb_x2 = pb->x2, pb_y2 = pb->y2, pb_deg2 = pb->deg2;
+
+ const float deg2rad = C_PI / 180;
+ b->x2 = b->x3 + pb_x2 + b->x * cos( -pb_deg2 * deg2rad ) - b->y * sin( -pb_deg2 * deg2rad );
+ b->y2 = -b->y3 + pb_y2 - b->y * cos( pb_deg2 * deg2rad ) + b->x * sin( pb_deg2 * deg2rad );
+ b->deg2 = -b->deg3 + pb_deg2 - b->deg;
+
+ prev = target;
+ target = vec3(b->x2,b->y2,b->deg2);
+ }
+
+ target.z = 0;
+ target = add3(target, offset);
+ prev.z = 0;
+ prev = add3(prev, offset);
+
+ if( flags & 2 ) {
+ ddraw_point( target );
+ ddraw_text( target, -0.25f, self->name );
+ ddraw_bone( prev, target ); // from parent to bone
+ }
+ if( flags & 1 ) {
+ spine_atlas_t *a = &p->atlas[self->atlas_id];
+ spine_rect_t *r = &p->skins[p->skin].rects[self->rect_id];
+
+ vec4 rect = ptr4(&a->x);
+ float zindex = self->z;
+ float offsx = 0;
+ float offsy = 0;
+ float tilt = self->deg2 + (a->deg - r->deg);
+ unsigned tint = self->atlas_id == p->debug_atlas_id ? 0xFF<<24 | 0xFF : ~0u;
+
+ if( 1 ) {
+ vec3 dir = vec3(r->x,r->y,0);
+ dir = rotatez3(dir, self->deg2);
+ offsx = dir.x * r->sx;
+ offsy = dir.y * r->sy;
+ }
+
+ sprite_rect(p->texture, rect, vec4(target.x,target.y,0,zindex), vec4(1,1,offsx,offsy), tilt, tint, 0);
+ }
+ }
+
+ ddraw_pop_2d();
+ ddraw_flush();
+}
+
+static
+void spine_animate_(spine_t *p, float *time, float *maxtime, float delta) {
+ if( !p->texture.id ) return;
+
+ if( delta > 1/120.f ) delta = 1/120.f;
+ if( *time >= *maxtime ) *time = 0; else *time += delta;
+
+ // reset root // needed?
+ p->bones[0].x2 = 0;
+ p->bones[0].y2 = 0;
+ p->bones[0].deg2 = 0;
+ p->bones[0].x3 = 0;
+ p->bones[0].y3 = 0;
+ p->bones[0].deg3 = 0;
+
+ for( int i = 0, end = array_count(p->bones); i < end; ++i) {
+ // @todo: attach channel
+ // @todo: per channel: if curve == linear || curve == stepped || array_count(curve) == 4 {...}
+ for each_array_ptr(p->anims[p->inuse].rotate_keys[i], spine_animkey_t, r) {
+ double r0 = r->time;
+ *maxtime = maxf( *maxtime, r0 );
+ if( absf(*time - r0) < delta ) {
+ p->bones[i].deg3 = r->deg;
+ }
+ }
+ for each_array_ptr(p->anims[p->inuse].translate_keys[i], spine_animkey_t, r) {
+ double r0 = r->time;
+ *maxtime = maxf( *maxtime, r0 );
+ if( absf(*time - r0) < delta ) {
+ p->bones[i].x3 = r->x;
+ p->bones[i].y3 = r->y;
+ }
+ }
+ }
+}
+
+void spine_animate(spine_t *p, float delta) {
+ spine_animate_(p, &p->time, &p->maxtime, delta);
+}
+
+void ui_spine(spine_t *p) {
+ if( ui_collapse(va("Anims: %d", array_count(p->anims)), va("%p-a", p))) {
+ for each_array_ptr(p->anims, spine_anim_t, q) {
+ if(ui_slider2("", &p->time, va("%.2f/%.0f %.2f%%", p->time, p->maxtime, p->time * 100.f))) {
+ spine_animate(p, 0);
+ }
+
+ int choice = ui_label2_toolbar(q->name, ICON_MD_PAUSE_CIRCLE " " ICON_MD_PLAY_CIRCLE);
+ if( choice == 1 ) window_pause( 0 ); // play
+ if( choice == 2 ) window_pause( 1 ); // pause
+
+ for( int i = 0; i < SPINE_MAX_BONES; ++i ) {
+ ui_separator();
+ ui_label(va("Bone %d: Attachment keys", i));
+ for each_array_ptr(q->attach_keys[i], spine_animkey_t, r) {
+ ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %s", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->name));
+ }
+ ui_label(va("Bone %d: Rotate keys", i));
+ for each_array_ptr(q->rotate_keys[i], spine_animkey_t, r) {
+ ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %.2f deg", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->deg));
+ }
+ ui_label(va("Bone %d: Translate keys", i));
+ for each_array_ptr(q->translate_keys[i], spine_animkey_t, r) {
+ ui_label(va("%.2f [%.2f %.2f %.2f %.2f] (%.2f,%.2f)", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->x, r->y));
+ }
+ }
+ }
+ ui_collapse_end();
+ }
+ if( ui_collapse(va("Bones: %d", array_count(p->bones)), va("%p-b", p))) {
+ for each_array_ptr(p->bones, spine_bone_t, q)
+ if( ui_collapse(q->name, va("%p-b2", q)) ) {
+ ui_label2("Parent:", q->parent);
+ ui_label2("X:", va("%.2f", q->x));
+ ui_label2("Y:", va("%.2f", q->y));
+ ui_label2("Length:", va("%.2f", q->len));
+ ui_label2("Rotation:", va("%.2f", q->deg));
+ ui_collapse_end();
+ }
+ ui_collapse_end();
+ }
+ if( ui_collapse(va("Slots: %d", array_count(p->slots)), va("%p-s", p))) {
+ for each_array_ptr(p->slots, spine_slot_t, q)
+ if( ui_collapse(q->name, va("%p-s2", q)) ) {
+ ui_label2("Bone:", q->bone);
+ ui_label2("Attachment:", q->attach);
+ ui_collapse_end();
+ }
+ ui_collapse_end();
+ }
+ if( ui_collapse(va("Skins: %d", array_count(p->skins)), va("%p-k", p))) {
+ for each_array_ptr(p->skins, spine_skin_t, q)
+ if( ui_collapse(q->name, va("%p-k2", q)) ) {
+ for each_array_ptr(q->rects, spine_rect_t, r)
+ if( ui_collapse(r->name, va("%p-k3", r)) ) {
+ ui_label2("X:", va("%.2f", r->x));
+ ui_label2("Y:", va("%.2f", r->y));
+ ui_label2("Scale X:", va("%.2f", r->sx));
+ ui_label2("Scale Y:", va("%.2f", r->sy));
+ ui_label2("Width:", va("%.2f", r->w));
+ ui_label2("Height:", va("%.2f", r->h));
+ ui_label2("Rotation:", va("%.2f", r->deg));
+ ui_collapse_end();
+
+ spine_bone_t *b = find_bone(p, r->name);
+ if( b ) {
+ p->debug_atlas_id = b->atlas_id;
+
+ static float tilt = 0;
+ if( input(KEY_LCTRL) ) tilt += 60*1/60.f; else tilt = 0;
+ spine_atlas_t *r = p->atlas + b->atlas_id;
+ sprite_flush();
+ camera_get_active()->position = vec3(0,0,2);
+ vec4 rect = ptr4(&r->x); float zindex = 0; vec4 scale_offset = vec4(1,1,0,0);
+ sprite_rect(p->texture, ptr4(&r->x), vec4(0,0,0,zindex), scale_offset, r->deg + tilt, ~0u, 0);
+ sprite_flush();
+ camera_get_active()->position = vec3(+window_width()/3,window_height()/2.25,2);
+ }
+ }
+ ui_collapse_end();
+ }
+ ui_collapse_end();
+ }
+
+ if( ui_int("Use skin", &p->skin) ) {
+ p->skin = clampf(p->skin, 0, array_count(p->skins) - 1);
+ spine_skin(p, p->skin);
+ }
+
+ if( p->texture.id ) ui_texture(0, p->texture);
+}
+
+// ----------------------------------------------------------------------------
+
+// texture_t texture_createclip(unsigned cx,unsigned cy,unsigned cw,unsigned ch, unsigned tw,unsigned th,unsigned tn,void *pixels, unsigned flags) {
+// return texture_create(tw,th,tn,pixels,flags);
+// static array(unsigned) clip = 0;
+// array_resize(clip, cw*ch*4);
+// for( unsigned y = 0; y < ch; ++y )
+// memcpy((char *)clip + (0+(0+y)*cw)*tn, (char*)pixels + (cx+(cy+y)*tw)*tn, cw*tn);
+// return texture_create(cw,ch,tn,clip,flags);
+// }
+
+typedef unsigned quark_t;
+
+#define array_reserve_(arr,x) (array_count(arr) > (x) ? (arr) : array_resize(arr, 1+(x)))
+
+#define ui_array(label,type,ptr) do { \
+ int changed = 0; \
+ if( ui_collapse(label, va(#type "%p",ptr)) ) { \
+ char label_ex[8]; \
+ for( int idx = 0, iend = array_count(*(ptr)); idx < iend; ++idx ) { \
+ type* it = *(ptr) + idx; \
+ snprintf(label_ex, sizeof(label_ex), "[%d]", idx); \
+ changed |= ui_##type(label_ex, it); \
+ } \
+ ui_collapse_end(); \
+ } \
+} while(0)
+
+int ui_vec2i(const char *label, vec2i *v) { return ui_unsigned2(label, (unsigned*)v); }
+int ui_vec3i(const char *label, vec3i *v) { return ui_unsigned3(label, (unsigned*)v); }
+int ui_vec2(const char *label, vec2 *v) { return ui_float2(label, (float*)v); }
+int ui_vec3(const char *label, vec3 *v) { return ui_float3(label, (float*)v); }
+int ui_vec4(const char *label, vec4 *v) { return ui_float4(label, (float*)v); }
+
+char *trimspace(char *str) {
+ for( char *s = str; *s; ++s )
+ if(*s <= 32) memmove(s, s+1, strlen(s));
+ return str;
+}
+
+char *file_parent(const char *f) { // folder/folder/abc
+ char *p = file_path(f); // folder/folder/
+ char *last = strrchr(p, '/'); // ^
+ if( !last ) return p; // return parent if no sep
+ *last = '\0'; // folder/folder
+ last = strrchr(p, '/'); // ^
+ return last ? last + 1 : p; // return parent if no sep
+}
+
+int ui_obj(const char *fmt, obj *o) {
+ int changed = 0, item = 1;
+ for each_objmember(o, TYPE,NAME,PTR) {
+ char *label = va(fmt, NAME);
+ /**/ if(!strcmp(TYPE,"float")) { if(ui_float(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"int")) { if(ui_int(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"unsigned")) { if(ui_unsigned(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"vec2")) { if(ui_float2(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"vec3")) { if(ui_float3(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"vec4")) { if(ui_float4(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"rgb")) { if(ui_color3(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"rgba")) { if(ui_color4(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"color")) { if(ui_color4f(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"color3f")) { if(ui_color3f(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"color4f")) { if(ui_color4f(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"char*")) { if(ui_string(label, PTR)) changed = item; }
+ else ui_label2(label, va("(%s)", TYPE)); // INFO instead of (TYPE)?
+ ++item;
+ }
+ return changed;
+}
+
+#define OBJTYPEDEF2(...) OBJTYPEDEF(__VA_ARGS__); AUTORUN
+
+// ----------------------------------------------------------------------------
+// atlas
+
+typedef struct atlas_frame_t {
+ unsigned delay;
+ vec4 sheet;
+ vec2 anchor; // @todo
+ array(vec3i) indices;
+ array(vec2) coords;
+ array(vec2) uvs;
+} atlas_frame_t;
+
+typedef struct atlas_anim_t {
+ quark_t name;
+ array(unsigned) frames;
+} atlas_anim_t;
+
+typedef struct atlas_t {
+ texture_t tex;
+
+ array(atlas_frame_t) frames;
+ array(atlas_anim_t) anims;
+
+ quarks_db db;
+} atlas_t;
+
+int ui_atlas_frame(atlas_frame_t *f) {
+ ui_unsigned("delay", &f->delay);
+ ui_vec4("sheet", &f->sheet);
+ ui_array("indices", vec3i, &f->indices);
+ ui_array("coords", vec2, &f->coords);
+ ui_array("uvs", vec2, &f->uvs);
+ return 0;
+}
+
+int ui_atlas(atlas_t *a) {
+ int changed = 0;
+ ui_texture(NULL, a->tex);
+ for( int i = 0; i < array_count(a->anims); ++i ) {
+ if( ui_collapse(quark_string(&a->db, a->anims[i].name), va("%p%d", a, a->anims[i].name) ) ) {
+ changed = i+1;
+ for( int j = 0; j < array_count(a->anims[i].frames); ++j ) {
+ if( ui_collapse(va("[%d]",j), va("%p%d.%d", a, a->anims[i].name,j) ) ) {
+ ui_unsigned("Frame", &a->anims[i].frames[j]);
+ ui_atlas_frame(a->frames + a->anims[i].frames[j]);
+ ui_collapse_end();
+ }
+ }
+ ui_collapse_end();
+ }
+ }
+ return changed;
+}
+
+void atlas_destroy(atlas_t *a) {
+ if( a ) {
+ texture_destroy(&a->tex);
+ memset(a, 0, sizeof(atlas_t));
+ }
+}
+atlas_t atlas_create(const char *inifile, unsigned flags) {
+ atlas_t a = {0};
+ int padding = 0, border = 0;
+
+ ini_t kv = ini(inifile);
+ for each_map(kv, char*,k, char*,v ) {
+ unsigned index = atoi(k);
+ /**/ if( strend(k, ".name") ) {
+ array_reserve_(a.anims, index);
+
+ a.anims[index].name = quark_intern(&a.db, v);
+ }
+ else if( strend(k, ".frames") ) {
+ array_reserve_(a.anims, index);
+
+ array(char*) pairs = strsplit(v, ",");
+ for( int i = 0, end = array_count(pairs); i < end; i += 2 ) {
+ unsigned frame = atoi(pairs[i]);
+ unsigned delay = atoi(pairs[i+1]);
+
+ array_reserve_(a.frames, frame);
+ a.frames[frame].delay = delay;
+
+ array_push(a.anims[index].frames, frame);
+ }
+ }
+ else if( strend(k, ".sheet") ) {
+ array_reserve_(a.frames, index);
+
+ vec4 sheet = atof4(v); //x,y,x2+2,y2+2 -> x,y,w,h (for 2,2 padding)
+ a.frames[index].sheet = vec4(sheet.x,sheet.y,sheet.z-sheet.x,sheet.w-sheet.y);
+ }
+ else if( strend(k, ".indices") ) {
+ array_reserve_(a.frames, index);
+
+ const char *text = v;
+ array(char*) tuples = strsplit(text, ",");
+ for( int i = 0, end = array_count(tuples); i < end; i += 3 ) {
+ unsigned p1 = atoi(tuples[i]);
+ unsigned p2 = atoi(tuples[i+1]);
+ unsigned p3 = atoi(tuples[i+2]);
+ array_push(a.frames[index].indices, vec3i(p1,p2,p3));
+ }
+ }
+ else if( strend(k, ".coords") ) {
+ array_reserve_(a.frames, index);
+
+ const char *text = v;
+ array(char*) pairs = strsplit(text, ",");
+ for( int i = 0, end = array_count(pairs); i < end; i += 2 ) {
+ unsigned x = atoi(pairs[i]);
+ unsigned y = atoi(pairs[i+1]);
+ array_push(a.frames[index].coords, vec2(x,y));
+ }
+ }
+ else if( strend(k, ".uvs") ) {
+ array_reserve_(a.frames, index);
+
+ const char *text = v;
+ array(char*) pairs = strsplit(text, ",");
+ for( int i = 0, end = array_count(pairs); i < end; i += 2 ) {
+ unsigned u = atoi(pairs[i]);
+ unsigned v = atoi(pairs[i+1]);
+ array_push(a.frames[index].uvs, vec2(u,v));
+ }
+ }
+ else if( strend(k, "padding") ) {
+ padding = atoi(v);
+ }
+ else if( strend(k, "border") ) {
+ border = atoi(v);
+ }
+ else if( strend(k, "file") ) {
+ a.tex = texture(v, 0);
+ }
+ else if( strend(k, "bitmap") ) {
+ const char *text = v;
+ array(char) bin = base64_decode(text, strlen(text));
+ a.tex = texture_from_mem(bin, array_count(bin), 0);
+ array_free(bin);
+ }
+#if 0
+ else if( strend(k, ".frame") ) {
+ array_reserve_(a.frames, index);
+ puts(k), puts(v);
+ }
+#endif
+ }
+
+ // post-process: normalize uvs and coords into [0..1] ranges
+ for each_array_ptr(a.frames, atlas_frame_t, f) {
+ for each_array_ptr(f->uvs, vec2, uv) {
+ uv->x /= a.tex.w;
+ uv->y /= a.tex.h;
+ }
+ for each_array_ptr(f->coords, vec2, xy) {
+ xy->x /= a.tex.w;
+ xy->y /= a.tex.h;
+ }
+ // @todo: adjust padding/border
+ }
+#if 0
+ // post-process: specify an anchor for each anim based on 1st frame dims
+ for each_array_ptr(a.anims, atlas_anim_t, anim) {
+ atlas_frame_t *first = a.frames + *anim->frames;
+ for( int i = 0; i < array_count(anim->frames); i += 2) {
+ atlas_frame_t *ff = a.frames + anim->frames[ i ];
+ ff->anchor.x = (ff->sheet.z - first->sheet.z) / 2;
+ ff->anchor.y = (ff->sheet.w - first->sheet.w) / 2;
+ }
+ }
+#endif
+
+ return a;
+}
+
+// ----------------------------------------------------------------------------
+// sprite v2
+
+void sprite_ctor(sprite_t *s) {
+ s->tint = WHITE;
+ s->timer_ms = 100;
+ s->flipped = 1;
+ s->sca.x += !s->sca.x;
+ s->sca.y += !s->sca.y;
+}
+void sprite_dtor(sprite_t *s) {
+ memset(s, 0, sizeof(*s));
+}
+void sprite_tick(sprite_t *s) {
+ int right = input(s->gamepad.array[3]) - input(s->gamepad.array[2]); // RIGHT - LEFT
+ int forward = input(s->gamepad.array[1]) - input(s->gamepad.array[0]); // DOWN - UP
+ int move = right || forward;
+ int dt = 16; // window_delta() * 1000;
+
+ unsigned over = (s->timer - dt) > s->timer;
+ if(!s->paused) s->timer -= dt;
+ if( over ) {
+ int len = array_count(s->a->anims[s->play].frames);
+ unsigned next = (s->frame + 1) % (len + !len);
+ unsigned eoa = next < s->frame;
+ s->frame = next;
+
+ atlas_frame_t *f = &s->a->frames[ s->a->anims[s->play].frames[s->frame] ];
+ s->timer_ms = f->delay;
+ s->timer += s->timer_ms;
+ }
+
+ if( s->play == 0 && move ) sprite_setanim(s, 1);
+ if( s->play == 1 ) { //<
+ if(right) s->flip_ = right < 0, sprite_setanim(s, 1);
+ if(!right && !forward) sprite_setanim(s, 0);
+
+ float speed = s->sca.x*2;
+ s->pos = add4(s->pos, scale4(norm4(vec4(right,0,forward,0)),speed));
+ }
+}
+void sprite_draw(sprite_t *s) {
+ atlas_frame_t *f = &s->a->frames[ s->a->anims[s->play].frames[s->frame] ];
+
+#if 1
+ // @todo {
+ unsigned sample = s->a->anims[s->play].frames[s->frame];
+ sample = 0;
+ f->anchor.x = (-s->a->frames[sample].sheet.z + f->sheet.z) / 2;
+ f->anchor.y = (+s->a->frames[sample].sheet.w - f->sheet.w) / 2;
+ // }
+#endif
+
+ // rect(x,y,w,h) is [0..1] normalized, z-index, pos(x,y,scale), rotation (degrees), color (rgba)
+ vec4 rect = { f->sheet.x / s->a->tex.w, f->sheet.y / s->a->tex.h, f->sheet.z / s->a->tex.w, f->sheet.w / s->a->tex.h };
+ sprite_rect(s->a->tex, rect, s->pos, vec4(s->flip_ ^ s->flipped?s->sca.x:-s->sca.x,s->sca.y,f->anchor.x,f->anchor.y), s->tilt, s->tint, 0|SPRITE_PROJECTED);
+}
+void sprite_edit(sprite_t *s) {
+ const char *name = obj_name(s);
+ const char *id = vac("%p", s);
+ if( s && ui_collapse(name ? name : id, id) ) {
+ ui_obj("%s", (obj*)s);
+
+ ui_bool("paused", &s->paused);
+ ui_label(va("frame anim [%d]", s->a->anims[s->play].frames[s->frame]));
+
+ int k = s->play;
+ if( ui_int("anim", &k) ) {
+ sprite_setanim(s, k);
+ }
+
+ int selected = ui_atlas(s->a);
+ if( selected ) sprite_setanim(s, selected - 1);
+
+ ui_collapse_end();
+ }
+}
+
+sprite_t* sprite_new(const char *ase, int bindings[6]) {
+ sprite_t *s = obj_new(sprite_t, {bindings[0],bindings[1],bindings[2],bindings[3]}, {bindings[4],bindings[5]});
+ atlas_t own = atlas_create(ase, 0);
+ memcpy(s->a = MALLOC(sizeof(atlas_t)), &own, sizeof(atlas_t)); // s->a = &s->own;
+ return s;
+}
+void sprite_del(sprite_t *s) {
+ if( s ) {
+ if( s->a ) atlas_destroy(s->a), FREE(s->a); // if( s->a == &s->own )
+ obj_free(s);
+ memset(s, 0, sizeof(sprite_t));
+ }
+}
+void sprite_setanim(sprite_t *s, unsigned name) {
+ if( s->play != name ) {
+ s->play = name;
+ s->frame = 0;
+
+ atlas_frame_t *f = &s->a->frames[ s->a->anims[s->play].frames[s->frame] ];
+
+ s->timer_ms = f->delay;
+ s->timer = s->timer_ms;
+ }
+}
+
+AUTORUN {
+ STRUCT(sprite_t, vec4, pos);
+ STRUCT(sprite_t, vec2, sca);
+ STRUCT(sprite_t, float, tilt);
+ STRUCT(sprite_t, vec4, gamepad);
+ STRUCT(sprite_t, vec2, fire);
+ STRUCT(sprite_t, rgba, tint);
+ STRUCT(sprite_t, unsigned, frame);
+ STRUCT(sprite_t, unsigned, timer);
+ STRUCT(sprite_t, unsigned, timer_ms);
+ STRUCT(sprite_t, unsigned, flipped);
+ STRUCT(sprite_t, unsigned, play);
+ EXTEND_T(sprite, ctor,edit,draw,tick);
+}
diff --git a/engine/split/v4k_sprite.h b/engine/split/v4k_sprite.h
new file mode 100644
index 0000000..97c5a5e
--- /dev/null
+++ b/engine/split/v4k_sprite.h
@@ -0,0 +1,114 @@
+// -----------------------------------------------------------------------------
+// sprites
+
+typedef enum SPRITE_FLAGS {
+ SPRITE_PROJECTED = 1,
+ SPRITE_ADDITIVE = 2,
+ SPRITE_CENTERED = 4,
+ SPRITE_RESOLUTION_INDEPENDANT = 128,
+} SPRITE_FLAGS;
+
+// texture id, position(x,y,depth sort), tint color, rotation angle
+API void sprite( texture_t texture, float position[3], float rotation /*0*/, unsigned color /*~0u*/, unsigned flags);
+
+// texture id, rect(x,y,w,h) is [0..1] normalized, then: pos(xyz,z-index), (scale.xy,offset.xy), rotation (degrees), color (rgba)
+API void sprite_rect( texture_t t, vec4 rect, vec4 pos, vec4 scaleoff, float tilt_deg, unsigned tint_rgba, unsigned flags);
+
+// texture id, sheet(frameNumber,X,Y) (frame in a X*Y spritesheet), position(x,y,depth sort), rotation angle, offset(x,y), scale(x,y), is_additive, tint color
+API void sprite_sheet( texture_t texture, float sheet[3], float position[3], float rotation, float offset[2], float scale[2], unsigned rgba, unsigned flags);
+
+API void sprite_flush();
+
+// -----------------------------------------------------------------------------
+// tilemaps
+
+typedef struct tileset_t {
+ texture_t tex; // spritesheet
+ unsigned tile_w, tile_h; // dimensions per tile in pixels
+ unsigned cols, rows; // tileset num_cols, num_rows
+ unsigned selected; // active tile (while editing)
+} tileset_t;
+
+API tileset_t tileset(texture_t tex, unsigned tile_w, unsigned tile_h, unsigned cols, unsigned rows);
+
+API int ui_tileset( tileset_t t );
+
+typedef struct tilemap_t {
+ int blank_chr; // transparent tile
+ unsigned cols, rows; // map dimensions (in tiles)
+ array(int) map;
+
+ vec3 position; // x,y,scale
+ float zindex;
+ float tilt;
+ unsigned tint;
+ bool is_additive;
+} tilemap_t;
+
+API tilemap_t tilemap(const char *map, int blank_chr, int linefeed_chr);
+API void tilemap_render( tilemap_t m, tileset_t style );
+API void tilemap_render_ext( tilemap_t m, tileset_t style, float zindex, float xy_zoom[3], float tilt, unsigned tint, bool is_additive );
+
+// -----------------------------------------------------------------------------
+// tiled maps
+
+typedef struct tiled_t {
+ char *map_name;
+ unsigned first_gid, tilew, tileh, w, h;
+
+ bool parallax;
+ vec3 position;
+ array(bool) visible;
+ array(tilemap_t) layers;
+ array(tileset_t) sets;
+ array(char*) names;
+} tiled_t;
+
+API tiled_t tiled(const char *file_tmx);
+API void tiled_render(tiled_t tmx, vec3 pos);
+
+API void ui_tiled(tiled_t *t);
+
+// -----------------------------------------------------------------------------
+// spines
+
+typedef struct spine_t spine_t;
+
+API spine_t*spine(const char *file_json, const char *file_atlas, unsigned flags);
+API void spine_skin(spine_t *p, unsigned skin);
+API void spine_render(spine_t *p, vec3 offset, unsigned flags);
+API void spine_animate(spine_t *p, float delta);
+
+API void ui_spine(spine_t *p);
+
+// ----------------------------------------------------------------------------
+// sprite v2 api
+
+typedef struct sprite_t { OBJ
+ vec4 gamepad; // up,down,left,right
+ vec2 fire; // a,b
+
+ vec4 pos;
+ vec2 sca;
+ float tilt;
+ unsigned tint;
+ unsigned frame;
+ unsigned timer, timer_ms;
+ unsigned flip_, flipped;
+ unsigned play;
+ bool paused;
+ // array(unsigned) play_queue; or unsigned play_next;
+ struct atlas_t *a; // shared
+ //atlas_t own; // owned
+} sprite_t;
+
+OBJTYPEDEF(sprite_t,10);
+API void sprite_ctor(sprite_t *s);
+API void sprite_dtor(sprite_t *s);
+API void sprite_tick(sprite_t *s);
+API void sprite_draw(sprite_t *s);
+API void sprite_edit(sprite_t *s);
+
+API sprite_t*sprite_new(const char *ase, int bindings[6]);
+API void sprite_del(sprite_t *s);
+API void sprite_setanim(sprite_t *s, unsigned name);
diff --git a/engine/split/v4k_string.c b/engine/split/v4k_string.c
index f185c28..addce48 100644
--- a/engine/split/v4k_string.c
+++ b/engine/split/v4k_string.c
@@ -418,3 +418,152 @@ AUTORUN {
test( !strcmp("Hello happy world.", buf) );
}
#endif
+
+// ----------------------------------------------------------------------------
+// localization kit
+
+static const char *kit_lang = "enUS", *kit_langs =
+ "enUS,enGB,"
+ "frFR,"
+ "esES,esAR,esMX,"
+ "deDE,deCH,deAT,"
+ "itIT,itCH,"
+ "ptBR,ptPT,"
+ "zhCN,zhSG,zhTW,zhHK,zhMO,"
+ "ruRU,elGR,trTR,daDK,noNB,svSE,nlNL,plPL,fiFI,jaJP,"
+ "koKR,csCZ,huHU,roRO,thTH,bgBG,heIL"
+;
+
+static map(char*,char*) kit_ids;
+static map(char*,char*) kit_vars;
+
+#ifndef KIT_FMT_ID2
+#define KIT_FMT_ID2 "%s.%s"
+#endif
+
+void kit_init() {
+ do_once map_init(kit_ids, less_str, hash_str);
+ do_once map_init(kit_vars, less_str, hash_str);
+}
+
+void kit_insert( const char *id, const char *translation) {
+ char *id2 = va(KIT_FMT_ID2, kit_lang, id);
+
+ char **found = map_find_or_add_allocated_key(kit_ids, STRDUP(id2), NULL);
+ if(*found) FREE(*found);
+ *found = STRDUP(translation);
+}
+
+bool kit_merge( const char *filename ) {
+ // @todo: xlsx2ini
+ return false;
+}
+
+void kit_clear() {
+ map_clear(kit_ids);
+}
+
+bool kit_load( const char *filename ) {
+ return kit_clear(), kit_merge( filename );
+}
+
+void kit_set( const char *key, const char *value ) {
+ value = value && value[0] ? value : "";
+
+ char **found = map_find_or_add_allocated_key(kit_vars, STRDUP(key), NULL );
+ if(*found) FREE(*found);
+ *found = STRDUP(value);
+}
+
+void kit_reset() {
+ map_clear(kit_vars);
+}
+
+char *kit_translate2( const char *id, const char *lang ) {
+ char *id2 = va(KIT_FMT_ID2, lang, id);
+
+ char **found = map_find(kit_ids, id2);
+
+ // return original [[ID]] if no translation is found
+ if( !found ) return va("[[%s]]", id);
+
+ // return translation if no {{moustaches}} are found
+ if( !strstr(*found, "{{") ) return *found;
+
+ // else replace all found {{moustaches}} with context vars
+ {
+ // make room
+ static __thread char *results[16] = {0};
+ static __thread unsigned counter = 0; counter = (counter+1) % 16;
+
+ char *buffer = results[ counter ];
+ if( buffer ) FREE(buffer), buffer = 0;
+
+ // iterate moustaches
+ const char *begin, *end, *text = *found;
+ while( NULL != (begin = strstr(text, "{{")) ) {
+ end = strstr(begin+2, "}}");
+ if( end ) {
+ char *var = va("%.*s", (int)(end - (begin+2)), begin+2);
+ char **found_var = map_find(kit_vars, var);
+
+ if( found_var && 0[*found_var] ) {
+ strcatf(&buffer, "%.*s%s", (int)(begin - text), text, *found_var);
+ } else {
+ strcatf(&buffer, "%.*s{{%s}}", (int)(begin - text), text, var);
+ }
+
+ text = end+2;
+ } else {
+ strcatf(&buffer, "%.*s", (int)(begin - text), text);
+
+ text = begin+2;
+ }
+ }
+
+ strcatf(&buffer, "%s", text);
+ return buffer;
+ }
+}
+
+char *kit_translate( const char *id ) {
+ return kit_translate2( id, kit_lang );
+}
+
+void kit_locale( const char *lang ) {
+ kit_lang = STRDUP(lang); // @leak
+}
+
+void kit_dump_state( FILE *fp ) {
+ for each_map(kit_ids, char *, k, char *, v) {
+ fprintf(fp, "[ID ] %s=%s\n", k, v);
+ }
+ for each_map(kit_vars, char *, k, char *, v) {
+ fprintf(fp, "[VAR] %s=%s\n", k, v);
+ }
+}
+
+/*
+int main() {
+ kit_init();
+
+ kit_locale("enUS");
+ kit_insert("HELLO_PLAYERS", "Hi {{PLAYER1}} and {{PLAYER2}}!");
+ kit_insert("GREET_PLAYERS", "Nice to meet you.");
+
+ kit_locale("esES");
+ kit_insert("HELLO_PLAYERS", "Hola {{PLAYER1}} y {{PLAYER2}}!");
+ kit_insert("GREET_PLAYERS", "Un placer conoceros.");
+
+ kit_locale("enUS");
+ printf("%s %s\n", kit_translate("HELLO_PLAYERS"), kit_translate("GREET_PLAYERS")); // Hi {{PLAYER1}} and {{PLAYER2}}! Nice to meet you.
+
+ kit_locale("esES");
+ kit_set("PLAYER1", "John");
+ kit_set("PLAYER2", "Karl");
+ printf("%s %s\n", kit_translate("HELLO_PLAYERS"), kit_translate("GREET_PLAYERS")); // Hola John y Karl! Un placer conoceros.
+
+ assert( 0 == strcmp(kit_translate("NON_EXISTING"), "[[NON_EXISTING]]")); // [[NON_EXISTING]]
+ assert(~puts("Ok"));
+}
+*/
diff --git a/engine/split/v4k_string.h b/engine/split/v4k_string.h
index 439f962..44b97fe 100644
--- a/engine/split/v4k_string.h
+++ b/engine/split/v4k_string.h
@@ -90,3 +90,20 @@ typedef struct quarks_db {
API unsigned quark_intern( quarks_db*, const char *string );
API const char *quark_string( quarks_db*, unsigned key );
+
+// -----------------------------------------------------------------------------
+// ## localization kit (I18N, L10N)
+
+API bool kit_load( const char *filename ); // load translations file (xlsx)
+API bool kit_merge( const char *filename ); // merge translations file into existing context
+API void kit_insert( const char *id, const char *translation ); // insert single translation unit
+API void kit_clear(); // delete all translations
+
+API void kit_set( const char *variable, const char *value ); // set context variable
+API void kit_reset(); // reset all variables in context
+API void kit_dump_state( FILE *fp ); // debug
+
+API char* kit_translate2( const char *id, const char *langcode_iso639_1 ); // perform a translation given explicit locale
+
+API void kit_locale( const char *langcode_iso639_1 ); // set current locale: enUS, ptBR, esES, ...
+API char* kit_translate( const char *id ); // perform a translation, given current locale
diff --git a/engine/split/v4k_system.c b/engine/split/v4k_system.c
index b378e89..bb4f446 100644
--- a/engine/split/v4k_system.c
+++ b/engine/split/v4k_system.c
@@ -200,8 +200,8 @@ static char **backtrace_symbols(void *const *list,int size) {
static __thread char **symbols = 0; //[32][64] = {0};
if( !symbols ) {
- symbols = SYS_REALLOC(0, 128 * sizeof(char*));
- for( int i = 0; i < 128; ++i) symbols[i] = SYS_REALLOC(0, 128 * sizeof(char));
+ symbols = SYS_MEM_REALLOC(0, 128 * sizeof(char*));
+ for( int i = 0; i < 128; ++i) symbols[i] = SYS_MEM_REALLOC(0, 128 * sizeof(char));
}
if(size > 128) size = 128;
@@ -234,7 +234,7 @@ static char **backtrace_symbols(void *const *sym,int num) { return 0; }
char *callstack( int traces ) {
static __thread char *output = 0;
- if(!output ) output = SYS_REALLOC( 0, 128 * (64+2) );
+ if(!output ) output = SYS_MEM_REALLOC( 0, 128 * (64+2) );
if( output ) output[0] = '\0';
char *ptr = output;
@@ -793,7 +793,7 @@ int (PRINTF)(const char *text, const char *stack, const char *file, int line, co
static void *panic_oom_reserve; // for out-of-memory recovery
int (PANIC)(const char *error, const char *file, int line) {
- panic_oom_reserve = SYS_REALLOC(panic_oom_reserve, 0);
+ panic_oom_reserve = SYS_MEM_REALLOC(panic_oom_reserve, 0);
tty_color(RED);
diff --git a/engine/split/v4k_ui.c b/engine/split/v4k_ui.c
index 4e75c69..ae60b9f 100644
--- a/engine/split/v4k_ui.c
+++ b/engine/split/v4k_ui.c
@@ -1901,8 +1901,8 @@ int ui_color4f(const char *label, float *color) {
nk_layout_row_dynamic(ui_ctx, 0, 2);
ui_label_(label, NK_TEXT_LEFT);
- struct nk_colorf after = { color[0]*ui_alpha, color[1]*ui_alpha, color[2]*ui_alpha, color[3] }, before = after;
- struct nk_colorf clamped = { clampf(color[0],0,1), clampf(color[1],0,1), clampf(color[2],0,1), clampf(color[3],0,1) };
+ struct nk_colorf after = { color[0]*ui_alpha, color[1]*ui_alpha, color[2]*ui_alpha, color[3]*ui_alpha }, before = after;
+ struct nk_colorf clamped = { clampf(after.r,0,1), clampf(after.g,0,1), clampf(after.b,0,1), clampf(after.a,0,1) };
if (nk_combo_begin_color(ui_ctx, nk_rgb_cf(clamped), nk_vec2(200,400))) {
nk_layout_row_dynamic(ui_ctx, 120, 1);
after = nk_color_picker(ui_ctx, after, NK_RGB);
@@ -1989,8 +1989,8 @@ int ui_color3f(const char *label, float *color) {
nk_layout_row_dynamic(ui_ctx, 0, 2);
ui_label_(label, NK_TEXT_LEFT);
- struct nk_colorf after = { color[0]*ui_alpha, color[1]*ui_alpha, color[2]*ui_alpha, ui_alpha }, before = after;
- struct nk_colorf clamped = { clampf(color[0],0,1), clampf(color[1],0,1), clampf(color[2],0,1), 1 };
+ struct nk_colorf after = { color[0]*ui_alpha, color[1]*ui_alpha, color[2]*ui_alpha, color[3]*ui_alpha }, before = after;
+ struct nk_colorf clamped = { clampf(after.r,0,1), clampf(after.g,0,1), clampf(after.b,0,1), ui_alpha };
if (nk_combo_begin_color(ui_ctx, nk_rgb_cf(clamped), nk_vec2(200,400))) {
nk_layout_row_dynamic(ui_ctx, 120, 1);
after = nk_color_picker(ui_ctx, after, NK_RGB);
@@ -2033,7 +2033,7 @@ int ui_color3(const char *label, unsigned *color) {
nk_layout_row_dynamic(ui_ctx, 0, 2);
ui_label_(label, NK_TEXT_LEFT);
- struct nk_colorf after = { r*ui_alpha, g*ui_alpha, b*ui_alpha, 1 }, before = after;
+ struct nk_colorf after = { r*ui_alpha/255, g*ui_alpha/255, b*ui_alpha/255, ui_alpha }, before = after;
if (nk_combo_begin_color(ui_ctx, nk_rgb_cf(after), nk_vec2(200,400))) {
nk_layout_row_dynamic(ui_ctx, 120, 1);
after = nk_color_picker(ui_ctx, after, NK_RGB);
@@ -2695,8 +2695,10 @@ int ui_demo(int do_windows) {
static float float2[2] = {1,2};
static float float3[3] = {1,2,3};
static float float4[4] = {1,2,3,4};
- static float rgb[3] = {0.84,0.67,0.17};
- static float rgba[4] = {0.67,0.90,0.12,1};
+ static float rgbf[3] = {0.84,0.67,0.17};
+ static float rgbaf[4] = {0.67,0.90,0.12,1};
+ static unsigned rgb = CYAN;
+ static unsigned rgba = PINK;
static float slider = 0.5f;
static float slider2 = 0.5f;
static char string[64] = "hello world 123";
@@ -2740,8 +2742,10 @@ int ui_demo(int do_windows) {
if( ui_list("my list", list, 3, &item ) ) puts("list changed");
if( ui_section("Colors")) {}
- if( ui_color3f("my color3", rgb) ) puts("color3 changed");
- if( ui_color4f("my color4@this is a tooltip", rgba) ) puts("color4 changed");
+ if( ui_color3("my color3", &rgb) ) puts("color3 changed");
+ if( ui_color4("my color4@this is a tooltip", &rgba) ) puts("color4 changed");
+ if( ui_color3f("my color3f", rgbf) ) puts("color3f changed");
+ if( ui_color4f("my color4f@this is a tooltip", rgbaf) ) puts("color4f changed");
if( ui_section("Sliders")) {}
if( ui_slider("my slider", &slider)) puts("slider changed");
diff --git a/engine/split/v4k_window.c b/engine/split/v4k_window.c
index 0d19068..1a21661 100644
--- a/engine/split/v4k_window.c
+++ b/engine/split/v4k_window.c
@@ -424,7 +424,7 @@ bool window_create_from_handle(void *handle, float scale, unsigned flags) {
#define ddraw_progress_bar(JOB_ID, JOB_MAX, PERCENT) do { \
/* NDC coordinates (2d): bottom-left(-1,-1), center(0,0), top-right(+1,+1) */ \
float progress = (PERCENT+1) / 100.f; if(progress > 1) progress = 1; \
- float speed = progress < 1 ? 0.2f : 0.5f; \
+ float speed = progress < 1 ? 0.05f : 0.75f; \
float smooth = previous[JOB_ID] = progress * speed + previous[JOB_ID] * (1-speed); \
\
float pixel = 2.f / window_height(), dist = smooth*2-1, y = pixel*3*JOB_ID; \
diff --git a/engine/v4k b/engine/v4k
index e6fe7cf..41bc0c4 100644
--- a/engine/v4k
+++ b/engine/v4k
@@ -6,7 +6,7 @@
#define GLAD_GL_IMPLEMENTATION // glad
#endif
-#line 1 "engine/split/3rd_glad.h"
+#line 1 "3rd_glad.h"
#ifndef __EMSCRIPTEN__
#ifndef _GNU_SOURCE // juicy linux headers
@@ -11688,7 +11688,7 @@ int gladLoadGL( GLADloadfunc load) {
#endif /* __EMSCRIPTEN__ */
#line 0
-#line 1 "engine/split/3rd_icon_md.h"
+#line 1 "3rd_icon_md.h"
// Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py for languages C and C++
// from https://github.com/google/material-design-icons/raw/master/font/MaterialIcons-Regular.codepoints
// for use with https://github.com/google/material-design-icons/blob/master/font/MaterialIcons-Regular.ttf
@@ -14032,7 +14032,7 @@ errno_t fopen_s(
#endif
//---
-#line 1 "engine/split/3rd_glfw3.h"
+#line 1 "3rd_glfw3.h"
#ifndef __EMSCRIPTEN__
// forked from https://github.com/SasLuca/glfw-single-header (CC0-1.0 licensed)
@@ -53229,7 +53229,7 @@ uint32_t _glfwKeySym2Unicode(unsigned int keysym)
#line 0
#undef timeGetTime
//---
-#line 1 "engine/split/3rd_swrap.h"
+#line 1 "3rd_swrap.h"
// https://github.com/BareRose/swrap/blob/master/swrap.h
/*
@@ -53522,7 +53522,7 @@ SWDEF int swrapMultiSelect (int* socks, size_t socks_size, double timeout) {
#endif //SWRAP_H
#line 0
//---
-#line 1 "engine/split/3rd_jo_mp1.h"
+#line 1 "3rd_jo_mp1.h"
/* public domain Simple, Minimalistic MPEG Layer 1 decoder - http://jonolick.com
*
* Revision History:
@@ -53933,7 +53933,7 @@ bool jo_read_mp1(const void *input, int inputSize, short **output_, int *outputS
#line 0
#define get_bits stb_vorbis_get_bits
#define error stb_vorbis_error
-#line 1 "engine/split/3rd_stb_vorbis.h"
+#line 1 "3rd_stb_vorbis.h"
// Ogg Vorbis audio decoder - v1.22 - public domain
// http://nothings.org/stb_vorbis/
//
@@ -59521,7 +59521,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#line 0
#undef error
#undef DEBUG
-#line 1 "engine/split/3rd_sts_mixer.h"
+#line 1 "3rd_sts_mixer.h"
///////////////////////////////////////////////////////////////////////////////
// sts_mixer.h - v0.02
// written 2016 by Sebastian Steinhauer
@@ -60034,7 +60034,7 @@ int main(int argc, char *argv[]) {
For more information, please refer to
*/
#line 0
-#line 1 "engine/split/3rd_miniaudio.h"
+#line 1 "3rd_miniaudio.h"
/*
Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file.
miniaudio - v0.11.18 - 2023-08-07
@@ -152579,12 +152579,12 @@ SOFTWARE.
#undef R
#define error l_error
#define panic l_panic
-#line 1 "engine/split/3rd_lua.h"
+#line 1 "3rd_lua.h"
/*
minilua.h -- Lua in a single header
Project URL: https://github.com/edubart/minilua
- This is Lua 5.4.4 contained in a single header to be bundled in C/C++ applications with ease.
+ This is Lua 5.4.6 contained in a single header to be bundled in C/C++ applications with ease.
Lua is a powerful, efficient, lightweight, embeddable scripting language.
Do the following in *one* C file to create the implementation:
@@ -152604,7 +152604,7 @@ SOFTWARE.
*/
/* detect system platform */
-#if !defined(LUA_USE_WINDOWS) && !defined(LUA_USE_LINUX) && !defined(LUA_USE_MACOSX) && !defined(LUA_USE_POSIX) && !defined(LUA_USE_C89)
+#if !defined(LUA_USE_WINDOWS) && !defined(LUA_USE_LINUX) && !defined(LUA_USE_MACOSX) && !defined(LUA_USE_POSIX) && !defined(LUA_USE_C89) && !defined(LUA_USE_IOS)
#if defined(_WIN32)
#define LUA_USE_WINDOWS
#elif defined(__linux__)
@@ -152740,6 +152740,12 @@ extern "C" {
#endif
+#if defined(LUA_USE_IOS)
+#define LUA_USE_POSIX
+#define LUA_USE_DLOPEN
+#endif
+
+
/*
@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.
*/
@@ -153398,7 +153404,7 @@ extern "C" {
** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices).
-** (It must fit into max(size_t)/32.)
+** (It must fit into max(size_t)/32 and max(int)/2.)
*/
#if LUAI_IS32INT
#define LUAI_MAXSTACK 1000000
@@ -153417,14 +153423,15 @@ extern "C" {
/*
@@ LUA_IDSIZE gives the maximum size for the description of the source
-@@ of a function in debug information.
+** of a function in debug information.
** CHANGE it if you want a different size.
*/
#define LUA_IDSIZE 60
/*
-@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
+@@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
+** buffer system.
*/
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
@@ -153474,14 +153481,14 @@ extern "C" {
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4"
-#define LUA_VERSION_RELEASE "4"
+#define LUA_VERSION_RELEASE "6"
#define LUA_VERSION_NUM 504
-#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 4)
+#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
-#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 Lua.org, PUC-Rio"
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -153587,6 +153594,16 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
+/*
+** Type used by the debug API to collect debug information
+*/
+typedef struct lua_Debug lua_Debug;
+
+
+/*
+** Functions to be called by the debugger in specific events
+*/
+typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
/*
@@ -153609,7 +153626,8 @@ extern const char lua_ident[];
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
-LUA_API int (lua_resetthread) (lua_State *L);
+LUA_API int (lua_closethread) (lua_State *L, lua_State *from);
+LUA_API int (lua_resetthread) (lua_State *L); /* Deprecated! */
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
@@ -153898,12 +153916,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
-typedef struct lua_Debug lua_Debug; /* activation record */
-
-
-/* Functions to be called by the debugger in specific events */
-typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
-
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
@@ -153948,7 +153960,7 @@ struct lua_Debug {
/******************************************************************************
-* Copyright (C) 1994-2022 Lua.org, PUC-Rio.
+* Copyright (C) 1994-2023 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -154326,6 +154338,7 @@ LUALIB_API void (luaL_openlibs) (lua_State *L);
#endif
#ifdef LUA_IMPL
+typedef struct CallInfo CallInfo;
/*
** $Id: llimits.h $
** Limits, basic types, and some other 'installation-dependent' definitions
@@ -154399,11 +154412,24 @@ typedef signed char ls_byte;
/*
-** conversion of pointer to unsigned integer:
-** this is for hashing only; there is no problem if the integer
-** cannot hold the whole pointer value
+** conversion of pointer to unsigned integer: this is for hashing only;
+** there is no problem if the integer cannot hold the whole pointer
+** value. (In strict ISO C this may cause undefined behavior, but no
+** actual machine seems to bother.)
*/
-#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX))
+#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
+ __STDC_VERSION__ >= 199901L
+#include
+#if defined(UINTPTR_MAX) /* even in C99 this type is optional */
+#define L_P2I uintptr_t
+#else /* no 'intptr'? */
+#define L_P2I uintmax_t /* use the largest available integer */
+#endif
+#else /* C89 option */
+#define L_P2I size_t
+#endif
+
+#define point2uint(p) ((unsigned int)((L_P2I)(p) & UINT_MAX))
@@ -154747,6 +154773,8 @@ typedef union Value {
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
+ /* not used, but may avoid warnings for uninitialized value */
+ lu_byte ub;
} Value;
@@ -154850,6 +154878,17 @@ typedef union StackValue {
/* index to stack elements */
typedef StackValue *StkId;
+
+/*
+** When reallocating the stack, change all pointers to the stack into
+** proper offsets.
+*/
+typedef union {
+ StkId p; /* actual pointer */
+ ptrdiff_t offset; /* used while the stack is being reallocated */
+} StkIdRel;
+
+
/* convert a 'StackValue' to a 'TValue' */
#define s2v(o) (&(o)->val)
@@ -155310,8 +155349,10 @@ typedef struct Proto {
*/
typedef struct UpVal {
CommonHeader;
- lu_byte tbc; /* true if it represents a to-be-closed variable */
- TValue *v; /* points to stack or to its own value */
+ union {
+ TValue *p; /* points to stack or to its own value */
+ ptrdiff_t offset; /* used while the stack is being reallocated */
+ } v;
union {
struct { /* (when open) */
struct UpVal *next; /* linked list */
@@ -155597,6 +155638,7 @@ LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag);
/*#include "lobject.h"*/
+/*#include "lstate.h"*/
/*
@@ -155683,8 +155725,8 @@ LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
int inv, int isfloat, TMS event);
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
- struct CallInfo *ci, const Proto *p);
-LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
+ CallInfo *ci, const Proto *p);
+LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci,
StkId where, int wanted);
@@ -155700,6 +155742,11 @@ LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci,
/*#include "lua.h"*/
+
+/* Some header files included here need this definition */
+typedef struct CallInfo CallInfo;
+
+
/*#include "lobject.h"*/
/*#include "ltm.h"*/
/*#include "lzio.h"*/
@@ -155830,7 +155877,7 @@ struct lua_longjmp; /* defined in ldo.c */
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
-#define stacksize(th) cast_int((th)->stack_last - (th)->stack)
+#define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
/* kinds of Garbage Collection */
@@ -155860,9 +155907,9 @@ typedef struct stringtable {
** - field 'transferinfo' is used only during call/returnhooks,
** before the function starts or after it ends.
*/
-typedef struct CallInfo {
- StkId func; /* function index in the stack */
- StkId top; /* top for this function */
+struct CallInfo {
+ StkIdRel func; /* function index in the stack */
+ StkIdRel top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */
union {
struct { /* only for Lua functions */
@@ -155887,7 +155934,7 @@ typedef struct CallInfo {
} u2;
short nresults; /* expected number of results from this function */
unsigned short callstatus;
-} CallInfo;
+};
/*
@@ -155982,7 +156029,7 @@ typedef struct global_State {
struct lua_State *mainthread;
TString *memerrmsg; /* message for memory-allocation errors */
TString *tmname[TM_N]; /* array with tag-method names */
- struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
+ struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
lua_WarnFunction warnf; /* warning function */
void *ud_warn; /* auxiliary data to 'warnf' */
@@ -155997,13 +156044,13 @@ struct lua_State {
lu_byte status;
lu_byte allowhook;
unsigned short nci; /* number of items in 'ci' list */
- StkId top; /* first free slot in the stack */
+ StkIdRel top; /* first free slot in the stack */
global_State *l_G;
CallInfo *ci; /* call info for current function */
- StkId stack_last; /* end of stack (last element + 1) */
- StkId stack; /* stack base */
+ StkIdRel stack_last; /* end of stack (last element + 1) */
+ StkIdRel stack; /* stack base */
UpVal *openupval; /* list of open upvalues in this stack */
- StkId tbclist; /* list of to-be-closed variables */
+ StkIdRel tbclist; /* list of to-be-closed variables */
GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
@@ -156182,7 +156229,7 @@ iABC C(8) | B(8) |k| A(8) | Op(7) |
iABx Bx(17) | A(8) | Op(7) |
iAsBx sBx (signed)(17) | A(8) | Op(7) |
iAx Ax(25) | Op(7) |
-isJ sJ(25) | Op(7) |
+isJ sJ (signed)(25) | Op(7) |
A signed argument is represented in excess K: the represented value is
the written unsigned value minus K, where K is half the maximum for the
@@ -156581,7 +156628,7 @@ LUAI_DDEC(const lu_byte luaP_opmodes[NUM_OPCODES];)
/* Active Lua function (given call info) */
-#define ci_func(ci) (clLvalue(s2v((ci)->func)))
+#define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
#define resethookcount(L) (L->hookcount = L->basehookcount)
@@ -156637,6 +156684,7 @@ LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
#define ldo_h
+/*#include "llimits.h"*/
/*#include "lobject.h"*/
/*#include "lstate.h"*/
/*#include "lzio.h"*/
@@ -156652,7 +156700,7 @@ LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
** at every check.
*/
#define luaD_checkstackaux(L,n,pre,pos) \
- if (l_unlikely(L->stack_last - L->top <= (n))) \
+ if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
{ pre; luaD_growstack(L, n, 1); pos; } \
else { condmovestack(L,pre,pos); }
@@ -156661,11 +156709,18 @@ LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc);
-#define savestack(L,p) ((char *)(p) - (char *)L->stack)
-#define restorestack(L,n) ((StkId)((char *)L->stack + (n)))
+#define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
+#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
/* macro to check stack size, preserving 'p' */
+#define checkstackp(L,n,p) \
+ luaD_checkstackaux(L, n, \
+ ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
+ p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
+
+
+/* macro to check stack size and GC, preserving 'p' */
#define checkstackGCp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
@@ -156687,7 +156742,8 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
int fTransfer, int nTransfer);
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
-LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1, int delta);
+LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
+ int narg1, int delta);
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
@@ -156880,24 +156936,27 @@ LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
-#define luaC_barrier(L,p,v) ( \
- (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
- luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
-
-#define luaC_barrierback(L,p,v) ( \
- (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
- luaC_barrierback_(L,p) : cast_void(0))
-
#define luaC_objbarrier(L,p,o) ( \
(isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
+#define luaC_barrier(L,p,v) ( \
+ iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
+
+#define luaC_objbarrierback(L,p,o) ( \
+ (isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
+
+#define luaC_barrierback(L,p,v) ( \
+ iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
+
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
+LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz,
+ size_t offset);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
@@ -156936,10 +156995,10 @@ LUAI_FUNC void luaC_changemode (lua_State *L, int newmode);
#define MAXUPVAL 255
-#define upisopen(up) ((up)->v != &(up)->u.value)
+#define upisopen(up) ((up)->v.p != &(up)->u.value)
-#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v))
+#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
/*
@@ -156961,7 +157020,7 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
-LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
+LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy);
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
@@ -157076,23 +157135,26 @@ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
/*#include "lstate.h"*/
-/* Increments 'L->top', checking for stack overflows */
-#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
- "stack overflow");}
+/* Increments 'L->top.p', checking for stack overflows */
+#define api_incr_top(L) {L->top.p++; \
+ api_check(L, L->top.p <= L->ci->top.p, \
+ "stack overflow");}
/*
** If a call returns too many multiple returns, the callee may not have
** stack space to accommodate all results. In this case, this macro
-** increases its stack space ('L->ci->top').
+** increases its stack space ('L->ci->top.p').
*/
#define adjustresults(L,nres) \
- { if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
+ { if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
+ L->ci->top.p = L->top.p; }
/* Ensure the stack has at least 'n' elements */
-#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
- "not enough elements in the stack")
+#define api_checknelems(L,n) \
+ api_check(L, (n) < (L->top.p - L->ci->func.p), \
+ "not enough elements in the stack")
/*
@@ -157263,7 +157325,6 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t);
#if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
-LUAI_FUNC int luaH_isdummy (const Table *t);
#endif
@@ -157655,6 +157716,11 @@ typedef enum {
luaC_barrierback(L, gcvalue(t), v); }
+/*
+** Shift right is the same as shift left with a negative 'y'
+*/
+#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
+
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
@@ -158040,25 +158106,6 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
/*#include "lstate.h"*/
-#if defined(EMERGENCYGCTESTS)
-/*
-** First allocation will fail whenever not building initial state.
-** (This fail will trigger 'tryagain' and a full GC cycle at every
-** allocation.)
-*/
-static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
- if (completestate(g) && ns > 0) /* frees never fail */
- return NULL; /* fail */
- else /* normal allocation */
- return (*g->frealloc)(g->ud, block, os, ns);
-}
-#else
-#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
-#endif
-
-
-
-
/*
** About the realloc function:
@@ -158078,6 +158125,43 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
*/
+/*
+** Macro to call the allocation function.
+*/
+#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
+
+
+/*
+** When an allocation fails, it will try again after an emergency
+** collection, except when it cannot run a collection. The GC should
+** not be called while the state is not fully built, as the collector
+** is not yet fully initialized. Also, it should not be called when
+** 'gcstopem' is true, because then the interpreter is in the middle of
+** a collection step.
+*/
+#define cantryagain(g) (completestate(g) && !g->gcstopem)
+
+
+
+
+#if defined(EMERGENCYGCTESTS)
+/*
+** First allocation will fail except when freeing a block (frees never
+** fail) and when it cannot try again; this fail will trigger 'tryagain'
+** and a full GC cycle at every allocation.
+*/
+static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
+ if (ns > 0 && cantryagain(g))
+ return NULL; /* fail */
+ else /* normal allocation */
+ return callfrealloc(g, block, os, ns);
+}
+#else
+#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns)
+#endif
+
+
+
/*
@@ -158150,7 +158234,7 @@ l_noret luaM_toobig (lua_State *L) {
void luaM_free_ (lua_State *L, void *block, size_t osize) {
global_State *g = G(L);
lua_assert((osize == 0) == (block == NULL));
- (*g->frealloc)(g->ud, block, osize, 0);
+ callfrealloc(g, block, osize, 0);
g->GCdebt -= osize;
}
@@ -158158,19 +158242,15 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
/*
** In case of allocation fail, this function will do an emergency
** collection to free some memory and then try the allocation again.
-** The GC should not be called while state is not fully built, as the
-** collector is not yet fully initialized. Also, it should not be called
-** when 'gcstopem' is true, because then the interpreter is in the
-** middle of a collection step.
*/
static void *tryagain (lua_State *L, void *block,
size_t osize, size_t nsize) {
global_State *g = G(L);
- if (completestate(g) && !g->gcstopem) {
+ if (cantryagain(g)) {
luaC_fullgc(L, 1); /* try to free some memory... */
- return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
+ return callfrealloc(g, block, osize, nsize); /* try again */
}
- else return NULL; /* cannot free any memory without a full state */
+ else return NULL; /* cannot run an emergency collection */
}
@@ -158339,10 +158419,10 @@ static TString *loadStringN (LoadState *S, Proto *p) {
}
else { /* long string */
ts = luaS_createlngstrobj(L, size); /* create string */
- setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */
+ setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
luaD_inctop(L);
loadVector(S, getstr(ts), size); /* load directly in final place */
- L->top--; /* pop string */
+ L->top.p--; /* pop string */
}
luaC_objbarrier(L, p, ts);
return ts;
@@ -158467,6 +158547,8 @@ static void loadDebug (LoadState *S, Proto *f) {
f->locvars[i].endpc = loadInt(S);
}
n = loadInt(S);
+ if (n != 0) /* does it have debug information? */
+ n = f->sizeupvalues; /* must be this many */
for (i = 0; i < n; i++)
f->upvalues[i].name = loadStringN(S, f);
}
@@ -158540,7 +158622,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
S.Z = Z;
checkHeader(&S);
cl = luaF_newLclosure(L, loadByte(&S));
- setclLvalue2s(L, L->top, cl);
+ setclLvalue2s(L, L->top.p, cl);
luaD_inctop(L);
cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
@@ -158562,6 +158644,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
/*#include "lprefix.h"*/
+#include
#include
/*#include "lua.h"*/
@@ -158607,8 +158690,11 @@ static void dumpByte (DumpState *D, int y) {
}
-/* dumpInt Buff Size */
-#define DIBS ((sizeof(size_t) * 8 / 7) + 1)
+/*
+** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6"
+** rounds up the division.)
+*/
+#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7)
static void dumpSize (DumpState *D, size_t x) {
lu_byte buff[DIBS];
@@ -158958,33 +159044,33 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
static void stack_init (lua_State *L1, lua_State *L) {
int i; CallInfo *ci;
/* initialize stack array */
- L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
- L1->tbclist = L1->stack;
+ L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
+ L1->tbclist.p = L1->stack.p;
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
- setnilvalue(s2v(L1->stack + i)); /* erase new stack */
- L1->top = L1->stack;
- L1->stack_last = L1->stack + BASIC_STACK_SIZE;
+ setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
+ L1->top.p = L1->stack.p;
+ L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
/* initialize first ci */
ci = &L1->base_ci;
ci->next = ci->previous = NULL;
ci->callstatus = CIST_C;
- ci->func = L1->top;
+ ci->func.p = L1->top.p;
ci->u.c.k = NULL;
ci->nresults = 0;
- setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */
- L1->top++;
- ci->top = L1->top + LUA_MINSTACK;
+ setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */
+ L1->top.p++;
+ ci->top.p = L1->top.p + LUA_MINSTACK;
L1->ci = ci;
}
static void freestack (lua_State *L) {
- if (L->stack == NULL)
+ if (L->stack.p == NULL)
return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L);
lua_assert(L->nci == 0);
- luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK); /* free stack */
+ luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */
}
@@ -159026,7 +159112,7 @@ static void f_luaopen (lua_State *L, void *ud) {
*/
static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g;
- L->stack = NULL;
+ L->stack.p = NULL;
L->ci = NULL;
L->nci = 0;
L->twups = L; /* thread has no upvalues */
@@ -159062,20 +159148,16 @@ static void close_state (lua_State *L) {
LUA_API lua_State *lua_newthread (lua_State *L) {
- global_State *g;
+ global_State *g = G(L);
+ GCObject *o;
lua_State *L1;
lua_lock(L);
- g = G(L);
luaC_checkGC(L);
/* create new thread */
- L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
- L1->marked = luaC_white(g);
- L1->tt = LUA_VTHREAD;
- /* link it on list 'allgc' */
- L1->next = g->allgc;
- g->allgc = obj2gco(L1);
+ o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
+ L1 = gco2th(o);
/* anchor it on L stack */
- setthvalue2s(L, L->top, L1);
+ setthvalue2s(L, L->top.p, L1);
api_incr_top(L);
preinit_thread(L1, g);
L1->hookmask = L->hookmask;
@@ -159094,7 +159176,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1);
- luaF_closeupval(L1, L1->stack); /* close all upvalues */
+ luaF_closeupval(L1, L1->stack.p); /* close all upvalues */
lua_assert(L1->openupval == NULL);
luai_userstatefree(L, L1);
freestack(L1);
@@ -159104,32 +159186,41 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
int luaE_resetthread (lua_State *L, int status) {
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
- setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */
- ci->func = L->stack;
+ setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */
+ ci->func.p = L->stack.p;
ci->callstatus = CIST_C;
if (status == LUA_YIELD)
status = LUA_OK;
L->status = LUA_OK; /* so it can run __close metamethods */
status = luaD_closeprotected(L, 1, status);
if (status != LUA_OK) /* errors? */
- luaD_seterrorobj(L, status, L->stack + 1);
+ luaD_seterrorobj(L, status, L->stack.p + 1);
else
- L->top = L->stack + 1;
- ci->top = L->top + LUA_MINSTACK;
- luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
+ L->top.p = L->stack.p + 1;
+ ci->top.p = L->top.p + LUA_MINSTACK;
+ luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0);
return status;
}
-LUA_API int lua_resetthread (lua_State *L) {
+LUA_API int lua_closethread (lua_State *L, lua_State *from) {
int status;
lua_lock(L);
+ L->nCcalls = (from) ? getCcalls(from) : 0;
status = luaE_resetthread(L, L->status);
lua_unlock(L);
return status;
}
+/*
+** Deprecated! Use 'lua_closethread' instead.
+*/
+LUA_API int lua_resetthread (lua_State *L) {
+ return lua_closethread(L, NULL);
+}
+
+
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i;
lua_State *L;
@@ -159204,7 +159295,7 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
** Generate a warning from an error message
*/
void luaE_warnerror (lua_State *L, const char *where) {
- TValue *errobj = s2v(L->top - 1); /* error object */
+ TValue *errobj = s2v(L->top.p - 1); /* error object */
const char *msg = (ttisstring(errobj))
? svalue(errobj)
: "error object is not a string";
@@ -159470,12 +159561,13 @@ void luaC_fix (lua_State *L, GCObject *o) {
/*
-** create a new collectable object (with given type and size) and link
-** it to 'allgc' list.
+** create a new collectable object (with given type, size, and offset)
+** and link it to 'allgc' list.
*/
-GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
+GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
global_State *g = G(L);
- GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));
+ char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
+ GCObject *o = cast(GCObject *, p + offset);
o->marked = luaC_white(g);
o->tt = tt;
o->next = g->allgc;
@@ -159483,6 +159575,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return o;
}
+
+GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
+ return luaC_newobjdt(L, tt, sz, 0);
+}
+
/* }====================================================== */
@@ -159519,7 +159616,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
set2gray(uv); /* open upvalues are kept gray */
else
set2black(uv); /* closed upvalues are visited here */
- markvalue(g, uv->v); /* mark its content */
+ markvalue(g, uv->v.p); /* mark its content */
break;
}
case LUA_VUSERDATA: {
@@ -159594,7 +159691,7 @@ static int remarkupvals (global_State *g) {
work++;
if (!iswhite(uv)) { /* upvalue already visited? */
lua_assert(upisopen(uv) && isgray(uv));
- markvalue(g, uv->v); /* mark its value */
+ markvalue(g, uv->v.p); /* mark its value */
}
}
}
@@ -159838,19 +159935,19 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
*/
static int traversethread (global_State *g, lua_State *th) {
UpVal *uv;
- StkId o = th->stack;
+ StkId o = th->stack.p;
if (isold(th) || g->gcstate == GCSpropagate)
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
if (o == NULL)
return 1; /* stack not completely built yet */
lua_assert(g->gcstate == GCSatomic ||
th->openupval == NULL || isintwups(th));
- for (; o < th->top; o++) /* mark live elements in the stack */
+ for (; o < th->top.p; o++) /* mark live elements in the stack */
markvalue(g, s2v(o));
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
markobject(g, uv); /* open upvalues cannot be collected */
if (g->gcstate == GCSatomic) { /* final traversal? */
- for (; o < th->stack_last + EXTRA_STACK; o++)
+ for (; o < th->stack_last.p + EXTRA_STACK; o++)
setnilvalue(s2v(o)); /* clear dead stack slice */
/* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) {
@@ -160110,7 +160207,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) {
UNUSED(ud);
- luaD_callnoyield(L, L->top - 2, 0);
+ luaD_callnoyield(L, L->top.p - 2, 0);
}
@@ -160127,16 +160224,16 @@ static void GCTM (lua_State *L) {
int oldgcstp = g->gcstp;
g->gcstp |= GCSTPGC; /* avoid GC steps */
L->allowhook = 0; /* stop debug hooks during GC metamethod */
- setobj2s(L, L->top++, tm); /* push finalizer... */
- setobj2s(L, L->top++, &v); /* ... and its argument */
+ setobj2s(L, L->top.p++, tm); /* push finalizer... */
+ setobj2s(L, L->top.p++, &v); /* ... and its argument */
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
- status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
+ status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */
g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc");
- L->top--; /* pops error object */
+ L->top.p--; /* pops error object */
}
}
}
@@ -160259,7 +160356,25 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
** =======================================================
*/
-static void setpause (global_State *g);
+
+/*
+** Set the "time" to wait before starting a new GC cycle; cycle will
+** start when memory use hits the threshold of ('estimate' * pause /
+** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
+** because Lua cannot even start with less than PAUSEADJ bytes).
+*/
+static void setpause (global_State *g) {
+ l_mem threshold, debt;
+ int pause = getgcparam(g->gcpause);
+ l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
+ lua_assert(estimate > 0);
+ threshold = (pause < MAX_LMEM / estimate) /* overflow? */
+ ? estimate * pause /* no overflow */
+ : MAX_LMEM; /* overflow; truncate to maximum */
+ debt = gettotalbytes(g) - threshold;
+ if (debt > 0) debt = 0;
+ luaE_setdebt(g, debt);
+}
/*
@@ -160503,6 +160618,15 @@ static void atomic2gen (lua_State *L, global_State *g) {
}
+/*
+** Set debt for the next minor collection, which will happen when
+** memory grows 'genminormul'%.
+*/
+static void setminordebt (global_State *g) {
+ luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
+}
+
+
/*
** Enter generational mode. Must go until the end of an atomic cycle
** to ensure that all objects are correctly marked and weak tables
@@ -160515,6 +160639,7 @@ static lu_mem entergen (lua_State *L, global_State *g) {
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
numobjs = atomic(L); /* propagates all and then do the atomic stuff */
atomic2gen(L, g);
+ setminordebt(g); /* set debt assuming next cycle will be minor */
return numobjs;
}
@@ -160560,15 +160685,6 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
}
-/*
-** Set debt for the next minor collection, which will happen when
-** memory grows 'genminormul'%.
-*/
-static void setminordebt (global_State *g) {
- luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
-}
-
-
/*
** Does a major collection after last collection was a "bad collection".
**
@@ -160640,8 +160756,8 @@ static void genstep (lua_State *L, global_State *g) {
lu_mem numobjs = fullgen(L, g); /* do a major collection */
if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
/* collected at least half of memory growth since last major
- collection; keep doing minor collections */
- setminordebt(g);
+ collection; keep doing minor collections. */
+ lua_assert(g->lastatomic == 0);
}
else { /* bad collection */
g->lastatomic = numobjs; /* signal that last collection was bad */
@@ -160667,26 +160783,6 @@ static void genstep (lua_State *L, global_State *g) {
*/
-/*
-** Set the "time" to wait before starting a new GC cycle; cycle will
-** start when memory use hits the threshold of ('estimate' * pause /
-** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
-** because Lua cannot even start with less than PAUSEADJ bytes).
-*/
-static void setpause (global_State *g) {
- l_mem threshold, debt;
- int pause = getgcparam(g->gcpause);
- l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
- lua_assert(estimate > 0);
- threshold = (pause < MAX_LMEM / estimate) /* overflow? */
- ? estimate * pause /* no overflow */
- : MAX_LMEM; /* overflow; truncate to maximum */
- debt = gettotalbytes(g) - threshold;
- if (debt > 0) debt = 0;
- luaE_setdebt(g, debt);
-}
-
-
/*
** Enter first sweep phase.
** The call to 'sweeptolive' makes the pointer point to an object
@@ -160894,12 +160990,15 @@ static void incstep (lua_State *L, global_State *g) {
}
/*
-** performs a basic GC step if collector is running
+** Performs a basic GC step if collector is running. (If collector is
+** not running, set a reasonable debt to avoid it being called at
+** every single check.)
*/
void luaC_step (lua_State *L) {
global_State *g = G(L);
- lua_assert(!g->gcemergency);
- if (gcrunning(g)) { /* running? */
+ if (!gcrunning(g)) /* not running? */
+ luaE_setdebt(g, -2000);
+ else {
if(isdecGCmodegen(g))
genstep(L, g);
else
@@ -161077,7 +161176,7 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
** ensuring there is only one copy of each unique string. The table
** here is used as a set: the string enters as the key, while its value
** is irrelevant. We use the string itself as the value only because it
-** is a TValue readly available. Later, the code generation can change
+** is a TValue readily available. Later, the code generation can change
** this value.
*/
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
@@ -161087,12 +161186,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
if (!ttisnil(o)) /* string already present? */
ts = keystrval(nodefromval(o)); /* get saved copy */
else { /* not in use yet */
- TValue *stv = s2v(L->top++); /* reserve stack space for string */
+ TValue *stv = s2v(L->top.p++); /* reserve stack space for string */
setsvalue(L, stv, ts); /* temporarily anchor the string */
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
/* table is not a metatable, so it does not need to invalidate cache */
luaC_checkGC(L);
- L->top--; /* remove string from stack */
+ L->top.p--; /* remove string from stack */
}
return ts;
}
@@ -162881,6 +162980,35 @@ static int constfolding (FuncState *fs, int op, expdesc *e1,
}
+/*
+** Convert a BinOpr to an OpCode (ORDER OPR - ORDER OP)
+*/
+l_sinline OpCode binopr2op (BinOpr opr, BinOpr baser, OpCode base) {
+ lua_assert(baser <= opr &&
+ ((baser == OPR_ADD && opr <= OPR_SHR) ||
+ (baser == OPR_LT && opr <= OPR_LE)));
+ return cast(OpCode, (cast_int(opr) - cast_int(baser)) + cast_int(base));
+}
+
+
+/*
+** Convert a UnOpr to an OpCode (ORDER OPR - ORDER OP)
+*/
+l_sinline OpCode unopr2op (UnOpr opr) {
+ return cast(OpCode, (cast_int(opr) - cast_int(OPR_MINUS)) +
+ cast_int(OP_UNM));
+}
+
+
+/*
+** Convert a BinOpr to a tag method (ORDER OPR - ORDER TM)
+*/
+l_sinline TMS binopr2TM (BinOpr opr) {
+ lua_assert(OPR_ADD <= opr && opr <= OPR_SHR);
+ return cast(TMS, (cast_int(opr) - cast_int(OPR_ADD)) + cast_int(TM_ADD));
+}
+
+
/*
** Emit code for unary expressions that "produce values"
** (everything but 'not').
@@ -162919,12 +163047,15 @@ static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
** Emit code for binary expressions that "produce values" over
** two registers.
*/
-static void codebinexpval (FuncState *fs, OpCode op,
+static void codebinexpval (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) {
- int v2 = luaK_exp2anyreg(fs, e2); /* both operands are in registers */
+ OpCode op = binopr2op(opr, OPR_ADD, OP_ADD);
+ int v2 = luaK_exp2anyreg(fs, e2); /* make sure 'e2' is in a register */
+ /* 'e1' must be already in a register or it is a constant */
+ lua_assert((VNIL <= e1->k && e1->k <= VKSTR) ||
+ e1->k == VNONRELOC || e1->k == VRELOC);
lua_assert(OP_ADD <= op && op <= OP_SHR);
- finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN,
- cast(TMS, (op - OP_ADD) + TM_ADD));
+ finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, binopr2TM(opr));
}
@@ -162940,6 +163071,18 @@ static void codebini (FuncState *fs, OpCode op,
}
+/*
+** Code binary operators with K operand.
+*/
+static void codebinK (FuncState *fs, BinOpr opr,
+ expdesc *e1, expdesc *e2, int flip, int line) {
+ TMS event = binopr2TM(opr);
+ int v2 = e2->u.info; /* K index */
+ OpCode op = binopr2op(opr, OPR_ADD, OP_ADDK);
+ finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
+}
+
+
/* Try to code a binary operator negating its second operand.
** For the metamethod, 2nd operand must keep its original value.
*/
@@ -162967,24 +163110,27 @@ static void swapexps (expdesc *e1, expdesc *e2) {
}
+/*
+** Code binary operators with no constant operand.
+*/
+static void codebinNoK (FuncState *fs, BinOpr opr,
+ expdesc *e1, expdesc *e2, int flip, int line) {
+ if (flip)
+ swapexps(e1, e2); /* back to original order */
+ codebinexpval(fs, opr, e1, e2, line); /* use standard operators */
+}
+
+
/*
** Code arithmetic operators ('+', '-', ...). If second operand is a
** constant in the proper range, use variant opcodes with K operands.
*/
static void codearith (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
- TMS event = cast(TMS, opr + TM_ADD);
- if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */
- int v2 = e2->u.info; /* K index */
- OpCode op = cast(OpCode, opr + OP_ADDK);
- finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
- }
- else { /* 'e2' is neither an immediate nor a K operand */
- OpCode op = cast(OpCode, opr + OP_ADD);
- if (flip)
- swapexps(e1, e2); /* back to original order */
- codebinexpval(fs, op, e1, e2, line); /* use standard operators */
- }
+ if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) /* K operand? */
+ codebinK(fs, opr, e1, e2, flip, line);
+ else /* 'e2' is neither an immediate nor a K operand */
+ codebinNoK(fs, opr, e1, e2, flip, line);
}
@@ -163001,35 +163147,27 @@ static void codecommutative (FuncState *fs, BinOpr op,
flip = 1;
}
if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */
- codebini(fs, cast(OpCode, OP_ADDI), e1, e2, flip, line, TM_ADD);
+ codebini(fs, OP_ADDI, e1, e2, flip, line, TM_ADD);
else
codearith(fs, op, e1, e2, flip, line);
}
/*
-** Code bitwise operations; they are all associative, so the function
+** Code bitwise operations; they are all commutative, so the function
** tries to put an integer constant as the 2nd operand (a K operand).
*/
static void codebitwise (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) {
int flip = 0;
- int v2;
- OpCode op;
- if (e1->k == VKINT && luaK_exp2RK(fs, e1)) {
+ if (e1->k == VKINT) {
swapexps(e1, e2); /* 'e2' will be the constant operand */
flip = 1;
}
- else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) { /* no constants? */
- op = cast(OpCode, opr + OP_ADD);
- codebinexpval(fs, op, e1, e2, line); /* all-register opcodes */
- return;
- }
- v2 = e2->u.info; /* index in K array */
- op = cast(OpCode, opr + OP_ADDK);
- lua_assert(ttisinteger(&fs->f->k[v2]));
- finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK,
- cast(TMS, opr + TM_ADD));
+ if (e2->k == VKINT && luaK_exp2K(fs, e2)) /* K operand? */
+ codebinK(fs, opr, e1, e2, flip, line);
+ else /* no constants */
+ codebinNoK(fs, opr, e1, e2, flip, line);
}
@@ -163037,25 +163175,27 @@ static void codebitwise (FuncState *fs, BinOpr opr,
** Emit code for order comparisons. When using an immediate operand,
** 'isfloat' tells whether the original value was a float.
*/
-static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
+static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
int r1, r2;
int im;
int isfloat = 0;
+ OpCode op;
if (isSCnumber(e2, &im, &isfloat)) {
/* use immediate operand */
r1 = luaK_exp2anyreg(fs, e1);
r2 = im;
- op = cast(OpCode, (op - OP_LT) + OP_LTI);
+ op = binopr2op(opr, OPR_LT, OP_LTI);
}
else if (isSCnumber(e1, &im, &isfloat)) {
/* transform (A < B) to (B > A) and (A <= B) to (B >= A) */
r1 = luaK_exp2anyreg(fs, e2);
r2 = im;
- op = (op == OP_LT) ? OP_GTI : OP_GEI;
+ op = binopr2op(opr, OPR_LT, OP_GTI);
}
else { /* regular case, compare two registers */
r1 = luaK_exp2anyreg(fs, e1);
r2 = luaK_exp2anyreg(fs, e2);
+ op = binopr2op(opr, OPR_LT, OP_LT);
}
freeexps(fs, e1, e2);
e1->u.info = condjump(fs, op, r1, r2, isfloat, 1);
@@ -163081,7 +163221,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
op = OP_EQI;
r2 = im; /* immediate operand */
}
- else if (luaK_exp2RK(fs, e2)) { /* 1st expression is constant? */
+ else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */
op = OP_EQK;
r2 = e2->u.info; /* constant index */
}
@@ -163098,16 +163238,16 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
/*
** Apply prefix operation 'op' to expression 'e'.
*/
-void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
+void luaK_prefix (FuncState *fs, UnOpr opr, expdesc *e, int line) {
static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
luaK_dischargevars(fs, e);
- switch (op) {
+ switch (opr) {
case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
- if (constfolding(fs, op + LUA_OPUNM, e, &ef))
+ if (constfolding(fs, opr + LUA_OPUNM, e, &ef))
break;
/* else */ /* FALLTHROUGH */
case OPR_LEN:
- codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
+ codeunexpval(fs, unopr2op(opr), e, line);
break;
case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0);
@@ -163141,7 +163281,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
case OPR_SHL: case OPR_SHR: {
if (!tonumeral(v, NULL))
luaK_exp2anyreg(fs, v);
- /* else keep numeral, which may be folded with 2nd operand */
+ /* else keep numeral, which may be folded or used as an immediate
+ operand */
break;
}
case OPR_EQ: case OPR_NE: {
@@ -163236,30 +163377,27 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
/* coded as (r1 >> -I) */;
}
else /* regular case (two registers) */
- codebinexpval(fs, OP_SHL, e1, e2, line);
+ codebinexpval(fs, opr, e1, e2, line);
break;
}
case OPR_SHR: {
if (isSCint(e2))
codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */
else /* regular case (two registers) */
- codebinexpval(fs, OP_SHR, e1, e2, line);
+ codebinexpval(fs, opr, e1, e2, line);
break;
}
case OPR_EQ: case OPR_NE: {
codeeq(fs, opr, e1, e2);
break;
}
- case OPR_LT: case OPR_LE: {
- OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
- codeorder(fs, op, e1, e2);
- break;
- }
case OPR_GT: case OPR_GE: {
/* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */
- OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
swapexps(e1, e2);
- codeorder(fs, op, e1, e2);
+ opr = cast(BinOpr, (opr - OPR_GT) + OPR_LT);
+ } /* FALLTHROUGH */
+ case OPR_LT: case OPR_LE: {
+ codeorder(fs, opr, e1, e2);
break;
}
default: lua_assert(0);
@@ -163830,6 +163968,7 @@ static void singlevar (LexState *ls, expdesc *var) {
expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k != VVOID); /* this one must exist */
+ luaK_exp2anyregup(fs, var); /* but could be a constant */
codestring(&key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */
}
@@ -163882,12 +164021,12 @@ static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
/*
** Solves the goto at index 'g' to given 'label' and removes it
-** from the list of pending goto's.
+** from the list of pending gotos.
** If it jumps into the scope of some variable, raises an error.
*/
static void solvegoto (LexState *ls, int g, Labeldesc *label) {
int i;
- Labellist *gl = &ls->dyd->gt; /* list of goto's */
+ Labellist *gl = &ls->dyd->gt; /* list of gotos */
Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */
lua_assert(eqstr(gt->name, label->name));
if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
@@ -163941,7 +164080,7 @@ static int newgotoentry (LexState *ls, TString *name, int line, int pc) {
/*
** Solves forward jumps. Check whether new label 'lb' matches any
** pending gotos in current block and solves them. Return true
-** if any of the goto's need to close upvalues.
+** if any of the gotos need to close upvalues.
*/
static int solvegotos (LexState *ls, Labeldesc *lb) {
Labellist *gl = &ls->dyd->gt;
@@ -163962,7 +164101,7 @@ static int solvegotos (LexState *ls, Labeldesc *lb) {
/*
** Create a new label with the given 'name' at the given 'line'.
** 'last' tells whether label is the last non-op statement in its
-** block. Solves all pending goto's to this new label and adds
+** block. Solves all pending gotos to this new label and adds
** a close instruction if necessary.
** Returns true iff it added a close instruction.
*/
@@ -164035,19 +164174,19 @@ static void leaveblock (FuncState *fs) {
LexState *ls = fs->ls;
int hasclose = 0;
int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
- if (bl->isloop) /* fix pending breaks? */
+ removevars(fs, bl->nactvar); /* remove block locals */
+ lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */
+ if (bl->isloop) /* has to fix pending breaks? */
hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
- if (!hasclose && bl->previous && bl->upval)
+ if (!hasclose && bl->previous && bl->upval) /* still need a 'close'? */
luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
- fs->bl = bl->previous;
- removevars(fs, bl->nactvar);
- lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = stklevel; /* free registers */
ls->dyd->label.n = bl->firstlabel; /* remove local labels */
- if (bl->previous) /* inner block? */
- movegotosout(fs, bl); /* update pending gotos to outer block */
+ fs->bl = bl->previous; /* current block now is previous one */
+ if (bl->previous) /* was it a nested block? */
+ movegotosout(fs, bl); /* update pending gotos to enclosing block */
else {
- if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */
+ if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */
undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
}
}
@@ -165305,10 +165444,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
LexState lexstate;
FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
- setclLvalue2s(L, L->top, cl); /* anchor it (to avoid being collected) */
+ setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */
- sethvalue2s(L, L->top, lexstate.h); /* anchor it */
+ sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
@@ -165322,7 +165461,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
- L->top--; /* remove scanner's table */
+ L->top.p--; /* remove scanner's table */
return cl; /* closure is on the stack, too */
}
@@ -165510,10 +165649,10 @@ static const char *upvalname (const Proto *p, int uv) {
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
- if (clLvalue(s2v(ci->func))->p->is_vararg) {
+ if (clLvalue(s2v(ci->func.p))->p->is_vararg) {
int nextra = ci->u.l.nextraargs;
if (n >= -nextra) { /* 'n' is negative */
- *pos = ci->func - nextra - (n + 1);
+ *pos = ci->func.p - nextra - (n + 1);
return "(vararg)"; /* generic name for any vararg */
}
}
@@ -165522,7 +165661,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
- StkId base = ci->func + 1;
+ StkId base = ci->func.p + 1;
const char *name = NULL;
if (isLua(ci)) {
if (n < 0) /* access to vararg values? */
@@ -165531,7 +165670,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
}
if (name == NULL) { /* no 'standard' name? */
- StkId limit = (ci == L->ci) ? L->top : ci->next->func;
+ StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
/* generic name for any valid slot */
name = isLua(ci) ? "(temporary)" : "(C temporary)";
@@ -165549,16 +165688,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name;
lua_lock(L);
if (ar == NULL) { /* information about non-active function? */
- if (!isLfunction(s2v(L->top - 1))) /* not a Lua function? */
+ if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
name = NULL;
else /* consider live variables at function start (parameters) */
- name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0);
+ name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
}
else { /* active function; get information through 'ar' */
StkId pos = NULL; /* to avoid warnings */
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
- setobjs2s(L, L->top, pos);
+ setobjs2s(L, L->top.p, pos);
api_incr_top(L);
}
}
@@ -165573,8 +165712,8 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
lua_lock(L);
name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) {
- setobjs2s(L, pos, L->top - 1);
- L->top--; /* pop value */
+ setobjs2s(L, pos, L->top.p - 1);
+ L->top.p--; /* pop value */
}
lua_unlock(L);
return name;
@@ -165617,7 +165756,7 @@ static int nextline (const Proto *p, int currentline, int pc) {
static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) {
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
api_incr_top(L);
}
else {
@@ -165626,7 +165765,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
const Proto *p = f->l.p;
int currentline = p->linedefined;
Table *t = luaH_new(L); /* new table to store active lines */
- sethvalue2s(L, L->top, t); /* push it on stack */
+ sethvalue2s(L, L->top.p, t); /* push it on stack */
api_incr_top(L);
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
if (!p->is_vararg) /* regular function? */
@@ -165716,20 +165855,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
lua_lock(L);
if (*what == '>') {
ci = NULL;
- func = s2v(L->top - 1);
+ func = s2v(L->top.p - 1);
api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */
- L->top--; /* pop function */
+ L->top.p--; /* pop function */
}
else {
ci = ar->i_ci;
- func = s2v(ci->func);
+ func = s2v(ci->func.p);
lua_assert(ttisfunction(func));
}
cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) {
- setobj2s(L, L->top, func);
+ setobj2s(L, L->top.p, func);
api_incr_top(L);
}
if (strchr(what, 'L'))
@@ -165984,18 +166123,19 @@ static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
/*
-** Check whether pointer 'o' points to some value in the stack
-** frame of the current function. Because 'o' may not point to a
-** value in this stack, we cannot compare it with the region
-** boundaries (undefined behaviour in ISO C).
+** Check whether pointer 'o' points to some value in the stack frame of
+** the current function and, if so, returns its index. Because 'o' may
+** not point to a value in this stack, we cannot compare it with the
+** region boundaries (undefined behavior in ISO C).
*/
-static int isinstack (CallInfo *ci, const TValue *o) {
- StkId pos;
- for (pos = ci->func + 1; pos < ci->top; pos++) {
- if (o == s2v(pos))
- return 1;
+static int instack (CallInfo *ci, const TValue *o) {
+ int pos;
+ StkId base = ci->func.p + 1;
+ for (pos = 0; base + pos < ci->top.p; pos++) {
+ if (o == s2v(base + pos))
+ return pos;
}
- return 0; /* not found */
+ return -1; /* not found */
}
@@ -166009,7 +166149,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
LClosure *c = ci_func(ci);
int i;
for (i = 0; i < c->nupvalues; i++) {
- if (c->upvals[i]->v == o) {
+ if (c->upvals[i]->v.p == o) {
*name = upvalname(c->p, i);
return "upvalue";
}
@@ -166036,9 +166176,11 @@ static const char *varinfo (lua_State *L, const TValue *o) {
const char *kind = NULL;
if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
- if (!kind && isinstack(ci, o)) /* no? try a register */
- kind = getobjname(ci_func(ci)->p, currentpc(ci),
- cast_int(cast(StkId, o) - (ci->func + 1)), &name);
+ if (!kind) { /* not an upvalue? */
+ int reg = instack(ci, o); /* try a register */
+ if (reg >= 0) /* is 'o' a register? */
+ kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
+ }
}
return formatvarinfo(L, kind, name);
}
@@ -166135,10 +166277,10 @@ l_noret luaG_errormsg (lua_State *L) {
if (L->errfunc != 0) { /* is there an error handling function? */
StkId errfunc = restorestack(L, L->errfunc);
lua_assert(ttisfunction(s2v(errfunc)));
- setobjs2s(L, L->top, L->top - 1); /* move argument */
- setobjs2s(L, L->top - 1, errfunc); /* push function */
- L->top++; /* assume EXTRA_STACK */
- luaD_callnoyield(L, L->top - 2, 1); /* call it */
+ setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
+ setobjs2s(L, L->top.p - 1, errfunc); /* push function */
+ L->top.p++; /* assume EXTRA_STACK */
+ luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
}
luaD_throw(L, LUA_ERRRUN);
}
@@ -166152,8 +166294,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
va_start(argp, fmt);
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp);
- if (isLua(ci)) /* if Lua function, add source:line information */
+ if (isLua(ci)) { /* if Lua function, add source:line information */
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
+ setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
+ L->top.p--;
+ }
luaG_errormsg(L);
}
@@ -166170,7 +166315,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
if (p->lineinfo == NULL) /* no debug information? */
return 0;
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
- int delta = 0; /* line diference */
+ int delta = 0; /* line difference */
int pc = oldpc;
for (;;) {
int lineinfo = p->lineinfo[++pc];
@@ -166197,7 +166342,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
** at most causes an extra call to a line hook.)
** This function is not "Protected" when called, so it should correct
-** 'L->top' before calling anything that can run the GC.
+** 'L->top.p' before calling anything that can run the GC.
*/
int luaG_traceexec (lua_State *L, const Instruction *pc) {
CallInfo *ci = L->ci;
@@ -166220,7 +166365,7 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
return 1; /* do not call hook again (VM yielded, so it did not move) */
}
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
- L->top = ci->top; /* correct top */
+ L->top.p = ci->top.p; /* correct top */
if (counthook)
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
if (mask & LUA_MASKLINE) {
@@ -166296,8 +166441,8 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
for (i = 0; i < cl->nupvalues; i++) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
- uv->v = &uv->u.value; /* make it closed */
- setnilvalue(uv->v);
+ uv->v.p = &uv->u.value; /* make it closed */
+ setnilvalue(uv->v.p);
cl->upvals[i] = uv;
luaC_objbarrier(L, cl, uv);
}
@@ -166308,12 +166453,11 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
** Create a new upvalue at the given level, and link it to the list of
** open upvalues of 'L' after entry 'prev'.
**/
-static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) {
+static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o);
UpVal *next = *prev;
- uv->v = s2v(level); /* current value lives in the stack */
- uv->tbc = tbc;
+ uv->v.p = s2v(level); /* current value lives in the stack */
uv->u.open.next = next; /* link it to list of open upvalues */
uv->u.open.previous = prev;
if (next)
@@ -166342,7 +166486,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
pp = &p->u.open.next;
}
/* not found: create a new upvalue after 'pp' */
- return newupval(L, 0, level, pp);
+ return newupval(L, level, pp);
}
@@ -166352,12 +166496,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
** (This function assumes EXTRA_STACK.)
*/
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
- StkId top = L->top;
+ StkId top = L->top.p;
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
setobj2s(L, top, tm); /* will call metamethod... */
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
- L->top = top + 3; /* add function and arguments */
+ L->top.p = top + 3; /* add function and arguments */
if (yy)
luaD_call(L, top, 0);
else
@@ -166372,7 +166516,7 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
static void checkclosemth (lua_State *L, StkId level) {
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
if (ttisnil(tm)) { /* no metamethod? */
- int idx = cast_int(level - L->ci->func); /* variable index */
+ int idx = cast_int(level - L->ci->func.p); /* variable index */
const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
if (vname == NULL) vname = "?";
luaG_runerror(L, "variable '%s' got a non-closable value", vname);
@@ -166406,23 +166550,23 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
** is used.)
*/
#define MAXDELTA \
- ((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
+ ((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1)
/*
** Insert a variable in the list of to-be-closed variables.
*/
void luaF_newtbcupval (lua_State *L, StkId level) {
- lua_assert(level > L->tbclist);
+ lua_assert(level > L->tbclist.p);
if (l_isfalse(s2v(level)))
return; /* false doesn't need to be closed */
checkclosemth(L, level); /* value must have a close method */
- while (cast_uint(level - L->tbclist) > MAXDELTA) {
- L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */
- L->tbclist->tbclist.delta = 0;
+ while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
+ L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */
+ L->tbclist.p->tbclist.delta = 0;
}
- level->tbclist.delta = cast(unsigned short, level - L->tbclist);
- L->tbclist = level;
+ level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
+ L->tbclist.p = level;
}
@@ -166442,10 +166586,10 @@ void luaF_closeupval (lua_State *L, StkId level) {
StkId upl; /* stack index pointed by 'uv' */
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
TValue *slot = &uv->u.value; /* new position for value */
- lua_assert(uplevel(uv) < L->top);
+ lua_assert(uplevel(uv) < L->top.p);
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
- setobj(L, slot, uv->v); /* move value to upvalue slot */
- uv->v = slot; /* now current value lives here */
+ setobj(L, slot, uv->v.p); /* move value to upvalue slot */
+ uv->v.p = slot; /* now current value lives here */
if (!iswhite(uv)) { /* neither white nor dead? */
nw2black(uv); /* closed upvalues cannot be gray */
luaC_barrier(L, uv, slot);
@@ -166455,31 +166599,32 @@ void luaF_closeupval (lua_State *L, StkId level) {
/*
-** Remove firt element from the tbclist plus its dummy nodes.
+** Remove first element from the tbclist plus its dummy nodes.
*/
static void poptbclist (lua_State *L) {
- StkId tbc = L->tbclist;
+ StkId tbc = L->tbclist.p;
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
tbc -= tbc->tbclist.delta;
- while (tbc > L->stack && tbc->tbclist.delta == 0)
+ while (tbc > L->stack.p && tbc->tbclist.delta == 0)
tbc -= MAXDELTA; /* remove dummy nodes */
- L->tbclist = tbc;
+ L->tbclist.p = tbc;
}
/*
** Close all upvalues and to-be-closed variables up to the given stack
-** level.
+** level. Return restored 'level'.
*/
-void luaF_close (lua_State *L, StkId level, int status, int yy) {
+StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
ptrdiff_t levelrel = savestack(L, level);
luaF_closeupval(L, level); /* first, close the upvalues */
- while (L->tbclist >= level) { /* traverse tbc's down to that level */
- StkId tbc = L->tbclist; /* get variable index */
+ while (L->tbclist.p >= level) { /* traverse tbc's down to that level */
+ StkId tbc = L->tbclist.p; /* get variable index */
poptbclist(L); /* remove it from list */
prepcallclosemth(L, tbc, status, yy); /* close variable */
level = restorestack(L, levelrel);
}
+ return level;
}
@@ -166602,7 +166747,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
case LUA_OPBOR: return intop(|, v1, v2);
case LUA_OPBXOR: return intop(^, v1, v2);
case LUA_OPSHL: return luaV_shiftl(v1, v2);
- case LUA_OPSHR: return luaV_shiftl(v1, -v2);
+ case LUA_OPSHR: return luaV_shiftr(v1, v2);
case LUA_OPUNM: return intop(-, 0, v1);
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
default: lua_assert(0); return 0;
@@ -166926,29 +167071,39 @@ void luaO_tostring (lua_State *L, TValue *obj) {
** ===================================================================
*/
-/* size for buffer space used by 'luaO_pushvfstring' */
-#define BUFVFS 200
+/*
+** Size for buffer space used by 'luaO_pushvfstring'. It should be
+** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
+** so that 'luaG_addinfo' can work directly on the buffer.
+*/
+#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95)
/* buffer used by 'luaO_pushvfstring' */
typedef struct BuffFS {
lua_State *L;
- int pushed; /* number of string pieces already on the stack */
+ int pushed; /* true if there is a part of the result on the stack */
int blen; /* length of partial string in 'space' */
char space[BUFVFS]; /* holds last part of the result */
} BuffFS;
/*
-** Push given string to the stack, as part of the buffer, and
-** join the partial strings in the stack into one.
+** Push given string to the stack, as part of the result, and
+** join it to previous partial result if there is one.
+** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
+** This call cannot invoke metamethods, as both operands must be
+** strings. It can, however, raise an error if the result is too
+** long. In that case, 'luaV_concat' frees the extra slot before
+** raising the error.
*/
-static void pushstr (BuffFS *buff, const char *str, size_t l) {
+static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
lua_State *L = buff->L;
- setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
- L->top++; /* may use one extra slot */
- buff->pushed++;
- luaV_concat(L, buff->pushed); /* join partial results into one */
- buff->pushed = 1;
+ setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr));
+ L->top.p++; /* may use one slot from EXTRA_STACK */
+ if (!buff->pushed) /* no previous string on the stack? */
+ buff->pushed = 1; /* now there is one */
+ else /* join previous string with new one */
+ luaV_concat(L, 2);
}
@@ -166994,7 +167149,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
/*
-** Add a number to the buffer.
+** Add a numeral to the buffer.
*/
static void addnum2buff (BuffFS *buff, TValue *num) {
char *numbuff = getbuff(buff, MAXNUMBER2STR);
@@ -167072,7 +167227,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
clearbuff(&buff); /* empty buffer into the stack */
lua_assert(buff.pushed == 1);
- return svalue(s2v(L->top - 1));
+ return svalue(s2v(L->top.p - 1));
}
@@ -167234,12 +167389,12 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) {
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, const TValue *p3) {
- StkId func = L->top;
+ StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
setobj2s(L, func + 3, p3); /* 3rd argument */
- L->top = func + 4;
+ L->top.p = func + 4;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 0);
@@ -167251,18 +167406,18 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, StkId res) {
ptrdiff_t result = savestack(L, res);
- StkId func = L->top;
+ StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
- L->top += 3;
+ L->top.p += 3;
/* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci))
luaD_call(L, func, 1);
else
luaD_callnoyield(L, func, 1);
res = restorestack(L, result);
- setobjs2s(L, res, --L->top); /* move result to its place */
+ setobjs2s(L, res, --L->top.p); /* move result to its place */
}
@@ -167297,7 +167452,7 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
void luaT_tryconcatTM (lua_State *L) {
- StkId top = L->top;
+ StkId top = L->top.p;
if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
TM_CONCAT)))
luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
@@ -167332,15 +167487,15 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
*/
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
TMS event) {
- if (callbinTM(L, p1, p2, L->top, event)) /* try original event */
- return !l_isfalse(s2v(L->top));
+ if (callbinTM(L, p1, p2, L->top.p, event)) /* try original event */
+ return !l_isfalse(s2v(L->top.p));
#if defined(LUA_COMPAT_LT_LE)
else if (event == TM_LE) {
/* try '!(p2 < p1)' for '(p1 <= p2)' */
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
- if (callbinTM(L, p2, p1, L->top, TM_LT)) {
+ if (callbinTM(L, p2, p1, L->top.p, TM_LT)) {
L->ci->callstatus ^= CIST_LEQ; /* clear mark */
- return l_isfalse(s2v(L->top));
+ return l_isfalse(s2v(L->top.p));
}
/* else error will remove this 'ci'; no need to clear mark */
}
@@ -167370,20 +167525,20 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
const Proto *p) {
int i;
- int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */
+ int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */
int nextra = actual - nfixparams; /* number of extra arguments */
ci->u.l.nextraargs = nextra;
luaD_checkstack(L, p->maxstacksize + 1);
/* copy function to the top of the stack */
- setobjs2s(L, L->top++, ci->func);
+ setobjs2s(L, L->top.p++, ci->func.p);
/* move fixed parameters to the top of the stack */
for (i = 1; i <= nfixparams; i++) {
- setobjs2s(L, L->top++, ci->func + i);
- setnilvalue(s2v(ci->func + i)); /* erase original parameter (for GC) */
+ setobjs2s(L, L->top.p++, ci->func.p + i);
+ setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
}
- ci->func += actual + 1;
- ci->top += actual + 1;
- lua_assert(L->top <= ci->top && ci->top <= L->stack_last);
+ ci->func.p += actual + 1;
+ ci->top.p += actual + 1;
+ lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
}
@@ -167393,10 +167548,10 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
if (wanted < 0) {
wanted = nextra; /* get all extra arguments available */
checkstackGCp(L, nextra, where); /* ensure stack space */
- L->top = where + nextra; /* next instruction will need top */
+ L->top.p = where + nextra; /* next instruction will need top */
}
for (i = 0; i < wanted && i < nextra; i++)
- setobjs2s(L, where + i, ci->func - nextra + i);
+ setobjs2s(L, where + i, ci->func.p - nextra + i);
for (; i < wanted; i++) /* complete required results with nil */
setnilvalue(s2v(where + i));
}
@@ -167783,7 +167938,7 @@ static const TValue absentkey = {ABSTKEYCONSTANT};
*/
static Node *hashint (const Table *t, lua_Integer i) {
lua_Unsigned ui = l_castS2U(i);
- if (ui <= (unsigned int)INT_MAX)
+ if (ui <= cast_uint(INT_MAX))
return hashmod(t, cast_int(ui));
else
return hashmod(t, ui);
@@ -167933,9 +168088,11 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
size |= (size >> 2);
size |= (size >> 4);
size |= (size >> 8);
+#if (UINT_MAX >> 14) > 3 /* unsigned int has more than 16 bits */
size |= (size >> 16);
#if (UINT_MAX >> 30) > 3
size |= (size >> 32); /* unsigned int has more than 32 bits */
+#endif
#endif
size++;
lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
@@ -168164,7 +168321,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
luaG_runerror(L, "table overflow");
size = twoto(lsize);
t->node = luaM_newvector(L, size, Node);
- for (i = 0; i < (int)size; i++) {
+ for (i = 0; i < cast_int(size); i++) {
Node *n = gnode(t, i);
gnext(n) = 0;
setnilkey(n);
@@ -168651,8 +168808,6 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainpositionTV(t, key);
}
-int luaH_isdummy (const Table *t) { return isdummy(t); }
-
#endif
/*
** $Id: ldo.c $
@@ -168760,11 +168915,11 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
}
default: {
lua_assert(errorstatus(errcode)); /* real error */
- setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
+ setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */
break;
}
}
- L->top = oldtop + 1;
+ L->top.p = oldtop + 1;
}
@@ -168777,7 +168932,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
global_State *g = G(L);
errcode = luaE_resetthread(L, errcode); /* close all upvalues */
if (g->mainthread->errorJmp) { /* main thread has a handler? */
- setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
+ setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */
luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
}
else { /* no handler at all; abort */
@@ -168813,16 +168968,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
** Stack reallocation
** ===================================================================
*/
-static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
+
+
+/*
+** Change all pointers to the stack into offsets.
+*/
+static void relstack (lua_State *L) {
CallInfo *ci;
UpVal *up;
- L->top = (L->top - oldstack) + newstack;
- L->tbclist = (L->tbclist - oldstack) + newstack;
+ L->top.offset = savestack(L, L->top.p);
+ L->tbclist.offset = savestack(L, L->tbclist.p);
for (up = L->openupval; up != NULL; up = up->u.open.next)
- up->v = s2v((uplevel(up) - oldstack) + newstack);
+ up->v.offset = savestack(L, uplevel(up));
for (ci = L->ci; ci != NULL; ci = ci->previous) {
- ci->top = (ci->top - oldstack) + newstack;
- ci->func = (ci->func - oldstack) + newstack;
+ ci->top.offset = savestack(L, ci->top.p);
+ ci->func.offset = savestack(L, ci->func.p);
+ }
+}
+
+
+/*
+** Change back all offsets into pointers.
+*/
+static void correctstack (lua_State *L) {
+ CallInfo *ci;
+ UpVal *up;
+ L->top.p = restorestack(L, L->top.offset);
+ L->tbclist.p = restorestack(L, L->tbclist.offset);
+ for (up = L->openupval; up != NULL; up = up->u.open.next)
+ up->v.p = s2v(restorestack(L, up->v.offset));
+ for (ci = L->ci; ci != NULL; ci = ci->previous) {
+ ci->top.p = restorestack(L, ci->top.offset);
+ ci->func.p = restorestack(L, ci->func.offset);
if (isLua(ci))
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
}
@@ -168832,44 +169009,45 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/* some space for error handling */
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
-
/*
-** Reallocate the stack to a new size, correcting all pointers into
-** it. (There are pointers to a stack from its upvalues, from its list
-** of call infos, plus a few individual pointers.) The reallocation is
-** done in two steps (allocation + free) because the correction must be
-** done while both addresses (the old stack and the new one) are valid.
-** (In ISO C, any pointer use after the pointer has been deallocated is
-** undefined behavior.)
+** Reallocate the stack to a new size, correcting all pointers into it.
+** In ISO C, any pointer use after the pointer has been deallocated is
+** undefined behavior. So, before the reallocation, all pointers are
+** changed to offsets, and after the reallocation they are changed back
+** to pointers. As during the reallocation the pointers are invalid, the
+** reallocation cannot run emergency collections.
+**
** In case of allocation error, raise an error or return false according
** to 'raiseerror'.
*/
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
int oldsize = stacksize(L);
int i;
- StkId newstack = luaM_reallocvector(L, NULL, 0,
- newsize + EXTRA_STACK, StackValue);
+ StkId newstack;
+ int oldgcstop = G(L)->gcstopem;
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
+ relstack(L); /* change pointers to offsets */
+ G(L)->gcstopem = 1; /* stop emergency collection */
+ newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
+ newsize + EXTRA_STACK, StackValue);
+ G(L)->gcstopem = oldgcstop; /* restore emergency collection */
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
+ correctstack(L); /* change offsets back to pointers */
if (raiseerror)
luaM_error(L);
else return 0; /* do not raise an error */
}
- /* number of elements to be copied to the new stack */
- i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK;
- memcpy(newstack, L->stack, i * sizeof(StackValue));
- for (; i < newsize + EXTRA_STACK; i++)
+ L->stack.p = newstack;
+ correctstack(L); /* change offsets back to pointers */
+ L->stack_last.p = L->stack.p + newsize;
+ for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
setnilvalue(s2v(newstack + i)); /* erase new segment */
- correctstack(L, L->stack, newstack);
- luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
- L->stack = newstack;
- L->stack_last = L->stack + newsize;
return 1;
}
/*
-** Try to grow the stack by at least 'n' elements. when 'raiseerror'
+** Try to grow the stack by at least 'n' elements. When 'raiseerror'
** is true, raises any error; otherwise, return 0 in case of errors.
*/
int luaD_growstack (lua_State *L, int n, int raiseerror) {
@@ -168883,35 +169061,38 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
luaD_throw(L, LUA_ERRERR); /* error inside message handler */
return 0; /* if not 'raiseerror', just signal it */
}
- else {
+ else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */
int newsize = 2 * size; /* tentative new size */
- int needed = cast_int(L->top - L->stack) + n;
+ int needed = cast_int(L->top.p - L->stack.p) + n;
if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */
newsize = LUAI_MAXSTACK;
if (newsize < needed) /* but must respect what was asked for */
newsize = needed;
if (l_likely(newsize <= LUAI_MAXSTACK))
return luaD_reallocstack(L, newsize, raiseerror);
- else { /* stack overflow */
- /* add extra size to be able to handle the error message */
- luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
- if (raiseerror)
- luaG_runerror(L, "stack overflow");
- return 0;
- }
}
+ /* else stack overflow */
+ /* add extra size to be able to handle the error message */
+ luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
+ if (raiseerror)
+ luaG_runerror(L, "stack overflow");
+ return 0;
}
+/*
+** Compute how much of the stack is being used, by computing the
+** maximum top of all call frames in the stack and the current top.
+*/
static int stackinuse (lua_State *L) {
CallInfo *ci;
int res;
- StkId lim = L->top;
+ StkId lim = L->top.p;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
- if (lim < ci->top) lim = ci->top;
+ if (lim < ci->top.p) lim = ci->top.p;
}
- lua_assert(lim <= L->stack_last);
- res = cast_int(lim - L->stack) + 1; /* part of stack in use */
+ lua_assert(lim <= L->stack_last.p + EXTRA_STACK);
+ res = cast_int(lim - L->stack.p) + 1; /* part of stack in use */
if (res < LUA_MINSTACK)
res = LUA_MINSTACK; /* ensure a minimum size */
return res;
@@ -168929,17 +169110,13 @@ static int stackinuse (lua_State *L) {
*/
void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
- int nsize = inuse * 2; /* proposed new size */
- int max = inuse * 3; /* maximum "reasonable" size */
- if (max > LUAI_MAXSTACK) {
- max = LUAI_MAXSTACK; /* respect stack limit */
- if (nsize > LUAI_MAXSTACK)
- nsize = LUAI_MAXSTACK;
- }
+ int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3;
/* if thread is currently not handling a stack overflow and its
size is larger than maximum "reasonable" size, shrink it */
- if (inuse <= LUAI_MAXSTACK && stacksize(L) > max)
+ if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) {
+ int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2;
luaD_reallocstack(L, nsize, 0); /* ok if that fails */
+ }
else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */
luaE_shrinkCI(L); /* shrink CI list */
@@ -168948,7 +169125,7 @@ void luaD_shrinkstack (lua_State *L) {
void luaD_inctop (lua_State *L) {
luaD_checkstack(L, 1);
- L->top++;
+ L->top.p++;
}
/* }================================================================== */
@@ -168965,8 +169142,8 @@ void luaD_hook (lua_State *L, int event, int line,
if (hook && L->allowhook) { /* make sure there is a hook */
int mask = CIST_HOOKED;
CallInfo *ci = L->ci;
- ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */
- ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */
+ ptrdiff_t top = savestack(L, L->top.p); /* preserve original 'top' */
+ ptrdiff_t ci_top = savestack(L, ci->top.p); /* idem for 'ci->top' */
lua_Debug ar;
ar.event = event;
ar.currentline = line;
@@ -168976,11 +169153,11 @@ void luaD_hook (lua_State *L, int event, int line,
ci->u2.transferinfo.ftransfer = ftransfer;
ci->u2.transferinfo.ntransfer = ntransfer;
}
- if (isLua(ci) && L->top < ci->top)
- L->top = ci->top; /* protect entire activation register */
+ if (isLua(ci) && L->top.p < ci->top.p)
+ L->top.p = ci->top.p; /* protect entire activation register */
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
- if (ci->top < L->top + LUA_MINSTACK)
- ci->top = L->top + LUA_MINSTACK;
+ if (ci->top.p < L->top.p + LUA_MINSTACK)
+ ci->top.p = L->top.p + LUA_MINSTACK;
L->allowhook = 0; /* cannot call hooks inside a hook */
ci->callstatus |= mask;
lua_unlock(L);
@@ -168988,8 +169165,8 @@ void luaD_hook (lua_State *L, int event, int line,
lua_lock(L);
lua_assert(!L->allowhook);
L->allowhook = 1;
- ci->top = restorestack(L, ci_top);
- L->top = restorestack(L, top);
+ ci->top.p = restorestack(L, ci_top);
+ L->top.p = restorestack(L, top);
ci->callstatus &= ~mask;
}
}
@@ -169020,7 +169197,7 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
*/
static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
- StkId firstres = L->top - nres; /* index of first result */
+ StkId firstres = L->top.p - nres; /* index of first result */
int delta = 0; /* correction for vararg functions */
int ftransfer;
if (isLua(ci)) {
@@ -169028,10 +169205,10 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (p->is_vararg)
delta = ci->u.l.nextraargs + p->numparams + 1;
}
- ci->func += delta; /* if vararg, back to virtual 'func' */
- ftransfer = cast(unsigned short, firstres - ci->func);
+ ci->func.p += delta; /* if vararg, back to virtual 'func' */
+ ftransfer = cast(unsigned short, firstres - ci->func.p);
luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */
- ci->func -= delta;
+ ci->func.p -= delta;
}
if (isLua(ci = ci->previous))
L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */
@@ -169050,9 +169227,9 @@ StkId luaD_tryfuncTM (lua_State *L, StkId func) {
tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */
if (l_unlikely(ttisnil(tm)))
luaG_callerror(L, s2v(func)); /* nothing to call */
- for (p = L->top; p > func; p--) /* open space for metamethod */
+ for (p = L->top.p; p > func; p--) /* open space for metamethod */
setobjs2s(L, p, p-1);
- L->top++; /* stack space pre-allocated by the caller */
+ L->top.p++; /* stack space pre-allocated by the caller */
setobj2s(L, func, tm); /* metamethod is the new function to be called */
return func;
}
@@ -169069,28 +169246,29 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
int i;
switch (wanted) { /* handle typical cases separately */
case 0: /* no values needed */
- L->top = res;
+ L->top.p = res;
return;
case 1: /* one value needed */
if (nres == 0) /* no results? */
setnilvalue(s2v(res)); /* adjust with nil */
else /* at least one result */
- setobjs2s(L, res, L->top - nres); /* move it to proper place */
- L->top = res + 1;
+ setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
+ L->top.p = res + 1;
return;
case LUA_MULTRET:
wanted = nres; /* we want all results */
break;
default: /* two/more results and/or to-be-closed variables */
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
- ptrdiff_t savedres = savestack(L, res);
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
L->ci->u2.nres = nres;
- luaF_close(L, res, CLOSEKTOP, 1);
+ res = luaF_close(L, res, CLOSEKTOP, 1);
L->ci->callstatus &= ~CIST_CLSRET;
- if (L->hookmask) /* if needed, call hook after '__close's */
+ if (L->hookmask) { /* if needed, call hook after '__close's */
+ ptrdiff_t savedres = savestack(L, res);
rethook(L, L->ci, nres);
- res = restorestack(L, savedres); /* close and hook can move stack */
+ res = restorestack(L, savedres); /* hook can move stack */
+ }
wanted = decodeNresults(wanted);
if (wanted == LUA_MULTRET)
wanted = nres; /* we want all results */
@@ -169098,14 +169276,14 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
break;
}
/* generic case */
- firstresult = L->top - nres; /* index of first result */
+ firstresult = L->top.p - nres; /* index of first result */
if (nres > wanted) /* extra results? */
nres = wanted; /* don't need them */
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstresult + i);
for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(s2v(res + i));
- L->top = res + wanted; /* top points after the last result */
+ L->top.p = res + wanted; /* top points after the last result */
}
@@ -169120,7 +169298,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
rethook(L, ci, nres);
/* move results to proper place */
- moveresults(L, ci->func, nres, wanted);
+ moveresults(L, ci->func.p, nres, wanted);
/* function cannot be in any of these cases when returning */
lua_assert(!(ci->callstatus &
(CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
@@ -169135,10 +169313,10 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
int mask, StkId top) {
CallInfo *ci = L->ci = next_ci(L); /* new frame */
- ci->func = func;
+ ci->func.p = func;
ci->nresults = nret;
ci->callstatus = mask;
- ci->top = top;
+ ci->top.p = top;
return ci;
}
@@ -169152,10 +169330,10 @@ l_sinline int precallC (lua_State *L, StkId func, int nresults,
CallInfo *ci;
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
- L->top + LUA_MINSTACK);
- lua_assert(ci->top <= L->stack_last);
+ L->top.p + LUA_MINSTACK);
+ lua_assert(ci->top.p <= L->stack_last.p);
if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
- int narg = cast_int(L->top - func) - 1;
+ int narg = cast_int(L->top.p - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
}
lua_unlock(L);
@@ -169187,17 +169365,17 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int nfixparams = p->numparams;
int i;
checkstackGCp(L, fsize - delta, func);
- ci->func -= delta; /* restore 'func' (if vararg) */
+ ci->func.p -= delta; /* restore 'func' (if vararg) */
for (i = 0; i < narg1; i++) /* move down function and arguments */
- setobjs2s(L, ci->func + i, func + i);
- func = ci->func; /* moved-down function */
+ setobjs2s(L, ci->func.p + i, func + i);
+ func = ci->func.p; /* moved-down function */
for (; narg1 <= nfixparams; narg1++)
setnilvalue(s2v(func + narg1)); /* complete missing arguments */
- ci->top = func + 1 + fsize; /* top for new function */
- lua_assert(ci->top <= L->stack_last);
+ ci->top.p = func + 1 + fsize; /* top for new function */
+ lua_assert(ci->top.p <= L->stack_last.p);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus |= CIST_TAIL;
- L->top = func + narg1; /* set top */
+ L->top.p = func + narg1; /* set top */
return -1;
}
default: { /* not a function */
@@ -169230,15 +169408,15 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
case LUA_VLCL: { /* Lua function */
CallInfo *ci;
Proto *p = clLvalue(s2v(func))->p;
- int narg = cast_int(L->top - func) - 1; /* number of real arguments */
+ int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */
int nfixparams = p->numparams;
int fsize = p->maxstacksize; /* frame size */
checkstackGCp(L, fsize, func);
L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
ci->u.l.savedpc = p->code; /* starting point */
for (; narg < nfixparams; narg++)
- setnilvalue(s2v(L->top++)); /* complete missing arguments */
- lua_assert(ci->top <= L->stack_last);
+ setnilvalue(s2v(L->top.p++)); /* complete missing arguments */
+ lua_assert(ci->top.p <= L->stack_last.p);
return ci;
}
default: { /* not a function */
@@ -169254,12 +169432,17 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
** Call a function (C or Lua) through C. 'inc' can be 1 (increment
** number of recursive invocations in the C stack) or nyci (the same
** plus increment number of non-yieldable calls).
+** This function can be called with some use of EXTRA_STACK, so it should
+** check the stack before doing anything else. 'luaD_precall' already
+** does that.
*/
-l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) {
+l_sinline void ccall (lua_State *L, StkId func, int nResults, l_uint32 inc) {
CallInfo *ci;
L->nCcalls += inc;
- if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
+ if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
+ checkstackp(L, 0, func); /* free any use of EXTRA_STACK */
luaE_checkcstack(L);
+ }
if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */
ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */
luaV_execute(L, ci); /* call it */
@@ -169307,8 +169490,7 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
else { /* error */
StkId func = restorestack(L, ci->u2.funcidx);
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
- luaF_close(L, func, status, 1); /* can yield or raise an error */
- func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
+ func = luaF_close(L, func, status, 1); /* can yield or raise an error */
luaD_seterrorobj(L, status, func);
luaD_shrinkstack(L); /* restore stack size in case of overflow */
setcistrecst(ci, LUA_OK); /* clear original status */
@@ -169396,8 +169578,8 @@ static CallInfo *findpcall (lua_State *L) {
** coroutine error handler and should not kill the coroutine.)
*/
static int resume_error (lua_State *L, const char *msg, int narg) {
- L->top -= narg; /* remove args from the stack */
- setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
+ L->top.p -= narg; /* remove args from the stack */
+ setsvalue2s(L, L->top.p, luaS_new(L, msg)); /* push error message */
api_incr_top(L);
lua_unlock(L);
return LUA_ERRRUN;
@@ -169413,7 +169595,7 @@ static int resume_error (lua_State *L, const char *msg, int narg) {
*/
static void resume (lua_State *L, void *ud) {
int n = *(cast(int*, ud)); /* number of arguments */
- StkId firstArg = L->top - n; /* first argument */
+ StkId firstArg = L->top.p - n; /* first argument */
CallInfo *ci = L->ci;
if (L->status == LUA_OK) /* starting a coroutine? */
ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */
@@ -169421,7 +169603,7 @@ static void resume (lua_State *L, void *ud) {
lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */
if (isLua(ci)) { /* yielded inside a hook? */
- L->top = firstArg; /* discard arguments */
+ L->top.p = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */
}
else { /* 'common' yield */
@@ -169464,7 +169646,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
if (L->status == LUA_OK) { /* may be starting a coroutine */
if (L->ci != &L->base_ci) /* not in base level? */
return resume_error(L, "cannot resume non-suspended coroutine", nargs);
- else if (L->top - (L->ci->func + 1) == nargs) /* no function? */
+ else if (L->top.p - (L->ci->func.p + 1) == nargs) /* no function? */
return resume_error(L, "cannot resume dead coroutine", nargs);
}
else if (L->status != LUA_YIELD) /* ended with errors? */
@@ -169482,11 +169664,11 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
lua_assert(status == L->status); /* normal end or yield */
else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as 'dead' */
- luaD_seterrorobj(L, status, L->top); /* push error message */
- L->ci->top = L->top;
+ luaD_seterrorobj(L, status, L->top.p); /* push error message */
+ L->ci->top.p = L->top.p;
}
*nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
- : cast_int(L->top - (L->ci->func + 1));
+ : cast_int(L->top.p - (L->ci->func.p + 1));
lua_unlock(L);
return status;
}
@@ -169641,7 +169823,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
p.dyd.label.arr = NULL; p.dyd.label.size = 0;
luaZ_initbuffer(L, &p.buff);
- status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
+ status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc);
luaZ_freebuffer(L, &p.buff);
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
@@ -170261,8 +170443,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
if (tm == NULL) /* no TM? */
return 0; /* objects are different */
else {
- luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */
- return !l_isfalse(s2v(L->top));
+ luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
+ return !l_isfalse(s2v(L->top.p));
}
}
@@ -170286,17 +170468,17 @@ static void copy2buff (StkId top, int n, char *buff) {
/*
** Main operation for concatenation: concat 'total' values in the stack,
-** from 'L->top - total' up to 'L->top - 1'.
+** from 'L->top.p - total' up to 'L->top.p - 1'.
*/
void luaV_concat (lua_State *L, int total) {
if (total == 1)
return; /* "all" values already concatenated */
do {
- StkId top = L->top;
+ StkId top = L->top.p;
int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) ||
!tostring(L, s2v(top - 1)))
- luaT_tryconcatTM(L);
+ luaT_tryconcatTM(L); /* may invalidate 'top' */
else if (isemptystr(s2v(top - 1))) /* second operand is empty? */
cast_void(tostring(L, s2v(top - 2))); /* result is first operand */
else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */
@@ -170309,8 +170491,10 @@ void luaV_concat (lua_State *L, int total) {
/* collect total length and number of strings */
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
size_t l = vslen(s2v(top - n - 1));
- if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl))
+ if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) {
+ L->top.p = top - total; /* pop strings to avoid wasting stack */
luaG_runerror(L, "string length overflow");
+ }
tl += l;
}
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
@@ -170324,8 +170508,8 @@ void luaV_concat (lua_State *L, int total) {
}
setsvalue2s(L, top - n, ts); /* create result */
}
- total -= n-1; /* got 'n' strings to create 1 new */
- L->top -= n-1; /* popped 'n' strings and pushed one */
+ total -= n - 1; /* got 'n' strings to create one new */
+ L->top.p -= n - 1; /* popped 'n' strings and pushed one */
} while (total > 1); /* repeat until only 1 result left */
}
@@ -170416,12 +170600,10 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
/* number of bits in an integer */
#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT)
+
/*
** Shift left operation. (Shift right just negates 'y'.)
*/
-#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
-
-
lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
if (y < 0) { /* shift right? */
if (y <= -NBITS) return 0;
@@ -170461,26 +170643,26 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
*/
void luaV_finishOp (lua_State *L) {
CallInfo *ci = L->ci;
- StkId base = ci->func + 1;
+ StkId base = ci->func.p + 1;
Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
OpCode op = GET_OPCODE(inst);
switch (op) { /* finish its execution */
case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
- setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top);
+ setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top.p);
break;
}
case OP_UNM: case OP_BNOT: case OP_LEN:
case OP_GETTABUP: case OP_GETTABLE: case OP_GETI:
case OP_GETFIELD: case OP_SELF: {
- setobjs2s(L, base + GETARG_A(inst), --L->top);
+ setobjs2s(L, base + GETARG_A(inst), --L->top.p);
break;
}
case OP_LT: case OP_LE:
case OP_LTI: case OP_LEI:
case OP_GTI: case OP_GEI:
case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */
- int res = !l_isfalse(s2v(L->top - 1));
- L->top--;
+ int res = !l_isfalse(s2v(L->top.p - 1));
+ L->top.p--;
#if defined(LUA_COMPAT_LT_LE)
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
ci->callstatus ^= CIST_LEQ; /* clear mark */
@@ -170493,11 +170675,11 @@ void luaV_finishOp (lua_State *L) {
break;
}
case OP_CONCAT: {
- StkId top = L->top - 1; /* top when 'luaT_tryconcatTM' was called */
+ StkId top = L->top.p - 1; /* top when 'luaT_tryconcatTM' was called */
int a = GETARG_A(inst); /* first element to concatenate */
int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */
setobjs2s(L, top - 2, top); /* put TM result in proper position */
- L->top = top - 1; /* top is one after last element (at top-2) */
+ L->top.p = top - 1; /* top is one after last element (at top-2) */
luaV_concat(L, total); /* concat them (may yield again) */
break;
}
@@ -170509,7 +170691,7 @@ void luaV_finishOp (lua_State *L) {
StkId ra = base + GETARG_A(inst);
/* adjust top to signal correct number of returns, in case the
return is "up to top" ('isIT') */
- L->top = ra + ci->u2.nres;
+ L->top.p = ra + ci->u2.nres;
/* repeat instruction to close other vars. and complete the return */
ci->u.l.savedpc--;
break;
@@ -170551,6 +170733,7 @@ void luaV_finishOp (lua_State *L) {
** operation, 'fop' is the float operation.
*/
#define op_arithI(L,iop,fop) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
int imm = GETARG_sC(i); \
if (ttisinteger(v1)) { \
@@ -170579,6 +170762,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over floats and others with register operands.
*/
#define op_arithf(L,fop) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
op_arithf_aux(L, v1, v2, fop); }
@@ -170588,6 +170772,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations with K operands for floats.
*/
#define op_arithfK(L,fop) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
op_arithf_aux(L, v1, v2, fop); }
@@ -170597,6 +170782,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over integers and floats.
*/
#define op_arith_aux(L,v1,v2,iop,fop) { \
+ StkId ra = RA(i); \
if (ttisinteger(v1) && ttisinteger(v2)) { \
lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \
pc++; setivalue(s2v(ra), iop(L, i1, i2)); \
@@ -170626,6 +170812,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with constant operand.
*/
#define op_bitwiseK(L,op) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = KC(i); \
lua_Integer i1; \
@@ -170639,6 +170826,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with register operands.
*/
#define op_bitwise(L,op) { \
+ StkId ra = RA(i); \
TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \
lua_Integer i1; lua_Integer i2; \
@@ -170653,18 +170841,19 @@ void luaV_finishOp (lua_State *L) {
** integers.
*/
#define op_order(L,opi,opn,other) { \
- int cond; \
- TValue *rb = vRB(i); \
- if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
- lua_Integer ia = ivalue(s2v(ra)); \
- lua_Integer ib = ivalue(rb); \
- cond = opi(ia, ib); \
- } \
- else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
- cond = opn(s2v(ra), rb); \
- else \
- Protect(cond = other(L, s2v(ra), rb)); \
- docondjump(); }
+ StkId ra = RA(i); \
+ int cond; \
+ TValue *rb = vRB(i); \
+ if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
+ lua_Integer ia = ivalue(s2v(ra)); \
+ lua_Integer ib = ivalue(rb); \
+ cond = opi(ia, ib); \
+ } \
+ else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
+ cond = opn(s2v(ra), rb); \
+ else \
+ Protect(cond = other(L, s2v(ra), rb)); \
+ docondjump(); }
/*
@@ -170672,20 +170861,21 @@ void luaV_finishOp (lua_State *L) {
** always small enough to have an exact representation as a float.)
*/
#define op_orderI(L,opi,opf,inv,tm) { \
- int cond; \
- int im = GETARG_sB(i); \
- if (ttisinteger(s2v(ra))) \
- cond = opi(ivalue(s2v(ra)), im); \
- else if (ttisfloat(s2v(ra))) { \
- lua_Number fa = fltvalue(s2v(ra)); \
- lua_Number fim = cast_num(im); \
- cond = opf(fa, fim); \
- } \
- else { \
- int isf = GETARG_C(i); \
- Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
- } \
- docondjump(); }
+ StkId ra = RA(i); \
+ int cond; \
+ int im = GETARG_sB(i); \
+ if (ttisinteger(s2v(ra))) \
+ cond = opi(ivalue(s2v(ra)), im); \
+ else if (ttisfloat(s2v(ra))) { \
+ lua_Number fa = fltvalue(s2v(ra)); \
+ lua_Number fim = cast_num(im); \
+ cond = opf(fa, fim); \
+ } \
+ else { \
+ int isf = GETARG_C(i); \
+ Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
+ } \
+ docondjump(); }
/* }================================================================== */
@@ -170714,7 +170904,7 @@ void luaV_finishOp (lua_State *L) {
#define updatetrap(ci) (trap = ci->u.l.trap)
-#define updatebase(ci) (base = ci->func + 1)
+#define updatebase(ci) (base = ci->func.p + 1)
#define updatestack(ci) \
@@ -170749,7 +170939,7 @@ void luaV_finishOp (lua_State *L) {
** Whenever code can raise errors, the global 'pc' and the global
** 'top' must be correct to report occasional errors.
*/
-#define savestate(L,ci) (savepc(L), L->top = ci->top)
+#define savestate(L,ci) (savepc(L), L->top.p = ci->top.p)
/*
@@ -170769,7 +170959,7 @@ void luaV_finishOp (lua_State *L) {
/* 'c' is the limit of live values in the stack */
#define checkGC(L,c) \
- { luaC_condGC(L, (savepc(L), L->top = (c)), \
+ { luaC_condGC(L, (savepc(L), L->top.p = (c)), \
updatetrap(ci)); \
luai_threadyield(L); }
@@ -170781,7 +170971,6 @@ void luaV_finishOp (lua_State *L) {
updatebase(ci); /* correct stack */ \
} \
i = *(pc++); \
- ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
}
#define vmdispatch(o) switch(o)
@@ -170913,7 +171102,7 @@ static const void *const disptab[NUM_OPCODES] = {
startfunc:
trap = L->hookmask;
returning: /* trap already set */
- cl = clLvalue(s2v(ci->func));
+ cl = clLvalue(s2v(ci->func.p));
k = cl->p->k;
pc = ci->u.l.savedpc;
if (l_unlikely(trap)) {
@@ -170925,60 +171114,68 @@ static const void *const disptab[NUM_OPCODES] = {
}
ci->u.l.trap = 1; /* assume trap is on, for now */
}
- base = ci->func + 1;
+ base = ci->func.p + 1;
/* main loop of interpreter */
for (;;) {
Instruction i; /* instruction being executed */
- StkId ra; /* instruction's A register */
vmfetch();
#if 0
/* low-level line tracing for debugging Lua */
printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
#endif
- lua_assert(base == ci->func + 1);
- lua_assert(base <= L->top && L->top < L->stack_last);
+ lua_assert(base == ci->func.p + 1);
+ lua_assert(base <= L->top.p && L->top.p <= L->stack_last.p);
/* invalidate top for instructions not expecting it */
- lua_assert(isIT(i) || (cast_void(L->top = base), 1));
+ lua_assert(isIT(i) || (cast_void(L->top.p = base), 1));
vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) {
+ StkId ra = RA(i);
setobjs2s(L, ra, RB(i));
vmbreak;
}
vmcase(OP_LOADI) {
+ StkId ra = RA(i);
lua_Integer b = GETARG_sBx(i);
setivalue(s2v(ra), b);
vmbreak;
}
vmcase(OP_LOADF) {
+ StkId ra = RA(i);
int b = GETARG_sBx(i);
setfltvalue(s2v(ra), cast_num(b));
vmbreak;
}
vmcase(OP_LOADK) {
+ StkId ra = RA(i);
TValue *rb = k + GETARG_Bx(i);
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADKX) {
+ StkId ra = RA(i);
TValue *rb;
rb = k + GETARG_Ax(*pc); pc++;
setobj2s(L, ra, rb);
vmbreak;
}
vmcase(OP_LOADFALSE) {
+ StkId ra = RA(i);
setbfvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LFALSESKIP) {
+ StkId ra = RA(i);
setbfvalue(s2v(ra));
pc++; /* skip next instruction */
vmbreak;
}
vmcase(OP_LOADTRUE) {
+ StkId ra = RA(i);
setbtvalue(s2v(ra));
vmbreak;
}
vmcase(OP_LOADNIL) {
+ StkId ra = RA(i);
int b = GETARG_B(i);
do {
setnilvalue(s2v(ra++));
@@ -170986,19 +171183,22 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_GETUPVAL) {
+ StkId ra = RA(i);
int b = GETARG_B(i);
- setobj2s(L, ra, cl->upvals[b]->v);
+ setobj2s(L, ra, cl->upvals[b]->v.p);
vmbreak;
}
vmcase(OP_SETUPVAL) {
+ StkId ra = RA(i);
UpVal *uv = cl->upvals[GETARG_B(i)];
- setobj(L, uv->v, s2v(ra));
+ setobj(L, uv->v.p, s2v(ra));
luaC_barrier(L, uv, s2v(ra));
vmbreak;
}
vmcase(OP_GETTABUP) {
+ StkId ra = RA(i);
const TValue *slot;
- TValue *upval = cl->upvals[GETARG_B(i)]->v;
+ TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
TValue *rc = KC(i);
TString *key = tsvalue(rc); /* key must be a string */
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
@@ -171009,6 +171209,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_GETTABLE) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = vRC(i);
@@ -171023,6 +171224,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_GETI) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
int c = GETARG_C(i);
@@ -171037,6 +171239,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_GETFIELD) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = KC(i);
@@ -171050,7 +171253,7 @@ static const void *const disptab[NUM_OPCODES] = {
}
vmcase(OP_SETTABUP) {
const TValue *slot;
- TValue *upval = cl->upvals[GETARG_A(i)]->v;
+ TValue *upval = cl->upvals[GETARG_A(i)]->v.p;
TValue *rb = KB(i);
TValue *rc = RKC(i);
TString *key = tsvalue(rb); /* key must be a string */
@@ -171062,6 +171265,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SETTABLE) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i); /* key (table is in 'ra') */
TValue *rc = RKC(i); /* value */
@@ -171076,6 +171280,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SETI) {
+ StkId ra = RA(i);
const TValue *slot;
int c = GETARG_B(i);
TValue *rc = RKC(i);
@@ -171090,6 +171295,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SETFIELD) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = KB(i);
TValue *rc = RKC(i);
@@ -171102,6 +171308,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_NEWTABLE) {
+ StkId ra = RA(i);
int b = GETARG_B(i); /* log2(hash size) + 1 */
int c = GETARG_C(i); /* array size */
Table *t;
@@ -171111,7 +171318,7 @@ static const void *const disptab[NUM_OPCODES] = {
if (TESTARG_k(i)) /* non-zero extra argument? */
c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */
pc++; /* skip extra argument */
- L->top = ra + 1; /* correct top in case of emergency GC */
+ L->top.p = ra + 1; /* correct top in case of emergency GC */
t = luaH_new(L); /* memory allocation */
sethvalue2s(L, ra, t);
if (b != 0 || c != 0)
@@ -171120,6 +171327,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SELF) {
+ StkId ra = RA(i);
const TValue *slot;
TValue *rb = vRB(i);
TValue *rc = RKC(i);
@@ -171149,6 +171357,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MODK) {
+ savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_mod, luaV_modf);
vmbreak;
}
@@ -171161,6 +171370,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_IDIVK) {
+ savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_idiv, luai_numidiv);
vmbreak;
}
@@ -171177,6 +171387,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SHRI) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
@@ -171186,6 +171397,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_SHLI) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
int ic = GETARG_sC(i);
lua_Integer ib;
@@ -171207,6 +171419,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MOD) {
+ savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_mod, luaV_modf);
vmbreak;
}
@@ -171219,6 +171432,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_IDIV) { /* floor division */
+ savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_idiv, luai_numidiv);
vmbreak;
}
@@ -171243,6 +171457,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MMBIN) {
+ StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
TValue *rb = vRB(i);
TMS tm = (TMS)GETARG_C(i);
@@ -171252,6 +171467,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MMBINI) {
+ StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
int imm = GETARG_sB(i);
TMS tm = (TMS)GETARG_C(i);
@@ -171261,6 +171477,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_MMBINK) {
+ StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */
TValue *imm = KB(i);
TMS tm = (TMS)GETARG_C(i);
@@ -171270,6 +171487,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_UNM) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Number nb;
if (ttisinteger(rb)) {
@@ -171284,6 +171502,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_BNOT) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
lua_Integer ib;
if (tointegerns(rb, &ib)) {
@@ -171294,6 +171513,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_NOT) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb))
setbtvalue(s2v(ra));
@@ -171302,21 +171522,25 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_LEN) {
+ StkId ra = RA(i);
Protect(luaV_objlen(L, ra, vRB(i)));
vmbreak;
}
vmcase(OP_CONCAT) {
+ StkId ra = RA(i);
int n = GETARG_B(i); /* number of elements to concatenate */
- L->top = ra + n; /* mark the end of concat operands */
+ L->top.p = ra + n; /* mark the end of concat operands */
ProtectNT(luaV_concat(L, n));
- checkGC(L, L->top); /* 'luaV_concat' ensures correct top */
+ checkGC(L, L->top.p); /* 'luaV_concat' ensures correct top */
vmbreak;
}
vmcase(OP_CLOSE) {
+ StkId ra = RA(i);
Protect(luaF_close(L, ra, LUA_OK, 1));
vmbreak;
}
vmcase(OP_TBC) {
+ StkId ra = RA(i);
/* create new to-be-closed upvalue */
halfProtect(luaF_newtbcupval(L, ra));
vmbreak;
@@ -171326,6 +171550,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_EQ) {
+ StkId ra = RA(i);
int cond;
TValue *rb = vRB(i);
Protect(cond = luaV_equalobj(L, s2v(ra), rb));
@@ -171341,6 +171566,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_EQK) {
+ StkId ra = RA(i);
TValue *rb = KB(i);
/* basic types do not use '__eq'; we can use raw equality */
int cond = luaV_rawequalobj(s2v(ra), rb);
@@ -171348,6 +171574,7 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_EQI) {
+ StkId ra = RA(i);
int cond;
int im = GETARG_sB(i);
if (ttisinteger(s2v(ra)))
@@ -171376,11 +171603,13 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_TEST) {
+ StkId ra = RA(i);
int cond = !l_isfalse(s2v(ra));
docondjump();
vmbreak;
}
vmcase(OP_TESTSET) {
+ StkId ra = RA(i);
TValue *rb = vRB(i);
if (l_isfalse(rb) == GETARG_k(i))
pc++;
@@ -171391,11 +171620,12 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_CALL) {
+ StkId ra = RA(i);
CallInfo *newci;
int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1;
if (b != 0) /* fixed number of arguments? */
- L->top = ra + b; /* top signals number of arguments */
+ L->top.p = ra + b; /* top signals number of arguments */
/* else previous instruction set top */
savepc(L); /* in case of errors */
if ((newci = luaD_precall(L, ra, nresults)) == NULL)
@@ -171407,54 +171637,57 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_TAILCALL) {
+ StkId ra = RA(i);
int b = GETARG_B(i); /* number of arguments + 1 (function) */
int n; /* number of results when calling a C function */
int nparams1 = GETARG_C(i);
/* delta is virtual 'func' - real 'func' (vararg functions) */
int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
if (b != 0)
- L->top = ra + b;
+ L->top.p = ra + b;
else /* previous instruction set top */
- b = cast_int(L->top - ra);
+ b = cast_int(L->top.p - ra);
savepc(ci); /* several calls here can raise errors */
if (TESTARG_k(i)) {
luaF_closeupval(L, base); /* close upvalues from current call */
- lua_assert(L->tbclist < base); /* no pending tbc variables */
- lua_assert(base == ci->func + 1);
+ lua_assert(L->tbclist.p < base); /* no pending tbc variables */
+ lua_assert(base == ci->func.p + 1);
}
if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */
goto startfunc; /* execute the callee */
else { /* C function? */
- ci->func -= delta; /* restore 'func' (if vararg) */
+ ci->func.p -= delta; /* restore 'func' (if vararg) */
luaD_poscall(L, ci, n); /* finish caller */
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; /* caller returns after the tail call */
}
}
vmcase(OP_RETURN) {
+ StkId ra = RA(i);
int n = GETARG_B(i) - 1; /* number of results */
int nparams1 = GETARG_C(i);
if (n < 0) /* not fixed? */
- n = cast_int(L->top - ra); /* get what is available */
+ n = cast_int(L->top.p - ra); /* get what is available */
savepc(ci);
if (TESTARG_k(i)) { /* may there be open upvalues? */
ci->u2.nres = n; /* save number of returns */
- if (L->top < ci->top)
- L->top = ci->top;
+ if (L->top.p < ci->top.p)
+ L->top.p = ci->top.p;
luaF_close(L, base, CLOSEKTOP, 1);
updatetrap(ci);
updatestack(ci);
}
if (nparams1) /* vararg function? */
- ci->func -= ci->u.l.nextraargs + nparams1;
- L->top = ra + n; /* set call for 'luaD_poscall' */
+ ci->func.p -= ci->u.l.nextraargs + nparams1;
+ L->top.p = ra + n; /* set call for 'luaD_poscall' */
luaD_poscall(L, ci, n);
updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret;
}
vmcase(OP_RETURN0) {
if (l_unlikely(L->hookmask)) {
- L->top = ra;
+ StkId ra = RA(i);
+ L->top.p = ra;
savepc(ci);
luaD_poscall(L, ci, 0); /* no hurry... */
trap = 1;
@@ -171462,15 +171695,16 @@ static const void *const disptab[NUM_OPCODES] = {
else { /* do the 'poscall' here */
int nres;
L->ci = ci->previous; /* back to caller */
- L->top = base - 1;
+ L->top.p = base - 1;
for (nres = ci->nresults; l_unlikely(nres > 0); nres--)
- setnilvalue(s2v(L->top++)); /* all results are nil */
+ setnilvalue(s2v(L->top.p++)); /* all results are nil */
}
goto ret;
}
vmcase(OP_RETURN1) {
if (l_unlikely(L->hookmask)) {
- L->top = ra + 1;
+ StkId ra = RA(i);
+ L->top.p = ra + 1;
savepc(ci);
luaD_poscall(L, ci, 1); /* no hurry... */
trap = 1;
@@ -171479,12 +171713,13 @@ static const void *const disptab[NUM_OPCODES] = {
int nres = ci->nresults;
L->ci = ci->previous; /* back to caller */
if (nres == 0)
- L->top = base - 1; /* asked for no results */
+ L->top.p = base - 1; /* asked for no results */
else {
+ StkId ra = RA(i);
setobjs2s(L, base - 1, ra); /* at least this result */
- L->top = base;
+ L->top.p = base;
for (; l_unlikely(nres > 1); nres--)
- setnilvalue(s2v(L->top++)); /* complete missing results */
+ setnilvalue(s2v(L->top.p++)); /* complete missing results */
}
}
ret: /* return from a Lua function */
@@ -171496,6 +171731,7 @@ static const void *const disptab[NUM_OPCODES] = {
}
}
vmcase(OP_FORLOOP) {
+ StkId ra = RA(i);
if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));
if (count > 0) { /* still more iterations? */
@@ -171514,12 +171750,14 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_FORPREP) {
+ StkId ra = RA(i);
savestate(L, ci); /* in case of errors */
if (forprep(L, ra))
pc += GETARG_Bx(i) + 1; /* skip the loop */
vmbreak;
}
vmcase(OP_TFORPREP) {
+ StkId ra = RA(i);
/* create to-be-closed upvalue (if needed) */
halfProtect(luaF_newtbcupval(L, ra + 3));
pc += GETARG_Bx(i);
@@ -171528,7 +171766,8 @@ static const void *const disptab[NUM_OPCODES] = {
goto l_tforcall;
}
vmcase(OP_TFORCALL) {
- l_tforcall:
+ l_tforcall: {
+ StkId ra = RA(i);
/* 'ra' has the iterator function, 'ra + 1' has the state,
'ra + 2' has the control variable, and 'ra + 3' has the
to-be-closed variable. The call will use the stack after
@@ -171536,29 +171775,31 @@ static const void *const disptab[NUM_OPCODES] = {
*/
/* push function, state, and control variable */
memcpy(ra + 4, ra, 3 * sizeof(*ra));
- L->top = ra + 4 + 3;
+ L->top.p = ra + 4 + 3;
ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */
updatestack(ci); /* stack may have changed */
i = *(pc++); /* go to next instruction */
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
goto l_tforloop;
- }
+ }}
vmcase(OP_TFORLOOP) {
- l_tforloop:
+ l_tforloop: {
+ StkId ra = RA(i);
if (!ttisnil(s2v(ra + 4))) { /* continue loop? */
setobjs2s(L, ra + 2, ra + 4); /* save control variable */
pc -= GETARG_Bx(i); /* jump back */
}
vmbreak;
- }
+ }}
vmcase(OP_SETLIST) {
+ StkId ra = RA(i);
int n = GETARG_B(i);
unsigned int last = GETARG_C(i);
Table *h = hvalue(s2v(ra));
if (n == 0)
- n = cast_int(L->top - ra) - 1; /* get up to the top */
+ n = cast_int(L->top.p - ra) - 1; /* get up to the top */
else
- L->top = ci->top; /* correct top in case of emergency GC */
+ L->top.p = ci->top.p; /* correct top in case of emergency GC */
last += n;
if (TESTARG_k(i)) {
last += GETARG_Ax(*pc) * (MAXARG_C + 1);
@@ -171575,12 +171816,14 @@ static const void *const disptab[NUM_OPCODES] = {
vmbreak;
}
vmcase(OP_CLOSURE) {
+ StkId ra = RA(i);
Proto *p = cl->p->p[GETARG_Bx(i)];
halfProtect(pushclosure(L, p, cl->upvals, base, ra));
checkGC(L, ra + 1);
vmbreak;
}
vmcase(OP_VARARG) {
+ StkId ra = RA(i);
int n = GETARG_C(i) - 1; /* required results */
Protect(luaT_getvarargs(L, ci, ra, n));
vmbreak;
@@ -171665,27 +171908,28 @@ const char lua_ident[] =
static TValue *index2value (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
- StkId o = ci->func + idx;
- api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index");
- if (o >= L->top) return &G(L)->nilvalue;
+ StkId o = ci->func.p + idx;
+ api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index");
+ if (o >= L->top.p) return &G(L)->nilvalue;
else return s2v(o);
}
else if (!ispseudo(idx)) { /* negative index */
- api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
- return s2v(L->top + idx);
+ api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
+ "invalid index");
+ return s2v(L->top.p + idx);
}
else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry;
else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
- if (ttisCclosure(s2v(ci->func))) { /* C closure? */
- CClosure *func = clCvalue(s2v(ci->func));
+ if (ttisCclosure(s2v(ci->func.p))) { /* C closure? */
+ CClosure *func = clCvalue(s2v(ci->func.p));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue;
}
else { /* light C function or Lua function (through a hook)?) */
- api_check(L, ttislcf(s2v(ci->func)), "caller not a C function");
+ api_check(L, ttislcf(s2v(ci->func.p)), "caller not a C function");
return &G(L)->nilvalue; /* no upvalues */
}
}
@@ -171699,14 +171943,15 @@ static TValue *index2value (lua_State *L, int idx) {
l_sinline StkId index2stack (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
- StkId o = ci->func + idx;
- api_check(L, o < L->top, "invalid index");
+ StkId o = ci->func.p + idx;
+ api_check(L, o < L->top.p, "invalid index");
return o;
}
else { /* non-positive index */
- api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
+ api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
+ "invalid index");
api_check(L, !ispseudo(idx), "invalid index");
- return L->top + idx;
+ return L->top.p + idx;
}
}
@@ -171717,17 +171962,12 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
lua_lock(L);
ci = L->ci;
api_check(L, n >= 0, "negative 'n'");
- if (L->stack_last - L->top > n) /* stack large enough? */
+ if (L->stack_last.p - L->top.p > n) /* stack large enough? */
res = 1; /* yes; check is OK */
- else { /* no; need to grow stack */
- int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;
- if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */
- res = 0; /* no */
- else /* try to grow stack */
- res = luaD_growstack(L, n, 0);
- }
- if (res && ci->top < L->top + n)
- ci->top = L->top + n; /* adjust frame top */
+ else /* need to grow stack */
+ res = luaD_growstack(L, n, 0);
+ if (res && ci->top.p < L->top.p + n)
+ ci->top.p = L->top.p + n; /* adjust frame top */
lua_unlock(L);
return res;
}
@@ -171739,11 +171979,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
lua_lock(to);
api_checknelems(from, n);
api_check(from, G(from) == G(to), "moving among independent states");
- api_check(from, to->ci->top - to->top >= n, "stack overflow");
- from->top -= n;
+ api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow");
+ from->top.p -= n;
for (i = 0; i < n; i++) {
- setobjs2s(to, to->top, from->top + i);
- to->top++; /* stack already checked by previous 'api_check' */
+ setobjs2s(to, to->top.p, from->top.p + i);
+ to->top.p++; /* stack already checked by previous 'api_check' */
}
lua_unlock(to);
}
@@ -171777,12 +172017,12 @@ LUA_API lua_Number lua_version (lua_State *L) {
LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx))
? idx
- : cast_int(L->top - L->ci->func) + idx;
+ : cast_int(L->top.p - L->ci->func.p) + idx;
}
LUA_API int lua_gettop (lua_State *L) {
- return cast_int(L->top - (L->ci->func + 1));
+ return cast_int(L->top.p - (L->ci->func.p + 1));
}
@@ -171792,24 +172032,24 @@ LUA_API void lua_settop (lua_State *L, int idx) {
ptrdiff_t diff; /* difference for new top */
lua_lock(L);
ci = L->ci;
- func = ci->func;
+ func = ci->func.p;
if (idx >= 0) {
- api_check(L, idx <= ci->top - (func + 1), "new top too large");
- diff = ((func + 1) + idx) - L->top;
+ api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
+ diff = ((func + 1) + idx) - L->top.p;
for (; diff > 0; diff--)
- setnilvalue(s2v(L->top++)); /* clear new slots */
+ setnilvalue(s2v(L->top.p++)); /* clear new slots */
}
else {
- api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
+ api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top");
diff = idx + 1; /* will "subtract" index (as it is negative) */
}
- api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot");
- newtop = L->top + diff;
- if (diff < 0 && L->tbclist >= newtop) {
+ api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot");
+ newtop = L->top.p + diff;
+ if (diff < 0 && L->tbclist.p >= newtop) {
lua_assert(hastocloseCfunc(ci->nresults));
- luaF_close(L, newtop, CLOSEKTOP, 0);
+ newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
}
- L->top = newtop; /* correct top only after closing any upvalue */
+ L->top.p = newtop; /* correct top only after closing any upvalue */
lua_unlock(L);
}
@@ -171818,10 +172058,9 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
StkId level;
lua_lock(L);
level = index2stack(L, idx);
- api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
+ api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
"no variable to close at given level");
- luaF_close(L, level, CLOSEKTOP, 0);
- level = index2stack(L, idx); /* stack may be moved */
+ level = luaF_close(L, level, CLOSEKTOP, 0);
setnilvalue(s2v(level));
lua_unlock(L);
}
@@ -171850,7 +172089,7 @@ l_sinline void reverse (lua_State *L, StkId from, StkId to) {
LUA_API void lua_rotate (lua_State *L, int idx, int n) {
StkId p, t, m;
lua_lock(L);
- t = L->top - 1; /* end of stack segment being rotated */
+ t = L->top.p - 1; /* end of stack segment being rotated */
p = index2stack(L, idx); /* start of segment */
api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
@@ -171869,7 +172108,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
api_check(L, isvalid(L, to), "invalid index");
setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */
- luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr);
+ luaC_barrier(L, clCvalue(s2v(L->ci->func.p)), fr);
/* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */
lua_unlock(L);
@@ -171878,7 +172117,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
LUA_API void lua_pushvalue (lua_State *L, int idx) {
lua_lock(L);
- setobj2s(L, L->top, index2value(L, idx));
+ setobj2s(L, L->top.p, index2value(L, idx));
api_incr_top(L);
lua_unlock(L);
}
@@ -171947,12 +172186,12 @@ LUA_API void lua_arith (lua_State *L, int op) {
api_checknelems(L, 2); /* all other operations expect two operands */
else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1);
- setobjs2s(L, L->top, L->top - 1);
+ setobjs2s(L, L->top.p, L->top.p - 1);
api_incr_top(L);
}
/* first operand at top - 2, second at top - 1; result go to top - 2 */
- luaO_arith(L, op, s2v(L->top - 2), s2v(L->top - 1), L->top - 2);
- L->top--; /* remove second operand */
+ luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2);
+ L->top.p--; /* remove second operand */
lua_unlock(L);
}
@@ -171978,7 +172217,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
- size_t sz = luaO_str2num(s, s2v(L->top));
+ size_t sz = luaO_str2num(s, s2v(L->top.p));
if (sz != 0)
api_incr_top(L);
return sz;
@@ -172105,7 +172344,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
LUA_API void lua_pushnil (lua_State *L) {
lua_lock(L);
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
api_incr_top(L);
lua_unlock(L);
}
@@ -172113,7 +172352,7 @@ LUA_API void lua_pushnil (lua_State *L) {
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
lua_lock(L);
- setfltvalue(s2v(L->top), n);
+ setfltvalue(s2v(L->top.p), n);
api_incr_top(L);
lua_unlock(L);
}
@@ -172121,7 +172360,7 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
lua_lock(L);
- setivalue(s2v(L->top), n);
+ setivalue(s2v(L->top.p), n);
api_incr_top(L);
lua_unlock(L);
}
@@ -172136,7 +172375,7 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts;
lua_lock(L);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
- setsvalue2s(L, L->top, ts);
+ setsvalue2s(L, L->top.p, ts);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
@@ -172147,11 +172386,11 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
lua_lock(L);
if (s == NULL)
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
else {
TString *ts;
ts = luaS_new(L, s);
- setsvalue2s(L, L->top, ts);
+ setsvalue2s(L, L->top.p, ts);
s = getstr(ts); /* internal copy's address */
}
api_incr_top(L);
@@ -172188,7 +172427,7 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L);
if (n == 0) {
- setfvalue(s2v(L->top), fn);
+ setfvalue(s2v(L->top.p), fn);
api_incr_top(L);
}
else {
@@ -172197,13 +172436,13 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n);
cl->f = fn;
- L->top -= n;
+ L->top.p -= n;
while (n--) {
- setobj2n(L, &cl->upvalue[n], s2v(L->top + n));
+ setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n));
/* does not need barrier because closure is white */
lua_assert(iswhite(cl));
}
- setclCvalue(L, s2v(L->top), cl);
+ setclCvalue(L, s2v(L->top.p), cl);
api_incr_top(L);
luaC_checkGC(L);
}
@@ -172214,9 +172453,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
LUA_API void lua_pushboolean (lua_State *L, int b) {
lua_lock(L);
if (b)
- setbtvalue(s2v(L->top));
+ setbtvalue(s2v(L->top.p));
else
- setbfvalue(s2v(L->top));
+ setbfvalue(s2v(L->top.p));
api_incr_top(L);
lua_unlock(L);
}
@@ -172224,7 +172463,7 @@ LUA_API void lua_pushboolean (lua_State *L, int b) {
LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
lua_lock(L);
- setpvalue(s2v(L->top), p);
+ setpvalue(s2v(L->top.p), p);
api_incr_top(L);
lua_unlock(L);
}
@@ -172232,7 +172471,7 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
LUA_API int lua_pushthread (lua_State *L) {
lua_lock(L);
- setthvalue(L, s2v(L->top), L);
+ setthvalue(L, s2v(L->top.p), L);
api_incr_top(L);
lua_unlock(L);
return (G(L)->mainthread == L);
@@ -172249,16 +172488,16 @@ l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
- setobj2s(L, L->top, slot);
+ setobj2s(L, L->top.p, slot);
api_incr_top(L);
}
else {
- setsvalue2s(L, L->top, str);
+ setsvalue2s(L, L->top.p, str);
api_incr_top(L);
- luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
+ luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
}
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
@@ -172285,13 +172524,13 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
TValue *t;
lua_lock(L);
t = index2value(L, idx);
- if (luaV_fastget(L, t, s2v(L->top - 1), slot, luaH_get)) {
- setobj2s(L, L->top - 1, slot);
+ if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) {
+ setobj2s(L, L->top.p - 1, slot);
}
else
- luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
+ luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
@@ -172307,27 +172546,27 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) {
- setobj2s(L, L->top, slot);
+ setobj2s(L, L->top.p, slot);
}
else {
TValue aux;
setivalue(&aux, n);
- luaV_finishget(L, t, &aux, L->top, slot);
+ luaV_finishget(L, t, &aux, L->top.p, slot);
}
api_incr_top(L);
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
l_sinline int finishrawget (lua_State *L, const TValue *val) {
if (isempty(val)) /* avoid copying empty items to the stack */
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
else
- setobj2s(L, L->top, val);
+ setobj2s(L, L->top.p, val);
api_incr_top(L);
lua_unlock(L);
- return ttype(s2v(L->top - 1));
+ return ttype(s2v(L->top.p - 1));
}
@@ -172344,8 +172583,8 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
- val = luaH_get(t, s2v(L->top - 1));
- L->top--; /* remove key */
+ val = luaH_get(t, s2v(L->top.p - 1));
+ L->top.p--; /* remove key */
return finishrawget(L, val);
}
@@ -172372,7 +172611,7 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t;
lua_lock(L);
t = luaH_new(L);
- sethvalue2s(L, L->top, t);
+ sethvalue2s(L, L->top.p, t);
api_incr_top(L);
if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec);
@@ -172399,7 +172638,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
break;
}
if (mt != NULL) {
- sethvalue2s(L, L->top, mt);
+ sethvalue2s(L, L->top.p, mt);
api_incr_top(L);
res = 1;
}
@@ -172415,12 +172654,12 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
o = index2value(L, idx);
api_check(L, ttisfulluserdata(o), "full userdata expected");
if (n <= 0 || n > uvalue(o)->nuvalue) {
- setnilvalue(s2v(L->top));
+ setnilvalue(s2v(L->top.p));
t = LUA_TNONE;
}
else {
- setobj2s(L, L->top, &uvalue(o)->uv[n - 1].uv);
- t = ttype(s2v(L->top));
+ setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv);
+ t = ttype(s2v(L->top.p));
}
api_incr_top(L);
lua_unlock(L);
@@ -172440,14 +172679,14 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
TString *str = luaS_new(L, k);
api_checknelems(L, 1);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
- luaV_finishfastset(L, t, slot, s2v(L->top - 1));
- L->top--; /* pop value */
+ luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
+ L->top.p--; /* pop value */
}
else {
- setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
+ setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */
api_incr_top(L);
- luaV_finishset(L, t, s2v(L->top - 1), s2v(L->top - 2), slot);
- L->top -= 2; /* pop value and key */
+ luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot);
+ L->top.p -= 2; /* pop value and key */
}
lua_unlock(L); /* lock done by caller */
}
@@ -172467,12 +172706,12 @@ LUA_API void lua_settable (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 2);
t = index2value(L, idx);
- if (luaV_fastget(L, t, s2v(L->top - 2), slot, luaH_get)) {
- luaV_finishfastset(L, t, slot, s2v(L->top - 1));
+ if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) {
+ luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
}
else
- luaV_finishset(L, t, s2v(L->top - 2), s2v(L->top - 1), slot);
- L->top -= 2; /* pop index and value */
+ luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot);
+ L->top.p -= 2; /* pop index and value */
lua_unlock(L);
}
@@ -172490,14 +172729,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
api_checknelems(L, 1);
t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) {
- luaV_finishfastset(L, t, slot, s2v(L->top - 1));
+ luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
}
else {
TValue aux;
setivalue(&aux, n);
- luaV_finishset(L, t, &aux, s2v(L->top - 1), slot);
+ luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot);
}
- L->top--; /* pop value */
+ L->top.p--; /* pop value */
lua_unlock(L);
}
@@ -172507,16 +172746,16 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
lua_lock(L);
api_checknelems(L, n);
t = gettable(L, idx);
- luaH_set(L, t, key, s2v(L->top - 1));
+ luaH_set(L, t, key, s2v(L->top.p - 1));
invalidateTMcache(t);
- luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
- L->top -= n;
+ luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
+ L->top.p -= n;
lua_unlock(L);
}
LUA_API void lua_rawset (lua_State *L, int idx) {
- aux_rawset(L, idx, s2v(L->top - 2), 2);
+ aux_rawset(L, idx, s2v(L->top.p - 2), 2);
}
@@ -172532,9 +172771,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
- luaH_setint(L, t, n, s2v(L->top - 1));
- luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
- L->top--;
+ luaH_setint(L, t, n, s2v(L->top.p - 1));
+ luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
+ L->top.p--;
lua_unlock(L);
}
@@ -172545,11 +172784,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
lua_lock(L);
api_checknelems(L, 1);
obj = index2value(L, objindex);
- if (ttisnil(s2v(L->top - 1)))
+ if (ttisnil(s2v(L->top.p - 1)))
mt = NULL;
else {
- api_check(L, ttistable(s2v(L->top - 1)), "table expected");
- mt = hvalue(s2v(L->top - 1));
+ api_check(L, ttistable(s2v(L->top.p - 1)), "table expected");
+ mt = hvalue(s2v(L->top.p - 1));
}
switch (ttype(obj)) {
case LUA_TTABLE: {
@@ -172573,7 +172812,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
break;
}
}
- L->top--;
+ L->top.p--;
lua_unlock(L);
return 1;
}
@@ -172589,11 +172828,11 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */
else {
- setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1));
- luaC_barrierback(L, gcvalue(o), s2v(L->top - 1));
+ setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1));
+ luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1));
res = 1;
}
- L->top--;
+ L->top.p--;
lua_unlock(L);
return res;
}
@@ -172605,7 +172844,8 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
#define checkresults(L,na,nr) \
- api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
+ api_check(L, (nr) == LUA_MULTRET \
+ || (L->ci->top.p - L->top.p >= (nr) - (na)), \
"results from function overflow current stack size")
@@ -172618,7 +172858,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
api_checknelems(L, nargs+1);
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults);
- func = L->top - (nargs+1);
+ func = L->top.p - (nargs+1);
if (k != NULL && yieldable(L)) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */
@@ -172666,7 +172906,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
api_check(L, ttisfunction(s2v(o)), "error handler must be a function");
func = savestack(L, o);
}
- c.func = L->top - (nargs+1); /* function to be called */
+ c.func = L->top.p - (nargs+1); /* function to be called */
if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */
c.nresults = nresults; /* do a 'conventional' protected call */
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
@@ -172701,12 +172941,12 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname, mode);
if (status == LUA_OK) { /* no errors? */
- LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */
+ LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */
if (f->nupvalues >= 1) { /* does it have an upvalue? */
/* get global table from registry */
const TValue *gt = getGtable(L);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
- setobj(L, f->upvals[0]->v, gt);
+ setobj(L, f->upvals[0]->v.p, gt);
luaC_barrier(L, f->upvals[0], gt);
}
}
@@ -172720,7 +172960,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
TValue *o;
lua_lock(L);
api_checknelems(L, 1);
- o = s2v(L->top - 1);
+ o = s2v(L->top.p - 1);
if (isLfunction(o))
status = luaU_dump(L, getproto(o), writer, data, strip);
else
@@ -172846,7 +173086,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
LUA_API int lua_error (lua_State *L) {
TValue *errobj;
lua_lock(L);
- errobj = s2v(L->top - 1);
+ errobj = s2v(L->top.p - 1);
api_checknelems(L, 1);
/* error object is the memory error message? */
if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
@@ -172864,12 +173104,12 @@ LUA_API int lua_next (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
t = gettable(L, idx);
- more = luaH_next(L, t, L->top - 1);
+ more = luaH_next(L, t, L->top.p - 1);
if (more) {
api_incr_top(L);
}
else /* no more elements */
- L->top -= 1; /* remove key */
+ L->top.p -= 1; /* remove key */
lua_unlock(L);
return more;
}
@@ -172881,7 +173121,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
lua_lock(L);
o = index2stack(L, idx);
nresults = L->ci->nresults;
- api_check(L, L->tbclist < o, "given index below or equal a marked one");
+ api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
if (!hastocloseCfunc(nresults)) /* function not marked yet? */
L->ci->nresults = codeNresults(nresults); /* mark it */
@@ -172896,7 +173136,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
if (n > 0)
luaV_concat(L, n);
else { /* nothing to concatenate */
- setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */
+ setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */
api_incr_top(L);
}
luaC_checkGC(L);
@@ -172908,7 +173148,7 @@ LUA_API void lua_len (lua_State *L, int idx) {
TValue *t;
lua_lock(L);
t = index2value(L, idx);
- luaV_objlen(L, L->top, t);
+ luaV_objlen(L, L->top.p, t);
api_incr_top(L);
lua_unlock(L);
}
@@ -172953,7 +173193,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
lua_lock(L);
api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value");
u = luaS_newudata(L, size, nuvalue);
- setuvalue(L, s2v(L->top), u);
+ setuvalue(L, s2v(L->top.p), u);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
@@ -172979,7 +173219,7 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
Proto *p = f->p;
if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues)))
return NULL; /* 'n' not in [1, p->sizeupvalues] */
- *val = f->upvals[n-1]->v;
+ *val = f->upvals[n-1]->v.p;
if (owner) *owner = obj2gco(f->upvals[n - 1]);
name = p->upvalues[n-1].name;
return (name == NULL) ? "(no name)" : getstr(name);
@@ -172995,7 +173235,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
lua_lock(L);
name = aux_upvalue(index2value(L, funcindex), n, &val, NULL);
if (name) {
- setobj2s(L, L->top, val);
+ setobj2s(L, L->top.p, val);
api_incr_top(L);
}
lua_unlock(L);
@@ -173013,8 +173253,8 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
api_checknelems(L, 1);
name = aux_upvalue(fi, n, &val, &owner);
if (name) {
- L->top--;
- setobj(L, val, s2v(L->top));
+ L->top.p--;
+ setobj(L, val, s2v(L->top.p));
luaC_barrier(L, owner, val);
}
lua_unlock(L);
@@ -173597,13 +173837,14 @@ static void newbox (lua_State *L) {
/*
** Compute new size for buffer 'B', enough to accommodate extra 'sz'
-** bytes.
+** bytes. (The test for "not big enough" also gets the case when the
+** computation of 'newsize' overflows.)
*/
static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
- size_t newsize = B->size * 2; /* double buffer size */
+ size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */
if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
return luaL_error(B->L, "buffer too large");
- if (newsize < B->n + sz) /* double is not big enough? */
+ if (newsize < B->n + sz) /* not big enough? */
newsize = B->n + sz;
return newsize;
}
@@ -173682,7 +173923,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
** box (if existent) is not on the top of the stack. So, instead of
** calling 'luaL_addlstring', it replicates the code using -2 as the
** last argument to 'prepbuffsize', signaling that the box is (or will
-** be) bellow the string being added to the buffer. (Box creation can
+** be) below the string being added to the buffer. (Box creation can
** trigger an emergency GC, so we should not remove the string from the
** stack before we have the space guaranteed.)
*/
@@ -173810,17 +174051,18 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
}
-static int skipBOM (LoadF *lf) {
- const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
- int c;
- lf->n = 0;
- do {
- c = getc(lf->f);
- if (c == EOF || c != *(const unsigned char *)p++) return c;
- lf->buff[lf->n++] = c; /* to be read by the parser */
- } while (*p != '\0');
- lf->n = 0; /* prefix matched; discard it */
- return getc(lf->f); /* return next character */
+/*
+** Skip an optional BOM at the start of a stream. If there is an
+** incomplete BOM (the first character is correct but the rest is
+** not), returns the first character anyway to force an error
+** (as no chunk can start with 0xEF).
+*/
+static int skipBOM (FILE *f) {
+ int c = getc(f); /* read first character */
+ if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */
+ return getc(f); /* ignore BOM and return next char */
+ else /* no (valid) BOM */
+ return c; /* return first character */
}
@@ -173831,13 +174073,13 @@ static int skipBOM (LoadF *lf) {
** first "valid" character of the file (after the optional BOM and
** a first-line comment).
*/
-static int skipcomment (LoadF *lf, int *cp) {
- int c = *cp = skipBOM(lf);
+static int skipcomment (FILE *f, int *cp) {
+ int c = *cp = skipBOM(f);
if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */
- c = getc(lf->f);
+ c = getc(f);
} while (c != EOF && c != '\n');
- *cp = getc(lf->f); /* skip end-of-line, if present */
+ *cp = getc(f); /* next character after comment, if present */
return 1; /* there was a comment */
}
else return 0; /* no comment */
@@ -173859,12 +174101,16 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex);
}
- if (skipcomment(&lf, &c)) /* read initial portion */
- lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
- if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
- lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
- if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
- skipcomment(&lf, &c); /* re-read initial portion */
+ lf.n = 0;
+ if (skipcomment(lf.f, &c)) /* read initial portion */
+ lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */
+ if (c == LUA_SIGNATURE[0]) { /* binary file? */
+ lf.n = 0; /* remove possible newline */
+ if (filename) { /* "real" file? */
+ lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
+ if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
+ skipcomment(lf.f, &c); /* re-read initial portion */
+ }
}
if (c != EOF)
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
@@ -174802,7 +175048,7 @@ static int luaB_auxwrap (lua_State *L) {
if (l_unlikely(r < 0)) { /* error? */
int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
- stat = lua_resetthread(co); /* close its tbc variables */
+ stat = lua_closethread(co, L); /* close its tbc variables */
lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* move error message to the caller */
}
@@ -174898,7 +175144,7 @@ static int luaB_close (lua_State *L) {
int status = auxstatus(L, co);
switch (status) {
case COS_DEAD: case COS_YIELD: {
- status = lua_resetthread(co);
+ status = lua_closethread(co, L);
if (status == LUA_OK) {
lua_pushboolean(L, 1);
return 1;
@@ -176514,7 +176760,7 @@ static int math_type (lua_State *L) {
/* try to find an integer type with at least 64 bits */
-#if (ULONG_MAX >> 31 >> 31) >= 3
+#if ((ULONG_MAX >> 31) >> 31) >= 3
/* 'long' has at least 64 bits */
#define Rand64 unsigned long
@@ -176524,9 +176770,9 @@ static int math_type (lua_State *L) {
/* there is a 'long long' type (which must have at least 64 bits) */
#define Rand64 unsigned long long
-#elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3
+#elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
-/* 'lua_Integer' has at least 64 bits */
+/* 'lua_Unsigned' has at least 64 bits */
#define Rand64 lua_Unsigned
#endif
@@ -176747,12 +176993,12 @@ static lua_Number I2d (Rand64 x) {
/* convert a 'Rand64' to a 'lua_Unsigned' */
static lua_Unsigned I2UInt (Rand64 x) {
- return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l);
+ return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
}
/* convert a 'lua_Unsigned' to a 'Rand64' */
static Rand64 Int2I (lua_Unsigned n) {
- return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n);
+ return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n);
}
#endif /* } */
@@ -177719,8 +177965,13 @@ static const luaL_Reg ll_funcs[] = {
static void createsearcherstable (lua_State *L) {
- static const lua_CFunction searchers[] =
- {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
+ static const lua_CFunction searchers[] = {
+ searcher_preload,
+ searcher_Lua,
+ searcher_C,
+ searcher_Croot,
+ NULL
+ };
int i;
/* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
@@ -177803,23 +178054,14 @@ LUAMOD_API int luaopen_package (lua_State *L) {
*/
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
-/* options for ANSI C 89 (only 1-char options) */
-#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
-
-/* options for ISO C 99 and POSIX */
-#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
- "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
-
-/* options for Windows */
-#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
- "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
-
#if defined(LUA_USE_WINDOWS)
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
-#elif defined(LUA_USE_C89)
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
+#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
+ "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
+#elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */
+#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
#else /* C99 specification */
-#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
+#define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
+ "||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
#endif
#endif /* } */
@@ -177911,12 +178153,21 @@ LUAMOD_API int luaopen_package (lua_State *L) {
/* }================================================================== */
+#if !defined(l_system)
+#if defined(LUA_USE_IOS)
+/* Despite claiming to be ISO C, iOS does not implement 'system'. */
+#define l_system(cmd) ((cmd) == NULL ? 0 : -1)
+#else
+#define l_system(cmd) system(cmd) /* default definition */
+#endif
+#endif
+
static int os_execute (lua_State *L) {
const char *cmd = luaL_optstring(L, 1, NULL);
int stat;
errno = 0;
- stat = system(cmd);
+ stat = l_system(cmd);
if (cmd != NULL)
return luaL_execresult(L, stat);
else {
@@ -178033,9 +178284,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
res = d;
}
else {
- /* unsigned avoids overflow when lua_Integer has 32 bits */
- if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta
- : (lua_Integer)INT_MIN + delta <= res))
+ if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta;
}
@@ -178773,7 +179022,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
static const char *match (MatchState *ms, const char *s, const char *p) {
if (l_unlikely(ms->matchdepth-- == 0))
luaL_error(ms->L, "pattern too complex");
- init: /* using goto's to optimize tail recursion */
+ init: /* using goto to optimize tail recursion */
if (p != ms->p_end) { /* end of pattern? */
switch (*p) {
case '(': { /* start capture */
@@ -180170,7 +180419,7 @@ static int tremove (lua_State *L) {
lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */
/* check whether 'pos' is in [1, size + 1] */
- luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1,
+ luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
"position out of bounds");
lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) {
@@ -180532,6 +180781,9 @@ LUAMOD_API int luaopen_table (lua_State *L) {
#define MAXUTF 0x7FFFFFFFu
+
+#define MSGInvalid "invalid UTF-8 code"
+
/*
** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
*/
@@ -180542,7 +180794,8 @@ typedef unsigned long utfint;
#endif
-#define iscont(p) ((*(p) & 0xC0) == 0x80)
+#define iscont(c) (((c) & 0xC0) == 0x80)
+#define iscontp(p) iscont(*(p))
/* from strlib */
@@ -180572,7 +180825,7 @@ static const char *utf8_decode (const char *s, utfint *val, int strict) {
int count = 0; /* to count number of continuation bytes */
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
unsigned int cc = (unsigned char)s[++count]; /* read next byte */
- if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
+ if (!iscont(cc)) /* not a continuation byte? */
return NULL; /* invalid byte sequence */
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
}
@@ -180647,7 +180900,7 @@ static int codepoint (lua_State *L) {
utfint code;
s = utf8_decode(s, &code, !lax);
if (s == NULL)
- return luaL_error(L, "invalid UTF-8 code");
+ return luaL_error(L, MSGInvalid);
lua_pushinteger(L, code);
n++;
}
@@ -180697,16 +180950,16 @@ static int byteoffset (lua_State *L) {
"position out of bounds");
if (n == 0) {
/* find beginning of current byte sequence */
- while (posi > 0 && iscont(s + posi)) posi--;
+ while (posi > 0 && iscontp(s + posi)) posi--;
}
else {
- if (iscont(s + posi))
+ if (iscontp(s + posi))
return luaL_error(L, "initial position is a continuation byte");
if (n < 0) {
while (n < 0 && posi > 0) { /* move back */
do { /* find beginning of previous character */
posi--;
- } while (posi > 0 && iscont(s + posi));
+ } while (posi > 0 && iscontp(s + posi));
n++;
}
}
@@ -180715,7 +180968,7 @@ static int byteoffset (lua_State *L) {
while (n > 0 && posi < (lua_Integer)len) {
do { /* find beginning of next character */
posi++;
- } while (iscont(s + posi)); /* (cannot pass final '\0') */
+ } while (iscontp(s + posi)); /* (cannot pass final '\0') */
n--;
}
}
@@ -180733,15 +180986,15 @@ static int iter_aux (lua_State *L, int strict) {
const char *s = luaL_checklstring(L, 1, &len);
lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
if (n < len) {
- while (iscont(s + n)) n++; /* skip continuation bytes */
+ while (iscontp(s + n)) n++; /* go to next character */
}
if (n >= len) /* (also handles original 'n' being negative) */
return 0; /* no more codepoints */
else {
utfint code;
const char *next = utf8_decode(s + n, &code, strict);
- if (next == NULL)
- return luaL_error(L, "invalid UTF-8 code");
+ if (next == NULL || iscontp(next))
+ return luaL_error(L, MSGInvalid);
lua_pushinteger(L, n + 1);
lua_pushinteger(L, code);
return 2;
@@ -180760,7 +181013,8 @@ static int iter_auxlax (lua_State *L) {
static int iter_codes (lua_State *L) {
int lax = lua_toboolean(L, 2);
- luaL_checkstring(L, 1);
+ const char *s = luaL_checkstring(L, 1);
+ luaL_argcheck(L, !iscontp(s), 1, MSGInvalid);
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
lua_pushvalue(L, 1);
lua_pushinteger(L, 0);
@@ -181040,10 +181294,11 @@ static void print_version (void) {
** to the script (everything after 'script') go to positive indices;
** other arguments (before the script name) go to negative indices.
** If there is no script name, assume interpreter's name as base.
+** (If there is no interpreter's name either, 'script' is -1, so
+** table sizes are zero.)
*/
static void createargtable (lua_State *L, char **argv, int argc, int script) {
int i, narg;
- if (script == argc) script = 0; /* no script name? */
narg = argc - (script + 1); /* number of positive indices */
lua_createtable(L, narg, script + 1);
for (i = 0; i < argc; i++) {
@@ -181131,14 +181386,23 @@ static int handle_script (lua_State *L, char **argv) {
/*
** Traverses all arguments from 'argv', returning a mask with those
-** needed before running any Lua code (or an error code if it finds
-** any invalid argument). 'first' returns the first not-handled argument
-** (either the script name or a bad argument in case of error).
+** needed before running any Lua code or an error code if it finds any
+** invalid argument. In case of error, 'first' is the index of the bad
+** argument. Otherwise, 'first' is -1 if there is no program name,
+** 0 if there is no script name, or the index of the script name.
*/
static int collectargs (char **argv, int *first) {
int args = 0;
int i;
- for (i = 1; argv[i] != NULL; i++) {
+ if (argv[0] != NULL) { /* is there a program name? */
+ if (argv[0][0]) /* not empty? */
+ progname = argv[0]; /* save it */
+ }
+ else { /* no program name */
+ *first = -1;
+ return 0;
+ }
+ for (i = 1; argv[i] != NULL; i++) { /* handle arguments */
*first = i;
if (argv[i][0] != '-') /* not an option? */
return args; /* stop handling options */
@@ -181179,7 +181443,7 @@ static int collectargs (char **argv, int *first) {
return has_error;
}
}
- *first = i; /* no script name */
+ *first = 0; /* no script name */
return args;
}
@@ -181472,8 +181736,8 @@ static int pmain (lua_State *L) {
char **argv = (char **)lua_touserdata(L, 2);
int script;
int args = collectargs(argv, &script);
+ int optlim = (script > 0) ? script : argc; /* first argv not an option */
luaL_checkversion(L); /* check that interpreter has correct version */
- if (argv[0] && argv[0][0]) progname = argv[0];
if (args == has_error) { /* bad arg? */
print_usage(argv[script]); /* 'script' has index of bad arg. */
return 0;
@@ -181486,19 +181750,21 @@ static int pmain (lua_State *L) {
}
luaL_openlibs(L); /* open standard libraries */
createargtable(L, argv, argc, script); /* create table 'arg' */
- lua_gc(L, LUA_GCGEN, 0, 0); /* GC in generational mode */
+ lua_gc(L, LUA_GCRESTART); /* start GC... */
+ lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */
if (!(args & has_E)) { /* no option '-E'? */
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */
}
- if (!runargs(L, argv, script)) /* execute arguments -e and -l */
+ if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */
return 0; /* something failed */
- if (script < argc && /* execute main script (if there is one) */
- handle_script(L, argv + script) != LUA_OK)
- return 0;
+ if (script > 0) { /* execute main script (if there is one) */
+ if (handle_script(L, argv + script) != LUA_OK)
+ return 0; /* interrupt in case of error */
+ }
if (args & has_i) /* -i option? */
doREPL(L); /* do read-eval-print loop */
- else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */
+ else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */
if (lua_stdin_is_tty()) { /* running in interactive mode? */
print_version();
doREPL(L); /* do read-eval-print loop */
@@ -181517,6 +181783,7 @@ int main (int argc, char **argv) {
l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE;
}
+ lua_gc(L, LUA_GCSTOP); /* stop GC while building state */
lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
lua_pushinteger(L, argc); /* 1st argument */
lua_pushlightuserdata(L, argv); /* 2nd argument */
@@ -181533,7 +181800,7 @@ int main (int argc, char **argv) {
MIT License
Copyright (c) 1994–2019 Lua.org, PUC-Rio.
- Copyright (c) 2020-2022 Eduardo Bart (https://github.com/edubart).
+ Copyright (c) 2020-2023 Eduardo Bart (https://github.com/edubart).
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -181557,7 +181824,7 @@ int main (int argc, char **argv) {
#undef cast
#undef G
//---
-#line 1 "engine/split/3rd_stb_image.h"
+#line 1 "3rd_stb_image.h"
/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk
@@ -189546,7 +189813,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/
#line 0
-#line 1 "engine/split/3rd_stb_image_write.h"
+#line 1 "3rd_stb_image_write.h"
/* stb_image_write - v1.16 - public domain - http://nothings.org/stb
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk
@@ -191278,7 +191545,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define STBTT_free(x,u) ((void)(u),FREE(x))
#define NK_ASSERT ASSERT
#define NK_DTOA(s,n) strcpy(s, va("%f", n)) // override cos built-in nk_dtoa() will freeze while parsing UINT_MAX otherwise
-#line 1 "engine/split/3rd_nuklear.h"
+#line 1 "3rd_nuklear.h"
/*
/// # Nuklear
/// ![](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)
@@ -221650,7 +221917,7 @@ nk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args)
/// for his single header file packer.
*/
#line 0
-#line 1 "engine/split/3rd_nuklear_glfw_gl3.h"
+#line 1 "3rd_nuklear_glfw_gl3.h"
/*
* Nuklear - 1.32.0 - public domain
@@ -222205,7 +222472,7 @@ void nk_glfw3_shutdown(struct nk_glfw* glfw)
#endif
#line 0
static char *ui_filter = 0;
-#line 1 "engine/split/3rd_nuklear_filebrowser.h"
+#line 1 "3rd_nuklear_filebrowser.h"
// file browser for nuklear, based on https://github.com/vurtun/nuklear/blob/master/example/file_browser.c (public domain)
// - rlyeh, public domain
//
@@ -222698,7 +222965,7 @@ static struct nk_image icon_load_rect(unsigned id, unsigned w, unsigned h, unsig
//#include "3rd_assimp/postprocess.h"
//#pragma comment(lib, "3rd/3rd_assimp/x64/assimp")
#endif
-#line 1 "engine/split/3rd_json5.h"
+#line 1 "3rd_json5.h"
// JSON5 + SJSON parser module
//
// License:
@@ -223140,7 +223407,7 @@ int main() {
#endif // JSON5_C
#line 0
-#line 1 "engine/split/3rd_gjk.h"
+#line 1 "3rd_gjk.h"
// GJK distance algorithm. original code by @vurtun and @randygaul, public domain.
// [src] https://gist.github.com/vurtun/29727217c269a2fbf4c0ed9a1d11cb40
// - rlyeh, public domain.
@@ -223749,7 +224016,7 @@ gjk_result gjk_quad(float a_radius, float b_radius) {
#endif
#line 0
-#line 1 "engine/split/3rd_compress.h"
+#line 1 "3rd_compress.h"
// compress.c de/compressors into a single-file header
// - rlyeh, public domain
//
@@ -234590,7 +234857,7 @@ unsigned file_decode(FILE* in, FILE* out, FILE *logfile) { // multi decoder
#endif // COMPRESS_C
#line 0
-#line 1 "engine/split/3rd_archive.h"
+#line 1 "3rd_archive.h"
// archive.c pak/zip/tar/dir archivers
// - rlyeh, public domain
@@ -236219,7 +236486,7 @@ int main( int argc, char **argv ) {
#if is(win32)
#include // timeapi.h
#endif
-#line 1 "engine/split/3rd_thread.h"
+#line 1 "3rd_thread.h"
/*
------------------------------------------------------------------------------
Licensing information can be found at the end of the file.
@@ -237949,7 +238216,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/
#line 0
-#line 1 "engine/split/3rd_plmpeg.h"
+#line 1 "3rd_plmpeg.h"
/*
PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer
@@ -242215,7 +242482,7 @@ void plm_audio_matrix_transform(int s[32][3], int ss, float *d, int dp) {
#endif // PL_MPEG_IMPLEMENTATION
#line 0
-#line 1 "engine/split/3rd_jo_mpeg.h"
+#line 1 "3rd_jo_mpeg.h"
/* public domain Simple, Minimalistic, No Allocations MPEG writer - http://jonolick.com
*
* Latest revisions:
@@ -242482,7 +242749,7 @@ void jo_write_mpeg(FILE *fp, const unsigned char *bgrx, int width, int height, i
#endif
#line 0
//#define _RTL_RUN_ONCE _RTL_RUN_ONCE2 // __MINGW64__
-#line 1 "engine/split/3rd_https.h"
+#line 1 "3rd_https.h"
/*
------------------------------------------------------------------------------
Licensing information can be found at the end of the file.
@@ -289465,7 +289732,7 @@ int main() {
#line 0
#undef F2
#undef F3
-#line 1 "engine/split/3rd_enet.h"
+#line 1 "3rd_enet.h"
/**
* include/enet.h - a Single-Header auto-generated variant of enet.h library.
*
@@ -295606,7 +295873,7 @@ extern "C" {
#endif // ENET_INCLUDE_H
#line 0
#define tls_init tls_init2
-#line 1 "engine/split/3rd_bq_websocket.h"
+#line 1 "3rd_bq_websocket.h"
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
@@ -301969,7 +302236,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#endif // BQ_PLATFORM_IMPLEMENTATION
#line 0
-#line 1 "engine/split/3rd_simplex.h"
+#line 1 "3rd_simplex.h"
/** 1D, 2D, 3D and 4D float Perlin Simplex noise */
/** Original code, stefan gustavson (PD). */
@@ -302452,7 +302719,7 @@ float snoise4(float x, float y, float z, float w) {
#endif
#line 0
-#line 1 "engine/split/3rd_tfd.h"
+#line 1 "3rd_tfd.h"
/* If you are using a C++ compiler to compile tinyfiledialogs.c (maybe renamed with an extension ".cpp")
then comment out << extern "C" >> bellow in this header file) */
@@ -310512,7 +310779,7 @@ tinyfd_messageBox("The selected hexcolor is",
#endif // TFD_IMPLEMENTATION
#line 0
-#line 1 "engine/split/3rd_stb_sprintf.h"
+#line 1 "3rd_stb_sprintf.h"
// stb_sprintf - v1.10 - public domain snprintf() implementation
// originally by Jeff Roberts / RAD Game Tools, 2015/10/20
// http://github.com/nothings/stb
@@ -312421,7 +312688,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#line 0
#define g g2
-#line 1 "engine/split/3rd_xml.h"
+#line 1 "3rd_xml.h"
// original xml.h/xml.c files by tor andersson, public domain
#ifndef xml_h
@@ -312952,7 +313219,7 @@ struct xml *xml_parse(char *s, int preserve_white, char **errorp)
#endif
#line 0
#undef g
-#line 1 "engine/split/3rd_polychop.h"
+#line 1 "3rd_polychop.h"
/* Progressive Mesh type Polygon Reduction Algorithm
*
* 1998: Original version by Stan Melax (c) 1998
@@ -313373,7 +313640,7 @@ API void ProgressiveMesh(int vert_n, int vert_stride, const float *v, int tri_n,
else if(!strcmp(id, "held") && nargs ==1) push(ev, input_held(pop(ev))); \
else if(!strcmp(id, "up") && nargs ==1) push(ev, input_up(pop(ev))); \
else if(!strcmp(id, "idle") && nargs ==1) push(ev, input_idle(pop(ev)));
-#line 1 "engine/split/3rd_eval.h"
+#line 1 "3rd_eval.h"
/* A mathematical expression evaluator.
* It uses a recursive descent parser internally.
* Author: Werner Stoop
@@ -313883,7 +314150,7 @@ int main() {
}
#endif
#line 0
-#line 1 "engine/split/3rd_luadebugger.h"
+#line 1 "3rd_luadebugger.h"
/*
Copyright (c) 2023 Scott Lembcke and Howling Moon Software
@@ -315363,7 +315630,7 @@ int dbg_pcall(lua_State *lua, int nargs, int nresults, int msgh){
return err;
}
#line 0
-#line 1 "engine/split/3rd_base64.h"
+#line 1 "3rd_base64.h"
// base64 de/encoder. Based on code by Jon Mayo - November 13, 2003 (PUBLIC DOMAIN).
// - rlyeh, public domain
@@ -315392,7 +315659,7 @@ unsigned base64_bounds(unsigned size) {
char* base64_encode(const void *inp, unsigned inlen) { // free() after use
unsigned outlen = base64_bounds(inlen);
- char *out_ = malloc(outlen);
+ char *out_ = MALLOC(outlen);
out_[outlen] = 0;
uint_least32_t v;
@@ -315409,21 +315676,21 @@ char* base64_encode(const void *inp, unsigned inlen) { // free() after use
while (rem >= 6) {
rem -= 6;
if (io >= outlen)
- return (free(out_), 0); /* truncation is failure */
+ return (FREE(out_), NULL); /* truncation is failure */
out[io ++] = base64enc_tab[(v >> rem) & 63];
}
}
if (rem) {
v <<= (6 - rem);
if (io >= outlen)
- return (free(out_), 0); /* truncation is failure */
+ return (FREE(out_), NULL); /* truncation is failure */
out[io ++] = base64enc_tab[v & 63];
}
while(io&3) {
- if(io>=outlen) return (free(out_), 0); /* truncation is failure */
+ if(io>=outlen) return (FREE(out_), NULL); /* truncation is failure */
out[io++]='=';
}
- if(io>=outlen) return (free(out_), 0); /* no room for null terminator */
+ if(io>=outlen) return (FREE(out_), NULL); /* no room for null terminator */
out[io]=0;
return out_;
}
@@ -315505,6 +315772,4020 @@ array(char) base64_decode(const char *inp, unsigned inlen) { // array_free() aft
#endif // array_resize
#endif // BASE64_C
#line 0
+
+#if ENABLE_RPMALLOC
+#line 1 "3rd_rpmalloc.h"
+/* rpmalloc.h - Memory allocator - Public Domain - 2016 Mattias Jansson
+ *
+ * This library provides a cross-platform lock free thread caching malloc implementation in C11.
+ * The latest source code is always available at
+ *
+ * https://github.com/mjansson/rpmalloc
+ *
+ * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
+ *
+ */
+
+#pragma once
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__clang__) || defined(__GNUC__)
+# define RPMALLOC_EXPORT __attribute__((visibility("default")))
+# define RPMALLOC_ALLOCATOR
+# if (defined(__clang_major__) && (__clang_major__ < 4)) || (defined(__GNUC__) && defined(ENABLE_PRELOAD) && ENABLE_PRELOAD)
+# define RPMALLOC_ATTRIB_MALLOC
+# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
+# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size)
+# else
+# define RPMALLOC_ATTRIB_MALLOC __attribute__((__malloc__))
+# define RPMALLOC_ATTRIB_ALLOC_SIZE(size) __attribute__((alloc_size(size)))
+# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count, size) __attribute__((alloc_size(count, size)))
+# endif
+# define RPMALLOC_CDECL
+#elif defined(_MSC_VER)
+# define RPMALLOC_EXPORT
+# define RPMALLOC_ALLOCATOR __declspec(allocator) __declspec(restrict)
+# define RPMALLOC_ATTRIB_MALLOC
+# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
+# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)
+# define RPMALLOC_CDECL __cdecl
+#else
+# define RPMALLOC_EXPORT
+# define RPMALLOC_ALLOCATOR
+# define RPMALLOC_ATTRIB_MALLOC
+# define RPMALLOC_ATTRIB_ALLOC_SIZE(size)
+# define RPMALLOC_ATTRIB_ALLOC_SIZE2(count,size)
+# define RPMALLOC_CDECL
+#endif
+
+//! Define RPMALLOC_CONFIGURABLE to enable configuring sizes. Will introduce
+// a very small overhead due to some size calculations not being compile time constants
+#ifndef RPMALLOC_CONFIGURABLE
+#define RPMALLOC_CONFIGURABLE 0
+#endif
+
+//! Define RPMALLOC_FIRST_CLASS_HEAPS to enable heap based API (rpmalloc_heap_* functions).
+// Will introduce a very small overhead to track fully allocated spans in heaps
+#ifndef RPMALLOC_FIRST_CLASS_HEAPS
+#define RPMALLOC_FIRST_CLASS_HEAPS 0
+#endif
+
+//! Flag to rpaligned_realloc to not preserve content in reallocation
+#define RPMALLOC_NO_PRESERVE 1
+//! Flag to rpaligned_realloc to fail and return null pointer if grow cannot be done in-place,
+// in which case the original pointer is still valid (just like a call to realloc which failes to allocate
+// a new block).
+#define RPMALLOC_GROW_OR_FAIL 2
+
+typedef struct rpmalloc_global_statistics_t {
+ //! Current amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
+ size_t mapped;
+ //! Peak amount of virtual memory mapped, all of which might not have been committed (only if ENABLE_STATISTICS=1)
+ size_t mapped_peak;
+ //! Current amount of memory in global caches for small and medium sizes (<32KiB)
+ size_t cached;
+ //! Current amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
+ size_t huge_alloc;
+ //! Peak amount of memory allocated in huge allocations, i.e larger than LARGE_SIZE_LIMIT which is 2MiB by default (only if ENABLE_STATISTICS=1)
+ size_t huge_alloc_peak;
+ //! Total amount of memory mapped since initialization (only if ENABLE_STATISTICS=1)
+ size_t mapped_total;
+ //! Total amount of memory unmapped since initialization (only if ENABLE_STATISTICS=1)
+ size_t unmapped_total;
+} rpmalloc_global_statistics_t;
+
+typedef struct rpmalloc_thread_statistics_t {
+ //! Current number of bytes available in thread size class caches for small and medium sizes (<32KiB)
+ size_t sizecache;
+ //! Current number of bytes available in thread span caches for small and medium sizes (<32KiB)
+ size_t spancache;
+ //! Total number of bytes transitioned from thread cache to global cache (only if ENABLE_STATISTICS=1)
+ size_t thread_to_global;
+ //! Total number of bytes transitioned from global cache to thread cache (only if ENABLE_STATISTICS=1)
+ size_t global_to_thread;
+ //! Per span count statistics (only if ENABLE_STATISTICS=1)
+ struct {
+ //! Currently used number of spans
+ size_t current;
+ //! High water mark of spans used
+ size_t peak;
+ //! Number of spans transitioned to global cache
+ size_t to_global;
+ //! Number of spans transitioned from global cache
+ size_t from_global;
+ //! Number of spans transitioned to thread cache
+ size_t to_cache;
+ //! Number of spans transitioned from thread cache
+ size_t from_cache;
+ //! Number of spans transitioned to reserved state
+ size_t to_reserved;
+ //! Number of spans transitioned from reserved state
+ size_t from_reserved;
+ //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
+ size_t map_calls;
+ } span_use[64];
+ //! Per size class statistics (only if ENABLE_STATISTICS=1)
+ struct {
+ //! Current number of allocations
+ size_t alloc_current;
+ //! Peak number of allocations
+ size_t alloc_peak;
+ //! Total number of allocations
+ size_t alloc_total;
+ //! Total number of frees
+ size_t free_total;
+ //! Number of spans transitioned to cache
+ size_t spans_to_cache;
+ //! Number of spans transitioned from cache
+ size_t spans_from_cache;
+ //! Number of spans transitioned from reserved state
+ size_t spans_from_reserved;
+ //! Number of raw memory map calls (not hitting the reserve spans but resulting in actual OS mmap calls)
+ size_t map_calls;
+ } size_use[128];
+} rpmalloc_thread_statistics_t;
+
+typedef struct rpmalloc_config_t {
+ //! Map memory pages for the given number of bytes. The returned address MUST be
+ // aligned to the rpmalloc span size, which will always be a power of two.
+ // Optionally the function can store an alignment offset in the offset variable
+ // in case it performs alignment and the returned pointer is offset from the
+ // actual start of the memory region due to this alignment. The alignment offset
+ // will be passed to the memory unmap function. The alignment offset MUST NOT be
+ // larger than 65535 (storable in an uint16_t), if it is you must use natural
+ // alignment to shift it into 16 bits. If you set a memory_map function, you
+ // must also set a memory_unmap function or else the default implementation will
+ // be used for both. This function must be thread safe, it can be called by
+ // multiple threads simultaneously.
+ void* (*memory_map)(size_t size, size_t* offset);
+ //! Unmap the memory pages starting at address and spanning the given number of bytes.
+ // If release is set to non-zero, the unmap is for an entire span range as returned by
+ // a previous call to memory_map and that the entire range should be released. The
+ // release argument holds the size of the entire span range. If release is set to 0,
+ // the unmap is a partial decommit of a subset of the mapped memory range.
+ // If you set a memory_unmap function, you must also set a memory_map function or
+ // else the default implementation will be used for both. This function must be thread
+ // safe, it can be called by multiple threads simultaneously.
+ void (*memory_unmap)(void* address, size_t size, size_t offset, size_t release);
+ //! Called when an assert fails, if asserts are enabled. Will use the standard assert()
+ // if this is not set.
+ void (*error_callback)(const char* message);
+ //! Called when a call to map memory pages fails (out of memory). If this callback is
+ // not set or returns zero the library will return a null pointer in the allocation
+ // call. If this callback returns non-zero the map call will be retried. The argument
+ // passed is the number of bytes that was requested in the map call. Only used if
+ // the default system memory map function is used (memory_map callback is not set).
+ int (*map_fail_callback)(size_t size);
+ //! Size of memory pages. The page size MUST be a power of two. All memory mapping
+ // requests to memory_map will be made with size set to a multiple of the page size.
+ // Used if RPMALLOC_CONFIGURABLE is defined to 1, otherwise system page size is used.
+ size_t page_size;
+ //! Size of a span of memory blocks. MUST be a power of two, and in [4096,262144]
+ // range (unless 0 - set to 0 to use the default span size). Used if RPMALLOC_CONFIGURABLE
+ // is defined to 1.
+ size_t span_size;
+ //! Number of spans to map at each request to map new virtual memory blocks. This can
+ // be used to minimize the system call overhead at the cost of virtual memory address
+ // space. The extra mapped pages will not be written until actually used, so physical
+ // committed memory should not be affected in the default implementation. Will be
+ // aligned to a multiple of spans that match memory page size in case of huge pages.
+ size_t span_map_count;
+ //! Enable use of large/huge pages. If this flag is set to non-zero and page size is
+ // zero, the allocator will try to enable huge pages and auto detect the configuration.
+ // If this is set to non-zero and page_size is also non-zero, the allocator will
+ // assume huge pages have been configured and enabled prior to initializing the
+ // allocator.
+ // For Windows, see https://docs.microsoft.com/en-us/windows/desktop/memory/large-page-support
+ // For Linux, see https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
+ int enable_huge_pages;
+ //! Respectively allocated pages and huge allocated pages names for systems
+ // supporting it to be able to distinguish among anonymous regions.
+ const char *page_name;
+ const char *huge_page_name;
+} rpmalloc_config_t;
+
+//! Initialize allocator with default configuration
+RPMALLOC_EXPORT int
+rpmalloc_initialize(void);
+
+//! Initialize allocator with given configuration
+RPMALLOC_EXPORT int
+rpmalloc_initialize_config(const rpmalloc_config_t* config);
+
+//! Get allocator configuration
+RPMALLOC_EXPORT const rpmalloc_config_t*
+rpmalloc_config(void);
+
+//! Finalize allocator
+RPMALLOC_EXPORT void
+rpmalloc_finalize(void);
+
+//! Initialize allocator for calling thread
+RPMALLOC_EXPORT void
+rpmalloc_thread_initialize(void);
+
+//! Finalize allocator for calling thread
+RPMALLOC_EXPORT void
+rpmalloc_thread_finalize(int release_caches);
+
+//! Perform deferred deallocations pending for the calling thread heap
+RPMALLOC_EXPORT void
+rpmalloc_thread_collect(void);
+
+//! Query if allocator is initialized for calling thread
+RPMALLOC_EXPORT int
+rpmalloc_is_thread_initialized(void);
+
+//! Get per-thread statistics
+RPMALLOC_EXPORT void
+rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats);
+
+//! Get global statistics
+RPMALLOC_EXPORT void
+rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats);
+
+//! Dump all statistics in human readable format to file (should be a FILE*)
+RPMALLOC_EXPORT void
+rpmalloc_dump_statistics(void* file);
+
+//! Allocate a memory block of at least the given size
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc(size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(1);
+
+//! Free the given memory block
+RPMALLOC_EXPORT void
+rpfree(void* ptr);
+
+//! Allocate a memory block of at least the given size and zero initialize it
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpcalloc(size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(1, 2);
+
+//! Reallocate the given block to at least the given size
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rprealloc(void* ptr, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+//! Reallocate the given block to at least the given size and alignment,
+// with optional control flags (see RPMALLOC_NO_PRESERVE).
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
+
+//! Allocate a memory block of at least the given size and alignment.
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpaligned_alloc(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+//! Allocate a memory block of at least the given size and alignment, and zero initialize it.
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpaligned_calloc(size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
+
+//! Allocate a memory block of at least the given size and alignment.
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmemalign(size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+//! Allocate a memory block of at least the given size and alignment.
+// Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB)
+RPMALLOC_EXPORT int
+rpposix_memalign(void** memptr, size_t alignment, size_t size);
+
+//! Query the usable size of the given memory block (from given pointer to the end of block)
+RPMALLOC_EXPORT size_t
+rpmalloc_usable_size(void* ptr);
+
+//! Dummy empty function for forcing linker symbol inclusion
+RPMALLOC_EXPORT void
+rpmalloc_linker_reference(void);
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+
+//! Heap type
+typedef struct heap_t rpmalloc_heap_t;
+
+//! Acquire a new heap. Will reuse existing released heaps or allocate memory for a new heap
+// if none available. Heap API is implemented with the strict assumption that only one single
+// thread will call heap functions for a given heap at any given time, no functions are thread safe.
+RPMALLOC_EXPORT rpmalloc_heap_t*
+rpmalloc_heap_acquire(void);
+
+//! Release a heap (does NOT free the memory allocated by the heap, use rpmalloc_heap_free_all before destroying the heap).
+// Releasing a heap will enable it to be reused by other threads. Safe to pass a null pointer.
+RPMALLOC_EXPORT void
+rpmalloc_heap_release(rpmalloc_heap_t* heap);
+
+//! Allocate a memory block of at least the given size using the given heap.
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(2);
+
+//! Allocate a memory block of at least the given size using the given heap. The returned
+// block will have the requested alignment. Alignment must be a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB).
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
+
+//! Allocate a memory block of at least the given size using the given heap and zero initialize it.
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
+
+//! Allocate a memory block of at least the given size using the given heap and zero initialize it. The returned
+// block will have the requested alignment. Alignment must either be zero, or a power of two and a multiple of sizeof(void*),
+// and should ideally be less than memory page size. A caveat of rpmalloc
+// internals is that this must also be strictly less than the span size (default 64KiB).
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE2(2, 3);
+
+//! Reallocate the given block to at least the given size. The memory block MUST be allocated
+// by the same heap given to this function.
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(3);
+
+//! Reallocate the given block to at least the given size. The memory block MUST be allocated
+// by the same heap given to this function. The returned block will have the requested alignment.
+// Alignment must be either zero, or a power of two and a multiple of sizeof(void*), and should ideally be
+// less than memory page size. A caveat of rpmalloc internals is that this must also be strictly less than
+// the span size (default 64KiB).
+RPMALLOC_EXPORT RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) RPMALLOC_ATTRIB_MALLOC RPMALLOC_ATTRIB_ALLOC_SIZE(4);
+
+//! Free the given memory block from the given heap. The memory block MUST be allocated
+// by the same heap given to this function.
+RPMALLOC_EXPORT void
+rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr);
+
+//! Free all memory allocated by the heap
+RPMALLOC_EXPORT void
+rpmalloc_heap_free_all(rpmalloc_heap_t* heap);
+
+//! Set the given heap as the current heap for the calling thread. A heap MUST only be current heap
+// for a single thread, a heap can never be shared between multiple threads. The previous
+// current heap for the calling thread is released to be reused by other threads.
+RPMALLOC_EXPORT void
+rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap);
+
+//! Returns which heap the given pointer is allocated on
+RPMALLOC_EXPORT rpmalloc_heap_t*
+rpmalloc_get_heap_for_ptr(void* ptr);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#line 0
+#line 1 "3rd_rpmalloc.c"
+/* rpmalloc.c - Memory allocator - Public Domain - 2016-2020 Mattias Jansson
+ *
+ * This library provides a cross-platform lock free thread caching malloc implementation in C11.
+ * The latest source code is always available at
+ *
+ * https://github.com/mjansson/rpmalloc
+ *
+ * This library is put in the public domain; you can redistribute it and/or modify it without any restrictions.
+ *
+ */
+
+// #include "rpmalloc.h" //< @r-lyeh
+
+////////////
+///
+/// Build time configurable limits
+///
+//////
+
+#if defined(__clang__)
+#pragma clang diagnostic ignored "-Wunused-macros"
+#pragma clang diagnostic ignored "-Wunused-function"
+#if __has_warning("-Wreserved-identifier")
+#pragma clang diagnostic ignored "-Wreserved-identifier"
+#endif
+#if __has_warning("-Wstatic-in-inline")
+#pragma clang diagnostic ignored "-Wstatic-in-inline"
+#endif
+#elif defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wunused-macros"
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+#if !defined(__has_builtin)
+#define __has_builtin(b) 0
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+
+#if __has_builtin(__builtin_memcpy_inline)
+#define _rpmalloc_memcpy_const(x, y, s) __builtin_memcpy_inline(x, y, s)
+#else
+#define _rpmalloc_memcpy_const(x, y, s) \
+ do { \
+ _Static_assert(__builtin_choose_expr(__builtin_constant_p(s), 1, 0), "len must be a constant integer"); \
+ memcpy(x, y, s); \
+ } while (0)
+#endif
+
+#if __has_builtin(__builtin_memset_inline)
+#define _rpmalloc_memset_const(x, y, s) __builtin_memset_inline(x, y, s)
+#else
+#define _rpmalloc_memset_const(x, y, s) \
+ do { \
+ _Static_assert(__builtin_choose_expr(__builtin_constant_p(s), 1, 0), "len must be a constant integer"); \
+ memset(x, y, s); \
+ } while (0)
+#endif
+#else
+#define _rpmalloc_memcpy_const(x, y, s) memcpy(x, y, s)
+#define _rpmalloc_memset_const(x, y, s) memset(x, y, s)
+#endif
+
+#if __has_builtin(__builtin_assume)
+#define rpmalloc_assume(cond) __builtin_assume(cond)
+#elif defined(__GNUC__)
+#define rpmalloc_assume(cond) \
+ do { \
+ if (!__builtin_expect(cond, 0)) \
+ __builtin_unreachable(); \
+ } while (0)
+#elif defined(_MSC_VER)
+#define rpmalloc_assume(cond) __assume(cond)
+#else
+#define rpmalloc_assume(cond) 0
+#endif
+
+#ifndef HEAP_ARRAY_SIZE
+//! Size of heap hashmap
+#define HEAP_ARRAY_SIZE 47
+#endif
+#ifndef ENABLE_THREAD_CACHE
+//! Enable per-thread cache
+#define ENABLE_THREAD_CACHE 1
+#endif
+#ifndef ENABLE_GLOBAL_CACHE
+//! Enable global cache shared between all threads, requires thread cache
+#define ENABLE_GLOBAL_CACHE 1
+#endif
+#ifndef ENABLE_VALIDATE_ARGS
+//! Enable validation of args to public entry points
+#define ENABLE_VALIDATE_ARGS 0
+#endif
+#ifndef ENABLE_STATISTICS
+//! Enable statistics collection
+#define ENABLE_STATISTICS 0
+#endif
+#ifndef ENABLE_ASSERTS
+//! Enable asserts
+#define ENABLE_ASSERTS 0
+#endif
+#ifndef ENABLE_OVERRIDE
+//! Override standard library malloc/free and new/delete entry points
+#define ENABLE_OVERRIDE 0
+#endif
+#ifndef ENABLE_PRELOAD
+//! Support preloading
+#define ENABLE_PRELOAD 0
+#endif
+#ifndef DISABLE_UNMAP
+//! Disable unmapping memory pages (also enables unlimited cache)
+#define DISABLE_UNMAP 0
+#endif
+#ifndef ENABLE_UNLIMITED_CACHE
+//! Enable unlimited global cache (no unmapping until finalization)
+#define ENABLE_UNLIMITED_CACHE 0
+#endif
+#ifndef ENABLE_ADAPTIVE_THREAD_CACHE
+//! Enable adaptive thread cache size based on use heuristics
+#define ENABLE_ADAPTIVE_THREAD_CACHE 0
+#endif
+#ifndef DEFAULT_SPAN_MAP_COUNT
+//! Default number of spans to map in call to map more virtual memory (default values yield 4MiB here)
+#define DEFAULT_SPAN_MAP_COUNT 64
+#endif
+#ifndef GLOBAL_CACHE_MULTIPLIER
+//! Multiplier for global cache
+#define GLOBAL_CACHE_MULTIPLIER 8
+#endif
+
+#if DISABLE_UNMAP && !ENABLE_GLOBAL_CACHE
+#error Must use global cache if unmap is disabled
+#endif
+
+#if DISABLE_UNMAP
+#undef ENABLE_UNLIMITED_CACHE
+#define ENABLE_UNLIMITED_CACHE 1
+#endif
+
+#if !ENABLE_GLOBAL_CACHE
+#undef ENABLE_UNLIMITED_CACHE
+#define ENABLE_UNLIMITED_CACHE 0
+#endif
+
+#if !ENABLE_THREAD_CACHE
+#undef ENABLE_ADAPTIVE_THREAD_CACHE
+#define ENABLE_ADAPTIVE_THREAD_CACHE 0
+#endif
+
+#if defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
+# define PLATFORM_WINDOWS 1
+# define PLATFORM_POSIX 0
+#else
+# define PLATFORM_WINDOWS 0
+# define PLATFORM_POSIX 1
+#endif
+
+/// Platform and arch specifics
+#if defined(_MSC_VER) && !defined(__clang__)
+# pragma warning (disable: 5105)
+# ifndef FORCEINLINE
+# define FORCEINLINE inline __forceinline
+# endif
+# define _Static_assert static_assert
+#else
+# ifndef FORCEINLINE
+# define FORCEINLINE inline __attribute__((__always_inline__))
+# endif
+#endif
+#if PLATFORM_WINDOWS
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include
+# if ENABLE_VALIDATE_ARGS
+# include
+# endif
+#else
+# include
+# include
+# include
+# include
+# if defined(__linux__) || defined(__ANDROID__)
+# include
+# if !defined(PR_SET_VMA)
+# define PR_SET_VMA 0x53564d41
+# define PR_SET_VMA_ANON_NAME 0
+# endif
+# endif
+# if defined(__APPLE__)
+# include
+# if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+# include
+# include
+# endif
+# include
+# endif
+# if defined(__HAIKU__) || defined(__TINYC__)
+# include
+# endif
+#endif
+
+#include
+#include
+#include
+
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+#include
+static DWORD fls_key;
+#endif
+
+#if PLATFORM_POSIX
+# include
+# include
+# ifdef __FreeBSD__
+# include
+# define MAP_HUGETLB MAP_ALIGNED_SUPER
+# ifndef PROT_MAX
+# define PROT_MAX(f) 0
+# endif
+# else
+# define PROT_MAX(f) 0
+# endif
+# ifdef __sun
+extern int madvise(caddr_t, size_t, int);
+# endif
+# ifndef MAP_UNINITIALIZED
+# define MAP_UNINITIALIZED 0
+# endif
+#endif
+#include
+
+#if ENABLE_ASSERTS
+# undef NDEBUG
+# if defined(_MSC_VER) && !defined(_DEBUG)
+# define _DEBUG
+# endif
+# include
+#define RPMALLOC_TOSTRING_M(x) #x
+#define RPMALLOC_TOSTRING(x) RPMALLOC_TOSTRING_M(x)
+#define rpmalloc_assert(truth, message) \
+ do { \
+ if (!(truth)) { \
+ if (_memory_config.error_callback) { \
+ _memory_config.error_callback( \
+ message " (" RPMALLOC_TOSTRING(truth) ") at " __FILE__ ":" RPMALLOC_TOSTRING(__LINE__)); \
+ } else { \
+ assert((truth) && message); \
+ } \
+ } \
+ } while (0)
+#else
+# define rpmalloc_assert(truth, message) do {} while(0)
+#endif
+#if ENABLE_STATISTICS
+# include
+#endif
+
+//////
+///
+/// Atomic access abstraction (since MSVC does not do C11 yet)
+///
+//////
+
+#if defined(_MSC_VER) && !defined(__clang__)
+
+typedef volatile long atomic32_t;
+typedef volatile long long atomic64_t;
+typedef volatile void* atomicptr_t;
+
+static FORCEINLINE int32_t atomic_load32(atomic32_t* src) { return *src; }
+static FORCEINLINE void atomic_store32(atomic32_t* dst, int32_t val) { *dst = val; }
+static FORCEINLINE int32_t atomic_incr32(atomic32_t* val) { return (int32_t)InterlockedIncrement(val); }
+static FORCEINLINE int32_t atomic_decr32(atomic32_t* val) { return (int32_t)InterlockedDecrement(val); }
+static FORCEINLINE int32_t atomic_add32(atomic32_t* val, int32_t add) { return (int32_t)InterlockedExchangeAdd(val, add) + add; }
+static FORCEINLINE int atomic_cas32_acquire(atomic32_t* dst, int32_t val, int32_t ref) { return (InterlockedCompareExchange(dst, val, ref) == ref) ? 1 : 0; }
+static FORCEINLINE void atomic_store32_release(atomic32_t* dst, int32_t val) { *dst = val; }
+static FORCEINLINE int64_t atomic_load64(atomic64_t* src) { return *src; }
+static FORCEINLINE int64_t atomic_add64(atomic64_t* val, int64_t add) { return (int64_t)InterlockedExchangeAdd64(val, add) + add; }
+static FORCEINLINE void* atomic_load_ptr(atomicptr_t* src) { return (void*)*src; }
+static FORCEINLINE void atomic_store_ptr(atomicptr_t* dst, void* val) { *dst = val; }
+static FORCEINLINE void atomic_store_ptr_release(atomicptr_t* dst, void* val) { *dst = val; }
+static FORCEINLINE void* atomic_exchange_ptr_acquire(atomicptr_t* dst, void* val) { return (void*)InterlockedExchangePointer((void* volatile*)dst, val); }
+static FORCEINLINE int atomic_cas_ptr(atomicptr_t* dst, void* val, void* ref) { return (InterlockedCompareExchangePointer((void* volatile*)dst, val, ref) == ref) ? 1 : 0; }
+
+#define EXPECTED(x) (x)
+#define UNEXPECTED(x) (x)
+
+#else
+
+#include
+
+typedef volatile _Atomic(int32_t) atomic32_t;
+typedef volatile _Atomic(int64_t) atomic64_t;
+typedef volatile _Atomic(void*) atomicptr_t;
+
+static FORCEINLINE int32_t atomic_load32(atomic32_t* src) { return atomic_load_explicit(src, memory_order_relaxed); }
+static FORCEINLINE void atomic_store32(atomic32_t* dst, int32_t val) { atomic_store_explicit(dst, val, memory_order_relaxed); }
+static FORCEINLINE int32_t atomic_incr32(atomic32_t* val) { return atomic_fetch_add_explicit(val, 1, memory_order_relaxed) + 1; }
+static FORCEINLINE int32_t atomic_decr32(atomic32_t* val) { return atomic_fetch_add_explicit(val, -1, memory_order_relaxed) - 1; }
+static FORCEINLINE int32_t atomic_add32(atomic32_t* val, int32_t add) { return atomic_fetch_add_explicit(val, add, memory_order_relaxed) + add; }
+static FORCEINLINE int atomic_cas32_acquire(atomic32_t* dst, int32_t val, int32_t ref) { return atomic_compare_exchange_weak_explicit(dst, &ref, val, memory_order_acquire, memory_order_relaxed); }
+static FORCEINLINE void atomic_store32_release(atomic32_t* dst, int32_t val) { atomic_store_explicit(dst, val, memory_order_release); }
+static FORCEINLINE int64_t atomic_load64(atomic64_t* val) { return atomic_load_explicit(val, memory_order_relaxed); }
+static FORCEINLINE int64_t atomic_add64(atomic64_t* val, int64_t add) { return atomic_fetch_add_explicit(val, add, memory_order_relaxed) + add; }
+static FORCEINLINE void* atomic_load_ptr(atomicptr_t* src) { return atomic_load_explicit(src, memory_order_relaxed); }
+static FORCEINLINE void atomic_store_ptr(atomicptr_t* dst, void* val) { atomic_store_explicit(dst, val, memory_order_relaxed); }
+static FORCEINLINE void atomic_store_ptr_release(atomicptr_t* dst, void* val) { atomic_store_explicit(dst, val, memory_order_release); }
+static FORCEINLINE void* atomic_exchange_ptr_acquire(atomicptr_t* dst, void* val) { return atomic_exchange_explicit(dst, val, memory_order_acquire); }
+static FORCEINLINE int atomic_cas_ptr(atomicptr_t* dst, void* val, void* ref) { return atomic_compare_exchange_weak_explicit(dst, &ref, val, memory_order_relaxed, memory_order_relaxed); }
+
+#define EXPECTED(x) __builtin_expect((x), 1)
+#define UNEXPECTED(x) __builtin_expect((x), 0)
+
+#endif
+
+////////////
+///
+/// Statistics related functions (evaluate to nothing when statistics not enabled)
+///
+//////
+
+#if ENABLE_STATISTICS
+# define _rpmalloc_stat_inc(counter) atomic_incr32(counter)
+# define _rpmalloc_stat_dec(counter) atomic_decr32(counter)
+# define _rpmalloc_stat_add(counter, value) atomic_add32(counter, (int32_t)(value))
+# define _rpmalloc_stat_add64(counter, value) atomic_add64(counter, (int64_t)(value))
+# define _rpmalloc_stat_add_peak(counter, value, peak) do { int32_t _cur_count = atomic_add32(counter, (int32_t)(value)); if (_cur_count > (peak)) peak = _cur_count; } while (0)
+# define _rpmalloc_stat_sub(counter, value) atomic_add32(counter, -(int32_t)(value))
+# define _rpmalloc_stat_inc_alloc(heap, class_idx) do { \
+ int32_t alloc_current = atomic_incr32(&heap->size_class_use[class_idx].alloc_current); \
+ if (alloc_current > heap->size_class_use[class_idx].alloc_peak) \
+ heap->size_class_use[class_idx].alloc_peak = alloc_current; \
+ atomic_incr32(&heap->size_class_use[class_idx].alloc_total); \
+} while(0)
+# define _rpmalloc_stat_inc_free(heap, class_idx) do { \
+ atomic_decr32(&heap->size_class_use[class_idx].alloc_current); \
+ atomic_incr32(&heap->size_class_use[class_idx].free_total); \
+} while(0)
+#else
+# define _rpmalloc_stat_inc(counter) do {} while(0)
+# define _rpmalloc_stat_dec(counter) do {} while(0)
+# define _rpmalloc_stat_add(counter, value) do {} while(0)
+# define _rpmalloc_stat_add64(counter, value) do {} while(0)
+# define _rpmalloc_stat_add_peak(counter, value, peak) do {} while (0)
+# define _rpmalloc_stat_sub(counter, value) do {} while(0)
+# define _rpmalloc_stat_inc_alloc(heap, class_idx) do {} while(0)
+# define _rpmalloc_stat_inc_free(heap, class_idx) do {} while(0)
+#endif
+
+
+///
+/// Preconfigured limits and sizes
+///
+
+//! Granularity of a small allocation block (must be power of two)
+#define SMALL_GRANULARITY 16
+//! Small granularity shift count
+#define SMALL_GRANULARITY_SHIFT 4
+//! Number of small block size classes
+#define SMALL_CLASS_COUNT 65
+//! Maximum size of a small block
+#define SMALL_SIZE_LIMIT (SMALL_GRANULARITY * (SMALL_CLASS_COUNT - 1))
+//! Granularity of a medium allocation block
+#define MEDIUM_GRANULARITY 512
+//! Medium granularity shift count
+#define MEDIUM_GRANULARITY_SHIFT 9
+//! Number of medium block size classes
+#define MEDIUM_CLASS_COUNT 61
+//! Total number of small + medium size classes
+#define SIZE_CLASS_COUNT (SMALL_CLASS_COUNT + MEDIUM_CLASS_COUNT)
+//! Number of large block size classes
+#define LARGE_CLASS_COUNT 63
+//! Maximum size of a medium block
+#define MEDIUM_SIZE_LIMIT (SMALL_SIZE_LIMIT + (MEDIUM_GRANULARITY * MEDIUM_CLASS_COUNT))
+//! Maximum size of a large block
+#define LARGE_SIZE_LIMIT ((LARGE_CLASS_COUNT * _memory_span_size) - SPAN_HEADER_SIZE)
+//! Size of a span header (must be a multiple of SMALL_GRANULARITY and a power of two)
+#define SPAN_HEADER_SIZE 128
+//! Number of spans in thread cache
+#define MAX_THREAD_SPAN_CACHE 400
+//! Number of spans to transfer between thread and global cache
+#define THREAD_SPAN_CACHE_TRANSFER 64
+//! Number of spans in thread cache for large spans (must be greater than LARGE_CLASS_COUNT / 2)
+#define MAX_THREAD_SPAN_LARGE_CACHE 100
+//! Number of spans to transfer between thread and global cache for large spans
+#define THREAD_SPAN_LARGE_CACHE_TRANSFER 6
+
+_Static_assert((SMALL_GRANULARITY & (SMALL_GRANULARITY - 1)) == 0, "Small granularity must be power of two");
+_Static_assert((SPAN_HEADER_SIZE & (SPAN_HEADER_SIZE - 1)) == 0, "Span header size must be power of two");
+
+#if ENABLE_VALIDATE_ARGS
+//! Maximum allocation size to avoid integer overflow
+#undef MAX_ALLOC_SIZE
+#define MAX_ALLOC_SIZE (((size_t)-1) - _memory_span_size)
+#endif
+
+#define pointer_offset(ptr, ofs) (void*)((char*)(ptr) + (ptrdiff_t)(ofs))
+#define pointer_diff(first, second) (ptrdiff_t)((const char*)(first) - (const char*)(second))
+
+#define INVALID_POINTER ((void*)((uintptr_t)-1))
+
+#define SIZE_CLASS_LARGE SIZE_CLASS_COUNT
+#define SIZE_CLASS_HUGE ((uint32_t)-1)
+
+////////////
+///
+/// Data types
+///
+//////
+
+//! A memory heap, per thread
+typedef struct heap_t heap_t;
+//! Span of memory pages
+typedef struct span_t span_t;
+//! Span list
+typedef struct span_list_t span_list_t;
+//! Span active data
+typedef struct span_active_t span_active_t;
+//! Size class definition
+typedef struct size_class_t size_class_t;
+//! Global cache
+typedef struct global_cache_t global_cache_t;
+
+//! Flag indicating span is the first (master) span of a split superspan
+#define SPAN_FLAG_MASTER 1U
+//! Flag indicating span is a secondary (sub) span of a split superspan
+#define SPAN_FLAG_SUBSPAN 2U
+//! Flag indicating span has blocks with increased alignment
+#define SPAN_FLAG_ALIGNED_BLOCKS 4U
+//! Flag indicating an unmapped master span
+#define SPAN_FLAG_UNMAPPED_MASTER 8U
+
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+struct span_use_t {
+ //! Current number of spans used (actually used, not in cache)
+ atomic32_t current;
+ //! High water mark of spans used
+ atomic32_t high;
+#if ENABLE_STATISTICS
+ //! Number of spans in deferred list
+ atomic32_t spans_deferred;
+ //! Number of spans transitioned to global cache
+ atomic32_t spans_to_global;
+ //! Number of spans transitioned from global cache
+ atomic32_t spans_from_global;
+ //! Number of spans transitioned to thread cache
+ atomic32_t spans_to_cache;
+ //! Number of spans transitioned from thread cache
+ atomic32_t spans_from_cache;
+ //! Number of spans transitioned to reserved state
+ atomic32_t spans_to_reserved;
+ //! Number of spans transitioned from reserved state
+ atomic32_t spans_from_reserved;
+ //! Number of raw memory map calls
+ atomic32_t spans_map_calls;
+#endif
+};
+typedef struct span_use_t span_use_t;
+#endif
+
+#if ENABLE_STATISTICS
+struct size_class_use_t {
+ //! Current number of allocations
+ atomic32_t alloc_current;
+ //! Peak number of allocations
+ int32_t alloc_peak;
+ //! Total number of allocations
+ atomic32_t alloc_total;
+ //! Total number of frees
+ atomic32_t free_total;
+ //! Number of spans in use
+ atomic32_t spans_current;
+ //! Number of spans transitioned to cache
+ int32_t spans_peak;
+ //! Number of spans transitioned to cache
+ atomic32_t spans_to_cache;
+ //! Number of spans transitioned from cache
+ atomic32_t spans_from_cache;
+ //! Number of spans transitioned from reserved state
+ atomic32_t spans_from_reserved;
+ //! Number of spans mapped
+ atomic32_t spans_map_calls;
+ int32_t unused;
+};
+typedef struct size_class_use_t size_class_use_t;
+#endif
+
+// A span can either represent a single span of memory pages with size declared by span_map_count configuration variable,
+// or a set of spans in a continuous region, a super span. Any reference to the term "span" usually refers to both a single
+// span or a super span. A super span can further be divided into multiple spans (or this, super spans), where the first
+// (super)span is the master and subsequent (super)spans are subspans. The master span keeps track of how many subspans
+// that are still alive and mapped in virtual memory, and once all subspans and master have been unmapped the entire
+// superspan region is released and unmapped (on Windows for example, the entire superspan range has to be released
+// in the same call to release the virtual memory range, but individual subranges can be decommitted individually
+// to reduce physical memory use).
+struct span_t {
+ //! Free list
+ void* free_list;
+ //! Total block count of size class
+ uint32_t block_count;
+ //! Size class
+ uint32_t size_class;
+ //! Index of last block initialized in free list
+ uint32_t free_list_limit;
+ //! Number of used blocks remaining when in partial state
+ uint32_t used_count;
+ //! Deferred free list
+ atomicptr_t free_list_deferred;
+ //! Size of deferred free list, or list of spans when part of a cache list
+ uint32_t list_size;
+ //! Size of a block
+ uint32_t block_size;
+ //! Flags and counters
+ uint32_t flags;
+ //! Number of spans
+ uint32_t span_count;
+ //! Total span counter for master spans
+ uint32_t total_spans;
+ //! Offset from master span for subspans
+ uint32_t offset_from_master;
+ //! Remaining span counter, for master spans
+ atomic32_t remaining_spans;
+ //! Alignment offset
+ uint32_t align_offset;
+ //! Owning heap
+ heap_t* heap;
+ //! Next span
+ span_t* next;
+ //! Previous span
+ span_t* prev;
+};
+_Static_assert(sizeof(span_t) <= SPAN_HEADER_SIZE, "span size mismatch");
+
+struct span_cache_t {
+ size_t count;
+ span_t* span[MAX_THREAD_SPAN_CACHE];
+};
+typedef struct span_cache_t span_cache_t;
+
+struct span_large_cache_t {
+ size_t count;
+ span_t* span[MAX_THREAD_SPAN_LARGE_CACHE];
+};
+typedef struct span_large_cache_t span_large_cache_t;
+
+struct heap_size_class_t {
+ //! Free list of active span
+ void* free_list;
+ //! Double linked list of partially used spans with free blocks.
+ // Previous span pointer in head points to tail span of list.
+ span_t* partial_span;
+ //! Early level cache of fully free spans
+ span_t* cache;
+};
+typedef struct heap_size_class_t heap_size_class_t;
+
+// Control structure for a heap, either a thread heap or a first class heap if enabled
+struct heap_t {
+ //! Owning thread ID
+ uintptr_t owner_thread;
+ //! Free lists for each size class
+ heap_size_class_t size_class[SIZE_CLASS_COUNT];
+#if ENABLE_THREAD_CACHE
+ //! Arrays of fully freed spans, single span
+ span_cache_t span_cache;
+#endif
+ //! List of deferred free spans (single linked list)
+ atomicptr_t span_free_deferred;
+ //! Number of full spans
+ size_t full_span_count;
+ //! Mapped but unused spans
+ span_t* span_reserve;
+ //! Master span for mapped but unused spans
+ span_t* span_reserve_master;
+ //! Number of mapped but unused spans
+ uint32_t spans_reserved;
+ //! Child count
+ atomic32_t child_count;
+ //! Next heap in id list
+ heap_t* next_heap;
+ //! Next heap in orphan list
+ heap_t* next_orphan;
+ //! Heap ID
+ int32_t id;
+ //! Finalization state flag
+ int finalize;
+ //! Master heap owning the memory pages
+ heap_t* master_heap;
+#if ENABLE_THREAD_CACHE
+ //! Arrays of fully freed spans, large spans with > 1 span count
+ span_large_cache_t span_large_cache[LARGE_CLASS_COUNT - 1];
+#endif
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ //! Double linked list of fully utilized spans with free blocks for each size class.
+ // Previous span pointer in head points to tail span of list.
+ span_t* full_span[SIZE_CLASS_COUNT];
+ //! Double linked list of large and huge spans allocated by this heap
+ span_t* large_huge_span;
+#endif
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+ //! Current and high water mark of spans used per span count
+ span_use_t span_use[LARGE_CLASS_COUNT];
+#endif
+#if ENABLE_STATISTICS
+ //! Allocation stats per size class
+ size_class_use_t size_class_use[SIZE_CLASS_COUNT + 1];
+ //! Number of bytes transitioned thread -> global
+ atomic64_t thread_to_global;
+ //! Number of bytes transitioned global -> thread
+ atomic64_t global_to_thread;
+#endif
+};
+
+// Size class for defining a block size bucket
+struct size_class_t {
+ //! Size of blocks in this class
+ uint32_t block_size;
+ //! Number of blocks in each chunk
+ uint16_t block_count;
+ //! Class index this class is merged with
+ uint16_t class_idx;
+};
+_Static_assert(sizeof(size_class_t) == 8, "Size class size mismatch");
+
+struct global_cache_t {
+ //! Cache lock
+ atomic32_t lock;
+ //! Cache count
+ uint32_t count;
+#if ENABLE_STATISTICS
+ //! Insert count
+ size_t insert_count;
+ //! Extract count
+ size_t extract_count;
+#endif
+ //! Cached spans
+ span_t* span[GLOBAL_CACHE_MULTIPLIER * MAX_THREAD_SPAN_CACHE];
+ //! Unlimited cache overflow
+ span_t* overflow;
+};
+
+////////////
+///
+/// Global data
+///
+//////
+
+//! Default span size (64KiB)
+#define _memory_default_span_size (64 * 1024)
+#define _memory_default_span_size_shift 16
+#define _memory_default_span_mask (~((uintptr_t)(_memory_span_size - 1)))
+
+//! Initialized flag
+static int _rpmalloc_initialized;
+//! Main thread ID
+static uintptr_t _rpmalloc_main_thread_id;
+//! Configuration
+static rpmalloc_config_t _memory_config;
+//! Memory page size
+static size_t _memory_page_size;
+//! Shift to divide by page size
+static size_t _memory_page_size_shift;
+//! Granularity at which memory pages are mapped by OS
+static size_t _memory_map_granularity;
+#if RPMALLOC_CONFIGURABLE
+//! Size of a span of memory pages
+static size_t _memory_span_size;
+//! Shift to divide by span size
+static size_t _memory_span_size_shift;
+//! Mask to get to start of a memory span
+static uintptr_t _memory_span_mask;
+#else
+//! Hardwired span size
+#define _memory_span_size _memory_default_span_size
+#define _memory_span_size_shift _memory_default_span_size_shift
+#define _memory_span_mask _memory_default_span_mask
+#endif
+//! Number of spans to map in each map call
+static size_t _memory_span_map_count;
+//! Number of spans to keep reserved in each heap
+static size_t _memory_heap_reserve_count;
+//! Global size classes
+static size_class_t _memory_size_class[SIZE_CLASS_COUNT];
+//! Run-time size limit of medium blocks
+static size_t _memory_medium_size_limit;
+//! Heap ID counter
+static atomic32_t _memory_heap_id;
+//! Huge page support
+static int _memory_huge_pages;
+#if ENABLE_GLOBAL_CACHE
+//! Global span cache
+static global_cache_t _memory_span_cache[LARGE_CLASS_COUNT];
+#endif
+//! Global reserved spans
+static span_t* _memory_global_reserve;
+//! Global reserved count
+static size_t _memory_global_reserve_count;
+//! Global reserved master
+static span_t* _memory_global_reserve_master;
+//! All heaps
+static heap_t* _memory_heaps[HEAP_ARRAY_SIZE];
+//! Used to restrict access to mapping memory for huge pages
+static atomic32_t _memory_global_lock;
+//! Orphaned heaps
+static heap_t* _memory_orphan_heaps;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+//! Orphaned heaps (first class heaps)
+static heap_t* _memory_first_class_orphan_heaps;
+#endif
+#if ENABLE_STATISTICS
+//! Allocations counter
+static atomic64_t _allocation_counter;
+//! Deallocations counter
+static atomic64_t _deallocation_counter;
+//! Active heap count
+static atomic32_t _memory_active_heaps;
+//! Number of currently mapped memory pages
+static atomic32_t _mapped_pages;
+//! Peak number of concurrently mapped memory pages
+static int32_t _mapped_pages_peak;
+//! Number of mapped master spans
+static atomic32_t _master_spans;
+//! Number of unmapped dangling master spans
+static atomic32_t _unmapped_master_spans;
+//! Running counter of total number of mapped memory pages since start
+static atomic32_t _mapped_total;
+//! Running counter of total number of unmapped memory pages since start
+static atomic32_t _unmapped_total;
+//! Number of currently mapped memory pages in OS calls
+static atomic32_t _mapped_pages_os;
+//! Number of currently allocated pages in huge allocations
+static atomic32_t _huge_pages_current;
+//! Peak number of currently allocated pages in huge allocations
+static int32_t _huge_pages_peak;
+#endif
+
+////////////
+///
+/// Thread local heap and ID
+///
+//////
+
+//! Current thread heap
+#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)
+static pthread_key_t _memory_thread_heap;
+#else
+# ifdef _MSC_VER
+# define _Thread_local __declspec(thread)
+# define TLS_MODEL
+# else
+# ifndef __HAIKU__
+# define TLS_MODEL __attribute__((tls_model("initial-exec")))
+# else
+# define TLS_MODEL
+# endif
+# if !defined(__clang__) && defined(__GNUC__)
+# define _Thread_local __thread
+# endif
+# endif
+static _Thread_local heap_t* _memory_thread_heap TLS_MODEL;
+#endif
+
+static inline heap_t*
+get_thread_heap_raw(void) {
+#if (defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD
+ return pthread_getspecific(_memory_thread_heap);
+#else
+ return _memory_thread_heap;
+#endif
+}
+
+//! Get the current thread heap
+static inline heap_t*
+get_thread_heap(void) {
+ heap_t* heap = get_thread_heap_raw();
+#if ENABLE_PRELOAD
+ if (EXPECTED(heap != 0))
+ return heap;
+ rpmalloc_initialize();
+ return get_thread_heap_raw();
+#else
+ return heap;
+#endif
+}
+
+//! Fast thread ID
+static inline uintptr_t
+get_thread_id(void) {
+#if defined(_WIN32)
+ return (uintptr_t)((void*)NtCurrentTeb());
+#elif (defined(__GNUC__) || defined(__clang__)) && !defined(__CYGWIN__)
+ uintptr_t tid;
+# if defined(__i386__)
+ __asm__("movl %%gs:0, %0" : "=r" (tid) : : );
+# elif defined(__x86_64__)
+# if defined(__MACH__)
+ __asm__("movq %%gs:0, %0" : "=r" (tid) : : );
+# else
+ __asm__("movq %%fs:0, %0" : "=r" (tid) : : );
+# endif
+# elif defined(__arm__)
+ __asm__ volatile ("mrc p15, 0, %0, c13, c0, 3" : "=r" (tid));
+# elif defined(__aarch64__)
+# if defined(__MACH__)
+ // tpidr_el0 likely unused, always return 0 on iOS
+ __asm__ volatile ("mrs %0, tpidrro_el0" : "=r" (tid));
+# else
+ __asm__ volatile ("mrs %0, tpidr_el0" : "=r" (tid));
+# endif
+# else
+# error This platform needs implementation of get_thread_id()
+# endif
+ return tid;
+#else
+# error This platform needs implementation of get_thread_id()
+#endif
+}
+
+//! Set the current thread heap
+static void
+set_thread_heap(heap_t* heap) {
+#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)
+ pthread_setspecific(_memory_thread_heap, heap);
+#else
+ _memory_thread_heap = heap;
+#endif
+ if (heap)
+ heap->owner_thread = get_thread_id();
+}
+
+//! Set main thread ID
+extern void
+rpmalloc_set_main_thread(void);
+
+void
+rpmalloc_set_main_thread(void) {
+ _rpmalloc_main_thread_id = get_thread_id();
+}
+
+static void
+_rpmalloc_spin(void) {
+#if defined(_MSC_VER)
+ _mm_pause();
+#elif defined(__x86_64__) || defined(__i386__)
+ __asm__ volatile("pause" ::: "memory");
+#elif defined(__aarch64__) || (defined(__arm__) && __ARM_ARCH >= 7)
+ __asm__ volatile("yield" ::: "memory");
+#elif defined(__powerpc__) || defined(__powerpc64__)
+ // No idea if ever been compiled in such archs but ... as precaution
+ __asm__ volatile("or 27,27,27");
+#elif defined(__sparc__)
+ __asm__ volatile("rd %ccr, %g0 \n\trd %ccr, %g0 \n\trd %ccr, %g0");
+#else
+ struct timespec ts = {0};
+ nanosleep(&ts, 0);
+#endif
+}
+
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+static void NTAPI
+_rpmalloc_thread_destructor(void* value) {
+#if ENABLE_OVERRIDE
+ // If this is called on main thread it means rpmalloc_finalize
+ // has not been called and shutdown is forced (through _exit) or unclean
+ if (get_thread_id() == _rpmalloc_main_thread_id)
+ return;
+#endif
+ if (value)
+ rpmalloc_thread_finalize(1);
+}
+#endif
+
+
+////////////
+///
+/// Low level memory map/unmap
+///
+//////
+
+static void
+_rpmalloc_set_name(void* address, size_t size) {
+#if defined(__linux__) || defined(__ANDROID__)
+ const char *name = _memory_huge_pages ? _memory_config.huge_page_name : _memory_config.page_name;
+ if (address == MAP_FAILED || !name)
+ return;
+ // If the kernel does not support CONFIG_ANON_VMA_NAME or if the call fails
+ // (e.g. invalid name) it is a no-op basically.
+ (void)prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (uintptr_t)address, size, (uintptr_t)name);
+#else
+ (void)sizeof(size);
+ (void)sizeof(address);
+#endif
+}
+
+
+//! Map more virtual memory
+// size is number of bytes to map
+// offset receives the offset in bytes from start of mapped region
+// returns address to start of mapped region to use
+static void*
+_rpmalloc_mmap(size_t size, size_t* offset) {
+ rpmalloc_assert(!(size % _memory_page_size), "Invalid mmap size");
+ rpmalloc_assert(size >= _memory_page_size, "Invalid mmap size");
+ void* address = _memory_config.memory_map(size, offset);
+ if (EXPECTED(address != 0)) {
+ _rpmalloc_stat_add_peak(&_mapped_pages, (size >> _memory_page_size_shift), _mapped_pages_peak);
+ _rpmalloc_stat_add(&_mapped_total, (size >> _memory_page_size_shift));
+ }
+ return address;
+}
+
+//! Unmap virtual memory
+// address is the memory address to unmap, as returned from _memory_map
+// size is the number of bytes to unmap, which might be less than full region for a partial unmap
+// offset is the offset in bytes to the actual mapped region, as set by _memory_map
+// release is set to 0 for partial unmap, or size of entire range for a full unmap
+static void
+_rpmalloc_unmap(void* address, size_t size, size_t offset, size_t release) {
+ rpmalloc_assert(!release || (release >= size), "Invalid unmap size");
+ rpmalloc_assert(!release || (release >= _memory_page_size), "Invalid unmap size");
+ if (release) {
+ rpmalloc_assert(!(release % _memory_page_size), "Invalid unmap size");
+ _rpmalloc_stat_sub(&_mapped_pages, (release >> _memory_page_size_shift));
+ _rpmalloc_stat_add(&_unmapped_total, (release >> _memory_page_size_shift));
+ }
+ _memory_config.memory_unmap(address, size, offset, release);
+}
+
+//! Default implementation to map new pages to virtual memory
+static void*
+_rpmalloc_mmap_os(size_t size, size_t* offset) {
+ //Either size is a heap (a single page) or a (multiple) span - we only need to align spans, and only if larger than map granularity
+ size_t padding = ((size >= _memory_span_size) && (_memory_span_size > _memory_map_granularity)) ? _memory_span_size : 0;
+ rpmalloc_assert(size >= _memory_page_size, "Invalid mmap size");
+#if PLATFORM_WINDOWS
+ //Ok to MEM_COMMIT - according to MSDN, "actual physical pages are not allocated unless/until the virtual addresses are actually accessed"
+ void* ptr = VirtualAlloc(0, size + padding, (_memory_huge_pages ? MEM_LARGE_PAGES : 0) | MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ if (!ptr) {
+ if (_memory_config.map_fail_callback) {
+ if (_memory_config.map_fail_callback(size + padding))
+ return _rpmalloc_mmap_os(size, offset);
+ } else {
+ rpmalloc_assert(ptr, "Failed to map virtual memory block");
+ }
+ return 0;
+ }
+#else
+ int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_UNINITIALIZED;
+# if defined(__APPLE__) && !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+ int fd = (int)VM_MAKE_TAG(240U);
+ if (_memory_huge_pages)
+ fd |= VM_FLAGS_SUPERPAGE_SIZE_2MB;
+ void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, fd, 0);
+# elif defined(MAP_HUGETLB)
+ void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE | PROT_MAX(PROT_READ | PROT_WRITE), (_memory_huge_pages ? MAP_HUGETLB : 0) | flags, -1, 0);
+# if defined(MADV_HUGEPAGE)
+ // In some configurations, huge pages allocations might fail thus
+ // we fallback to normal allocations and promote the region as transparent huge page
+ if ((ptr == MAP_FAILED || !ptr) && _memory_huge_pages) {
+ ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, -1, 0);
+ if (ptr && ptr != MAP_FAILED) {
+ int prm = madvise(ptr, size + padding, MADV_HUGEPAGE);
+ (void)prm;
+ rpmalloc_assert((prm == 0), "Failed to promote the page to THP");
+ }
+ }
+# endif
+ _rpmalloc_set_name(ptr, size + padding);
+# elif defined(MAP_ALIGNED)
+ const size_t align = (sizeof(size_t) * 8) - (size_t)(__builtin_clzl(size - 1));
+ void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, (_memory_huge_pages ? MAP_ALIGNED(align) : 0) | flags, -1, 0);
+# elif defined(MAP_ALIGN)
+ caddr_t base = (_memory_huge_pages ? (caddr_t)(4 << 20) : 0);
+ void* ptr = mmap(base, size + padding, PROT_READ | PROT_WRITE, (_memory_huge_pages ? MAP_ALIGN : 0) | flags, -1, 0);
+# else
+ void* ptr = mmap(0, size + padding, PROT_READ | PROT_WRITE, flags, -1, 0);
+# endif
+ if ((ptr == MAP_FAILED) || !ptr) {
+ if (_memory_config.map_fail_callback) {
+ if (_memory_config.map_fail_callback(size + padding))
+ return _rpmalloc_mmap_os(size, offset);
+ } else if (errno != ENOMEM) {
+ rpmalloc_assert((ptr != MAP_FAILED) && ptr, "Failed to map virtual memory block");
+ }
+ return 0;
+ }
+#endif
+ _rpmalloc_stat_add(&_mapped_pages_os, (int32_t)((size + padding) >> _memory_page_size_shift));
+ if (padding) {
+ size_t final_padding = padding - ((uintptr_t)ptr & ~_memory_span_mask);
+ rpmalloc_assert(final_padding <= _memory_span_size, "Internal failure in padding");
+ rpmalloc_assert(final_padding <= padding, "Internal failure in padding");
+ rpmalloc_assert(!(final_padding % 8), "Internal failure in padding");
+ ptr = pointer_offset(ptr, final_padding);
+ *offset = final_padding >> 3;
+ }
+ rpmalloc_assert((size < _memory_span_size) || !((uintptr_t)ptr & ~_memory_span_mask), "Internal failure in padding");
+ return ptr;
+}
+
+//! Default implementation to unmap pages from virtual memory
+static void
+_rpmalloc_unmap_os(void* address, size_t size, size_t offset, size_t release) {
+ rpmalloc_assert(release || (offset == 0), "Invalid unmap size");
+ rpmalloc_assert(!release || (release >= _memory_page_size), "Invalid unmap size");
+ rpmalloc_assert(size >= _memory_page_size, "Invalid unmap size");
+ if (release && offset) {
+ offset <<= 3;
+ address = pointer_offset(address, -(int32_t)offset);
+ if ((release >= _memory_span_size) && (_memory_span_size > _memory_map_granularity)) {
+ //Padding is always one span size
+ release += _memory_span_size;
+ }
+ }
+#if !DISABLE_UNMAP
+#if PLATFORM_WINDOWS
+ if (!VirtualFree(address, release ? 0 : size, release ? MEM_RELEASE : MEM_DECOMMIT)) {
+ rpmalloc_assert(0, "Failed to unmap virtual memory block");
+ }
+#else
+ if (release) {
+ if (munmap(address, release)) {
+ rpmalloc_assert(0, "Failed to unmap virtual memory block");
+ }
+ } else {
+#if defined(MADV_FREE_REUSABLE)
+ int ret;
+ while ((ret = madvise(address, size, MADV_FREE_REUSABLE)) == -1 && (errno == EAGAIN))
+ errno = 0;
+ if ((ret == -1) && (errno != 0)) {
+#elif defined(MADV_DONTNEED)
+ if (madvise(address, size, MADV_DONTNEED)) {
+#elif defined(MADV_PAGEOUT)
+ if (madvise(address, size, MADV_PAGEOUT)) {
+#elif defined(MADV_FREE)
+ if (madvise(address, size, MADV_FREE)) {
+#else
+ if (posix_madvise(address, size, POSIX_MADV_DONTNEED)) {
+#endif
+ rpmalloc_assert(0, "Failed to madvise virtual memory block as free");
+ }
+ }
+#endif
+#endif
+ if (release)
+ _rpmalloc_stat_sub(&_mapped_pages_os, release >> _memory_page_size_shift);
+}
+
+static void
+_rpmalloc_span_mark_as_subspan_unless_master(span_t* master, span_t* subspan, size_t span_count);
+
+//! Use global reserved spans to fulfill a memory map request (reserve size must be checked by caller)
+static span_t*
+_rpmalloc_global_get_reserved_spans(size_t span_count) {
+ span_t* span = _memory_global_reserve;
+ _rpmalloc_span_mark_as_subspan_unless_master(_memory_global_reserve_master, span, span_count);
+ _memory_global_reserve_count -= span_count;
+ if (_memory_global_reserve_count)
+ _memory_global_reserve = (span_t*)pointer_offset(span, span_count << _memory_span_size_shift);
+ else
+ _memory_global_reserve = 0;
+ return span;
+}
+
+//! Store the given spans as global reserve (must only be called from within new heap allocation, not thread safe)
+static void
+_rpmalloc_global_set_reserved_spans(span_t* master, span_t* reserve, size_t reserve_span_count) {
+ _memory_global_reserve_master = master;
+ _memory_global_reserve_count = reserve_span_count;
+ _memory_global_reserve = reserve;
+}
+
+
+////////////
+///
+/// Span linked list management
+///
+//////
+
+//! Add a span to double linked list at the head
+static void
+_rpmalloc_span_double_link_list_add(span_t** head, span_t* span) {
+ if (*head)
+ (*head)->prev = span;
+ span->next = *head;
+ *head = span;
+}
+
+//! Pop head span from double linked list
+static void
+_rpmalloc_span_double_link_list_pop_head(span_t** head, span_t* span) {
+ rpmalloc_assert(*head == span, "Linked list corrupted");
+ span = *head;
+ *head = span->next;
+}
+
+//! Remove a span from double linked list
+static void
+_rpmalloc_span_double_link_list_remove(span_t** head, span_t* span) {
+ rpmalloc_assert(*head, "Linked list corrupted");
+ if (*head == span) {
+ *head = span->next;
+ } else {
+ span_t* next_span = span->next;
+ span_t* prev_span = span->prev;
+ prev_span->next = next_span;
+ if (EXPECTED(next_span != 0))
+ next_span->prev = prev_span;
+ }
+}
+
+
+////////////
+///
+/// Span control
+///
+//////
+
+static void
+_rpmalloc_heap_cache_insert(heap_t* heap, span_t* span);
+
+static void
+_rpmalloc_heap_finalize(heap_t* heap);
+
+static void
+_rpmalloc_heap_set_reserved_spans(heap_t* heap, span_t* master, span_t* reserve, size_t reserve_span_count);
+
+//! Declare the span to be a subspan and store distance from master span and span count
+static void
+_rpmalloc_span_mark_as_subspan_unless_master(span_t* master, span_t* subspan, size_t span_count) {
+ rpmalloc_assert((subspan != master) || (subspan->flags & SPAN_FLAG_MASTER), "Span master pointer and/or flag mismatch");
+ if (subspan != master) {
+ subspan->flags = SPAN_FLAG_SUBSPAN;
+ subspan->offset_from_master = (uint32_t)((uintptr_t)pointer_diff(subspan, master) >> _memory_span_size_shift);
+ subspan->align_offset = 0;
+ }
+ subspan->span_count = (uint32_t)span_count;
+}
+
+//! Use reserved spans to fulfill a memory map request (reserve size must be checked by caller)
+static span_t*
+_rpmalloc_span_map_from_reserve(heap_t* heap, size_t span_count) {
+ //Update the heap span reserve
+ span_t* span = heap->span_reserve;
+ heap->span_reserve = (span_t*)pointer_offset(span, span_count * _memory_span_size);
+ heap->spans_reserved -= (uint32_t)span_count;
+
+ _rpmalloc_span_mark_as_subspan_unless_master(heap->span_reserve_master, span, span_count);
+ if (span_count <= LARGE_CLASS_COUNT)
+ _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_from_reserved);
+
+ return span;
+}
+
+//! Get the aligned number of spans to map in based on wanted count, configured mapping granularity and the page size
+static size_t
+_rpmalloc_span_align_count(size_t span_count) {
+ size_t request_count = (span_count > _memory_span_map_count) ? span_count : _memory_span_map_count;
+ if ((_memory_page_size > _memory_span_size) && ((request_count * _memory_span_size) % _memory_page_size))
+ request_count += _memory_span_map_count - (request_count % _memory_span_map_count);
+ return request_count;
+}
+
+//! Setup a newly mapped span
+static void
+_rpmalloc_span_initialize(span_t* span, size_t total_span_count, size_t span_count, size_t align_offset) {
+ span->total_spans = (uint32_t)total_span_count;
+ span->span_count = (uint32_t)span_count;
+ span->align_offset = (uint32_t)align_offset;
+ span->flags = SPAN_FLAG_MASTER;
+ atomic_store32(&span->remaining_spans, (int32_t)total_span_count);
+}
+
+static void
+_rpmalloc_span_unmap(span_t* span);
+
+//! Map an aligned set of spans, taking configured mapping granularity and the page size into account
+static span_t*
+_rpmalloc_span_map_aligned_count(heap_t* heap, size_t span_count) {
+ //If we already have some, but not enough, reserved spans, release those to heap cache and map a new
+ //full set of spans. Otherwise we would waste memory if page size > span size (huge pages)
+ size_t aligned_span_count = _rpmalloc_span_align_count(span_count);
+ size_t align_offset = 0;
+ span_t* span = (span_t*)_rpmalloc_mmap(aligned_span_count * _memory_span_size, &align_offset);
+ if (!span)
+ return 0;
+ _rpmalloc_span_initialize(span, aligned_span_count, span_count, align_offset);
+ _rpmalloc_stat_inc(&_master_spans);
+ if (span_count <= LARGE_CLASS_COUNT)
+ _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_map_calls);
+ if (aligned_span_count > span_count) {
+ span_t* reserved_spans = (span_t*)pointer_offset(span, span_count * _memory_span_size);
+ size_t reserved_count = aligned_span_count - span_count;
+ if (heap->spans_reserved) {
+ _rpmalloc_span_mark_as_subspan_unless_master(heap->span_reserve_master, heap->span_reserve, heap->spans_reserved);
+ _rpmalloc_heap_cache_insert(heap, heap->span_reserve);
+ }
+ if (reserved_count > _memory_heap_reserve_count) {
+ // If huge pages or eager spam map count, the global reserve spin lock is held by caller, _rpmalloc_span_map
+ rpmalloc_assert(atomic_load32(&_memory_global_lock) == 1, "Global spin lock not held as expected");
+ size_t remain_count = reserved_count - _memory_heap_reserve_count;
+ reserved_count = _memory_heap_reserve_count;
+ span_t* remain_span = (span_t*)pointer_offset(reserved_spans, reserved_count * _memory_span_size);
+ if (_memory_global_reserve) {
+ _rpmalloc_span_mark_as_subspan_unless_master(_memory_global_reserve_master, _memory_global_reserve, _memory_global_reserve_count);
+ _rpmalloc_span_unmap(_memory_global_reserve);
+ }
+ _rpmalloc_global_set_reserved_spans(span, remain_span, remain_count);
+ }
+ _rpmalloc_heap_set_reserved_spans(heap, span, reserved_spans, reserved_count);
+ }
+ return span;
+}
+
+//! Map in memory pages for the given number of spans (or use previously reserved pages)
+static span_t*
+_rpmalloc_span_map(heap_t* heap, size_t span_count) {
+ if (span_count <= heap->spans_reserved)
+ return _rpmalloc_span_map_from_reserve(heap, span_count);
+ span_t* span = 0;
+ int use_global_reserve = (_memory_page_size > _memory_span_size) || (_memory_span_map_count > _memory_heap_reserve_count);
+ if (use_global_reserve) {
+ // If huge pages, make sure only one thread maps more memory to avoid bloat
+ while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))
+ _rpmalloc_spin();
+ if (_memory_global_reserve_count >= span_count) {
+ size_t reserve_count = (!heap->spans_reserved ? _memory_heap_reserve_count : span_count);
+ if (_memory_global_reserve_count < reserve_count)
+ reserve_count = _memory_global_reserve_count;
+ span = _rpmalloc_global_get_reserved_spans(reserve_count);
+ if (span) {
+ if (reserve_count > span_count) {
+ span_t* reserved_span = (span_t*)pointer_offset(span, span_count << _memory_span_size_shift);
+ _rpmalloc_heap_set_reserved_spans(heap, _memory_global_reserve_master, reserved_span, reserve_count - span_count);
+ }
+ // Already marked as subspan in _rpmalloc_global_get_reserved_spans
+ span->span_count = (uint32_t)span_count;
+ }
+ }
+ }
+ if (!span)
+ span = _rpmalloc_span_map_aligned_count(heap, span_count);
+ if (use_global_reserve)
+ atomic_store32_release(&_memory_global_lock, 0);
+ return span;
+}
+
+//! Unmap memory pages for the given number of spans (or mark as unused if no partial unmappings)
+static void
+_rpmalloc_span_unmap(span_t* span) {
+ rpmalloc_assert((span->flags & SPAN_FLAG_MASTER) || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ rpmalloc_assert(!(span->flags & SPAN_FLAG_MASTER) || !(span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+
+ int is_master = !!(span->flags & SPAN_FLAG_MASTER);
+ span_t* master = is_master ? span : ((span_t*)pointer_offset(span, -(intptr_t)((uintptr_t)span->offset_from_master * _memory_span_size)));
+ rpmalloc_assert(is_master || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ rpmalloc_assert(master->flags & SPAN_FLAG_MASTER, "Span flag corrupted");
+
+ size_t span_count = span->span_count;
+ if (!is_master) {
+ //Directly unmap subspans (unless huge pages, in which case we defer and unmap entire page range with master)
+ rpmalloc_assert(span->align_offset == 0, "Span align offset corrupted");
+ if (_memory_span_size >= _memory_page_size)
+ _rpmalloc_unmap(span, span_count * _memory_span_size, 0, 0);
+ } else {
+ //Special double flag to denote an unmapped master
+ //It must be kept in memory since span header must be used
+ span->flags |= SPAN_FLAG_MASTER | SPAN_FLAG_SUBSPAN | SPAN_FLAG_UNMAPPED_MASTER;
+ _rpmalloc_stat_add(&_unmapped_master_spans, 1);
+ }
+
+ if (atomic_add32(&master->remaining_spans, -(int32_t)span_count) <= 0) {
+ //Everything unmapped, unmap the master span with release flag to unmap the entire range of the super span
+ rpmalloc_assert(!!(master->flags & SPAN_FLAG_MASTER) && !!(master->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ size_t unmap_count = master->span_count;
+ if (_memory_span_size < _memory_page_size)
+ unmap_count = master->total_spans;
+ _rpmalloc_stat_sub(&_master_spans, 1);
+ _rpmalloc_stat_sub(&_unmapped_master_spans, 1);
+ _rpmalloc_unmap(master, unmap_count * _memory_span_size, master->align_offset, (size_t)master->total_spans * _memory_span_size);
+ }
+}
+
+//! Move the span (used for small or medium allocations) to the heap thread cache
+static void
+_rpmalloc_span_release_to_cache(heap_t* heap, span_t* span) {
+ rpmalloc_assert(heap == span->heap, "Span heap pointer corrupted");
+ rpmalloc_assert(span->size_class < SIZE_CLASS_COUNT, "Invalid span size class");
+ rpmalloc_assert(span->span_count == 1, "Invalid span count");
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+ atomic_decr32(&heap->span_use[0].current);
+#endif
+ _rpmalloc_stat_dec(&heap->size_class_use[span->size_class].spans_current);
+ if (!heap->finalize) {
+ _rpmalloc_stat_inc(&heap->span_use[0].spans_to_cache);
+ _rpmalloc_stat_inc(&heap->size_class_use[span->size_class].spans_to_cache);
+ if (heap->size_class[span->size_class].cache)
+ _rpmalloc_heap_cache_insert(heap, heap->size_class[span->size_class].cache);
+ heap->size_class[span->size_class].cache = span;
+ } else {
+ _rpmalloc_span_unmap(span);
+ }
+}
+
+//! Initialize a (partial) free list up to next system memory page, while reserving the first block
+//! as allocated, returning number of blocks in list
+static uint32_t
+free_list_partial_init(void** list, void** first_block, void* page_start, void* block_start, uint32_t block_count, uint32_t block_size) {
+ rpmalloc_assert(block_count, "Internal failure");
+ *first_block = block_start;
+ if (block_count > 1) {
+ void* free_block = pointer_offset(block_start, block_size);
+ void* block_end = pointer_offset(block_start, (size_t)block_size * block_count);
+ //If block size is less than half a memory page, bound init to next memory page boundary
+ if (block_size < (_memory_page_size >> 1)) {
+ void* page_end = pointer_offset(page_start, _memory_page_size);
+ if (page_end < block_end)
+ block_end = page_end;
+ }
+ *list = free_block;
+ block_count = 2;
+ void* next_block = pointer_offset(free_block, block_size);
+ while (next_block < block_end) {
+ *((void**)free_block) = next_block;
+ free_block = next_block;
+ ++block_count;
+ next_block = pointer_offset(next_block, block_size);
+ }
+ *((void**)free_block) = 0;
+ } else {
+ *list = 0;
+ }
+ return block_count;
+}
+
+//! Initialize an unused span (from cache or mapped) to be new active span, putting the initial free list in heap class free list
+static void*
+_rpmalloc_span_initialize_new(heap_t* heap, heap_size_class_t* heap_size_class, span_t* span, uint32_t class_idx) {
+ rpmalloc_assert(span->span_count == 1, "Internal failure");
+ size_class_t* size_class = _memory_size_class + class_idx;
+ span->size_class = class_idx;
+ span->heap = heap;
+ span->flags &= ~SPAN_FLAG_ALIGNED_BLOCKS;
+ span->block_size = size_class->block_size;
+ span->block_count = size_class->block_count;
+ span->free_list = 0;
+ span->list_size = 0;
+ atomic_store_ptr_release(&span->free_list_deferred, 0);
+
+ //Setup free list. Only initialize one system page worth of free blocks in list
+ void* block;
+ span->free_list_limit = free_list_partial_init(&heap_size_class->free_list, &block,
+ span, pointer_offset(span, SPAN_HEADER_SIZE), size_class->block_count, size_class->block_size);
+ //Link span as partial if there remains blocks to be initialized as free list, or full if fully initialized
+ if (span->free_list_limit < span->block_count) {
+ _rpmalloc_span_double_link_list_add(&heap_size_class->partial_span, span);
+ span->used_count = span->free_list_limit;
+ } else {
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->full_span[class_idx], span);
+#endif
+ ++heap->full_span_count;
+ span->used_count = span->block_count;
+ }
+ return block;
+}
+
+static void
+_rpmalloc_span_extract_free_list_deferred(span_t* span) {
+ // We need acquire semantics on the CAS operation since we are interested in the list size
+ // Refer to _rpmalloc_deallocate_defer_small_or_medium for further comments on this dependency
+ do {
+ span->free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);
+ } while (span->free_list == INVALID_POINTER);
+ span->used_count -= span->list_size;
+ span->list_size = 0;
+ atomic_store_ptr_release(&span->free_list_deferred, 0);
+}
+
+static int
+_rpmalloc_span_is_fully_utilized(span_t* span) {
+ rpmalloc_assert(span->free_list_limit <= span->block_count, "Span free list corrupted");
+ return !span->free_list && (span->free_list_limit >= span->block_count);
+}
+
+static int
+_rpmalloc_span_finalize(heap_t* heap, size_t iclass, span_t* span, span_t** list_head) {
+ void* free_list = heap->size_class[iclass].free_list;
+ span_t* class_span = (span_t*)((uintptr_t)free_list & _memory_span_mask);
+ if (span == class_span) {
+ // Adopt the heap class free list back into the span free list
+ void* block = span->free_list;
+ void* last_block = 0;
+ while (block) {
+ last_block = block;
+ block = *((void**)block);
+ }
+ uint32_t free_count = 0;
+ block = free_list;
+ while (block) {
+ ++free_count;
+ block = *((void**)block);
+ }
+ if (last_block) {
+ *((void**)last_block) = free_list;
+ } else {
+ span->free_list = free_list;
+ }
+ heap->size_class[iclass].free_list = 0;
+ span->used_count -= free_count;
+ }
+ //If this assert triggers you have memory leaks
+ rpmalloc_assert(span->list_size == span->used_count, "Memory leak detected");
+ if (span->list_size == span->used_count) {
+ _rpmalloc_stat_dec(&heap->span_use[0].current);
+ _rpmalloc_stat_dec(&heap->size_class_use[iclass].spans_current);
+ // This function only used for spans in double linked lists
+ if (list_head)
+ _rpmalloc_span_double_link_list_remove(list_head, span);
+ _rpmalloc_span_unmap(span);
+ return 1;
+ }
+ return 0;
+}
+
+
+////////////
+///
+/// Global cache
+///
+//////
+
+#if ENABLE_GLOBAL_CACHE
+
+//! Finalize a global cache
+static void
+_rpmalloc_global_cache_finalize(global_cache_t* cache) {
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+
+ for (size_t ispan = 0; ispan < cache->count; ++ispan)
+ _rpmalloc_span_unmap(cache->span[ispan]);
+ cache->count = 0;
+
+ while (cache->overflow) {
+ span_t* span = cache->overflow;
+ cache->overflow = span->next;
+ _rpmalloc_span_unmap(span);
+ }
+
+ atomic_store32_release(&cache->lock, 0);
+}
+
+static void
+_rpmalloc_global_cache_insert_spans(span_t** span, size_t span_count, size_t count) {
+ const size_t cache_limit = (span_count == 1) ?
+ GLOBAL_CACHE_MULTIPLIER * MAX_THREAD_SPAN_CACHE :
+ GLOBAL_CACHE_MULTIPLIER * (MAX_THREAD_SPAN_LARGE_CACHE - (span_count >> 1));
+
+ global_cache_t* cache = &_memory_span_cache[span_count - 1];
+
+ size_t insert_count = count;
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+
+#if ENABLE_STATISTICS
+ cache->insert_count += count;
+#endif
+ if ((cache->count + insert_count) > cache_limit)
+ insert_count = cache_limit - cache->count;
+
+ memcpy(cache->span + cache->count, span, sizeof(span_t*) * insert_count);
+ cache->count += (uint32_t)insert_count;
+
+#if ENABLE_UNLIMITED_CACHE
+ while (insert_count < count) {
+#else
+ // Enable unlimited cache if huge pages, or we will leak since it is unlikely that an entire huge page
+ // will be unmapped, and we're unable to partially decommit a huge page
+ while ((_memory_page_size > _memory_span_size) && (insert_count < count)) {
+#endif
+ span_t* current_span = span[insert_count++];
+ current_span->next = cache->overflow;
+ cache->overflow = current_span;
+ }
+ atomic_store32_release(&cache->lock, 0);
+
+ span_t* keep = 0;
+ for (size_t ispan = insert_count; ispan < count; ++ispan) {
+ span_t* current_span = span[ispan];
+ // Keep master spans that has remaining subspans to avoid dangling them
+ if ((current_span->flags & SPAN_FLAG_MASTER) &&
+ (atomic_load32(¤t_span->remaining_spans) > (int32_t)current_span->span_count)) {
+ current_span->next = keep;
+ keep = current_span;
+ } else {
+ _rpmalloc_span_unmap(current_span);
+ }
+ }
+
+ if (keep) {
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+
+ size_t islot = 0;
+ while (keep) {
+ for (; islot < cache->count; ++islot) {
+ span_t* current_span = cache->span[islot];
+ if (!(current_span->flags & SPAN_FLAG_MASTER) || ((current_span->flags & SPAN_FLAG_MASTER) &&
+ (atomic_load32(¤t_span->remaining_spans) <= (int32_t)current_span->span_count))) {
+ _rpmalloc_span_unmap(current_span);
+ cache->span[islot] = keep;
+ break;
+ }
+ }
+ if (islot == cache->count)
+ break;
+ keep = keep->next;
+ }
+
+ if (keep) {
+ span_t* tail = keep;
+ while (tail->next)
+ tail = tail->next;
+ tail->next = cache->overflow;
+ cache->overflow = keep;
+ }
+
+ atomic_store32_release(&cache->lock, 0);
+ }
+}
+
+static size_t
+_rpmalloc_global_cache_extract_spans(span_t** span, size_t span_count, size_t count) {
+ global_cache_t* cache = &_memory_span_cache[span_count - 1];
+
+ size_t extract_count = 0;
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+
+#if ENABLE_STATISTICS
+ cache->extract_count += count;
+#endif
+ size_t want = count - extract_count;
+ if (want > cache->count)
+ want = cache->count;
+
+ memcpy(span + extract_count, cache->span + (cache->count - want), sizeof(span_t*) * want);
+ cache->count -= (uint32_t)want;
+ extract_count += want;
+
+ while ((extract_count < count) && cache->overflow) {
+ span_t* current_span = cache->overflow;
+ span[extract_count++] = current_span;
+ cache->overflow = current_span->next;
+ }
+
+#if ENABLE_ASSERTS
+ for (size_t ispan = 0; ispan < extract_count; ++ispan) {
+ rpmalloc_assert(span[ispan]->span_count == span_count, "Global cache span count mismatch");
+ }
+#endif
+
+ atomic_store32_release(&cache->lock, 0);
+
+ return extract_count;
+}
+
+#endif
+
+////////////
+///
+/// Heap control
+///
+//////
+
+static void _rpmalloc_deallocate_huge(span_t*);
+
+//! Store the given spans as reserve in the given heap
+static void
+_rpmalloc_heap_set_reserved_spans(heap_t* heap, span_t* master, span_t* reserve, size_t reserve_span_count) {
+ heap->span_reserve_master = master;
+ heap->span_reserve = reserve;
+ heap->spans_reserved = (uint32_t)reserve_span_count;
+}
+
+//! Adopt the deferred span cache list, optionally extracting the first single span for immediate re-use
+static void
+_rpmalloc_heap_cache_adopt_deferred(heap_t* heap, span_t** single_span) {
+ span_t* span = (span_t*)((void*)atomic_exchange_ptr_acquire(&heap->span_free_deferred, 0));
+ while (span) {
+ span_t* next_span = (span_t*)span->free_list;
+ rpmalloc_assert(span->heap == heap, "Span heap pointer corrupted");
+ if (EXPECTED(span->size_class < SIZE_CLASS_COUNT)) {
+ rpmalloc_assert(heap->full_span_count, "Heap span counter corrupted");
+ --heap->full_span_count;
+ _rpmalloc_stat_dec(&heap->span_use[0].spans_deferred);
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&heap->full_span[span->size_class], span);
+#endif
+ _rpmalloc_stat_dec(&heap->span_use[0].current);
+ _rpmalloc_stat_dec(&heap->size_class_use[span->size_class].spans_current);
+ if (single_span && !*single_span)
+ *single_span = span;
+ else
+ _rpmalloc_heap_cache_insert(heap, span);
+ } else {
+ if (span->size_class == SIZE_CLASS_HUGE) {
+ _rpmalloc_deallocate_huge(span);
+ } else {
+ rpmalloc_assert(span->size_class == SIZE_CLASS_LARGE, "Span size class invalid");
+ rpmalloc_assert(heap->full_span_count, "Heap span counter corrupted");
+ --heap->full_span_count;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&heap->large_huge_span, span);
+#endif
+ uint32_t idx = span->span_count - 1;
+ _rpmalloc_stat_dec(&heap->span_use[idx].spans_deferred);
+ _rpmalloc_stat_dec(&heap->span_use[idx].current);
+ if (!idx && single_span && !*single_span)
+ *single_span = span;
+ else
+ _rpmalloc_heap_cache_insert(heap, span);
+ }
+ }
+ span = next_span;
+ }
+}
+
+static void
+_rpmalloc_heap_unmap(heap_t* heap) {
+ if (!heap->master_heap) {
+ if ((heap->finalize > 1) && !atomic_load32(&heap->child_count)) {
+ span_t* span = (span_t*)((uintptr_t)heap & _memory_span_mask);
+ _rpmalloc_span_unmap(span);
+ }
+ } else {
+ if (atomic_decr32(&heap->master_heap->child_count) == 0) {
+ _rpmalloc_heap_unmap(heap->master_heap);
+ }
+ }
+}
+
+static void
+_rpmalloc_heap_global_finalize(heap_t* heap) {
+ if (heap->finalize++ > 1) {
+ --heap->finalize;
+ return;
+ }
+
+ _rpmalloc_heap_finalize(heap);
+
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+ span_cache->count = 0;
+ }
+#endif
+
+ if (heap->full_span_count) {
+ --heap->finalize;
+ return;
+ }
+
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ if (heap->size_class[iclass].free_list || heap->size_class[iclass].partial_span) {
+ --heap->finalize;
+ return;
+ }
+ }
+ //Heap is now completely free, unmap and remove from heap list
+ size_t list_idx = (size_t)heap->id % HEAP_ARRAY_SIZE;
+ heap_t* list_heap = _memory_heaps[list_idx];
+ if (list_heap == heap) {
+ _memory_heaps[list_idx] = heap->next_heap;
+ } else {
+ while (list_heap->next_heap != heap)
+ list_heap = list_heap->next_heap;
+ list_heap->next_heap = heap->next_heap;
+ }
+
+ _rpmalloc_heap_unmap(heap);
+}
+
+//! Insert a single span into thread heap cache, releasing to global cache if overflow
+static void
+_rpmalloc_heap_cache_insert(heap_t* heap, span_t* span) {
+ if (UNEXPECTED(heap->finalize != 0)) {
+ _rpmalloc_span_unmap(span);
+ _rpmalloc_heap_global_finalize(heap);
+ return;
+ }
+#if ENABLE_THREAD_CACHE
+ size_t span_count = span->span_count;
+ _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_to_cache);
+ if (span_count == 1) {
+ span_cache_t* span_cache = &heap->span_cache;
+ span_cache->span[span_cache->count++] = span;
+ if (span_cache->count == MAX_THREAD_SPAN_CACHE) {
+ const size_t remain_count = MAX_THREAD_SPAN_CACHE - THREAD_SPAN_CACHE_TRANSFER;
+#if ENABLE_GLOBAL_CACHE
+ _rpmalloc_stat_add64(&heap->thread_to_global, THREAD_SPAN_CACHE_TRANSFER * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_to_global, THREAD_SPAN_CACHE_TRANSFER);
+ _rpmalloc_global_cache_insert_spans(span_cache->span + remain_count, span_count, THREAD_SPAN_CACHE_TRANSFER);
+#else
+ for (size_t ispan = 0; ispan < THREAD_SPAN_CACHE_TRANSFER; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[remain_count + ispan]);
+#endif
+ span_cache->count = remain_count;
+ }
+ } else {
+ size_t cache_idx = span_count - 2;
+ span_large_cache_t* span_cache = heap->span_large_cache + cache_idx;
+ span_cache->span[span_cache->count++] = span;
+ const size_t cache_limit = (MAX_THREAD_SPAN_LARGE_CACHE - (span_count >> 1));
+ if (span_cache->count == cache_limit) {
+ const size_t transfer_limit = 2 + (cache_limit >> 2);
+ const size_t transfer_count = (THREAD_SPAN_LARGE_CACHE_TRANSFER <= transfer_limit ? THREAD_SPAN_LARGE_CACHE_TRANSFER : transfer_limit);
+ const size_t remain_count = cache_limit - transfer_count;
+#if ENABLE_GLOBAL_CACHE
+ _rpmalloc_stat_add64(&heap->thread_to_global, transfer_count * span_count * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_to_global, transfer_count);
+ _rpmalloc_global_cache_insert_spans(span_cache->span + remain_count, span_count, transfer_count);
+#else
+ for (size_t ispan = 0; ispan < transfer_count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[remain_count + ispan]);
+#endif
+ span_cache->count = remain_count;
+ }
+ }
+#else
+ (void)sizeof(heap);
+ _rpmalloc_span_unmap(span);
+#endif
+}
+
+//! Extract the given number of spans from the different cache levels
+static span_t*
+_rpmalloc_heap_thread_cache_extract(heap_t* heap, size_t span_count) {
+ span_t* span = 0;
+#if ENABLE_THREAD_CACHE
+ span_cache_t* span_cache;
+ if (span_count == 1)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (span_count - 2));
+ if (span_cache->count) {
+ _rpmalloc_stat_inc(&heap->span_use[span_count - 1].spans_from_cache);
+ return span_cache->span[--span_cache->count];
+ }
+#endif
+ return span;
+}
+
+static span_t*
+_rpmalloc_heap_thread_cache_deferred_extract(heap_t* heap, size_t span_count) {
+ span_t* span = 0;
+ if (span_count == 1) {
+ _rpmalloc_heap_cache_adopt_deferred(heap, &span);
+ } else {
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+ span = _rpmalloc_heap_thread_cache_extract(heap, span_count);
+ }
+ return span;
+}
+
+static span_t*
+_rpmalloc_heap_reserved_extract(heap_t* heap, size_t span_count) {
+ if (heap->spans_reserved >= span_count)
+ return _rpmalloc_span_map(heap, span_count);
+ return 0;
+}
+
+//! Extract a span from the global cache
+static span_t*
+_rpmalloc_heap_global_cache_extract(heap_t* heap, size_t span_count) {
+#if ENABLE_GLOBAL_CACHE
+#if ENABLE_THREAD_CACHE
+ span_cache_t* span_cache;
+ size_t wanted_count;
+ if (span_count == 1) {
+ span_cache = &heap->span_cache;
+ wanted_count = THREAD_SPAN_CACHE_TRANSFER;
+ } else {
+ span_cache = (span_cache_t*)(heap->span_large_cache + (span_count - 2));
+ wanted_count = THREAD_SPAN_LARGE_CACHE_TRANSFER;
+ }
+ span_cache->count = _rpmalloc_global_cache_extract_spans(span_cache->span, span_count, wanted_count);
+ if (span_cache->count) {
+ _rpmalloc_stat_add64(&heap->global_to_thread, span_count * span_cache->count * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_from_global, span_cache->count);
+ return span_cache->span[--span_cache->count];
+ }
+#else
+ span_t* span = 0;
+ size_t count = _rpmalloc_global_cache_extract_spans(&span, span_count, 1);
+ if (count) {
+ _rpmalloc_stat_add64(&heap->global_to_thread, span_count * count * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[span_count - 1].spans_from_global, count);
+ return span;
+ }
+#endif
+#endif
+ (void)sizeof(heap);
+ (void)sizeof(span_count);
+ return 0;
+}
+
+static void
+_rpmalloc_inc_span_statistics(heap_t* heap, size_t span_count, uint32_t class_idx) {
+ (void)sizeof(heap);
+ (void)sizeof(span_count);
+ (void)sizeof(class_idx);
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+ uint32_t idx = (uint32_t)span_count - 1;
+ uint32_t current_count = (uint32_t)atomic_incr32(&heap->span_use[idx].current);
+ if (current_count > (uint32_t)atomic_load32(&heap->span_use[idx].high))
+ atomic_store32(&heap->span_use[idx].high, (int32_t)current_count);
+ _rpmalloc_stat_add_peak(&heap->size_class_use[class_idx].spans_current, 1, heap->size_class_use[class_idx].spans_peak);
+#endif
+}
+
+//! Get a span from one of the cache levels (thread cache, reserved, global cache) or fallback to mapping more memory
+static span_t*
+_rpmalloc_heap_extract_new_span(heap_t* heap, heap_size_class_t* heap_size_class, size_t span_count, uint32_t class_idx) {
+ span_t* span;
+#if ENABLE_THREAD_CACHE
+ if (heap_size_class && heap_size_class->cache) {
+ span = heap_size_class->cache;
+ heap_size_class->cache = (heap->span_cache.count ? heap->span_cache.span[--heap->span_cache.count] : 0);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+#endif
+ (void)sizeof(class_idx);
+ // Allow 50% overhead to increase cache hits
+ size_t base_span_count = span_count;
+ size_t limit_span_count = (span_count > 2) ? (span_count + (span_count >> 1)) : span_count;
+ if (limit_span_count > LARGE_CLASS_COUNT)
+ limit_span_count = LARGE_CLASS_COUNT;
+ do {
+ span = _rpmalloc_heap_thread_cache_extract(heap, span_count);
+ if (EXPECTED(span != 0)) {
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+ span = _rpmalloc_heap_thread_cache_deferred_extract(heap, span_count);
+ if (EXPECTED(span != 0)) {
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+ span = _rpmalloc_heap_reserved_extract(heap, span_count);
+ if (EXPECTED(span != 0)) {
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_reserved);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+ span = _rpmalloc_heap_global_cache_extract(heap, span_count);
+ if (EXPECTED(span != 0)) {
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_from_cache);
+ _rpmalloc_inc_span_statistics(heap, span_count, class_idx);
+ return span;
+ }
+ ++span_count;
+ } while (span_count <= limit_span_count);
+ //Final fallback, map in more virtual memory
+ span = _rpmalloc_span_map(heap, base_span_count);
+ _rpmalloc_inc_span_statistics(heap, base_span_count, class_idx);
+ _rpmalloc_stat_inc(&heap->size_class_use[class_idx].spans_map_calls);
+ return span;
+}
+
+static void
+_rpmalloc_heap_initialize(heap_t* heap) {
+ _rpmalloc_memset_const(heap, 0, sizeof(heap_t));
+ //Get a new heap ID
+ heap->id = 1 + atomic_incr32(&_memory_heap_id);
+
+ //Link in heap in heap ID map
+ size_t list_idx = (size_t)heap->id % HEAP_ARRAY_SIZE;
+ heap->next_heap = _memory_heaps[list_idx];
+ _memory_heaps[list_idx] = heap;
+}
+
+static void
+_rpmalloc_heap_orphan(heap_t* heap, int first_class) {
+ heap->owner_thread = (uintptr_t)-1;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ heap_t** heap_list = (first_class ? &_memory_first_class_orphan_heaps : &_memory_orphan_heaps);
+#else
+ (void)sizeof(first_class);
+ heap_t** heap_list = &_memory_orphan_heaps;
+#endif
+ heap->next_orphan = *heap_list;
+ *heap_list = heap;
+}
+
+//! Allocate a new heap from newly mapped memory pages
+static heap_t*
+_rpmalloc_heap_allocate_new(void) {
+ // Map in pages for a 16 heaps. If page size is greater than required size for this, map a page and
+ // use first part for heaps and remaining part for spans for allocations. Adds a lot of complexity,
+ // but saves a lot of memory on systems where page size > 64 spans (4MiB)
+ size_t heap_size = sizeof(heap_t);
+ size_t aligned_heap_size = 16 * ((heap_size + 15) / 16);
+ size_t request_heap_count = 16;
+ size_t heap_span_count = ((aligned_heap_size * request_heap_count) + sizeof(span_t) + _memory_span_size - 1) / _memory_span_size;
+ size_t block_size = _memory_span_size * heap_span_count;
+ size_t span_count = heap_span_count;
+ span_t* span = 0;
+ // If there are global reserved spans, use these first
+ if (_memory_global_reserve_count >= heap_span_count) {
+ span = _rpmalloc_global_get_reserved_spans(heap_span_count);
+ }
+ if (!span) {
+ if (_memory_page_size > block_size) {
+ span_count = _memory_page_size / _memory_span_size;
+ block_size = _memory_page_size;
+ // If using huge pages, make sure to grab enough heaps to avoid reallocating a huge page just to serve new heaps
+ size_t possible_heap_count = (block_size - sizeof(span_t)) / aligned_heap_size;
+ if (possible_heap_count >= (request_heap_count * 16))
+ request_heap_count *= 16;
+ else if (possible_heap_count < request_heap_count)
+ request_heap_count = possible_heap_count;
+ heap_span_count = ((aligned_heap_size * request_heap_count) + sizeof(span_t) + _memory_span_size - 1) / _memory_span_size;
+ }
+
+ size_t align_offset = 0;
+ span = (span_t*)_rpmalloc_mmap(block_size, &align_offset);
+ if (!span)
+ return 0;
+
+ // Master span will contain the heaps
+ _rpmalloc_stat_inc(&_master_spans);
+ _rpmalloc_span_initialize(span, span_count, heap_span_count, align_offset);
+ }
+
+ size_t remain_size = _memory_span_size - sizeof(span_t);
+ heap_t* heap = (heap_t*)pointer_offset(span, sizeof(span_t));
+ _rpmalloc_heap_initialize(heap);
+
+ // Put extra heaps as orphans
+ size_t num_heaps = remain_size / aligned_heap_size;
+ if (num_heaps < request_heap_count)
+ num_heaps = request_heap_count;
+ atomic_store32(&heap->child_count, (int32_t)num_heaps - 1);
+ heap_t* extra_heap = (heap_t*)pointer_offset(heap, aligned_heap_size);
+ while (num_heaps > 1) {
+ _rpmalloc_heap_initialize(extra_heap);
+ extra_heap->master_heap = heap;
+ _rpmalloc_heap_orphan(extra_heap, 1);
+ extra_heap = (heap_t*)pointer_offset(extra_heap, aligned_heap_size);
+ --num_heaps;
+ }
+
+ if (span_count > heap_span_count) {
+ // Cap reserved spans
+ size_t remain_count = span_count - heap_span_count;
+ size_t reserve_count = (remain_count > _memory_heap_reserve_count ? _memory_heap_reserve_count : remain_count);
+ span_t* remain_span = (span_t*)pointer_offset(span, heap_span_count * _memory_span_size);
+ _rpmalloc_heap_set_reserved_spans(heap, span, remain_span, reserve_count);
+
+ if (remain_count > reserve_count) {
+ // Set to global reserved spans
+ remain_span = (span_t*)pointer_offset(remain_span, reserve_count * _memory_span_size);
+ reserve_count = remain_count - reserve_count;
+ _rpmalloc_global_set_reserved_spans(span, remain_span, reserve_count);
+ }
+ }
+
+ return heap;
+}
+
+static heap_t*
+_rpmalloc_heap_extract_orphan(heap_t** heap_list) {
+ heap_t* heap = *heap_list;
+ *heap_list = (heap ? heap->next_orphan : 0);
+ return heap;
+}
+
+//! Allocate a new heap, potentially reusing a previously orphaned heap
+static heap_t*
+_rpmalloc_heap_allocate(int first_class) {
+ heap_t* heap = 0;
+ while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))
+ _rpmalloc_spin();
+ if (first_class == 0)
+ heap = _rpmalloc_heap_extract_orphan(&_memory_orphan_heaps);
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ if (!heap)
+ heap = _rpmalloc_heap_extract_orphan(&_memory_first_class_orphan_heaps);
+#endif
+ if (!heap)
+ heap = _rpmalloc_heap_allocate_new();
+ atomic_store32_release(&_memory_global_lock, 0);
+ if (heap)
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+ return heap;
+}
+
+static void
+_rpmalloc_heap_release(void* heapptr, int first_class, int release_cache) {
+ heap_t* heap = (heap_t*)heapptr;
+ if (!heap)
+ return;
+ //Release thread cache spans back to global cache
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+ if (release_cache || heap->finalize) {
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ if (!span_cache->count)
+ continue;
+#if ENABLE_GLOBAL_CACHE
+ if (heap->finalize) {
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+ } else {
+ _rpmalloc_stat_add64(&heap->thread_to_global, span_cache->count * (iclass + 1) * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[iclass].spans_to_global, span_cache->count);
+ _rpmalloc_global_cache_insert_spans(span_cache->span, iclass + 1, span_cache->count);
+ }
+#else
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+#endif
+ span_cache->count = 0;
+ }
+#endif
+ }
+
+ if (get_thread_heap_raw() == heap)
+ set_thread_heap(0);
+
+#if ENABLE_STATISTICS
+ atomic_decr32(&_memory_active_heaps);
+ rpmalloc_assert(atomic_load32(&_memory_active_heaps) >= 0, "Still active heaps during finalization");
+#endif
+
+ // If we are forcibly terminating with _exit the state of the
+ // lock atomic is unknown and it's best to just go ahead and exit
+ if (get_thread_id() != _rpmalloc_main_thread_id) {
+ while (!atomic_cas32_acquire(&_memory_global_lock, 1, 0))
+ _rpmalloc_spin();
+ }
+ _rpmalloc_heap_orphan(heap, first_class);
+ atomic_store32_release(&_memory_global_lock, 0);
+}
+
+static void
+_rpmalloc_heap_release_raw(void* heapptr, int release_cache) {
+ _rpmalloc_heap_release(heapptr, 0, release_cache);
+}
+
+static void
+_rpmalloc_heap_release_raw_fc(void* heapptr) {
+ _rpmalloc_heap_release_raw(heapptr, 1);
+}
+
+static void
+_rpmalloc_heap_finalize(heap_t* heap) {
+ if (heap->spans_reserved) {
+ span_t* span = _rpmalloc_span_map(heap, heap->spans_reserved);
+ _rpmalloc_span_unmap(span);
+ heap->spans_reserved = 0;
+ }
+
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ if (heap->size_class[iclass].cache)
+ _rpmalloc_span_unmap(heap->size_class[iclass].cache);
+ heap->size_class[iclass].cache = 0;
+ span_t* span = heap->size_class[iclass].partial_span;
+ while (span) {
+ span_t* next = span->next;
+ _rpmalloc_span_finalize(heap, iclass, span, &heap->size_class[iclass].partial_span);
+ span = next;
+ }
+ // If class still has a free list it must be a full span
+ if (heap->size_class[iclass].free_list) {
+ span_t* class_span = (span_t*)((uintptr_t)heap->size_class[iclass].free_list & _memory_span_mask);
+ span_t** list = 0;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ list = &heap->full_span[iclass];
+#endif
+ --heap->full_span_count;
+ if (!_rpmalloc_span_finalize(heap, iclass, class_span, list)) {
+ if (list)
+ _rpmalloc_span_double_link_list_remove(list, class_span);
+ _rpmalloc_span_double_link_list_add(&heap->size_class[iclass].partial_span, class_span);
+ }
+ }
+ }
+
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+ span_cache->count = 0;
+ }
+#endif
+ rpmalloc_assert(!atomic_load_ptr(&heap->span_free_deferred), "Heaps still active during finalization");
+}
+
+
+////////////
+///
+/// Allocation entry points
+///
+//////
+
+//! Pop first block from a free list
+static void*
+free_list_pop(void** list) {
+ void* block = *list;
+ *list = *((void**)block);
+ return block;
+}
+
+//! Allocate a small/medium sized memory block from the given heap
+static void*
+_rpmalloc_allocate_from_heap_fallback(heap_t* heap, heap_size_class_t* heap_size_class, uint32_t class_idx) {
+ span_t* span = heap_size_class->partial_span;
+ rpmalloc_assume(heap != 0);
+ if (EXPECTED(span != 0)) {
+ rpmalloc_assert(span->block_count == _memory_size_class[span->size_class].block_count, "Span block count corrupted");
+ rpmalloc_assert(!_rpmalloc_span_is_fully_utilized(span), "Internal failure");
+ void* block;
+ if (span->free_list) {
+ //Span local free list is not empty, swap to size class free list
+ block = free_list_pop(&span->free_list);
+ heap_size_class->free_list = span->free_list;
+ span->free_list = 0;
+ } else {
+ //If the span did not fully initialize free list, link up another page worth of blocks
+ void* block_start = pointer_offset(span, SPAN_HEADER_SIZE + ((size_t)span->free_list_limit * span->block_size));
+ span->free_list_limit += free_list_partial_init(&heap_size_class->free_list, &block,
+ (void*)((uintptr_t)block_start & ~(_memory_page_size - 1)), block_start,
+ span->block_count - span->free_list_limit, span->block_size);
+ }
+ rpmalloc_assert(span->free_list_limit <= span->block_count, "Span block count corrupted");
+ span->used_count = span->free_list_limit;
+
+ //Swap in deferred free list if present
+ if (atomic_load_ptr(&span->free_list_deferred))
+ _rpmalloc_span_extract_free_list_deferred(span);
+
+ //If span is still not fully utilized keep it in partial list and early return block
+ if (!_rpmalloc_span_is_fully_utilized(span))
+ return block;
+
+ //The span is fully utilized, unlink from partial list and add to fully utilized list
+ _rpmalloc_span_double_link_list_pop_head(&heap_size_class->partial_span, span);
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->full_span[class_idx], span);
+#endif
+ ++heap->full_span_count;
+ return block;
+ }
+
+ //Find a span in one of the cache levels
+ span = _rpmalloc_heap_extract_new_span(heap, heap_size_class, 1, class_idx);
+ if (EXPECTED(span != 0)) {
+ //Mark span as owned by this heap and set base data, return first block
+ return _rpmalloc_span_initialize_new(heap, heap_size_class, span, class_idx);
+ }
+
+ return 0;
+}
+
+//! Allocate a small sized memory block from the given heap
+static void*
+_rpmalloc_allocate_small(heap_t* heap, size_t size) {
+ rpmalloc_assert(heap, "No thread heap");
+ //Small sizes have unique size classes
+ const uint32_t class_idx = (uint32_t)((size + (SMALL_GRANULARITY - 1)) >> SMALL_GRANULARITY_SHIFT);
+ heap_size_class_t* heap_size_class = heap->size_class + class_idx;
+ _rpmalloc_stat_inc_alloc(heap, class_idx);
+ if (EXPECTED(heap_size_class->free_list != 0))
+ return free_list_pop(&heap_size_class->free_list);
+ return _rpmalloc_allocate_from_heap_fallback(heap, heap_size_class, class_idx);
+}
+
+//! Allocate a medium sized memory block from the given heap
+static void*
+_rpmalloc_allocate_medium(heap_t* heap, size_t size) {
+ rpmalloc_assert(heap, "No thread heap");
+ //Calculate the size class index and do a dependent lookup of the final class index (in case of merged classes)
+ const uint32_t base_idx = (uint32_t)(SMALL_CLASS_COUNT + ((size - (SMALL_SIZE_LIMIT + 1)) >> MEDIUM_GRANULARITY_SHIFT));
+ const uint32_t class_idx = _memory_size_class[base_idx].class_idx;
+ heap_size_class_t* heap_size_class = heap->size_class + class_idx;
+ _rpmalloc_stat_inc_alloc(heap, class_idx);
+ if (EXPECTED(heap_size_class->free_list != 0))
+ return free_list_pop(&heap_size_class->free_list);
+ return _rpmalloc_allocate_from_heap_fallback(heap, heap_size_class, class_idx);
+}
+
+//! Allocate a large sized memory block from the given heap
+static void*
+_rpmalloc_allocate_large(heap_t* heap, size_t size) {
+ rpmalloc_assert(heap, "No thread heap");
+ //Calculate number of needed max sized spans (including header)
+ //Since this function is never called if size > LARGE_SIZE_LIMIT
+ //the span_count is guaranteed to be <= LARGE_CLASS_COUNT
+ size += SPAN_HEADER_SIZE;
+ size_t span_count = size >> _memory_span_size_shift;
+ if (size & (_memory_span_size - 1))
+ ++span_count;
+
+ //Find a span in one of the cache levels
+ span_t* span = _rpmalloc_heap_extract_new_span(heap, 0, span_count, SIZE_CLASS_LARGE);
+ if (!span)
+ return span;
+
+ //Mark span as owned by this heap and set base data
+ rpmalloc_assert(span->span_count >= span_count, "Internal failure");
+ span->size_class = SIZE_CLASS_LARGE;
+ span->heap = heap;
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);
+#endif
+ ++heap->full_span_count;
+
+ return pointer_offset(span, SPAN_HEADER_SIZE);
+}
+
+//! Allocate a huge block by mapping memory pages directly
+static void*
+_rpmalloc_allocate_huge(heap_t* heap, size_t size) {
+ rpmalloc_assert(heap, "No thread heap");
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+ size += SPAN_HEADER_SIZE;
+ size_t num_pages = size >> _memory_page_size_shift;
+ if (size & (_memory_page_size - 1))
+ ++num_pages;
+ size_t align_offset = 0;
+ span_t* span = (span_t*)_rpmalloc_mmap(num_pages * _memory_page_size, &align_offset);
+ if (!span)
+ return span;
+
+ //Store page count in span_count
+ span->size_class = SIZE_CLASS_HUGE;
+ span->span_count = (uint32_t)num_pages;
+ span->align_offset = (uint32_t)align_offset;
+ span->heap = heap;
+ _rpmalloc_stat_add_peak(&_huge_pages_current, num_pages, _huge_pages_peak);
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);
+#endif
+ ++heap->full_span_count;
+
+ return pointer_offset(span, SPAN_HEADER_SIZE);
+}
+
+//! Allocate a block of the given size
+static void*
+_rpmalloc_allocate(heap_t* heap, size_t size) {
+ _rpmalloc_stat_add64(&_allocation_counter, 1);
+ if (EXPECTED(size <= SMALL_SIZE_LIMIT))
+ return _rpmalloc_allocate_small(heap, size);
+ else if (size <= _memory_medium_size_limit)
+ return _rpmalloc_allocate_medium(heap, size);
+ else if (size <= LARGE_SIZE_LIMIT)
+ return _rpmalloc_allocate_large(heap, size);
+ return _rpmalloc_allocate_huge(heap, size);
+}
+
+static void*
+_rpmalloc_aligned_allocate(heap_t* heap, size_t alignment, size_t size) {
+ if (alignment <= SMALL_GRANULARITY)
+ return _rpmalloc_allocate(heap, size);
+
+#if ENABLE_VALIDATE_ARGS
+ if ((size + alignment) < size) {
+ errno = EINVAL;
+ return 0;
+ }
+ if (alignment & (alignment - 1)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+
+ if ((alignment <= SPAN_HEADER_SIZE) && ((size + SPAN_HEADER_SIZE) < _memory_medium_size_limit)) {
+ // If alignment is less or equal to span header size (which is power of two),
+ // and size aligned to span header size multiples is less than size + alignment,
+ // then use natural alignment of blocks to provide alignment
+ size_t multiple_size = size ? (size + (SPAN_HEADER_SIZE - 1)) & ~(uintptr_t)(SPAN_HEADER_SIZE - 1) : SPAN_HEADER_SIZE;
+ rpmalloc_assert(!(multiple_size % SPAN_HEADER_SIZE), "Failed alignment calculation");
+ if (multiple_size <= (size + alignment))
+ return _rpmalloc_allocate(heap, multiple_size);
+ }
+
+ void* ptr = 0;
+ size_t align_mask = alignment - 1;
+ if (alignment <= _memory_page_size) {
+ ptr = _rpmalloc_allocate(heap, size + alignment);
+ if ((uintptr_t)ptr & align_mask) {
+ ptr = (void*)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment);
+ //Mark as having aligned blocks
+ span_t* span = (span_t*)((uintptr_t)ptr & _memory_span_mask);
+ span->flags |= SPAN_FLAG_ALIGNED_BLOCKS;
+ }
+ return ptr;
+ }
+
+ // Fallback to mapping new pages for this request. Since pointers passed
+ // to rpfree must be able to reach the start of the span by bitmasking of
+ // the address with the span size, the returned aligned pointer from this
+ // function must be with a span size of the start of the mapped area.
+ // In worst case this requires us to loop and map pages until we get a
+ // suitable memory address. It also means we can never align to span size
+ // or greater, since the span header will push alignment more than one
+ // span size away from span start (thus causing pointer mask to give us
+ // an invalid span start on free)
+ if (alignment & align_mask) {
+ errno = EINVAL;
+ return 0;
+ }
+ if (alignment >= _memory_span_size) {
+ errno = EINVAL;
+ return 0;
+ }
+
+ size_t extra_pages = alignment / _memory_page_size;
+
+ // Since each span has a header, we will at least need one extra memory page
+ size_t num_pages = 1 + (size / _memory_page_size);
+ if (size & (_memory_page_size - 1))
+ ++num_pages;
+
+ if (extra_pages > num_pages)
+ num_pages = 1 + extra_pages;
+
+ size_t original_pages = num_pages;
+ size_t limit_pages = (_memory_span_size / _memory_page_size) * 2;
+ if (limit_pages < (original_pages * 2))
+ limit_pages = original_pages * 2;
+
+ size_t mapped_size, align_offset;
+ span_t* span;
+
+retry:
+ align_offset = 0;
+ mapped_size = num_pages * _memory_page_size;
+
+ span = (span_t*)_rpmalloc_mmap(mapped_size, &align_offset);
+ if (!span) {
+ errno = ENOMEM;
+ return 0;
+ }
+ ptr = pointer_offset(span, SPAN_HEADER_SIZE);
+
+ if ((uintptr_t)ptr & align_mask)
+ ptr = (void*)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment);
+
+ if (((size_t)pointer_diff(ptr, span) >= _memory_span_size) ||
+ (pointer_offset(ptr, size) > pointer_offset(span, mapped_size)) ||
+ (((uintptr_t)ptr & _memory_span_mask) != (uintptr_t)span)) {
+ _rpmalloc_unmap(span, mapped_size, align_offset, mapped_size);
+ ++num_pages;
+ if (num_pages > limit_pages) {
+ errno = EINVAL;
+ return 0;
+ }
+ goto retry;
+ }
+
+ //Store page count in span_count
+ span->size_class = SIZE_CLASS_HUGE;
+ span->span_count = (uint32_t)num_pages;
+ span->align_offset = (uint32_t)align_offset;
+ span->heap = heap;
+ _rpmalloc_stat_add_peak(&_huge_pages_current, num_pages, _huge_pages_peak);
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_add(&heap->large_huge_span, span);
+#endif
+ ++heap->full_span_count;
+
+ _rpmalloc_stat_add64(&_allocation_counter, 1);
+
+ return ptr;
+}
+
+
+////////////
+///
+/// Deallocation entry points
+///
+//////
+
+//! Deallocate the given small/medium memory block in the current thread local heap
+static void
+_rpmalloc_deallocate_direct_small_or_medium(span_t* span, void* block) {
+ heap_t* heap = span->heap;
+ rpmalloc_assert(heap->owner_thread == get_thread_id() || !heap->owner_thread || heap->finalize, "Internal failure");
+ //Add block to free list
+ if (UNEXPECTED(_rpmalloc_span_is_fully_utilized(span))) {
+ span->used_count = span->block_count;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&heap->full_span[span->size_class], span);
+#endif
+ _rpmalloc_span_double_link_list_add(&heap->size_class[span->size_class].partial_span, span);
+ --heap->full_span_count;
+ }
+ *((void**)block) = span->free_list;
+ --span->used_count;
+ span->free_list = block;
+ if (UNEXPECTED(span->used_count == span->list_size)) {
+ // If there are no used blocks it is guaranteed that no other external thread is accessing the span
+ if (span->used_count) {
+ // Make sure we have synchronized the deferred list and list size by using acquire semantics
+ // and guarantee that no external thread is accessing span concurrently
+ void* free_list;
+ do {
+ free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);
+ } while (free_list == INVALID_POINTER);
+ atomic_store_ptr_release(&span->free_list_deferred, free_list);
+ }
+ _rpmalloc_span_double_link_list_remove(&heap->size_class[span->size_class].partial_span, span);
+ _rpmalloc_span_release_to_cache(heap, span);
+ }
+}
+
+static void
+_rpmalloc_deallocate_defer_free_span(heap_t* heap, span_t* span) {
+ if (span->size_class != SIZE_CLASS_HUGE)
+ _rpmalloc_stat_inc(&heap->span_use[span->span_count - 1].spans_deferred);
+ //This list does not need ABA protection, no mutable side state
+ do {
+ span->free_list = (void*)atomic_load_ptr(&heap->span_free_deferred);
+ } while (!atomic_cas_ptr(&heap->span_free_deferred, span, span->free_list));
+}
+
+//! Put the block in the deferred free list of the owning span
+static void
+_rpmalloc_deallocate_defer_small_or_medium(span_t* span, void* block) {
+ // The memory ordering here is a bit tricky, to avoid having to ABA protect
+ // the deferred free list to avoid desynchronization of list and list size
+ // we need to have acquire semantics on successful CAS of the pointer to
+ // guarantee the list_size variable validity + release semantics on pointer store
+ void* free_list;
+ do {
+ free_list = atomic_exchange_ptr_acquire(&span->free_list_deferred, INVALID_POINTER);
+ } while (free_list == INVALID_POINTER);
+ *((void**)block) = free_list;
+ uint32_t free_count = ++span->list_size;
+ int all_deferred_free = (free_count == span->block_count);
+ atomic_store_ptr_release(&span->free_list_deferred, block);
+ if (all_deferred_free) {
+ // Span was completely freed by this block. Due to the INVALID_POINTER spin lock
+ // no other thread can reach this state simultaneously on this span.
+ // Safe to move to owner heap deferred cache
+ _rpmalloc_deallocate_defer_free_span(span->heap, span);
+ }
+}
+
+static void
+_rpmalloc_deallocate_small_or_medium(span_t* span, void* p) {
+ _rpmalloc_stat_inc_free(span->heap, span->size_class);
+ if (span->flags & SPAN_FLAG_ALIGNED_BLOCKS) {
+ //Realign pointer to block start
+ void* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);
+ uint32_t block_offset = (uint32_t)pointer_diff(p, blocks_start);
+ p = pointer_offset(p, -(int32_t)(block_offset % span->block_size));
+ }
+ //Check if block belongs to this heap or if deallocation should be deferred
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#else
+ int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#endif
+ if (!defer)
+ _rpmalloc_deallocate_direct_small_or_medium(span, p);
+ else
+ _rpmalloc_deallocate_defer_small_or_medium(span, p);
+}
+
+//! Deallocate the given large memory block to the current heap
+static void
+_rpmalloc_deallocate_large(span_t* span) {
+ rpmalloc_assert(span->size_class == SIZE_CLASS_LARGE, "Bad span size class");
+ rpmalloc_assert(!(span->flags & SPAN_FLAG_MASTER) || !(span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ rpmalloc_assert((span->flags & SPAN_FLAG_MASTER) || (span->flags & SPAN_FLAG_SUBSPAN), "Span flag corrupted");
+ //We must always defer (unless finalizing) if from another heap since we cannot touch the list or counters of another heap
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#else
+ int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#endif
+ if (defer) {
+ _rpmalloc_deallocate_defer_free_span(span->heap, span);
+ return;
+ }
+ rpmalloc_assert(span->heap->full_span_count, "Heap span counter corrupted");
+ --span->heap->full_span_count;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&span->heap->large_huge_span, span);
+#endif
+#if ENABLE_ADAPTIVE_THREAD_CACHE || ENABLE_STATISTICS
+ //Decrease counter
+ size_t idx = span->span_count - 1;
+ atomic_decr32(&span->heap->span_use[idx].current);
+#endif
+ heap_t* heap = span->heap;
+ rpmalloc_assert(heap, "No thread heap");
+#if ENABLE_THREAD_CACHE
+ const int set_as_reserved = ((span->span_count > 1) && (heap->span_cache.count == 0) && !heap->finalize && !heap->spans_reserved);
+#else
+ const int set_as_reserved = ((span->span_count > 1) && !heap->finalize && !heap->spans_reserved);
+#endif
+ if (set_as_reserved) {
+ heap->span_reserve = span;
+ heap->spans_reserved = span->span_count;
+ if (span->flags & SPAN_FLAG_MASTER) {
+ heap->span_reserve_master = span;
+ } else { //SPAN_FLAG_SUBSPAN
+ span_t* master = (span_t*)pointer_offset(span, -(intptr_t)((size_t)span->offset_from_master * _memory_span_size));
+ heap->span_reserve_master = master;
+ rpmalloc_assert(master->flags & SPAN_FLAG_MASTER, "Span flag corrupted");
+ rpmalloc_assert(atomic_load32(&master->remaining_spans) >= (int32_t)span->span_count, "Master span count corrupted");
+ }
+ _rpmalloc_stat_inc(&heap->span_use[idx].spans_to_reserved);
+ } else {
+ //Insert into cache list
+ _rpmalloc_heap_cache_insert(heap, span);
+ }
+}
+
+//! Deallocate the given huge span
+static void
+_rpmalloc_deallocate_huge(span_t* span) {
+ rpmalloc_assert(span->heap, "No span heap");
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ int defer = (span->heap->owner_thread && (span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#else
+ int defer = ((span->heap->owner_thread != get_thread_id()) && !span->heap->finalize);
+#endif
+ if (defer) {
+ _rpmalloc_deallocate_defer_free_span(span->heap, span);
+ return;
+ }
+ rpmalloc_assert(span->heap->full_span_count, "Heap span counter corrupted");
+ --span->heap->full_span_count;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _rpmalloc_span_double_link_list_remove(&span->heap->large_huge_span, span);
+#endif
+
+ //Oversized allocation, page count is stored in span_count
+ size_t num_pages = span->span_count;
+ _rpmalloc_unmap(span, num_pages * _memory_page_size, span->align_offset, num_pages * _memory_page_size);
+ _rpmalloc_stat_sub(&_huge_pages_current, num_pages);
+}
+
+//! Deallocate the given block
+static void
+_rpmalloc_deallocate(void* p) {
+ _rpmalloc_stat_add64(&_deallocation_counter, 1);
+ //Grab the span (always at start of span, using span alignment)
+ span_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);
+ if (UNEXPECTED(!span))
+ return;
+ if (EXPECTED(span->size_class < SIZE_CLASS_COUNT))
+ _rpmalloc_deallocate_small_or_medium(span, p);
+ else if (span->size_class == SIZE_CLASS_LARGE)
+ _rpmalloc_deallocate_large(span);
+ else
+ _rpmalloc_deallocate_huge(span);
+}
+
+////////////
+///
+/// Reallocation entry points
+///
+//////
+
+static size_t
+_rpmalloc_usable_size(void* p);
+
+//! Reallocate the given block to the given size
+static void*
+_rpmalloc_reallocate(heap_t* heap, void* p, size_t size, size_t oldsize, unsigned int flags) {
+ if (p) {
+ //Grab the span using guaranteed span alignment
+ span_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);
+ if (EXPECTED(span->size_class < SIZE_CLASS_COUNT)) {
+ //Small/medium sized block
+ rpmalloc_assert(span->span_count == 1, "Span counter corrupted");
+ void* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);
+ uint32_t block_offset = (uint32_t)pointer_diff(p, blocks_start);
+ uint32_t block_idx = block_offset / span->block_size;
+ void* block = pointer_offset(blocks_start, (size_t)block_idx * span->block_size);
+ if (!oldsize)
+ oldsize = (size_t)((ptrdiff_t)span->block_size - pointer_diff(p, block));
+ if ((size_t)span->block_size >= size) {
+ //Still fits in block, never mind trying to save memory, but preserve data if alignment changed
+ if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))
+ memmove(block, p, oldsize);
+ return block;
+ }
+ } else if (span->size_class == SIZE_CLASS_LARGE) {
+ //Large block
+ size_t total_size = size + SPAN_HEADER_SIZE;
+ size_t num_spans = total_size >> _memory_span_size_shift;
+ if (total_size & (_memory_span_mask - 1))
+ ++num_spans;
+ size_t current_spans = span->span_count;
+ void* block = pointer_offset(span, SPAN_HEADER_SIZE);
+ if (!oldsize)
+ oldsize = (current_spans * _memory_span_size) - (size_t)pointer_diff(p, block) - SPAN_HEADER_SIZE;
+ if ((current_spans >= num_spans) && (total_size >= (oldsize / 2))) {
+ //Still fits in block, never mind trying to save memory, but preserve data if alignment changed
+ if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))
+ memmove(block, p, oldsize);
+ return block;
+ }
+ } else {
+ //Oversized block
+ size_t total_size = size + SPAN_HEADER_SIZE;
+ size_t num_pages = total_size >> _memory_page_size_shift;
+ if (total_size & (_memory_page_size - 1))
+ ++num_pages;
+ //Page count is stored in span_count
+ size_t current_pages = span->span_count;
+ void* block = pointer_offset(span, SPAN_HEADER_SIZE);
+ if (!oldsize)
+ oldsize = (current_pages * _memory_page_size) - (size_t)pointer_diff(p, block) - SPAN_HEADER_SIZE;
+ if ((current_pages >= num_pages) && (num_pages >= (current_pages / 2))) {
+ //Still fits in block, never mind trying to save memory, but preserve data if alignment changed
+ if ((p != block) && !(flags & RPMALLOC_NO_PRESERVE))
+ memmove(block, p, oldsize);
+ return block;
+ }
+ }
+ } else {
+ oldsize = 0;
+ }
+
+ if (!!(flags & RPMALLOC_GROW_OR_FAIL))
+ return 0;
+
+ //Size is greater than block size, need to allocate a new block and deallocate the old
+ //Avoid hysteresis by overallocating if increase is small (below 37%)
+ size_t lower_bound = oldsize + (oldsize >> 2) + (oldsize >> 3);
+ size_t new_size = (size > lower_bound) ? size : ((size > oldsize) ? lower_bound : size);
+ void* block = _rpmalloc_allocate(heap, new_size);
+ if (p && block) {
+ if (!(flags & RPMALLOC_NO_PRESERVE))
+ memcpy(block, p, oldsize < new_size ? oldsize : new_size);
+ _rpmalloc_deallocate(p);
+ }
+
+ return block;
+}
+
+static void*
+_rpmalloc_aligned_reallocate(heap_t* heap, void* ptr, size_t alignment, size_t size, size_t oldsize,
+ unsigned int flags) {
+ if (alignment <= SMALL_GRANULARITY)
+ return _rpmalloc_reallocate(heap, ptr, size, oldsize, flags);
+
+ int no_alloc = !!(flags & RPMALLOC_GROW_OR_FAIL);
+ size_t usablesize = (ptr ? _rpmalloc_usable_size(ptr) : 0);
+ if ((usablesize >= size) && !((uintptr_t)ptr & (alignment - 1))) {
+ if (no_alloc || (size >= (usablesize / 2)))
+ return ptr;
+ }
+ // Aligned alloc marks span as having aligned blocks
+ void* block = (!no_alloc ? _rpmalloc_aligned_allocate(heap, alignment, size) : 0);
+ if (EXPECTED(block != 0)) {
+ if (!(flags & RPMALLOC_NO_PRESERVE) && ptr) {
+ if (!oldsize)
+ oldsize = usablesize;
+ memcpy(block, ptr, oldsize < size ? oldsize : size);
+ }
+ _rpmalloc_deallocate(ptr);
+ }
+ return block;
+}
+
+
+////////////
+///
+/// Initialization, finalization and utility
+///
+//////
+
+//! Get the usable size of the given block
+static size_t
+_rpmalloc_usable_size(void* p) {
+ //Grab the span using guaranteed span alignment
+ span_t* span = (span_t*)((uintptr_t)p & _memory_span_mask);
+ if (span->size_class < SIZE_CLASS_COUNT) {
+ //Small/medium block
+ void* blocks_start = pointer_offset(span, SPAN_HEADER_SIZE);
+ return span->block_size - ((size_t)pointer_diff(p, blocks_start) % span->block_size);
+ }
+ if (span->size_class == SIZE_CLASS_LARGE) {
+ //Large block
+ size_t current_spans = span->span_count;
+ return (current_spans * _memory_span_size) - (size_t)pointer_diff(p, span);
+ }
+ //Oversized block, page count is stored in span_count
+ size_t current_pages = span->span_count;
+ return (current_pages * _memory_page_size) - (size_t)pointer_diff(p, span);
+}
+
+//! Adjust and optimize the size class properties for the given class
+static void
+_rpmalloc_adjust_size_class(size_t iclass) {
+ size_t block_size = _memory_size_class[iclass].block_size;
+ size_t block_count = (_memory_span_size - SPAN_HEADER_SIZE) / block_size;
+
+ _memory_size_class[iclass].block_count = (uint16_t)block_count;
+ _memory_size_class[iclass].class_idx = (uint16_t)iclass;
+
+ //Check if previous size classes can be merged
+ if (iclass >= SMALL_CLASS_COUNT) {
+ size_t prevclass = iclass;
+ while (prevclass > 0) {
+ --prevclass;
+ //A class can be merged if number of pages and number of blocks are equal
+ if (_memory_size_class[prevclass].block_count == _memory_size_class[iclass].block_count)
+ _rpmalloc_memcpy_const(_memory_size_class + prevclass, _memory_size_class + iclass, sizeof(_memory_size_class[iclass]));
+ else
+ break;
+ }
+ }
+}
+
+//! Initialize the allocator and setup global data
+extern inline int
+rpmalloc_initialize(void) {
+ if (_rpmalloc_initialized) {
+ rpmalloc_thread_initialize();
+ return 0;
+ }
+ return rpmalloc_initialize_config(0);
+}
+
+int
+rpmalloc_initialize_config(const rpmalloc_config_t* config) {
+ if (_rpmalloc_initialized) {
+ rpmalloc_thread_initialize();
+ return 0;
+ }
+ _rpmalloc_initialized = 1;
+
+ if (config)
+ memcpy(&_memory_config, config, sizeof(rpmalloc_config_t));
+ else
+ _rpmalloc_memset_const(&_memory_config, 0, sizeof(rpmalloc_config_t));
+
+ if (!_memory_config.memory_map || !_memory_config.memory_unmap) {
+ _memory_config.memory_map = _rpmalloc_mmap_os;
+ _memory_config.memory_unmap = _rpmalloc_unmap_os;
+ }
+
+#if PLATFORM_WINDOWS
+ SYSTEM_INFO system_info;
+ memset(&system_info, 0, sizeof(system_info));
+ GetSystemInfo(&system_info);
+ _memory_map_granularity = system_info.dwAllocationGranularity;
+#else
+ _memory_map_granularity = (size_t)sysconf(_SC_PAGESIZE);
+#endif
+
+#if RPMALLOC_CONFIGURABLE
+ _memory_page_size = _memory_config.page_size;
+#else
+ _memory_page_size = 0;
+#endif
+ _memory_huge_pages = 0;
+ if (!_memory_page_size) {
+#if PLATFORM_WINDOWS
+ _memory_page_size = system_info.dwPageSize;
+#else
+ _memory_page_size = _memory_map_granularity;
+ if (_memory_config.enable_huge_pages) {
+#if defined(__linux__)
+ size_t huge_page_size = 0;
+ FILE* meminfo = fopen("/proc/meminfo", "r");
+ if (meminfo) {
+ char line[128];
+ while (!huge_page_size && fgets(line, sizeof(line) - 1, meminfo)) {
+ line[sizeof(line) - 1] = 0;
+ if (strstr(line, "Hugepagesize:"))
+ huge_page_size = (size_t)strtol(line + 13, 0, 10) * 1024;
+ }
+ fclose(meminfo);
+ }
+ if (huge_page_size) {
+ _memory_huge_pages = 1;
+ _memory_page_size = huge_page_size;
+ _memory_map_granularity = huge_page_size;
+ }
+#elif defined(__FreeBSD__)
+ int rc;
+ size_t sz = sizeof(rc);
+
+ if (sysctlbyname("vm.pmap.pg_ps_enabled", &rc, &sz, NULL, 0) == 0 && rc == 1) {
+ static size_t defsize = 2 * 1024 * 1024;
+ int nsize = 0;
+ size_t sizes[4] = {0};
+ _memory_huge_pages = 1;
+ _memory_page_size = defsize;
+ if ((nsize = getpagesizes(sizes, 4)) >= 2) {
+ nsize --;
+ for (size_t csize = sizes[nsize]; nsize >= 0 && csize; --nsize, csize = sizes[nsize]) {
+ //! Unlikely, but as a precaution..
+ rpmalloc_assert(!(csize & (csize -1)) && !(csize % 1024), "Invalid page size");
+ if (defsize < csize) {
+ _memory_page_size = csize;
+ break;
+ }
+ }
+ }
+ _memory_map_granularity = _memory_page_size;
+ }
+#elif defined(__APPLE__) || defined(__NetBSD__)
+ _memory_huge_pages = 1;
+ _memory_page_size = 2 * 1024 * 1024;
+ _memory_map_granularity = _memory_page_size;
+#endif
+ }
+#endif
+ } else {
+ if (_memory_config.enable_huge_pages)
+ _memory_huge_pages = 1;
+ }
+
+#if PLATFORM_WINDOWS
+ if (_memory_config.enable_huge_pages) {
+ HANDLE token = 0;
+ size_t large_page_minimum = GetLargePageMinimum();
+ if (large_page_minimum)
+ OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token);
+ if (token) {
+ LUID luid;
+ if (LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &luid)) {
+ TOKEN_PRIVILEGES token_privileges;
+ memset(&token_privileges, 0, sizeof(token_privileges));
+ token_privileges.PrivilegeCount = 1;
+ token_privileges.Privileges[0].Luid = luid;
+ token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ if (AdjustTokenPrivileges(token, FALSE, &token_privileges, 0, 0, 0)) {
+ if (GetLastError() == ERROR_SUCCESS)
+ _memory_huge_pages = 1;
+ }
+ }
+ CloseHandle(token);
+ }
+ if (_memory_huge_pages) {
+ if (large_page_minimum > _memory_page_size)
+ _memory_page_size = large_page_minimum;
+ if (large_page_minimum > _memory_map_granularity)
+ _memory_map_granularity = large_page_minimum;
+ }
+ }
+#endif
+
+ size_t min_span_size = 256;
+ size_t max_page_size;
+#if UINTPTR_MAX > 0xFFFFFFFF
+ max_page_size = 4096ULL * 1024ULL * 1024ULL;
+#else
+ max_page_size = 4 * 1024 * 1024;
+#endif
+ if (_memory_page_size < min_span_size)
+ _memory_page_size = min_span_size;
+ if (_memory_page_size > max_page_size)
+ _memory_page_size = max_page_size;
+ _memory_page_size_shift = 0;
+ size_t page_size_bit = _memory_page_size;
+ while (page_size_bit != 1) {
+ ++_memory_page_size_shift;
+ page_size_bit >>= 1;
+ }
+ _memory_page_size = ((size_t)1 << _memory_page_size_shift);
+
+#if RPMALLOC_CONFIGURABLE
+ if (!_memory_config.span_size) {
+ _memory_span_size = _memory_default_span_size;
+ _memory_span_size_shift = _memory_default_span_size_shift;
+ _memory_span_mask = _memory_default_span_mask;
+ } else {
+ size_t span_size = _memory_config.span_size;
+ if (span_size > (256 * 1024))
+ span_size = (256 * 1024);
+ _memory_span_size = 4096;
+ _memory_span_size_shift = 12;
+ while (_memory_span_size < span_size) {
+ _memory_span_size <<= 1;
+ ++_memory_span_size_shift;
+ }
+ _memory_span_mask = ~(uintptr_t)(_memory_span_size - 1);
+ }
+#endif
+
+ _memory_span_map_count = ( _memory_config.span_map_count ? _memory_config.span_map_count : DEFAULT_SPAN_MAP_COUNT);
+ if ((_memory_span_size * _memory_span_map_count) < _memory_page_size)
+ _memory_span_map_count = (_memory_page_size / _memory_span_size);
+ if ((_memory_page_size >= _memory_span_size) && ((_memory_span_map_count * _memory_span_size) % _memory_page_size))
+ _memory_span_map_count = (_memory_page_size / _memory_span_size);
+ _memory_heap_reserve_count = (_memory_span_map_count > DEFAULT_SPAN_MAP_COUNT) ? DEFAULT_SPAN_MAP_COUNT : _memory_span_map_count;
+
+ _memory_config.page_size = _memory_page_size;
+ _memory_config.span_size = _memory_span_size;
+ _memory_config.span_map_count = _memory_span_map_count;
+ _memory_config.enable_huge_pages = _memory_huge_pages;
+
+#if ((defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD) || defined(__TINYC__)
+ if (pthread_key_create(&_memory_thread_heap, _rpmalloc_heap_release_raw_fc))
+ return -1;
+#endif
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+ fls_key = FlsAlloc(&_rpmalloc_thread_destructor);
+#endif
+
+ //Setup all small and medium size classes
+ size_t iclass = 0;
+ _memory_size_class[iclass].block_size = SMALL_GRANULARITY;
+ _rpmalloc_adjust_size_class(iclass);
+ for (iclass = 1; iclass < SMALL_CLASS_COUNT; ++iclass) {
+ size_t size = iclass * SMALL_GRANULARITY;
+ _memory_size_class[iclass].block_size = (uint32_t)size;
+ _rpmalloc_adjust_size_class(iclass);
+ }
+ //At least two blocks per span, then fall back to large allocations
+ _memory_medium_size_limit = (_memory_span_size - SPAN_HEADER_SIZE) >> 1;
+ if (_memory_medium_size_limit > MEDIUM_SIZE_LIMIT)
+ _memory_medium_size_limit = MEDIUM_SIZE_LIMIT;
+ for (iclass = 0; iclass < MEDIUM_CLASS_COUNT; ++iclass) {
+ size_t size = SMALL_SIZE_LIMIT + ((iclass + 1) * MEDIUM_GRANULARITY);
+ if (size > _memory_medium_size_limit) {
+ _memory_medium_size_limit = SMALL_SIZE_LIMIT + (iclass * MEDIUM_GRANULARITY);
+ break;
+ }
+ _memory_size_class[SMALL_CLASS_COUNT + iclass].block_size = (uint32_t)size;
+ _rpmalloc_adjust_size_class(SMALL_CLASS_COUNT + iclass);
+ }
+
+ _memory_orphan_heaps = 0;
+#if RPMALLOC_FIRST_CLASS_HEAPS
+ _memory_first_class_orphan_heaps = 0;
+#endif
+#if ENABLE_STATISTICS
+ atomic_store32(&_memory_active_heaps, 0);
+ atomic_store32(&_mapped_pages, 0);
+ _mapped_pages_peak = 0;
+ atomic_store32(&_master_spans, 0);
+ atomic_store32(&_mapped_total, 0);
+ atomic_store32(&_unmapped_total, 0);
+ atomic_store32(&_mapped_pages_os, 0);
+ atomic_store32(&_huge_pages_current, 0);
+ _huge_pages_peak = 0;
+#endif
+ memset(_memory_heaps, 0, sizeof(_memory_heaps));
+ atomic_store32_release(&_memory_global_lock, 0);
+
+ rpmalloc_linker_reference();
+
+ //Initialize this thread
+ rpmalloc_thread_initialize();
+ return 0;
+}
+
+//! Finalize the allocator
+void
+rpmalloc_finalize(void) {
+ rpmalloc_thread_finalize(1);
+ //rpmalloc_dump_statistics(stdout);
+
+ if (_memory_global_reserve) {
+ atomic_add32(&_memory_global_reserve_master->remaining_spans, -(int32_t)_memory_global_reserve_count);
+ _memory_global_reserve_master = 0;
+ _memory_global_reserve_count = 0;
+ _memory_global_reserve = 0;
+ }
+ atomic_store32_release(&_memory_global_lock, 0);
+
+ //Free all thread caches and fully free spans
+ for (size_t list_idx = 0; list_idx < HEAP_ARRAY_SIZE; ++list_idx) {
+ heap_t* heap = _memory_heaps[list_idx];
+ while (heap) {
+ heap_t* next_heap = heap->next_heap;
+ heap->finalize = 1;
+ _rpmalloc_heap_global_finalize(heap);
+ heap = next_heap;
+ }
+ }
+
+#if ENABLE_GLOBAL_CACHE
+ //Free global caches
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass)
+ _rpmalloc_global_cache_finalize(&_memory_span_cache[iclass]);
+#endif
+
+#if (defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD
+ pthread_key_delete(_memory_thread_heap);
+#endif
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+ FlsFree(fls_key);
+ fls_key = 0;
+#endif
+#if ENABLE_STATISTICS
+ //If you hit these asserts you probably have memory leaks (perhaps global scope data doing dynamic allocations) or double frees in your code
+ rpmalloc_assert(atomic_load32(&_mapped_pages) == 0, "Memory leak detected");
+ rpmalloc_assert(atomic_load32(&_mapped_pages_os) == 0, "Memory leak detected");
+#endif
+
+ _rpmalloc_initialized = 0;
+}
+
+//! Initialize thread, assign heap
+extern inline void
+rpmalloc_thread_initialize(void) {
+ if (!get_thread_heap_raw()) {
+ heap_t* heap = _rpmalloc_heap_allocate(0);
+ if (heap) {
+ _rpmalloc_stat_inc(&_memory_active_heaps);
+ set_thread_heap(heap);
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+ FlsSetValue(fls_key, heap);
+#endif
+ }
+ }
+}
+
+//! Finalize thread, orphan heap
+void
+rpmalloc_thread_finalize(int release_caches) {
+ heap_t* heap = get_thread_heap_raw();
+ if (heap)
+ _rpmalloc_heap_release_raw(heap, release_caches);
+ set_thread_heap(0);
+#if defined(_WIN32) && (!defined(BUILD_DYNAMIC_LINK) || !BUILD_DYNAMIC_LINK)
+ FlsSetValue(fls_key, 0);
+#endif
+}
+
+int
+rpmalloc_is_thread_initialized(void) {
+ return (get_thread_heap_raw() != 0) ? 1 : 0;
+}
+
+const rpmalloc_config_t*
+rpmalloc_config(void) {
+ return &_memory_config;
+}
+
+// Extern interface
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc(size_t size) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ heap_t* heap = get_thread_heap();
+ return _rpmalloc_allocate(heap, size);
+}
+
+extern inline void
+rpfree(void* ptr) {
+ _rpmalloc_deallocate(ptr);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpcalloc(size_t num, size_t size) {
+ size_t total;
+#if ENABLE_VALIDATE_ARGS
+#if PLATFORM_WINDOWS
+ int err = SizeTMult(num, size, &total);
+ if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#else
+ int err = __builtin_umull_overflow(num, size, &total);
+ if (err || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+#else
+ total = num * size;
+#endif
+ heap_t* heap = get_thread_heap();
+ void* block = _rpmalloc_allocate(heap, total);
+ if (block)
+ memset(block, 0, total);
+ return block;
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rprealloc(void* ptr, size_t size) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return ptr;
+ }
+#endif
+ heap_t* heap = get_thread_heap();
+ return _rpmalloc_reallocate(heap, ptr, size, 0, 0);
+}
+
+extern RPMALLOC_ALLOCATOR void*
+rpaligned_realloc(void* ptr, size_t alignment, size_t size, size_t oldsize,
+ unsigned int flags) {
+#if ENABLE_VALIDATE_ARGS
+ if ((size + alignment < size) || (alignment > _memory_page_size)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ heap_t* heap = get_thread_heap();
+ return _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, oldsize, flags);
+}
+
+extern RPMALLOC_ALLOCATOR void*
+rpaligned_alloc(size_t alignment, size_t size) {
+ heap_t* heap = get_thread_heap();
+ return _rpmalloc_aligned_allocate(heap, alignment, size);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpaligned_calloc(size_t alignment, size_t num, size_t size) {
+ size_t total;
+#if ENABLE_VALIDATE_ARGS
+#if PLATFORM_WINDOWS
+ int err = SizeTMult(num, size, &total);
+ if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#else
+ int err = __builtin_umull_overflow(num, size, &total);
+ if (err || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+#else
+ total = num * size;
+#endif
+ void* block = rpaligned_alloc(alignment, total);
+ if (block)
+ memset(block, 0, total);
+ return block;
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmemalign(size_t alignment, size_t size) {
+ return rpaligned_alloc(alignment, size);
+}
+
+extern inline int
+rpposix_memalign(void **memptr, size_t alignment, size_t size) {
+ if (memptr)
+ *memptr = rpaligned_alloc(alignment, size);
+ else
+ return EINVAL;
+ return *memptr ? 0 : ENOMEM;
+}
+
+extern inline size_t
+rpmalloc_usable_size(void* ptr) {
+ return (ptr ? _rpmalloc_usable_size(ptr) : 0);
+}
+
+extern inline void
+rpmalloc_thread_collect(void) {
+}
+
+void
+rpmalloc_thread_statistics(rpmalloc_thread_statistics_t* stats) {
+ memset(stats, 0, sizeof(rpmalloc_thread_statistics_t));
+ heap_t* heap = get_thread_heap_raw();
+ if (!heap)
+ return;
+
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ size_class_t* size_class = _memory_size_class + iclass;
+ span_t* span = heap->size_class[iclass].partial_span;
+ while (span) {
+ size_t free_count = span->list_size;
+ size_t block_count = size_class->block_count;
+ if (span->free_list_limit < block_count)
+ block_count = span->free_list_limit;
+ free_count += (block_count - span->used_count);
+ stats->sizecache += free_count * size_class->block_size;
+ span = span->next;
+ }
+ }
+
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ stats->spancache += span_cache->count * (iclass + 1) * _memory_span_size;
+ }
+#endif
+
+ span_t* deferred = (span_t*)atomic_load_ptr(&heap->span_free_deferred);
+ while (deferred) {
+ if (deferred->size_class != SIZE_CLASS_HUGE)
+ stats->spancache += (size_t)deferred->span_count * _memory_span_size;
+ deferred = (span_t*)deferred->free_list;
+ }
+
+#if ENABLE_STATISTICS
+ stats->thread_to_global = (size_t)atomic_load64(&heap->thread_to_global);
+ stats->global_to_thread = (size_t)atomic_load64(&heap->global_to_thread);
+
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ stats->span_use[iclass].current = (size_t)atomic_load32(&heap->span_use[iclass].current);
+ stats->span_use[iclass].peak = (size_t)atomic_load32(&heap->span_use[iclass].high);
+ stats->span_use[iclass].to_global = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_global);
+ stats->span_use[iclass].from_global = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_global);
+ stats->span_use[iclass].to_cache = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_cache);
+ stats->span_use[iclass].from_cache = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_cache);
+ stats->span_use[iclass].to_reserved = (size_t)atomic_load32(&heap->span_use[iclass].spans_to_reserved);
+ stats->span_use[iclass].from_reserved = (size_t)atomic_load32(&heap->span_use[iclass].spans_from_reserved);
+ stats->span_use[iclass].map_calls = (size_t)atomic_load32(&heap->span_use[iclass].spans_map_calls);
+ }
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ stats->size_use[iclass].alloc_current = (size_t)atomic_load32(&heap->size_class_use[iclass].alloc_current);
+ stats->size_use[iclass].alloc_peak = (size_t)heap->size_class_use[iclass].alloc_peak;
+ stats->size_use[iclass].alloc_total = (size_t)atomic_load32(&heap->size_class_use[iclass].alloc_total);
+ stats->size_use[iclass].free_total = (size_t)atomic_load32(&heap->size_class_use[iclass].free_total);
+ stats->size_use[iclass].spans_to_cache = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_to_cache);
+ stats->size_use[iclass].spans_from_cache = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_cache);
+ stats->size_use[iclass].spans_from_reserved = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_reserved);
+ stats->size_use[iclass].map_calls = (size_t)atomic_load32(&heap->size_class_use[iclass].spans_map_calls);
+ }
+#endif
+}
+
+void
+rpmalloc_global_statistics(rpmalloc_global_statistics_t* stats) {
+ memset(stats, 0, sizeof(rpmalloc_global_statistics_t));
+#if ENABLE_STATISTICS
+ stats->mapped = (size_t)atomic_load32(&_mapped_pages) * _memory_page_size;
+ stats->mapped_peak = (size_t)_mapped_pages_peak * _memory_page_size;
+ stats->mapped_total = (size_t)atomic_load32(&_mapped_total) * _memory_page_size;
+ stats->unmapped_total = (size_t)atomic_load32(&_unmapped_total) * _memory_page_size;
+ stats->huge_alloc = (size_t)atomic_load32(&_huge_pages_current) * _memory_page_size;
+ stats->huge_alloc_peak = (size_t)_huge_pages_peak * _memory_page_size;
+#endif
+#if ENABLE_GLOBAL_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ global_cache_t* cache = &_memory_span_cache[iclass];
+ while (!atomic_cas32_acquire(&cache->lock, 1, 0))
+ _rpmalloc_spin();
+ uint32_t count = cache->count;
+#if ENABLE_UNLIMITED_CACHE
+ span_t* current_span = cache->overflow;
+ while (current_span) {
+ ++count;
+ current_span = current_span->next;
+ }
+#endif
+ atomic_store32_release(&cache->lock, 0);
+ stats->cached += count * (iclass + 1) * _memory_span_size;
+ }
+#endif
+}
+
+#if ENABLE_STATISTICS
+
+static void
+_memory_heap_dump_statistics(heap_t* heap, void* file) {
+ fprintf(file, "Heap %d stats:\n", heap->id);
+ fprintf(file, "Class CurAlloc PeakAlloc TotAlloc TotFree BlkSize BlkCount SpansCur SpansPeak PeakAllocMiB ToCacheMiB FromCacheMiB FromReserveMiB MmapCalls\n");
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ if (!atomic_load32(&heap->size_class_use[iclass].alloc_total))
+ continue;
+ fprintf(file, "%3u: %10u %10u %10u %10u %8u %8u %8d %9d %13zu %11zu %12zu %14zu %9u\n", (uint32_t)iclass,
+ atomic_load32(&heap->size_class_use[iclass].alloc_current),
+ heap->size_class_use[iclass].alloc_peak,
+ atomic_load32(&heap->size_class_use[iclass].alloc_total),
+ atomic_load32(&heap->size_class_use[iclass].free_total),
+ _memory_size_class[iclass].block_size,
+ _memory_size_class[iclass].block_count,
+ atomic_load32(&heap->size_class_use[iclass].spans_current),
+ heap->size_class_use[iclass].spans_peak,
+ ((size_t)heap->size_class_use[iclass].alloc_peak * (size_t)_memory_size_class[iclass].block_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_to_cache) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_cache) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->size_class_use[iclass].spans_from_reserved) * _memory_span_size) / (size_t)(1024 * 1024),
+ atomic_load32(&heap->size_class_use[iclass].spans_map_calls));
+ }
+ fprintf(file, "Spans Current Peak Deferred PeakMiB Cached ToCacheMiB FromCacheMiB ToReserveMiB FromReserveMiB ToGlobalMiB FromGlobalMiB MmapCalls\n");
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ if (!atomic_load32(&heap->span_use[iclass].high) && !atomic_load32(&heap->span_use[iclass].spans_map_calls))
+ continue;
+ fprintf(file, "%4u: %8d %8u %8u %8zu %7u %11zu %12zu %12zu %14zu %11zu %13zu %10u\n", (uint32_t)(iclass + 1),
+ atomic_load32(&heap->span_use[iclass].current),
+ atomic_load32(&heap->span_use[iclass].high),
+ atomic_load32(&heap->span_use[iclass].spans_deferred),
+ ((size_t)atomic_load32(&heap->span_use[iclass].high) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),
+#if ENABLE_THREAD_CACHE
+ (unsigned int)(!iclass ? heap->span_cache.count : heap->span_large_cache[iclass - 1].count),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_cache) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_cache) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
+#else
+ 0, (size_t)0, (size_t)0,
+#endif
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_reserved) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_reserved) * (iclass + 1) * _memory_span_size) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_to_global) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),
+ ((size_t)atomic_load32(&heap->span_use[iclass].spans_from_global) * (size_t)_memory_span_size * (iclass + 1)) / (size_t)(1024 * 1024),
+ atomic_load32(&heap->span_use[iclass].spans_map_calls));
+ }
+ fprintf(file, "Full spans: %zu\n", heap->full_span_count);
+ fprintf(file, "ThreadToGlobalMiB GlobalToThreadMiB\n");
+ fprintf(file, "%17zu %17zu\n", (size_t)atomic_load64(&heap->thread_to_global) / (size_t)(1024 * 1024), (size_t)atomic_load64(&heap->global_to_thread) / (size_t)(1024 * 1024));
+}
+
+#endif
+
+void
+rpmalloc_dump_statistics(void* file) {
+#if ENABLE_STATISTICS
+ for (size_t list_idx = 0; list_idx < HEAP_ARRAY_SIZE; ++list_idx) {
+ heap_t* heap = _memory_heaps[list_idx];
+ while (heap) {
+ int need_dump = 0;
+ for (size_t iclass = 0; !need_dump && (iclass < SIZE_CLASS_COUNT); ++iclass) {
+ if (!atomic_load32(&heap->size_class_use[iclass].alloc_total)) {
+ rpmalloc_assert(!atomic_load32(&heap->size_class_use[iclass].free_total), "Heap statistics counter mismatch");
+ rpmalloc_assert(!atomic_load32(&heap->size_class_use[iclass].spans_map_calls), "Heap statistics counter mismatch");
+ continue;
+ }
+ need_dump = 1;
+ }
+ for (size_t iclass = 0; !need_dump && (iclass < LARGE_CLASS_COUNT); ++iclass) {
+ if (!atomic_load32(&heap->span_use[iclass].high) && !atomic_load32(&heap->span_use[iclass].spans_map_calls))
+ continue;
+ need_dump = 1;
+ }
+ if (need_dump)
+ _memory_heap_dump_statistics(heap, file);
+ heap = heap->next_heap;
+ }
+ }
+ fprintf(file, "Global stats:\n");
+ size_t huge_current = (size_t)atomic_load32(&_huge_pages_current) * _memory_page_size;
+ size_t huge_peak = (size_t)_huge_pages_peak * _memory_page_size;
+ fprintf(file, "HugeCurrentMiB HugePeakMiB\n");
+ fprintf(file, "%14zu %11zu\n", huge_current / (size_t)(1024 * 1024), huge_peak / (size_t)(1024 * 1024));
+
+#if ENABLE_GLOBAL_CACHE
+ fprintf(file, "GlobalCacheMiB\n");
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ global_cache_t* cache = _memory_span_cache + iclass;
+ size_t global_cache = (size_t)cache->count * iclass * _memory_span_size;
+
+ size_t global_overflow_cache = 0;
+ span_t* span = cache->overflow;
+ while (span) {
+ global_overflow_cache += iclass * _memory_span_size;
+ span = span->next;
+ }
+ if (global_cache || global_overflow_cache || cache->insert_count || cache->extract_count)
+ fprintf(file, "%4zu: %8zuMiB (%8zuMiB overflow) %14zu insert %14zu extract\n", iclass + 1, global_cache / (size_t)(1024 * 1024), global_overflow_cache / (size_t)(1024 * 1024), cache->insert_count, cache->extract_count);
+ }
+#endif
+
+ size_t mapped = (size_t)atomic_load32(&_mapped_pages) * _memory_page_size;
+ size_t mapped_os = (size_t)atomic_load32(&_mapped_pages_os) * _memory_page_size;
+ size_t mapped_peak = (size_t)_mapped_pages_peak * _memory_page_size;
+ size_t mapped_total = (size_t)atomic_load32(&_mapped_total) * _memory_page_size;
+ size_t unmapped_total = (size_t)atomic_load32(&_unmapped_total) * _memory_page_size;
+ fprintf(file, "MappedMiB MappedOSMiB MappedPeakMiB MappedTotalMiB UnmappedTotalMiB\n");
+ fprintf(file, "%9zu %11zu %13zu %14zu %16zu\n",
+ mapped / (size_t)(1024 * 1024),
+ mapped_os / (size_t)(1024 * 1024),
+ mapped_peak / (size_t)(1024 * 1024),
+ mapped_total / (size_t)(1024 * 1024),
+ unmapped_total / (size_t)(1024 * 1024));
+
+ fprintf(file, "\n");
+#if 0
+ int64_t allocated = atomic_load64(&_allocation_counter);
+ int64_t deallocated = atomic_load64(&_deallocation_counter);
+ fprintf(file, "Allocation count: %lli\n", allocated);
+ fprintf(file, "Deallocation count: %lli\n", deallocated);
+ fprintf(file, "Current allocations: %lli\n", (allocated - deallocated));
+ fprintf(file, "Master spans: %d\n", atomic_load32(&_master_spans));
+ fprintf(file, "Dangling master spans: %d\n", atomic_load32(&_unmapped_master_spans));
+#endif
+#endif
+ (void)sizeof(file);
+}
+
+#if RPMALLOC_FIRST_CLASS_HEAPS
+
+extern inline rpmalloc_heap_t*
+rpmalloc_heap_acquire(void) {
+ // Must be a pristine heap from newly mapped memory pages, or else memory blocks
+ // could already be allocated from the heap which would (wrongly) be released when
+ // heap is cleared with rpmalloc_heap_free_all(). Also heaps guaranteed to be
+ // pristine from the dedicated orphan list can be used.
+ heap_t* heap = _rpmalloc_heap_allocate(1);
+ rpmalloc_assume(heap != NULL);
+ heap->owner_thread = 0;
+ _rpmalloc_stat_inc(&_memory_active_heaps);
+ return heap;
+}
+
+extern inline void
+rpmalloc_heap_release(rpmalloc_heap_t* heap) {
+ if (heap)
+ _rpmalloc_heap_release(heap, 1, 1);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_alloc(rpmalloc_heap_t* heap, size_t size) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ return _rpmalloc_allocate(heap, size);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_alloc(rpmalloc_heap_t* heap, size_t alignment, size_t size) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ return _rpmalloc_aligned_allocate(heap, alignment, size);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_calloc(rpmalloc_heap_t* heap, size_t num, size_t size) {
+ return rpmalloc_heap_aligned_calloc(heap, 0, num, size);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_calloc(rpmalloc_heap_t* heap, size_t alignment, size_t num, size_t size) {
+ size_t total;
+#if ENABLE_VALIDATE_ARGS
+#if PLATFORM_WINDOWS
+ int err = SizeTMult(num, size, &total);
+ if ((err != S_OK) || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#else
+ int err = __builtin_umull_overflow(num, size, &total);
+ if (err || (total >= MAX_ALLOC_SIZE)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+#else
+ total = num * size;
+#endif
+ void* block = _rpmalloc_aligned_allocate(heap, alignment, total);
+ if (block)
+ memset(block, 0, total);
+ return block;
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_realloc(rpmalloc_heap_t* heap, void* ptr, size_t size, unsigned int flags) {
+#if ENABLE_VALIDATE_ARGS
+ if (size >= MAX_ALLOC_SIZE) {
+ errno = EINVAL;
+ return ptr;
+ }
+#endif
+ return _rpmalloc_reallocate(heap, ptr, size, 0, flags);
+}
+
+extern inline RPMALLOC_ALLOCATOR void*
+rpmalloc_heap_aligned_realloc(rpmalloc_heap_t* heap, void* ptr, size_t alignment, size_t size, unsigned int flags) {
+#if ENABLE_VALIDATE_ARGS
+ if ((size + alignment < size) || (alignment > _memory_page_size)) {
+ errno = EINVAL;
+ return 0;
+ }
+#endif
+ return _rpmalloc_aligned_reallocate(heap, ptr, alignment, size, 0, flags);
+}
+
+extern inline void
+rpmalloc_heap_free(rpmalloc_heap_t* heap, void* ptr) {
+ (void)sizeof(heap);
+ _rpmalloc_deallocate(ptr);
+}
+
+extern inline void
+rpmalloc_heap_free_all(rpmalloc_heap_t* heap) {
+ span_t* span;
+ span_t* next_span;
+
+ _rpmalloc_heap_cache_adopt_deferred(heap, 0);
+
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ span = heap->size_class[iclass].partial_span;
+ while (span) {
+ next_span = span->next;
+ _rpmalloc_heap_cache_insert(heap, span);
+ span = next_span;
+ }
+ heap->size_class[iclass].partial_span = 0;
+ span = heap->full_span[iclass];
+ while (span) {
+ next_span = span->next;
+ _rpmalloc_heap_cache_insert(heap, span);
+ span = next_span;
+ }
+ }
+ memset(heap->size_class, 0, sizeof(heap->size_class));
+ memset(heap->full_span, 0, sizeof(heap->full_span));
+
+ span = heap->large_huge_span;
+ while (span) {
+ next_span = span->next;
+ if (UNEXPECTED(span->size_class == SIZE_CLASS_HUGE))
+ _rpmalloc_deallocate_huge(span);
+ else
+ _rpmalloc_heap_cache_insert(heap, span);
+ span = next_span;
+ }
+ heap->large_huge_span = 0;
+ heap->full_span_count = 0;
+
+#if ENABLE_THREAD_CACHE
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ span_cache_t* span_cache;
+ if (!iclass)
+ span_cache = &heap->span_cache;
+ else
+ span_cache = (span_cache_t*)(heap->span_large_cache + (iclass - 1));
+ if (!span_cache->count)
+ continue;
+#if ENABLE_GLOBAL_CACHE
+ _rpmalloc_stat_add64(&heap->thread_to_global, span_cache->count * (iclass + 1) * _memory_span_size);
+ _rpmalloc_stat_add(&heap->span_use[iclass].spans_to_global, span_cache->count);
+ _rpmalloc_global_cache_insert_spans(span_cache->span, iclass + 1, span_cache->count);
+#else
+ for (size_t ispan = 0; ispan < span_cache->count; ++ispan)
+ _rpmalloc_span_unmap(span_cache->span[ispan]);
+#endif
+ span_cache->count = 0;
+ }
+#endif
+
+#if ENABLE_STATISTICS
+ for (size_t iclass = 0; iclass < SIZE_CLASS_COUNT; ++iclass) {
+ atomic_store32(&heap->size_class_use[iclass].alloc_current, 0);
+ atomic_store32(&heap->size_class_use[iclass].spans_current, 0);
+ }
+ for (size_t iclass = 0; iclass < LARGE_CLASS_COUNT; ++iclass) {
+ atomic_store32(&heap->span_use[iclass].current, 0);
+ }
+#endif
+}
+
+extern inline void
+rpmalloc_heap_thread_set_current(rpmalloc_heap_t* heap) {
+ heap_t* prev_heap = get_thread_heap_raw();
+ if (prev_heap != heap) {
+ set_thread_heap(heap);
+ if (prev_heap)
+ rpmalloc_heap_release(prev_heap);
+ }
+}
+
+extern inline rpmalloc_heap_t*
+rpmalloc_get_heap_for_ptr(void* ptr)
+{
+ //Grab the span, and then the heap from the span
+ span_t* span = (span_t*)((uintptr_t)ptr & _memory_span_mask);
+ if (span)
+ {
+ return span->heap;
+ }
+ return 0;
+}
+
+#endif
+
+#if ENABLE_PRELOAD || ENABLE_OVERRIDE
+
+#include "malloc.c"
+
+#endif
+
+void
+rpmalloc_linker_reference(void) {
+ (void)sizeof(_rpmalloc_initialized);
+}
+#line 0
+//{{FILE: 3rd_rpmalloci.c}}
+#define SYS_MEM_INIT() rpmalloc_initialize()
+#define SYS_MEM_REALLOC rprealloc
+#define SYS_MEM_SIZE rpmalloc_usable_size
+#endif
+
//#define SQLITE_OMIT_LOAD_EXTENSION
//#define SQLITE_CORE 1
//#define SQLITE_DEBUG 1
@@ -315518,4 +319799,9242 @@ array(char) base64_decode(const char *inp, unsigned inlen) { // array_free() aft
//#undef rehash
//#undef NB
//#undef threadid
+
+// editor
+#line 1 "3rd_icon_mdi.h"
+// Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py for languages C and C++
+// from https://raw.githubusercontent.com/Templarian/MaterialDesign-Webfont/master/css/materialdesignicons.css
+// for use with https://github.com/Templarian/MaterialDesign-Webfont/raw/master/fonts/materialdesignicons-webfont.ttf
+#pragma once
+
+#define FONT_ICON_FILE_NAME_MDI "materialdesignicons-webfont.ttf"
+
+#define ICON_MIN_MDI 0xF68C
+#define ICON_MAX_16_MDI 0xF68C
+#define ICON_MAX_MDI 0xF1CC7
+#define ICON_MDI_AB_TESTING "\xf3\xb0\x87\x89" // U+F01C9
+#define ICON_MDI_ABACUS "\xf3\xb1\x9b\xa0" // U+F16E0
+#define ICON_MDI_ABJAD_ARABIC "\xf3\xb1\x8c\xa8" // U+F1328
+#define ICON_MDI_ABJAD_HEBREW "\xf3\xb1\x8c\xa9" // U+F1329
+#define ICON_MDI_ABUGIDA_DEVANAGARI "\xf3\xb1\x8c\xaa" // U+F132A
+#define ICON_MDI_ABUGIDA_THAI "\xf3\xb1\x8c\xab" // U+F132B
+#define ICON_MDI_ACCESS_POINT "\xf3\xb0\x80\x83" // U+F0003
+#define ICON_MDI_ACCESS_POINT_CHECK "\xf3\xb1\x94\xb8" // U+F1538
+#define ICON_MDI_ACCESS_POINT_MINUS "\xf3\xb1\x94\xb9" // U+F1539
+#define ICON_MDI_ACCESS_POINT_NETWORK "\xf3\xb0\x80\x82" // U+F0002
+#define ICON_MDI_ACCESS_POINT_NETWORK_OFF "\xf3\xb0\xaf\xa1" // U+F0BE1
+#define ICON_MDI_ACCESS_POINT_OFF "\xf3\xb1\x94\x91" // U+F1511
+#define ICON_MDI_ACCESS_POINT_PLUS "\xf3\xb1\x94\xba" // U+F153A
+#define ICON_MDI_ACCESS_POINT_REMOVE "\xf3\xb1\x94\xbb" // U+F153B
+#define ICON_MDI_ACCOUNT "\xf3\xb0\x80\x84" // U+F0004
+#define ICON_MDI_ACCOUNT_ALERT "\xf3\xb0\x80\x85" // U+F0005
+#define ICON_MDI_ACCOUNT_ALERT_OUTLINE "\xf3\xb0\xad\x90" // U+F0B50
+#define ICON_MDI_ACCOUNT_ARROW_DOWN "\xf3\xb1\xa1\xa8" // U+F1868
+#define ICON_MDI_ACCOUNT_ARROW_DOWN_OUTLINE "\xf3\xb1\xa1\xa9" // U+F1869
+#define ICON_MDI_ACCOUNT_ARROW_LEFT "\xf3\xb0\xad\x91" // U+F0B51
+#define ICON_MDI_ACCOUNT_ARROW_LEFT_OUTLINE "\xf3\xb0\xad\x92" // U+F0B52
+#define ICON_MDI_ACCOUNT_ARROW_RIGHT "\xf3\xb0\xad\x93" // U+F0B53
+#define ICON_MDI_ACCOUNT_ARROW_RIGHT_OUTLINE "\xf3\xb0\xad\x94" // U+F0B54
+#define ICON_MDI_ACCOUNT_ARROW_UP "\xf3\xb1\xa1\xa7" // U+F1867
+#define ICON_MDI_ACCOUNT_ARROW_UP_OUTLINE "\xf3\xb1\xa1\xaa" // U+F186A
+#define ICON_MDI_ACCOUNT_BADGE "\xf3\xb1\xac\x8a" // U+F1B0A
+#define ICON_MDI_ACCOUNT_BADGE_OUTLINE "\xf3\xb1\xac\x8b" // U+F1B0B
+#define ICON_MDI_ACCOUNT_BOX "\xf3\xb0\x80\x86" // U+F0006
+#define ICON_MDI_ACCOUNT_BOX_MULTIPLE "\xf3\xb0\xa4\xb4" // U+F0934
+#define ICON_MDI_ACCOUNT_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x80\x8a" // U+F100A
+#define ICON_MDI_ACCOUNT_BOX_OUTLINE "\xf3\xb0\x80\x87" // U+F0007
+#define ICON_MDI_ACCOUNT_CANCEL "\xf3\xb1\x8b\x9f" // U+F12DF
+#define ICON_MDI_ACCOUNT_CANCEL_OUTLINE "\xf3\xb1\x8b\xa0" // U+F12E0
+#define ICON_MDI_ACCOUNT_CARD "\xf3\xb1\xae\xa4" // U+F1BA4
+#define ICON_MDI_ACCOUNT_CARD_OUTLINE "\xf3\xb1\xae\xa5" // U+F1BA5
+#define ICON_MDI_ACCOUNT_CASH "\xf3\xb1\x82\x97" // U+F1097
+#define ICON_MDI_ACCOUNT_CASH_OUTLINE "\xf3\xb1\x82\x98" // U+F1098
+#define ICON_MDI_ACCOUNT_CHECK "\xf3\xb0\x80\x88" // U+F0008
+#define ICON_MDI_ACCOUNT_CHECK_OUTLINE "\xf3\xb0\xaf\xa2" // U+F0BE2
+#define ICON_MDI_ACCOUNT_CHILD "\xf3\xb0\xaa\x89" // U+F0A89
+#define ICON_MDI_ACCOUNT_CHILD_CIRCLE "\xf3\xb0\xaa\x8a" // U+F0A8A
+#define ICON_MDI_ACCOUNT_CHILD_OUTLINE "\xf3\xb1\x83\x88" // U+F10C8
+#define ICON_MDI_ACCOUNT_CIRCLE "\xf3\xb0\x80\x89" // U+F0009
+#define ICON_MDI_ACCOUNT_CIRCLE_OUTLINE "\xf3\xb0\xad\x95" // U+F0B55
+#define ICON_MDI_ACCOUNT_CLOCK "\xf3\xb0\xad\x96" // U+F0B56
+#define ICON_MDI_ACCOUNT_CLOCK_OUTLINE "\xf3\xb0\xad\x97" // U+F0B57
+#define ICON_MDI_ACCOUNT_COG "\xf3\xb1\x8d\xb0" // U+F1370
+#define ICON_MDI_ACCOUNT_COG_OUTLINE "\xf3\xb1\x8d\xb1" // U+F1371
+#define ICON_MDI_ACCOUNT_CONVERT "\xf3\xb0\x80\x8a" // U+F000A
+#define ICON_MDI_ACCOUNT_CONVERT_OUTLINE "\xf3\xb1\x8c\x81" // U+F1301
+#define ICON_MDI_ACCOUNT_COWBOY_HAT "\xf3\xb0\xba\x9b" // U+F0E9B
+#define ICON_MDI_ACCOUNT_COWBOY_HAT_OUTLINE "\xf3\xb1\x9f\xb3" // U+F17F3
+#define ICON_MDI_ACCOUNT_CREDIT_CARD "\xf3\xb1\xae\xa6" // U+F1BA6
+#define ICON_MDI_ACCOUNT_CREDIT_CARD_OUTLINE "\xf3\xb1\xae\xa7" // U+F1BA7
+#define ICON_MDI_ACCOUNT_DETAILS "\xf3\xb0\x98\xb1" // U+F0631
+#define ICON_MDI_ACCOUNT_DETAILS_OUTLINE "\xf3\xb1\x8d\xb2" // U+F1372
+#define ICON_MDI_ACCOUNT_EDIT "\xf3\xb0\x9a\xbc" // U+F06BC
+#define ICON_MDI_ACCOUNT_EDIT_OUTLINE "\xf3\xb0\xbf\xbb" // U+F0FFB
+#define ICON_MDI_ACCOUNT_EYE "\xf3\xb0\x90\xa0" // U+F0420
+#define ICON_MDI_ACCOUNT_EYE_OUTLINE "\xf3\xb1\x89\xbb" // U+F127B
+#define ICON_MDI_ACCOUNT_FILE "\xf3\xb1\xb2\xa7" // U+F1CA7
+#define ICON_MDI_ACCOUNT_FILE_OUTLINE "\xf3\xb1\xb2\xa8" // U+F1CA8
+#define ICON_MDI_ACCOUNT_FILE_TEXT "\xf3\xb1\xb2\xa9" // U+F1CA9
+#define ICON_MDI_ACCOUNT_FILE_TEXT_OUTLINE "\xf3\xb1\xb2\xaa" // U+F1CAA
+#define ICON_MDI_ACCOUNT_FILTER "\xf3\xb0\xa4\xb6" // U+F0936
+#define ICON_MDI_ACCOUNT_FILTER_OUTLINE "\xf3\xb0\xbe\x9d" // U+F0F9D
+#define ICON_MDI_ACCOUNT_GROUP "\xf3\xb0\xa1\x89" // U+F0849
+#define ICON_MDI_ACCOUNT_GROUP_OUTLINE "\xf3\xb0\xad\x98" // U+F0B58
+#define ICON_MDI_ACCOUNT_HARD_HAT "\xf3\xb0\x96\xb5" // U+F05B5
+#define ICON_MDI_ACCOUNT_HARD_HAT_OUTLINE "\xf3\xb1\xa8\x9f" // U+F1A1F
+#define ICON_MDI_ACCOUNT_HEART "\xf3\xb0\xa2\x99" // U+F0899
+#define ICON_MDI_ACCOUNT_HEART_OUTLINE "\xf3\xb0\xaf\xa3" // U+F0BE3
+#define ICON_MDI_ACCOUNT_INJURY "\xf3\xb1\xa0\x95" // U+F1815
+#define ICON_MDI_ACCOUNT_INJURY_OUTLINE "\xf3\xb1\xa0\x96" // U+F1816
+#define ICON_MDI_ACCOUNT_KEY "\xf3\xb0\x80\x8b" // U+F000B
+#define ICON_MDI_ACCOUNT_KEY_OUTLINE "\xf3\xb0\xaf\xa4" // U+F0BE4
+#define ICON_MDI_ACCOUNT_LOCK "\xf3\xb1\x85\x9e" // U+F115E
+#define ICON_MDI_ACCOUNT_LOCK_OPEN "\xf3\xb1\xa5\xa0" // U+F1960
+#define ICON_MDI_ACCOUNT_LOCK_OPEN_OUTLINE "\xf3\xb1\xa5\xa1" // U+F1961
+#define ICON_MDI_ACCOUNT_LOCK_OUTLINE "\xf3\xb1\x85\x9f" // U+F115F
+#define ICON_MDI_ACCOUNT_MINUS "\xf3\xb0\x80\x8d" // U+F000D
+#define ICON_MDI_ACCOUNT_MINUS_OUTLINE "\xf3\xb0\xab\xac" // U+F0AEC
+#define ICON_MDI_ACCOUNT_MULTIPLE "\xf3\xb0\x80\x8e" // U+F000E
+#define ICON_MDI_ACCOUNT_MULTIPLE_CHECK "\xf3\xb0\xa3\x85" // U+F08C5
+#define ICON_MDI_ACCOUNT_MULTIPLE_CHECK_OUTLINE "\xf3\xb1\x87\xbe" // U+F11FE
+#define ICON_MDI_ACCOUNT_MULTIPLE_MINUS "\xf3\xb0\x97\x93" // U+F05D3
+#define ICON_MDI_ACCOUNT_MULTIPLE_MINUS_OUTLINE "\xf3\xb0\xaf\xa5" // U+F0BE5
+#define ICON_MDI_ACCOUNT_MULTIPLE_OUTLINE "\xf3\xb0\x80\x8f" // U+F000F
+#define ICON_MDI_ACCOUNT_MULTIPLE_PLUS "\xf3\xb0\x80\x90" // U+F0010
+#define ICON_MDI_ACCOUNT_MULTIPLE_PLUS_OUTLINE "\xf3\xb0\xa0\x80" // U+F0800
+#define ICON_MDI_ACCOUNT_MULTIPLE_REMOVE "\xf3\xb1\x88\x8a" // U+F120A
+#define ICON_MDI_ACCOUNT_MULTIPLE_REMOVE_OUTLINE "\xf3\xb1\x88\x8b" // U+F120B
+#define ICON_MDI_ACCOUNT_MUSIC "\xf3\xb0\xa0\x83" // U+F0803
+#define ICON_MDI_ACCOUNT_MUSIC_OUTLINE "\xf3\xb0\xb3\xa9" // U+F0CE9
+#define ICON_MDI_ACCOUNT_NETWORK "\xf3\xb0\x80\x91" // U+F0011
+#define ICON_MDI_ACCOUNT_NETWORK_OFF "\xf3\xb1\xab\xb1" // U+F1AF1
+#define ICON_MDI_ACCOUNT_NETWORK_OFF_OUTLINE "\xf3\xb1\xab\xb2" // U+F1AF2
+#define ICON_MDI_ACCOUNT_NETWORK_OUTLINE "\xf3\xb0\xaf\xa6" // U+F0BE6
+#define ICON_MDI_ACCOUNT_OFF "\xf3\xb0\x80\x92" // U+F0012
+#define ICON_MDI_ACCOUNT_OFF_OUTLINE "\xf3\xb0\xaf\xa7" // U+F0BE7
+#define ICON_MDI_ACCOUNT_OUTLINE "\xf3\xb0\x80\x93" // U+F0013
+#define ICON_MDI_ACCOUNT_PLUS "\xf3\xb0\x80\x94" // U+F0014
+#define ICON_MDI_ACCOUNT_PLUS_OUTLINE "\xf3\xb0\xa0\x81" // U+F0801
+#define ICON_MDI_ACCOUNT_QUESTION "\xf3\xb0\xad\x99" // U+F0B59
+#define ICON_MDI_ACCOUNT_QUESTION_OUTLINE "\xf3\xb0\xad\x9a" // U+F0B5A
+#define ICON_MDI_ACCOUNT_REACTIVATE "\xf3\xb1\x94\xab" // U+F152B
+#define ICON_MDI_ACCOUNT_REACTIVATE_OUTLINE "\xf3\xb1\x94\xac" // U+F152C
+#define ICON_MDI_ACCOUNT_REMOVE "\xf3\xb0\x80\x95" // U+F0015
+#define ICON_MDI_ACCOUNT_REMOVE_OUTLINE "\xf3\xb0\xab\xad" // U+F0AED
+#define ICON_MDI_ACCOUNT_SCHOOL "\xf3\xb1\xa8\xa0" // U+F1A20
+#define ICON_MDI_ACCOUNT_SCHOOL_OUTLINE "\xf3\xb1\xa8\xa1" // U+F1A21
+#define ICON_MDI_ACCOUNT_SEARCH "\xf3\xb0\x80\x96" // U+F0016
+#define ICON_MDI_ACCOUNT_SEARCH_OUTLINE "\xf3\xb0\xa4\xb5" // U+F0935
+#define ICON_MDI_ACCOUNT_SETTINGS "\xf3\xb0\x98\xb0" // U+F0630
+#define ICON_MDI_ACCOUNT_SETTINGS_OUTLINE "\xf3\xb1\x83\x89" // U+F10C9
+#define ICON_MDI_ACCOUNT_STAR "\xf3\xb0\x80\x97" // U+F0017
+#define ICON_MDI_ACCOUNT_STAR_OUTLINE "\xf3\xb0\xaf\xa8" // U+F0BE8
+#define ICON_MDI_ACCOUNT_SUPERVISOR "\xf3\xb0\xaa\x8b" // U+F0A8B
+#define ICON_MDI_ACCOUNT_SUPERVISOR_CIRCLE "\xf3\xb0\xaa\x8c" // U+F0A8C
+#define ICON_MDI_ACCOUNT_SUPERVISOR_CIRCLE_OUTLINE "\xf3\xb1\x93\xac" // U+F14EC
+#define ICON_MDI_ACCOUNT_SUPERVISOR_OUTLINE "\xf3\xb1\x84\xad" // U+F112D
+#define ICON_MDI_ACCOUNT_SWITCH "\xf3\xb0\x80\x99" // U+F0019
+#define ICON_MDI_ACCOUNT_SWITCH_OUTLINE "\xf3\xb0\x93\x8b" // U+F04CB
+#define ICON_MDI_ACCOUNT_SYNC "\xf3\xb1\xa4\x9b" // U+F191B
+#define ICON_MDI_ACCOUNT_SYNC_OUTLINE "\xf3\xb1\xa4\x9c" // U+F191C
+#define ICON_MDI_ACCOUNT_TAG "\xf3\xb1\xb0\x9b" // U+F1C1B
+#define ICON_MDI_ACCOUNT_TAG_OUTLINE "\xf3\xb1\xb0\x9c" // U+F1C1C
+#define ICON_MDI_ACCOUNT_TIE "\xf3\xb0\xb3\xa3" // U+F0CE3
+#define ICON_MDI_ACCOUNT_TIE_HAT "\xf3\xb1\xa2\x98" // U+F1898
+#define ICON_MDI_ACCOUNT_TIE_HAT_OUTLINE "\xf3\xb1\xa2\x99" // U+F1899
+#define ICON_MDI_ACCOUNT_TIE_OUTLINE "\xf3\xb1\x83\x8a" // U+F10CA
+#define ICON_MDI_ACCOUNT_TIE_VOICE "\xf3\xb1\x8c\x88" // U+F1308
+#define ICON_MDI_ACCOUNT_TIE_VOICE_OFF "\xf3\xb1\x8c\x8a" // U+F130A
+#define ICON_MDI_ACCOUNT_TIE_VOICE_OFF_OUTLINE "\xf3\xb1\x8c\x8b" // U+F130B
+#define ICON_MDI_ACCOUNT_TIE_VOICE_OUTLINE "\xf3\xb1\x8c\x89" // U+F1309
+#define ICON_MDI_ACCOUNT_TIE_WOMAN "\xf3\xb1\xaa\x8c" // U+F1A8C
+#define ICON_MDI_ACCOUNT_VOICE "\xf3\xb0\x97\x8b" // U+F05CB
+#define ICON_MDI_ACCOUNT_VOICE_OFF "\xf3\xb0\xbb\x94" // U+F0ED4
+#define ICON_MDI_ACCOUNT_WRENCH "\xf3\xb1\xa2\x9a" // U+F189A
+#define ICON_MDI_ACCOUNT_WRENCH_OUTLINE "\xf3\xb1\xa2\x9b" // U+F189B
+#define ICON_MDI_ADJUST "\xf3\xb0\x80\x9a" // U+F001A
+#define ICON_MDI_ADVERTISEMENTS "\xf3\xb1\xa4\xaa" // U+F192A
+#define ICON_MDI_ADVERTISEMENTS_OFF "\xf3\xb1\xa4\xab" // U+F192B
+#define ICON_MDI_AIR_CONDITIONER "\xf3\xb0\x80\x9b" // U+F001B
+#define ICON_MDI_AIR_FILTER "\xf3\xb0\xb5\x83" // U+F0D43
+#define ICON_MDI_AIR_HORN "\xf3\xb0\xb6\xac" // U+F0DAC
+#define ICON_MDI_AIR_HUMIDIFIER "\xf3\xb1\x82\x99" // U+F1099
+#define ICON_MDI_AIR_HUMIDIFIER_OFF "\xf3\xb1\x91\xa6" // U+F1466
+#define ICON_MDI_AIR_PURIFIER "\xf3\xb0\xb5\x84" // U+F0D44
+#define ICON_MDI_AIR_PURIFIER_OFF "\xf3\xb1\xad\x97" // U+F1B57
+#define ICON_MDI_AIRBAG "\xf3\xb0\xaf\xa9" // U+F0BE9
+#define ICON_MDI_AIRBALLOON "\xf3\xb0\x80\x9c" // U+F001C
+#define ICON_MDI_AIRBALLOON_OUTLINE "\xf3\xb1\x80\x8b" // U+F100B
+#define ICON_MDI_AIRPLANE "\xf3\xb0\x80\x9d" // U+F001D
+#define ICON_MDI_AIRPLANE_ALERT "\xf3\xb1\xa1\xba" // U+F187A
+#define ICON_MDI_AIRPLANE_CHECK "\xf3\xb1\xa1\xbb" // U+F187B
+#define ICON_MDI_AIRPLANE_CLOCK "\xf3\xb1\xa1\xbc" // U+F187C
+#define ICON_MDI_AIRPLANE_COG "\xf3\xb1\xa1\xbd" // U+F187D
+#define ICON_MDI_AIRPLANE_EDIT "\xf3\xb1\xa1\xbe" // U+F187E
+#define ICON_MDI_AIRPLANE_LANDING "\xf3\xb0\x97\x94" // U+F05D4
+#define ICON_MDI_AIRPLANE_MARKER "\xf3\xb1\xa1\xbf" // U+F187F
+#define ICON_MDI_AIRPLANE_MINUS "\xf3\xb1\xa2\x80" // U+F1880
+#define ICON_MDI_AIRPLANE_OFF "\xf3\xb0\x80\x9e" // U+F001E
+#define ICON_MDI_AIRPLANE_PLUS "\xf3\xb1\xa2\x81" // U+F1881
+#define ICON_MDI_AIRPLANE_REMOVE "\xf3\xb1\xa2\x82" // U+F1882
+#define ICON_MDI_AIRPLANE_SEARCH "\xf3\xb1\xa2\x83" // U+F1883
+#define ICON_MDI_AIRPLANE_SETTINGS "\xf3\xb1\xa2\x84" // U+F1884
+#define ICON_MDI_AIRPLANE_TAKEOFF "\xf3\xb0\x97\x95" // U+F05D5
+#define ICON_MDI_AIRPORT "\xf3\xb0\xa1\x8b" // U+F084B
+#define ICON_MDI_ALARM "\xf3\xb0\x80\xa0" // U+F0020
+#define ICON_MDI_ALARM_BELL "\xf3\xb0\x9e\x8e" // U+F078E
+#define ICON_MDI_ALARM_CHECK "\xf3\xb0\x80\xa1" // U+F0021
+#define ICON_MDI_ALARM_LIGHT "\xf3\xb0\x9e\x8f" // U+F078F
+#define ICON_MDI_ALARM_LIGHT_OFF "\xf3\xb1\x9c\x9e" // U+F171E
+#define ICON_MDI_ALARM_LIGHT_OFF_OUTLINE "\xf3\xb1\x9c\x9f" // U+F171F
+#define ICON_MDI_ALARM_LIGHT_OUTLINE "\xf3\xb0\xaf\xaa" // U+F0BEA
+#define ICON_MDI_ALARM_MULTIPLE "\xf3\xb0\x80\xa2" // U+F0022
+#define ICON_MDI_ALARM_NOTE "\xf3\xb0\xb9\xb1" // U+F0E71
+#define ICON_MDI_ALARM_NOTE_OFF "\xf3\xb0\xb9\xb2" // U+F0E72
+#define ICON_MDI_ALARM_OFF "\xf3\xb0\x80\xa3" // U+F0023
+#define ICON_MDI_ALARM_PANEL "\xf3\xb1\x97\x84" // U+F15C4
+#define ICON_MDI_ALARM_PANEL_OUTLINE "\xf3\xb1\x97\x85" // U+F15C5
+#define ICON_MDI_ALARM_PLUS "\xf3\xb0\x80\xa4" // U+F0024
+#define ICON_MDI_ALARM_SNOOZE "\xf3\xb0\x9a\x8e" // U+F068E
+#define ICON_MDI_ALBUM "\xf3\xb0\x80\xa5" // U+F0025
+#define ICON_MDI_ALERT "\xf3\xb0\x80\xa6" // U+F0026
+#define ICON_MDI_ALERT_BOX "\xf3\xb0\x80\xa7" // U+F0027
+#define ICON_MDI_ALERT_BOX_OUTLINE "\xf3\xb0\xb3\xa4" // U+F0CE4
+#define ICON_MDI_ALERT_CIRCLE "\xf3\xb0\x80\xa8" // U+F0028
+#define ICON_MDI_ALERT_CIRCLE_CHECK "\xf3\xb1\x87\xad" // U+F11ED
+#define ICON_MDI_ALERT_CIRCLE_CHECK_OUTLINE "\xf3\xb1\x87\xae" // U+F11EE
+#define ICON_MDI_ALERT_CIRCLE_OUTLINE "\xf3\xb0\x97\x96" // U+F05D6
+#define ICON_MDI_ALERT_DECAGRAM "\xf3\xb0\x9a\xbd" // U+F06BD
+#define ICON_MDI_ALERT_DECAGRAM_OUTLINE "\xf3\xb0\xb3\xa5" // U+F0CE5
+#define ICON_MDI_ALERT_MINUS "\xf3\xb1\x92\xbb" // U+F14BB
+#define ICON_MDI_ALERT_MINUS_OUTLINE "\xf3\xb1\x92\xbe" // U+F14BE
+#define ICON_MDI_ALERT_OCTAGON "\xf3\xb0\x80\xa9" // U+F0029
+#define ICON_MDI_ALERT_OCTAGON_OUTLINE "\xf3\xb0\xb3\xa6" // U+F0CE6
+#define ICON_MDI_ALERT_OCTAGRAM "\xf3\xb0\x9d\xa7" // U+F0767
+#define ICON_MDI_ALERT_OCTAGRAM_OUTLINE "\xf3\xb0\xb3\xa7" // U+F0CE7
+#define ICON_MDI_ALERT_OUTLINE "\xf3\xb0\x80\xaa" // U+F002A
+#define ICON_MDI_ALERT_PLUS "\xf3\xb1\x92\xba" // U+F14BA
+#define ICON_MDI_ALERT_PLUS_OUTLINE "\xf3\xb1\x92\xbd" // U+F14BD
+#define ICON_MDI_ALERT_REMOVE "\xf3\xb1\x92\xbc" // U+F14BC
+#define ICON_MDI_ALERT_REMOVE_OUTLINE "\xf3\xb1\x92\xbf" // U+F14BF
+#define ICON_MDI_ALERT_RHOMBUS "\xf3\xb1\x87\x8e" // U+F11CE
+#define ICON_MDI_ALERT_RHOMBUS_OUTLINE "\xf3\xb1\x87\x8f" // U+F11CF
+#define ICON_MDI_ALIEN "\xf3\xb0\xa2\x9a" // U+F089A
+#define ICON_MDI_ALIEN_OUTLINE "\xf3\xb1\x83\x8b" // U+F10CB
+#define ICON_MDI_ALIGN_HORIZONTAL_CENTER "\xf3\xb1\x87\x83" // U+F11C3
+#define ICON_MDI_ALIGN_HORIZONTAL_DISTRIBUTE "\xf3\xb1\xa5\xa2" // U+F1962
+#define ICON_MDI_ALIGN_HORIZONTAL_LEFT "\xf3\xb1\x87\x82" // U+F11C2
+#define ICON_MDI_ALIGN_HORIZONTAL_RIGHT "\xf3\xb1\x87\x84" // U+F11C4
+#define ICON_MDI_ALIGN_VERTICAL_BOTTOM "\xf3\xb1\x87\x85" // U+F11C5
+#define ICON_MDI_ALIGN_VERTICAL_CENTER "\xf3\xb1\x87\x86" // U+F11C6
+#define ICON_MDI_ALIGN_VERTICAL_DISTRIBUTE "\xf3\xb1\xa5\xa3" // U+F1963
+#define ICON_MDI_ALIGN_VERTICAL_TOP "\xf3\xb1\x87\x87" // U+F11C7
+#define ICON_MDI_ALL_INCLUSIVE "\xf3\xb0\x9a\xbe" // U+F06BE
+#define ICON_MDI_ALL_INCLUSIVE_BOX "\xf3\xb1\xa2\x8d" // U+F188D
+#define ICON_MDI_ALL_INCLUSIVE_BOX_OUTLINE "\xf3\xb1\xa2\x8e" // U+F188E
+#define ICON_MDI_ALLERGY "\xf3\xb1\x89\x98" // U+F1258
+#define ICON_MDI_ALPHA "\xf3\xb0\x80\xab" // U+F002B
+#define ICON_MDI_ALPHA_A "\xf3\xb0\xab\xae" // U+F0AEE
+#define ICON_MDI_ALPHA_A_BOX "\xf3\xb0\xac\x88" // U+F0B08
+#define ICON_MDI_ALPHA_A_BOX_OUTLINE "\xf3\xb0\xaf\xab" // U+F0BEB
+#define ICON_MDI_ALPHA_A_CIRCLE "\xf3\xb0\xaf\xac" // U+F0BEC
+#define ICON_MDI_ALPHA_A_CIRCLE_OUTLINE "\xf3\xb0\xaf\xad" // U+F0BED
+#define ICON_MDI_ALPHA_B "\xf3\xb0\xab\xaf" // U+F0AEF
+#define ICON_MDI_ALPHA_B_BOX "\xf3\xb0\xac\x89" // U+F0B09
+#define ICON_MDI_ALPHA_B_BOX_OUTLINE "\xf3\xb0\xaf\xae" // U+F0BEE
+#define ICON_MDI_ALPHA_B_CIRCLE "\xf3\xb0\xaf\xaf" // U+F0BEF
+#define ICON_MDI_ALPHA_B_CIRCLE_OUTLINE "\xf3\xb0\xaf\xb0" // U+F0BF0
+#define ICON_MDI_ALPHA_C "\xf3\xb0\xab\xb0" // U+F0AF0
+#define ICON_MDI_ALPHA_C_BOX "\xf3\xb0\xac\x8a" // U+F0B0A
+#define ICON_MDI_ALPHA_C_BOX_OUTLINE "\xf3\xb0\xaf\xb1" // U+F0BF1
+#define ICON_MDI_ALPHA_C_CIRCLE "\xf3\xb0\xaf\xb2" // U+F0BF2
+#define ICON_MDI_ALPHA_C_CIRCLE_OUTLINE "\xf3\xb0\xaf\xb3" // U+F0BF3
+#define ICON_MDI_ALPHA_D "\xf3\xb0\xab\xb1" // U+F0AF1
+#define ICON_MDI_ALPHA_D_BOX "\xf3\xb0\xac\x8b" // U+F0B0B
+#define ICON_MDI_ALPHA_D_BOX_OUTLINE "\xf3\xb0\xaf\xb4" // U+F0BF4
+#define ICON_MDI_ALPHA_D_CIRCLE "\xf3\xb0\xaf\xb5" // U+F0BF5
+#define ICON_MDI_ALPHA_D_CIRCLE_OUTLINE "\xf3\xb0\xaf\xb6" // U+F0BF6
+#define ICON_MDI_ALPHA_E "\xf3\xb0\xab\xb2" // U+F0AF2
+#define ICON_MDI_ALPHA_E_BOX "\xf3\xb0\xac\x8c" // U+F0B0C
+#define ICON_MDI_ALPHA_E_BOX_OUTLINE "\xf3\xb0\xaf\xb7" // U+F0BF7
+#define ICON_MDI_ALPHA_E_CIRCLE "\xf3\xb0\xaf\xb8" // U+F0BF8
+#define ICON_MDI_ALPHA_E_CIRCLE_OUTLINE "\xf3\xb0\xaf\xb9" // U+F0BF9
+#define ICON_MDI_ALPHA_F "\xf3\xb0\xab\xb3" // U+F0AF3
+#define ICON_MDI_ALPHA_F_BOX "\xf3\xb0\xac\x8d" // U+F0B0D
+#define ICON_MDI_ALPHA_F_BOX_OUTLINE "\xf3\xb0\xaf\xba" // U+F0BFA
+#define ICON_MDI_ALPHA_F_CIRCLE "\xf3\xb0\xaf\xbb" // U+F0BFB
+#define ICON_MDI_ALPHA_F_CIRCLE_OUTLINE "\xf3\xb0\xaf\xbc" // U+F0BFC
+#define ICON_MDI_ALPHA_G "\xf3\xb0\xab\xb4" // U+F0AF4
+#define ICON_MDI_ALPHA_G_BOX "\xf3\xb0\xac\x8e" // U+F0B0E
+#define ICON_MDI_ALPHA_G_BOX_OUTLINE "\xf3\xb0\xaf\xbd" // U+F0BFD
+#define ICON_MDI_ALPHA_G_CIRCLE "\xf3\xb0\xaf\xbe" // U+F0BFE
+#define ICON_MDI_ALPHA_G_CIRCLE_OUTLINE "\xf3\xb0\xaf\xbf" // U+F0BFF
+#define ICON_MDI_ALPHA_H "\xf3\xb0\xab\xb5" // U+F0AF5
+#define ICON_MDI_ALPHA_H_BOX "\xf3\xb0\xac\x8f" // U+F0B0F
+#define ICON_MDI_ALPHA_H_BOX_OUTLINE "\xf3\xb0\xb0\x80" // U+F0C00
+#define ICON_MDI_ALPHA_H_CIRCLE "\xf3\xb0\xb0\x81" // U+F0C01
+#define ICON_MDI_ALPHA_H_CIRCLE_OUTLINE "\xf3\xb0\xb0\x82" // U+F0C02
+#define ICON_MDI_ALPHA_I "\xf3\xb0\xab\xb6" // U+F0AF6
+#define ICON_MDI_ALPHA_I_BOX "\xf3\xb0\xac\x90" // U+F0B10
+#define ICON_MDI_ALPHA_I_BOX_OUTLINE "\xf3\xb0\xb0\x83" // U+F0C03
+#define ICON_MDI_ALPHA_I_CIRCLE "\xf3\xb0\xb0\x84" // U+F0C04
+#define ICON_MDI_ALPHA_I_CIRCLE_OUTLINE "\xf3\xb0\xb0\x85" // U+F0C05
+#define ICON_MDI_ALPHA_J "\xf3\xb0\xab\xb7" // U+F0AF7
+#define ICON_MDI_ALPHA_J_BOX "\xf3\xb0\xac\x91" // U+F0B11
+#define ICON_MDI_ALPHA_J_BOX_OUTLINE "\xf3\xb0\xb0\x86" // U+F0C06
+#define ICON_MDI_ALPHA_J_CIRCLE "\xf3\xb0\xb0\x87" // U+F0C07
+#define ICON_MDI_ALPHA_J_CIRCLE_OUTLINE "\xf3\xb0\xb0\x88" // U+F0C08
+#define ICON_MDI_ALPHA_K "\xf3\xb0\xab\xb8" // U+F0AF8
+#define ICON_MDI_ALPHA_K_BOX "\xf3\xb0\xac\x92" // U+F0B12
+#define ICON_MDI_ALPHA_K_BOX_OUTLINE "\xf3\xb0\xb0\x89" // U+F0C09
+#define ICON_MDI_ALPHA_K_CIRCLE "\xf3\xb0\xb0\x8a" // U+F0C0A
+#define ICON_MDI_ALPHA_K_CIRCLE_OUTLINE "\xf3\xb0\xb0\x8b" // U+F0C0B
+#define ICON_MDI_ALPHA_L "\xf3\xb0\xab\xb9" // U+F0AF9
+#define ICON_MDI_ALPHA_L_BOX "\xf3\xb0\xac\x93" // U+F0B13
+#define ICON_MDI_ALPHA_L_BOX_OUTLINE "\xf3\xb0\xb0\x8c" // U+F0C0C
+#define ICON_MDI_ALPHA_L_CIRCLE "\xf3\xb0\xb0\x8d" // U+F0C0D
+#define ICON_MDI_ALPHA_L_CIRCLE_OUTLINE "\xf3\xb0\xb0\x8e" // U+F0C0E
+#define ICON_MDI_ALPHA_M "\xf3\xb0\xab\xba" // U+F0AFA
+#define ICON_MDI_ALPHA_M_BOX "\xf3\xb0\xac\x94" // U+F0B14
+#define ICON_MDI_ALPHA_M_BOX_OUTLINE "\xf3\xb0\xb0\x8f" // U+F0C0F
+#define ICON_MDI_ALPHA_M_CIRCLE "\xf3\xb0\xb0\x90" // U+F0C10
+#define ICON_MDI_ALPHA_M_CIRCLE_OUTLINE "\xf3\xb0\xb0\x91" // U+F0C11
+#define ICON_MDI_ALPHA_N "\xf3\xb0\xab\xbb" // U+F0AFB
+#define ICON_MDI_ALPHA_N_BOX "\xf3\xb0\xac\x95" // U+F0B15
+#define ICON_MDI_ALPHA_N_BOX_OUTLINE "\xf3\xb0\xb0\x92" // U+F0C12
+#define ICON_MDI_ALPHA_N_CIRCLE "\xf3\xb0\xb0\x93" // U+F0C13
+#define ICON_MDI_ALPHA_N_CIRCLE_OUTLINE "\xf3\xb0\xb0\x94" // U+F0C14
+#define ICON_MDI_ALPHA_O "\xf3\xb0\xab\xbc" // U+F0AFC
+#define ICON_MDI_ALPHA_O_BOX "\xf3\xb0\xac\x96" // U+F0B16
+#define ICON_MDI_ALPHA_O_BOX_OUTLINE "\xf3\xb0\xb0\x95" // U+F0C15
+#define ICON_MDI_ALPHA_O_CIRCLE "\xf3\xb0\xb0\x96" // U+F0C16
+#define ICON_MDI_ALPHA_O_CIRCLE_OUTLINE "\xf3\xb0\xb0\x97" // U+F0C17
+#define ICON_MDI_ALPHA_P "\xf3\xb0\xab\xbd" // U+F0AFD
+#define ICON_MDI_ALPHA_P_BOX "\xf3\xb0\xac\x97" // U+F0B17
+#define ICON_MDI_ALPHA_P_BOX_OUTLINE "\xf3\xb0\xb0\x98" // U+F0C18
+#define ICON_MDI_ALPHA_P_CIRCLE "\xf3\xb0\xb0\x99" // U+F0C19
+#define ICON_MDI_ALPHA_P_CIRCLE_OUTLINE "\xf3\xb0\xb0\x9a" // U+F0C1A
+#define ICON_MDI_ALPHA_Q "\xf3\xb0\xab\xbe" // U+F0AFE
+#define ICON_MDI_ALPHA_Q_BOX "\xf3\xb0\xac\x98" // U+F0B18
+#define ICON_MDI_ALPHA_Q_BOX_OUTLINE "\xf3\xb0\xb0\x9b" // U+F0C1B
+#define ICON_MDI_ALPHA_Q_CIRCLE "\xf3\xb0\xb0\x9c" // U+F0C1C
+#define ICON_MDI_ALPHA_Q_CIRCLE_OUTLINE "\xf3\xb0\xb0\x9d" // U+F0C1D
+#define ICON_MDI_ALPHA_R "\xf3\xb0\xab\xbf" // U+F0AFF
+#define ICON_MDI_ALPHA_R_BOX "\xf3\xb0\xac\x99" // U+F0B19
+#define ICON_MDI_ALPHA_R_BOX_OUTLINE "\xf3\xb0\xb0\x9e" // U+F0C1E
+#define ICON_MDI_ALPHA_R_CIRCLE "\xf3\xb0\xb0\x9f" // U+F0C1F
+#define ICON_MDI_ALPHA_R_CIRCLE_OUTLINE "\xf3\xb0\xb0\xa0" // U+F0C20
+#define ICON_MDI_ALPHA_S "\xf3\xb0\xac\x80" // U+F0B00
+#define ICON_MDI_ALPHA_S_BOX "\xf3\xb0\xac\x9a" // U+F0B1A
+#define ICON_MDI_ALPHA_S_BOX_OUTLINE "\xf3\xb0\xb0\xa1" // U+F0C21
+#define ICON_MDI_ALPHA_S_CIRCLE "\xf3\xb0\xb0\xa2" // U+F0C22
+#define ICON_MDI_ALPHA_S_CIRCLE_OUTLINE "\xf3\xb0\xb0\xa3" // U+F0C23
+#define ICON_MDI_ALPHA_T "\xf3\xb0\xac\x81" // U+F0B01
+#define ICON_MDI_ALPHA_T_BOX "\xf3\xb0\xac\x9b" // U+F0B1B
+#define ICON_MDI_ALPHA_T_BOX_OUTLINE "\xf3\xb0\xb0\xa4" // U+F0C24
+#define ICON_MDI_ALPHA_T_CIRCLE "\xf3\xb0\xb0\xa5" // U+F0C25
+#define ICON_MDI_ALPHA_T_CIRCLE_OUTLINE "\xf3\xb0\xb0\xa6" // U+F0C26
+#define ICON_MDI_ALPHA_U "\xf3\xb0\xac\x82" // U+F0B02
+#define ICON_MDI_ALPHA_U_BOX "\xf3\xb0\xac\x9c" // U+F0B1C
+#define ICON_MDI_ALPHA_U_BOX_OUTLINE "\xf3\xb0\xb0\xa7" // U+F0C27
+#define ICON_MDI_ALPHA_U_CIRCLE "\xf3\xb0\xb0\xa8" // U+F0C28
+#define ICON_MDI_ALPHA_U_CIRCLE_OUTLINE "\xf3\xb0\xb0\xa9" // U+F0C29
+#define ICON_MDI_ALPHA_V "\xf3\xb0\xac\x83" // U+F0B03
+#define ICON_MDI_ALPHA_V_BOX "\xf3\xb0\xac\x9d" // U+F0B1D
+#define ICON_MDI_ALPHA_V_BOX_OUTLINE "\xf3\xb0\xb0\xaa" // U+F0C2A
+#define ICON_MDI_ALPHA_V_CIRCLE "\xf3\xb0\xb0\xab" // U+F0C2B
+#define ICON_MDI_ALPHA_V_CIRCLE_OUTLINE "\xf3\xb0\xb0\xac" // U+F0C2C
+#define ICON_MDI_ALPHA_W "\xf3\xb0\xac\x84" // U+F0B04
+#define ICON_MDI_ALPHA_W_BOX "\xf3\xb0\xac\x9e" // U+F0B1E
+#define ICON_MDI_ALPHA_W_BOX_OUTLINE "\xf3\xb0\xb0\xad" // U+F0C2D
+#define ICON_MDI_ALPHA_W_CIRCLE "\xf3\xb0\xb0\xae" // U+F0C2E
+#define ICON_MDI_ALPHA_W_CIRCLE_OUTLINE "\xf3\xb0\xb0\xaf" // U+F0C2F
+#define ICON_MDI_ALPHA_X "\xf3\xb0\xac\x85" // U+F0B05
+#define ICON_MDI_ALPHA_X_BOX "\xf3\xb0\xac\x9f" // U+F0B1F
+#define ICON_MDI_ALPHA_X_BOX_OUTLINE "\xf3\xb0\xb0\xb0" // U+F0C30
+#define ICON_MDI_ALPHA_X_CIRCLE "\xf3\xb0\xb0\xb1" // U+F0C31
+#define ICON_MDI_ALPHA_X_CIRCLE_OUTLINE "\xf3\xb0\xb0\xb2" // U+F0C32
+#define ICON_MDI_ALPHA_Y "\xf3\xb0\xac\x86" // U+F0B06
+#define ICON_MDI_ALPHA_Y_BOX "\xf3\xb0\xac\xa0" // U+F0B20
+#define ICON_MDI_ALPHA_Y_BOX_OUTLINE "\xf3\xb0\xb0\xb3" // U+F0C33
+#define ICON_MDI_ALPHA_Y_CIRCLE "\xf3\xb0\xb0\xb4" // U+F0C34
+#define ICON_MDI_ALPHA_Y_CIRCLE_OUTLINE "\xf3\xb0\xb0\xb5" // U+F0C35
+#define ICON_MDI_ALPHA_Z "\xf3\xb0\xac\x87" // U+F0B07
+#define ICON_MDI_ALPHA_Z_BOX "\xf3\xb0\xac\xa1" // U+F0B21
+#define ICON_MDI_ALPHA_Z_BOX_OUTLINE "\xf3\xb0\xb0\xb6" // U+F0C36
+#define ICON_MDI_ALPHA_Z_CIRCLE "\xf3\xb0\xb0\xb7" // U+F0C37
+#define ICON_MDI_ALPHA_Z_CIRCLE_OUTLINE "\xf3\xb0\xb0\xb8" // U+F0C38
+#define ICON_MDI_ALPHABET_AUREBESH "\xf3\xb1\x8c\xac" // U+F132C
+#define ICON_MDI_ALPHABET_CYRILLIC "\xf3\xb1\x8c\xad" // U+F132D
+#define ICON_MDI_ALPHABET_GREEK "\xf3\xb1\x8c\xae" // U+F132E
+#define ICON_MDI_ALPHABET_LATIN "\xf3\xb1\x8c\xaf" // U+F132F
+#define ICON_MDI_ALPHABET_PIQAD "\xf3\xb1\x8c\xb0" // U+F1330
+#define ICON_MDI_ALPHABET_TENGWAR "\xf3\xb1\x8c\xb7" // U+F1337
+#define ICON_MDI_ALPHABETICAL "\xf3\xb0\x80\xac" // U+F002C
+#define ICON_MDI_ALPHABETICAL_OFF "\xf3\xb1\x80\x8c" // U+F100C
+#define ICON_MDI_ALPHABETICAL_VARIANT "\xf3\xb1\x80\x8d" // U+F100D
+#define ICON_MDI_ALPHABETICAL_VARIANT_OFF "\xf3\xb1\x80\x8e" // U+F100E
+#define ICON_MDI_ALTIMETER "\xf3\xb0\x97\x97" // U+F05D7
+#define ICON_MDI_AMBULANCE "\xf3\xb0\x80\xaf" // U+F002F
+#define ICON_MDI_AMMUNITION "\xf3\xb0\xb3\xa8" // U+F0CE8
+#define ICON_MDI_AMPERSAND "\xf3\xb0\xaa\x8d" // U+F0A8D
+#define ICON_MDI_AMPLIFIER "\xf3\xb0\x80\xb0" // U+F0030
+#define ICON_MDI_AMPLIFIER_OFF "\xf3\xb1\x86\xb5" // U+F11B5
+#define ICON_MDI_ANCHOR "\xf3\xb0\x80\xb1" // U+F0031
+#define ICON_MDI_ANDROID "\xf3\xb0\x80\xb2" // U+F0032
+#define ICON_MDI_ANDROID_STUDIO "\xf3\xb0\x80\xb4" // U+F0034
+#define ICON_MDI_ANGLE_ACUTE "\xf3\xb0\xa4\xb7" // U+F0937
+#define ICON_MDI_ANGLE_OBTUSE "\xf3\xb0\xa4\xb8" // U+F0938
+#define ICON_MDI_ANGLE_RIGHT "\xf3\xb0\xa4\xb9" // U+F0939
+#define ICON_MDI_ANGULAR "\xf3\xb0\x9a\xb2" // U+F06B2
+#define ICON_MDI_ANGULARJS "\xf3\xb0\x9a\xbf" // U+F06BF
+#define ICON_MDI_ANIMATION "\xf3\xb0\x97\x98" // U+F05D8
+#define ICON_MDI_ANIMATION_OUTLINE "\xf3\xb0\xaa\x8f" // U+F0A8F
+#define ICON_MDI_ANIMATION_PLAY "\xf3\xb0\xa4\xba" // U+F093A
+#define ICON_MDI_ANIMATION_PLAY_OUTLINE "\xf3\xb0\xaa\x90" // U+F0A90
+#define ICON_MDI_ANSIBLE "\xf3\xb1\x82\x9a" // U+F109A
+#define ICON_MDI_ANTENNA "\xf3\xb1\x84\x99" // U+F1119
+#define ICON_MDI_ANVIL "\xf3\xb0\xa2\x9b" // U+F089B
+#define ICON_MDI_APACHE_KAFKA "\xf3\xb1\x80\x8f" // U+F100F
+#define ICON_MDI_API "\xf3\xb1\x82\x9b" // U+F109B
+#define ICON_MDI_API_OFF "\xf3\xb1\x89\x97" // U+F1257
+#define ICON_MDI_APPLE "\xf3\xb0\x80\xb5" // U+F0035
+#define ICON_MDI_APPLE_FINDER "\xf3\xb0\x80\xb6" // U+F0036
+#define ICON_MDI_APPLE_ICLOUD "\xf3\xb0\x80\xb8" // U+F0038
+#define ICON_MDI_APPLE_IOS "\xf3\xb0\x80\xb7" // U+F0037
+#define ICON_MDI_APPLE_KEYBOARD_CAPS "\xf3\xb0\x98\xb2" // U+F0632
+#define ICON_MDI_APPLE_KEYBOARD_COMMAND "\xf3\xb0\x98\xb3" // U+F0633
+#define ICON_MDI_APPLE_KEYBOARD_CONTROL "\xf3\xb0\x98\xb4" // U+F0634
+#define ICON_MDI_APPLE_KEYBOARD_OPTION "\xf3\xb0\x98\xb5" // U+F0635
+#define ICON_MDI_APPLE_KEYBOARD_SHIFT "\xf3\xb0\x98\xb6" // U+F0636
+#define ICON_MDI_APPLE_SAFARI "\xf3\xb0\x80\xb9" // U+F0039
+#define ICON_MDI_APPLICATION "\xf3\xb0\xa3\x86" // U+F08C6
+#define ICON_MDI_APPLICATION_ARRAY "\xf3\xb1\x83\xb5" // U+F10F5
+#define ICON_MDI_APPLICATION_ARRAY_OUTLINE "\xf3\xb1\x83\xb6" // U+F10F6
+#define ICON_MDI_APPLICATION_BRACES "\xf3\xb1\x83\xb7" // U+F10F7
+#define ICON_MDI_APPLICATION_BRACES_OUTLINE "\xf3\xb1\x83\xb8" // U+F10F8
+#define ICON_MDI_APPLICATION_BRACKETS "\xf3\xb0\xb2\x8b" // U+F0C8B
+#define ICON_MDI_APPLICATION_BRACKETS_OUTLINE "\xf3\xb0\xb2\x8c" // U+F0C8C
+#define ICON_MDI_APPLICATION_COG "\xf3\xb0\x99\xb5" // U+F0675
+#define ICON_MDI_APPLICATION_COG_OUTLINE "\xf3\xb1\x95\xb7" // U+F1577
+#define ICON_MDI_APPLICATION_EDIT "\xf3\xb0\x82\xae" // U+F00AE
+#define ICON_MDI_APPLICATION_EDIT_OUTLINE "\xf3\xb0\x98\x99" // U+F0619
+#define ICON_MDI_APPLICATION_EXPORT "\xf3\xb0\xb6\xad" // U+F0DAD
+#define ICON_MDI_APPLICATION_IMPORT "\xf3\xb0\xb6\xae" // U+F0DAE
+#define ICON_MDI_APPLICATION_OUTLINE "\xf3\xb0\x98\x94" // U+F0614
+#define ICON_MDI_APPLICATION_PARENTHESES "\xf3\xb1\x83\xb9" // U+F10F9
+#define ICON_MDI_APPLICATION_PARENTHESES_OUTLINE "\xf3\xb1\x83\xba" // U+F10FA
+#define ICON_MDI_APPLICATION_SETTINGS "\xf3\xb0\xad\xa0" // U+F0B60
+#define ICON_MDI_APPLICATION_SETTINGS_OUTLINE "\xf3\xb1\x95\x95" // U+F1555
+#define ICON_MDI_APPLICATION_VARIABLE "\xf3\xb1\x83\xbb" // U+F10FB
+#define ICON_MDI_APPLICATION_VARIABLE_OUTLINE "\xf3\xb1\x83\xbc" // U+F10FC
+#define ICON_MDI_APPROXIMATELY_EQUAL "\xf3\xb0\xbe\x9e" // U+F0F9E
+#define ICON_MDI_APPROXIMATELY_EQUAL_BOX "\xf3\xb0\xbe\x9f" // U+F0F9F
+#define ICON_MDI_APPS "\xf3\xb0\x80\xbb" // U+F003B
+#define ICON_MDI_APPS_BOX "\xf3\xb0\xb5\x86" // U+F0D46
+#define ICON_MDI_ARCH "\xf3\xb0\xa3\x87" // U+F08C7
+#define ICON_MDI_ARCHIVE "\xf3\xb0\x80\xbc" // U+F003C
+#define ICON_MDI_ARCHIVE_ALERT "\xf3\xb1\x93\xbd" // U+F14FD
+#define ICON_MDI_ARCHIVE_ALERT_OUTLINE "\xf3\xb1\x93\xbe" // U+F14FE
+#define ICON_MDI_ARCHIVE_ARROW_DOWN "\xf3\xb1\x89\x99" // U+F1259
+#define ICON_MDI_ARCHIVE_ARROW_DOWN_OUTLINE "\xf3\xb1\x89\x9a" // U+F125A
+#define ICON_MDI_ARCHIVE_ARROW_UP "\xf3\xb1\x89\x9b" // U+F125B
+#define ICON_MDI_ARCHIVE_ARROW_UP_OUTLINE "\xf3\xb1\x89\x9c" // U+F125C
+#define ICON_MDI_ARCHIVE_CANCEL "\xf3\xb1\x9d\x8b" // U+F174B
+#define ICON_MDI_ARCHIVE_CANCEL_OUTLINE "\xf3\xb1\x9d\x8c" // U+F174C
+#define ICON_MDI_ARCHIVE_CHECK "\xf3\xb1\x9d\x8d" // U+F174D
+#define ICON_MDI_ARCHIVE_CHECK_OUTLINE "\xf3\xb1\x9d\x8e" // U+F174E
+#define ICON_MDI_ARCHIVE_CLOCK "\xf3\xb1\x9d\x8f" // U+F174F
+#define ICON_MDI_ARCHIVE_CLOCK_OUTLINE "\xf3\xb1\x9d\x90" // U+F1750
+#define ICON_MDI_ARCHIVE_COG "\xf3\xb1\x9d\x91" // U+F1751
+#define ICON_MDI_ARCHIVE_COG_OUTLINE "\xf3\xb1\x9d\x92" // U+F1752
+#define ICON_MDI_ARCHIVE_EDIT "\xf3\xb1\x9d\x93" // U+F1753
+#define ICON_MDI_ARCHIVE_EDIT_OUTLINE "\xf3\xb1\x9d\x94" // U+F1754
+#define ICON_MDI_ARCHIVE_EYE "\xf3\xb1\x9d\x95" // U+F1755
+#define ICON_MDI_ARCHIVE_EYE_OUTLINE "\xf3\xb1\x9d\x96" // U+F1756
+#define ICON_MDI_ARCHIVE_LOCK "\xf3\xb1\x9d\x97" // U+F1757
+#define ICON_MDI_ARCHIVE_LOCK_OPEN "\xf3\xb1\x9d\x98" // U+F1758
+#define ICON_MDI_ARCHIVE_LOCK_OPEN_OUTLINE "\xf3\xb1\x9d\x99" // U+F1759
+#define ICON_MDI_ARCHIVE_LOCK_OUTLINE "\xf3\xb1\x9d\x9a" // U+F175A
+#define ICON_MDI_ARCHIVE_MARKER "\xf3\xb1\x9d\x9b" // U+F175B
+#define ICON_MDI_ARCHIVE_MARKER_OUTLINE "\xf3\xb1\x9d\x9c" // U+F175C
+#define ICON_MDI_ARCHIVE_MINUS "\xf3\xb1\x9d\x9d" // U+F175D
+#define ICON_MDI_ARCHIVE_MINUS_OUTLINE "\xf3\xb1\x9d\x9e" // U+F175E
+#define ICON_MDI_ARCHIVE_MUSIC "\xf3\xb1\x9d\x9f" // U+F175F
+#define ICON_MDI_ARCHIVE_MUSIC_OUTLINE "\xf3\xb1\x9d\xa0" // U+F1760
+#define ICON_MDI_ARCHIVE_OFF "\xf3\xb1\x9d\xa1" // U+F1761
+#define ICON_MDI_ARCHIVE_OFF_OUTLINE "\xf3\xb1\x9d\xa2" // U+F1762
+#define ICON_MDI_ARCHIVE_OUTLINE "\xf3\xb1\x88\x8e" // U+F120E
+#define ICON_MDI_ARCHIVE_PLUS "\xf3\xb1\x9d\xa3" // U+F1763
+#define ICON_MDI_ARCHIVE_PLUS_OUTLINE "\xf3\xb1\x9d\xa4" // U+F1764
+#define ICON_MDI_ARCHIVE_REFRESH "\xf3\xb1\x9d\xa5" // U+F1765
+#define ICON_MDI_ARCHIVE_REFRESH_OUTLINE "\xf3\xb1\x9d\xa6" // U+F1766
+#define ICON_MDI_ARCHIVE_REMOVE "\xf3\xb1\x9d\xa7" // U+F1767
+#define ICON_MDI_ARCHIVE_REMOVE_OUTLINE "\xf3\xb1\x9d\xa8" // U+F1768
+#define ICON_MDI_ARCHIVE_SEARCH "\xf3\xb1\x9d\xa9" // U+F1769
+#define ICON_MDI_ARCHIVE_SEARCH_OUTLINE "\xf3\xb1\x9d\xaa" // U+F176A
+#define ICON_MDI_ARCHIVE_SETTINGS "\xf3\xb1\x9d\xab" // U+F176B
+#define ICON_MDI_ARCHIVE_SETTINGS_OUTLINE "\xf3\xb1\x9d\xac" // U+F176C
+#define ICON_MDI_ARCHIVE_STAR "\xf3\xb1\x9d\xad" // U+F176D
+#define ICON_MDI_ARCHIVE_STAR_OUTLINE "\xf3\xb1\x9d\xae" // U+F176E
+#define ICON_MDI_ARCHIVE_SYNC "\xf3\xb1\x9d\xaf" // U+F176F
+#define ICON_MDI_ARCHIVE_SYNC_OUTLINE "\xf3\xb1\x9d\xb0" // U+F1770
+#define ICON_MDI_ARM_FLEX "\xf3\xb0\xbf\x97" // U+F0FD7
+#define ICON_MDI_ARM_FLEX_OUTLINE "\xf3\xb0\xbf\x96" // U+F0FD6
+#define ICON_MDI_ARRANGE_BRING_FORWARD "\xf3\xb0\x80\xbd" // U+F003D
+#define ICON_MDI_ARRANGE_BRING_TO_FRONT "\xf3\xb0\x80\xbe" // U+F003E
+#define ICON_MDI_ARRANGE_SEND_BACKWARD "\xf3\xb0\x80\xbf" // U+F003F
+#define ICON_MDI_ARRANGE_SEND_TO_BACK "\xf3\xb0\x81\x80" // U+F0040
+#define ICON_MDI_ARROW_ALL "\xf3\xb0\x81\x81" // U+F0041
+#define ICON_MDI_ARROW_BOTTOM_LEFT "\xf3\xb0\x81\x82" // U+F0042
+#define ICON_MDI_ARROW_BOTTOM_LEFT_BOLD_BOX "\xf3\xb1\xa5\xa4" // U+F1964
+#define ICON_MDI_ARROW_BOTTOM_LEFT_BOLD_BOX_OUTLINE "\xf3\xb1\xa5\xa5" // U+F1965
+#define ICON_MDI_ARROW_BOTTOM_LEFT_BOLD_OUTLINE "\xf3\xb0\xa6\xb7" // U+F09B7
+#define ICON_MDI_ARROW_BOTTOM_LEFT_THICK "\xf3\xb0\xa6\xb8" // U+F09B8
+#define ICON_MDI_ARROW_BOTTOM_LEFT_THIN "\xf3\xb1\xa6\xb6" // U+F19B6
+#define ICON_MDI_ARROW_BOTTOM_LEFT_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x96" // U+F1596
+#define ICON_MDI_ARROW_BOTTOM_RIGHT "\xf3\xb0\x81\x83" // U+F0043
+#define ICON_MDI_ARROW_BOTTOM_RIGHT_BOLD_BOX "\xf3\xb1\xa5\xa6" // U+F1966
+#define ICON_MDI_ARROW_BOTTOM_RIGHT_BOLD_BOX_OUTLINE "\xf3\xb1\xa5\xa7" // U+F1967
+#define ICON_MDI_ARROW_BOTTOM_RIGHT_BOLD_OUTLINE "\xf3\xb0\xa6\xb9" // U+F09B9
+#define ICON_MDI_ARROW_BOTTOM_RIGHT_THICK "\xf3\xb0\xa6\xba" // U+F09BA
+#define ICON_MDI_ARROW_BOTTOM_RIGHT_THIN "\xf3\xb1\xa6\xb7" // U+F19B7
+#define ICON_MDI_ARROW_BOTTOM_RIGHT_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x95" // U+F1595
+#define ICON_MDI_ARROW_COLLAPSE "\xf3\xb0\x98\x95" // U+F0615
+#define ICON_MDI_ARROW_COLLAPSE_ALL "\xf3\xb0\x81\x84" // U+F0044
+#define ICON_MDI_ARROW_COLLAPSE_DOWN "\xf3\xb0\x9e\x92" // U+F0792
+#define ICON_MDI_ARROW_COLLAPSE_HORIZONTAL "\xf3\xb0\xa1\x8c" // U+F084C
+#define ICON_MDI_ARROW_COLLAPSE_LEFT "\xf3\xb0\x9e\x93" // U+F0793
+#define ICON_MDI_ARROW_COLLAPSE_RIGHT "\xf3\xb0\x9e\x94" // U+F0794
+#define ICON_MDI_ARROW_COLLAPSE_UP "\xf3\xb0\x9e\x95" // U+F0795
+#define ICON_MDI_ARROW_COLLAPSE_VERTICAL "\xf3\xb0\xa1\x8d" // U+F084D
+#define ICON_MDI_ARROW_DECISION "\xf3\xb0\xa6\xbb" // U+F09BB
+#define ICON_MDI_ARROW_DECISION_AUTO "\xf3\xb0\xa6\xbc" // U+F09BC
+#define ICON_MDI_ARROW_DECISION_AUTO_OUTLINE "\xf3\xb0\xa6\xbd" // U+F09BD
+#define ICON_MDI_ARROW_DECISION_OUTLINE "\xf3\xb0\xa6\xbe" // U+F09BE
+#define ICON_MDI_ARROW_DOWN "\xf3\xb0\x81\x85" // U+F0045
+#define ICON_MDI_ARROW_DOWN_BOLD "\xf3\xb0\x9c\xae" // U+F072E
+#define ICON_MDI_ARROW_DOWN_BOLD_BOX "\xf3\xb0\x9c\xaf" // U+F072F
+#define ICON_MDI_ARROW_DOWN_BOLD_BOX_OUTLINE "\xf3\xb0\x9c\xb0" // U+F0730
+#define ICON_MDI_ARROW_DOWN_BOLD_CIRCLE "\xf3\xb0\x81\x87" // U+F0047
+#define ICON_MDI_ARROW_DOWN_BOLD_CIRCLE_OUTLINE "\xf3\xb0\x81\x88" // U+F0048
+#define ICON_MDI_ARROW_DOWN_BOLD_HEXAGON_OUTLINE "\xf3\xb0\x81\x89" // U+F0049
+#define ICON_MDI_ARROW_DOWN_BOLD_OUTLINE "\xf3\xb0\xa6\xbf" // U+F09BF
+#define ICON_MDI_ARROW_DOWN_BOX "\xf3\xb0\x9b\x80" // U+F06C0
+#define ICON_MDI_ARROW_DOWN_CIRCLE "\xf3\xb0\xb3\x9b" // U+F0CDB
+#define ICON_MDI_ARROW_DOWN_CIRCLE_OUTLINE "\xf3\xb0\xb3\x9c" // U+F0CDC
+#define ICON_MDI_ARROW_DOWN_DROP_CIRCLE "\xf3\xb0\x81\x8a" // U+F004A
+#define ICON_MDI_ARROW_DOWN_DROP_CIRCLE_OUTLINE "\xf3\xb0\x81\x8b" // U+F004B
+#define ICON_MDI_ARROW_DOWN_LEFT "\xf3\xb1\x9e\xa1" // U+F17A1
+#define ICON_MDI_ARROW_DOWN_LEFT_BOLD "\xf3\xb1\x9e\xa2" // U+F17A2
+#define ICON_MDI_ARROW_DOWN_RIGHT "\xf3\xb1\x9e\xa3" // U+F17A3
+#define ICON_MDI_ARROW_DOWN_RIGHT_BOLD "\xf3\xb1\x9e\xa4" // U+F17A4
+#define ICON_MDI_ARROW_DOWN_THICK "\xf3\xb0\x81\x86" // U+F0046
+#define ICON_MDI_ARROW_DOWN_THIN "\xf3\xb1\xa6\xb3" // U+F19B3
+#define ICON_MDI_ARROW_DOWN_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x99" // U+F1599
+#define ICON_MDI_ARROW_EXPAND "\xf3\xb0\x98\x96" // U+F0616
+#define ICON_MDI_ARROW_EXPAND_ALL "\xf3\xb0\x81\x8c" // U+F004C
+#define ICON_MDI_ARROW_EXPAND_DOWN "\xf3\xb0\x9e\x96" // U+F0796
+#define ICON_MDI_ARROW_EXPAND_HORIZONTAL "\xf3\xb0\xa1\x8e" // U+F084E
+#define ICON_MDI_ARROW_EXPAND_LEFT "\xf3\xb0\x9e\x97" // U+F0797
+#define ICON_MDI_ARROW_EXPAND_RIGHT "\xf3\xb0\x9e\x98" // U+F0798
+#define ICON_MDI_ARROW_EXPAND_UP "\xf3\xb0\x9e\x99" // U+F0799
+#define ICON_MDI_ARROW_EXPAND_VERTICAL "\xf3\xb0\xa1\x8f" // U+F084F
+#define ICON_MDI_ARROW_HORIZONTAL_LOCK "\xf3\xb1\x85\x9b" // U+F115B
+#define ICON_MDI_ARROW_LEFT "\xf3\xb0\x81\x8d" // U+F004D
+#define ICON_MDI_ARROW_LEFT_BOLD "\xf3\xb0\x9c\xb1" // U+F0731
+#define ICON_MDI_ARROW_LEFT_BOLD_BOX "\xf3\xb0\x9c\xb2" // U+F0732
+#define ICON_MDI_ARROW_LEFT_BOLD_BOX_OUTLINE "\xf3\xb0\x9c\xb3" // U+F0733
+#define ICON_MDI_ARROW_LEFT_BOLD_CIRCLE "\xf3\xb0\x81\x8f" // U+F004F
+#define ICON_MDI_ARROW_LEFT_BOLD_CIRCLE_OUTLINE "\xf3\xb0\x81\x90" // U+F0050
+#define ICON_MDI_ARROW_LEFT_BOLD_HEXAGON_OUTLINE "\xf3\xb0\x81\x91" // U+F0051
+#define ICON_MDI_ARROW_LEFT_BOLD_OUTLINE "\xf3\xb0\xa7\x80" // U+F09C0
+#define ICON_MDI_ARROW_LEFT_BOTTOM "\xf3\xb1\x9e\xa5" // U+F17A5
+#define ICON_MDI_ARROW_LEFT_BOTTOM_BOLD "\xf3\xb1\x9e\xa6" // U+F17A6
+#define ICON_MDI_ARROW_LEFT_BOX "\xf3\xb0\x9b\x81" // U+F06C1
+#define ICON_MDI_ARROW_LEFT_CIRCLE "\xf3\xb0\xb3\x9d" // U+F0CDD
+#define ICON_MDI_ARROW_LEFT_CIRCLE_OUTLINE "\xf3\xb0\xb3\x9e" // U+F0CDE
+#define ICON_MDI_ARROW_LEFT_DROP_CIRCLE "\xf3\xb0\x81\x92" // U+F0052
+#define ICON_MDI_ARROW_LEFT_DROP_CIRCLE_OUTLINE "\xf3\xb0\x81\x93" // U+F0053
+#define ICON_MDI_ARROW_LEFT_RIGHT "\xf3\xb0\xb9\xb3" // U+F0E73
+#define ICON_MDI_ARROW_LEFT_RIGHT_BOLD "\xf3\xb0\xb9\xb4" // U+F0E74
+#define ICON_MDI_ARROW_LEFT_RIGHT_BOLD_OUTLINE "\xf3\xb0\xa7\x81" // U+F09C1
+#define ICON_MDI_ARROW_LEFT_THICK "\xf3\xb0\x81\x8e" // U+F004E
+#define ICON_MDI_ARROW_LEFT_THIN "\xf3\xb1\xa6\xb1" // U+F19B1
+#define ICON_MDI_ARROW_LEFT_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x9a" // U+F159A
+#define ICON_MDI_ARROW_LEFT_TOP "\xf3\xb1\x9e\xa7" // U+F17A7
+#define ICON_MDI_ARROW_LEFT_TOP_BOLD "\xf3\xb1\x9e\xa8" // U+F17A8
+#define ICON_MDI_ARROW_OSCILLATING "\xf3\xb1\xb2\x91" // U+F1C91
+#define ICON_MDI_ARROW_OSCILLATING_OFF "\xf3\xb1\xb2\x92" // U+F1C92
+#define ICON_MDI_ARROW_PROJECTILE "\xf3\xb1\xa1\x80" // U+F1840
+#define ICON_MDI_ARROW_PROJECTILE_MULTIPLE "\xf3\xb1\xa0\xbf" // U+F183F
+#define ICON_MDI_ARROW_RIGHT "\xf3\xb0\x81\x94" // U+F0054
+#define ICON_MDI_ARROW_RIGHT_BOLD "\xf3\xb0\x9c\xb4" // U+F0734
+#define ICON_MDI_ARROW_RIGHT_BOLD_BOX "\xf3\xb0\x9c\xb5" // U+F0735
+#define ICON_MDI_ARROW_RIGHT_BOLD_BOX_OUTLINE "\xf3\xb0\x9c\xb6" // U+F0736
+#define ICON_MDI_ARROW_RIGHT_BOLD_CIRCLE "\xf3\xb0\x81\x96" // U+F0056
+#define ICON_MDI_ARROW_RIGHT_BOLD_CIRCLE_OUTLINE "\xf3\xb0\x81\x97" // U+F0057
+#define ICON_MDI_ARROW_RIGHT_BOLD_HEXAGON_OUTLINE "\xf3\xb0\x81\x98" // U+F0058
+#define ICON_MDI_ARROW_RIGHT_BOLD_OUTLINE "\xf3\xb0\xa7\x82" // U+F09C2
+#define ICON_MDI_ARROW_RIGHT_BOTTOM "\xf3\xb1\x9e\xa9" // U+F17A9
+#define ICON_MDI_ARROW_RIGHT_BOTTOM_BOLD "\xf3\xb1\x9e\xaa" // U+F17AA
+#define ICON_MDI_ARROW_RIGHT_BOX "\xf3\xb0\x9b\x82" // U+F06C2
+#define ICON_MDI_ARROW_RIGHT_CIRCLE "\xf3\xb0\xb3\x9f" // U+F0CDF
+#define ICON_MDI_ARROW_RIGHT_CIRCLE_OUTLINE "\xf3\xb0\xb3\xa0" // U+F0CE0
+#define ICON_MDI_ARROW_RIGHT_DROP_CIRCLE "\xf3\xb0\x81\x99" // U+F0059
+#define ICON_MDI_ARROW_RIGHT_DROP_CIRCLE_OUTLINE "\xf3\xb0\x81\x9a" // U+F005A
+#define ICON_MDI_ARROW_RIGHT_THICK "\xf3\xb0\x81\x95" // U+F0055
+#define ICON_MDI_ARROW_RIGHT_THIN "\xf3\xb1\xa6\xb0" // U+F19B0
+#define ICON_MDI_ARROW_RIGHT_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x98" // U+F1598
+#define ICON_MDI_ARROW_RIGHT_TOP "\xf3\xb1\x9e\xab" // U+F17AB
+#define ICON_MDI_ARROW_RIGHT_TOP_BOLD "\xf3\xb1\x9e\xac" // U+F17AC
+#define ICON_MDI_ARROW_SPLIT_HORIZONTAL "\xf3\xb0\xa4\xbb" // U+F093B
+#define ICON_MDI_ARROW_SPLIT_VERTICAL "\xf3\xb0\xa4\xbc" // U+F093C
+#define ICON_MDI_ARROW_TOP_LEFT "\xf3\xb0\x81\x9b" // U+F005B
+#define ICON_MDI_ARROW_TOP_LEFT_BOLD_BOX "\xf3\xb1\xa5\xa8" // U+F1968
+#define ICON_MDI_ARROW_TOP_LEFT_BOLD_BOX_OUTLINE "\xf3\xb1\xa5\xa9" // U+F1969
+#define ICON_MDI_ARROW_TOP_LEFT_BOLD_OUTLINE "\xf3\xb0\xa7\x83" // U+F09C3
+#define ICON_MDI_ARROW_TOP_LEFT_BOTTOM_RIGHT "\xf3\xb0\xb9\xb5" // U+F0E75
+#define ICON_MDI_ARROW_TOP_LEFT_BOTTOM_RIGHT_BOLD "\xf3\xb0\xb9\xb6" // U+F0E76
+#define ICON_MDI_ARROW_TOP_LEFT_THICK "\xf3\xb0\xa7\x84" // U+F09C4
+#define ICON_MDI_ARROW_TOP_LEFT_THIN "\xf3\xb1\xa6\xb5" // U+F19B5
+#define ICON_MDI_ARROW_TOP_LEFT_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x93" // U+F1593
+#define ICON_MDI_ARROW_TOP_RIGHT "\xf3\xb0\x81\x9c" // U+F005C
+#define ICON_MDI_ARROW_TOP_RIGHT_BOLD_BOX "\xf3\xb1\xa5\xaa" // U+F196A
+#define ICON_MDI_ARROW_TOP_RIGHT_BOLD_BOX_OUTLINE "\xf3\xb1\xa5\xab" // U+F196B
+#define ICON_MDI_ARROW_TOP_RIGHT_BOLD_OUTLINE "\xf3\xb0\xa7\x85" // U+F09C5
+#define ICON_MDI_ARROW_TOP_RIGHT_BOTTOM_LEFT "\xf3\xb0\xb9\xb7" // U+F0E77
+#define ICON_MDI_ARROW_TOP_RIGHT_BOTTOM_LEFT_BOLD "\xf3\xb0\xb9\xb8" // U+F0E78
+#define ICON_MDI_ARROW_TOP_RIGHT_THICK "\xf3\xb0\xa7\x86" // U+F09C6
+#define ICON_MDI_ARROW_TOP_RIGHT_THIN "\xf3\xb1\xa6\xb4" // U+F19B4
+#define ICON_MDI_ARROW_TOP_RIGHT_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x94" // U+F1594
+#define ICON_MDI_ARROW_U_DOWN_LEFT "\xf3\xb1\x9e\xad" // U+F17AD
+#define ICON_MDI_ARROW_U_DOWN_LEFT_BOLD "\xf3\xb1\x9e\xae" // U+F17AE
+#define ICON_MDI_ARROW_U_DOWN_RIGHT "\xf3\xb1\x9e\xaf" // U+F17AF
+#define ICON_MDI_ARROW_U_DOWN_RIGHT_BOLD "\xf3\xb1\x9e\xb0" // U+F17B0
+#define ICON_MDI_ARROW_U_LEFT_BOTTOM "\xf3\xb1\x9e\xb1" // U+F17B1
+#define ICON_MDI_ARROW_U_LEFT_BOTTOM_BOLD "\xf3\xb1\x9e\xb2" // U+F17B2
+#define ICON_MDI_ARROW_U_LEFT_TOP "\xf3\xb1\x9e\xb3" // U+F17B3
+#define ICON_MDI_ARROW_U_LEFT_TOP_BOLD "\xf3\xb1\x9e\xb4" // U+F17B4
+#define ICON_MDI_ARROW_U_RIGHT_BOTTOM "\xf3\xb1\x9e\xb5" // U+F17B5
+#define ICON_MDI_ARROW_U_RIGHT_BOTTOM_BOLD "\xf3\xb1\x9e\xb6" // U+F17B6
+#define ICON_MDI_ARROW_U_RIGHT_TOP "\xf3\xb1\x9e\xb7" // U+F17B7
+#define ICON_MDI_ARROW_U_RIGHT_TOP_BOLD "\xf3\xb1\x9e\xb8" // U+F17B8
+#define ICON_MDI_ARROW_U_UP_LEFT "\xf3\xb1\x9e\xb9" // U+F17B9
+#define ICON_MDI_ARROW_U_UP_LEFT_BOLD "\xf3\xb1\x9e\xba" // U+F17BA
+#define ICON_MDI_ARROW_U_UP_RIGHT "\xf3\xb1\x9e\xbb" // U+F17BB
+#define ICON_MDI_ARROW_U_UP_RIGHT_BOLD "\xf3\xb1\x9e\xbc" // U+F17BC
+#define ICON_MDI_ARROW_UP "\xf3\xb0\x81\x9d" // U+F005D
+#define ICON_MDI_ARROW_UP_BOLD "\xf3\xb0\x9c\xb7" // U+F0737
+#define ICON_MDI_ARROW_UP_BOLD_BOX "\xf3\xb0\x9c\xb8" // U+F0738
+#define ICON_MDI_ARROW_UP_BOLD_BOX_OUTLINE "\xf3\xb0\x9c\xb9" // U+F0739
+#define ICON_MDI_ARROW_UP_BOLD_CIRCLE "\xf3\xb0\x81\x9f" // U+F005F
+#define ICON_MDI_ARROW_UP_BOLD_CIRCLE_OUTLINE "\xf3\xb0\x81\xa0" // U+F0060
+#define ICON_MDI_ARROW_UP_BOLD_HEXAGON_OUTLINE "\xf3\xb0\x81\xa1" // U+F0061
+#define ICON_MDI_ARROW_UP_BOLD_OUTLINE "\xf3\xb0\xa7\x87" // U+F09C7
+#define ICON_MDI_ARROW_UP_BOX "\xf3\xb0\x9b\x83" // U+F06C3
+#define ICON_MDI_ARROW_UP_CIRCLE "\xf3\xb0\xb3\xa1" // U+F0CE1
+#define ICON_MDI_ARROW_UP_CIRCLE_OUTLINE "\xf3\xb0\xb3\xa2" // U+F0CE2
+#define ICON_MDI_ARROW_UP_DOWN "\xf3\xb0\xb9\xb9" // U+F0E79
+#define ICON_MDI_ARROW_UP_DOWN_BOLD "\xf3\xb0\xb9\xba" // U+F0E7A
+#define ICON_MDI_ARROW_UP_DOWN_BOLD_OUTLINE "\xf3\xb0\xa7\x88" // U+F09C8
+#define ICON_MDI_ARROW_UP_DROP_CIRCLE "\xf3\xb0\x81\xa2" // U+F0062
+#define ICON_MDI_ARROW_UP_DROP_CIRCLE_OUTLINE "\xf3\xb0\x81\xa3" // U+F0063
+#define ICON_MDI_ARROW_UP_LEFT "\xf3\xb1\x9e\xbd" // U+F17BD
+#define ICON_MDI_ARROW_UP_LEFT_BOLD "\xf3\xb1\x9e\xbe" // U+F17BE
+#define ICON_MDI_ARROW_UP_RIGHT "\xf3\xb1\x9e\xbf" // U+F17BF
+#define ICON_MDI_ARROW_UP_RIGHT_BOLD "\xf3\xb1\x9f\x80" // U+F17C0
+#define ICON_MDI_ARROW_UP_THICK "\xf3\xb0\x81\x9e" // U+F005E
+#define ICON_MDI_ARROW_UP_THIN "\xf3\xb1\xa6\xb2" // U+F19B2
+#define ICON_MDI_ARROW_UP_THIN_CIRCLE_OUTLINE "\xf3\xb1\x96\x97" // U+F1597
+#define ICON_MDI_ARROW_VERTICAL_LOCK "\xf3\xb1\x85\x9c" // U+F115C
+#define ICON_MDI_ARTBOARD "\xf3\xb1\xae\x9a" // U+F1B9A
+#define ICON_MDI_ARTSTATION "\xf3\xb0\xad\x9b" // U+F0B5B
+#define ICON_MDI_ASPECT_RATIO "\xf3\xb0\xa8\xa4" // U+F0A24
+#define ICON_MDI_ASSISTANT "\xf3\xb0\x81\xa4" // U+F0064
+#define ICON_MDI_ASTERISK "\xf3\xb0\x9b\x84" // U+F06C4
+#define ICON_MDI_ASTERISK_CIRCLE_OUTLINE "\xf3\xb1\xa8\xa7" // U+F1A27
+#define ICON_MDI_AT "\xf3\xb0\x81\xa5" // U+F0065
+#define ICON_MDI_ATLASSIAN "\xf3\xb0\xa0\x84" // U+F0804
+#define ICON_MDI_ATM "\xf3\xb0\xb5\x87" // U+F0D47
+#define ICON_MDI_ATOM "\xf3\xb0\x9d\xa8" // U+F0768
+#define ICON_MDI_ATOM_VARIANT "\xf3\xb0\xb9\xbb" // U+F0E7B
+#define ICON_MDI_ATTACHMENT "\xf3\xb0\x81\xa6" // U+F0066
+#define ICON_MDI_ATTACHMENT_CHECK "\xf3\xb1\xab\x81" // U+F1AC1
+#define ICON_MDI_ATTACHMENT_LOCK "\xf3\xb1\xa7\x84" // U+F19C4
+#define ICON_MDI_ATTACHMENT_MINUS "\xf3\xb1\xab\x82" // U+F1AC2
+#define ICON_MDI_ATTACHMENT_OFF "\xf3\xb1\xab\x83" // U+F1AC3
+#define ICON_MDI_ATTACHMENT_PLUS "\xf3\xb1\xab\x84" // U+F1AC4
+#define ICON_MDI_ATTACHMENT_REMOVE "\xf3\xb1\xab\x85" // U+F1AC5
+#define ICON_MDI_ATV "\xf3\xb1\xad\xb0" // U+F1B70
+#define ICON_MDI_AUDIO_INPUT_RCA "\xf3\xb1\xa1\xab" // U+F186B
+#define ICON_MDI_AUDIO_INPUT_STEREO_MINIJACK "\xf3\xb1\xa1\xac" // U+F186C
+#define ICON_MDI_AUDIO_INPUT_XLR "\xf3\xb1\xa1\xad" // U+F186D
+#define ICON_MDI_AUDIO_VIDEO "\xf3\xb0\xa4\xbd" // U+F093D
+#define ICON_MDI_AUDIO_VIDEO_OFF "\xf3\xb1\x86\xb6" // U+F11B6
+#define ICON_MDI_AUGMENTED_REALITY "\xf3\xb0\xa1\x90" // U+F0850
+#define ICON_MDI_AURORA "\xf3\xb1\xae\xb9" // U+F1BB9
+#define ICON_MDI_AUTO_DOWNLOAD "\xf3\xb1\x8d\xbe" // U+F137E
+#define ICON_MDI_AUTO_FIX "\xf3\xb0\x81\xa8" // U+F0068
+#define ICON_MDI_AUTO_MODE "\xf3\xb1\xb0\xa0" // U+F1C20
+#define ICON_MDI_AUTO_UPLOAD "\xf3\xb0\x81\xa9" // U+F0069
+#define ICON_MDI_AUTORENEW "\xf3\xb0\x81\xaa" // U+F006A
+#define ICON_MDI_AUTORENEW_OFF "\xf3\xb1\xa7\xa7" // U+F19E7
+#define ICON_MDI_AV_TIMER "\xf3\xb0\x81\xab" // U+F006B
+#define ICON_MDI_AWNING "\xf3\xb1\xae\x87" // U+F1B87
+#define ICON_MDI_AWNING_OUTLINE "\xf3\xb1\xae\x88" // U+F1B88
+#define ICON_MDI_AWS "\xf3\xb0\xb8\x8f" // U+F0E0F
+#define ICON_MDI_AXE "\xf3\xb0\xa3\x88" // U+F08C8
+#define ICON_MDI_AXE_BATTLE "\xf3\xb1\xa1\x82" // U+F1842
+#define ICON_MDI_AXIS "\xf3\xb0\xb5\x88" // U+F0D48
+#define ICON_MDI_AXIS_ARROW "\xf3\xb0\xb5\x89" // U+F0D49
+#define ICON_MDI_AXIS_ARROW_INFO "\xf3\xb1\x90\x8e" // U+F140E
+#define ICON_MDI_AXIS_ARROW_LOCK "\xf3\xb0\xb5\x8a" // U+F0D4A
+#define ICON_MDI_AXIS_LOCK "\xf3\xb0\xb5\x8b" // U+F0D4B
+#define ICON_MDI_AXIS_X_ARROW "\xf3\xb0\xb5\x8c" // U+F0D4C
+#define ICON_MDI_AXIS_X_ARROW_LOCK "\xf3\xb0\xb5\x8d" // U+F0D4D
+#define ICON_MDI_AXIS_X_ROTATE_CLOCKWISE "\xf3\xb0\xb5\x8e" // U+F0D4E
+#define ICON_MDI_AXIS_X_ROTATE_COUNTERCLOCKWISE "\xf3\xb0\xb5\x8f" // U+F0D4F
+#define ICON_MDI_AXIS_X_Y_ARROW_LOCK "\xf3\xb0\xb5\x90" // U+F0D50
+#define ICON_MDI_AXIS_Y_ARROW "\xf3\xb0\xb5\x91" // U+F0D51
+#define ICON_MDI_AXIS_Y_ARROW_LOCK "\xf3\xb0\xb5\x92" // U+F0D52
+#define ICON_MDI_AXIS_Y_ROTATE_CLOCKWISE "\xf3\xb0\xb5\x93" // U+F0D53
+#define ICON_MDI_AXIS_Y_ROTATE_COUNTERCLOCKWISE "\xf3\xb0\xb5\x94" // U+F0D54
+#define ICON_MDI_AXIS_Z_ARROW "\xf3\xb0\xb5\x95" // U+F0D55
+#define ICON_MDI_AXIS_Z_ARROW_LOCK "\xf3\xb0\xb5\x96" // U+F0D56
+#define ICON_MDI_AXIS_Z_ROTATE_CLOCKWISE "\xf3\xb0\xb5\x97" // U+F0D57
+#define ICON_MDI_AXIS_Z_ROTATE_COUNTERCLOCKWISE "\xf3\xb0\xb5\x98" // U+F0D58
+#define ICON_MDI_BABEL "\xf3\xb0\xa8\xa5" // U+F0A25
+#define ICON_MDI_BABY "\xf3\xb0\x81\xac" // U+F006C
+#define ICON_MDI_BABY_BOTTLE "\xf3\xb0\xbc\xb9" // U+F0F39
+#define ICON_MDI_BABY_BOTTLE_OUTLINE "\xf3\xb0\xbc\xba" // U+F0F3A
+#define ICON_MDI_BABY_BUGGY "\xf3\xb1\x8f\xa0" // U+F13E0
+#define ICON_MDI_BABY_BUGGY_OFF "\xf3\xb1\xab\xb3" // U+F1AF3
+#define ICON_MDI_BABY_CARRIAGE "\xf3\xb0\x9a\x8f" // U+F068F
+#define ICON_MDI_BABY_CARRIAGE_OFF "\xf3\xb0\xbe\xa0" // U+F0FA0
+#define ICON_MDI_BABY_FACE "\xf3\xb0\xb9\xbc" // U+F0E7C
+#define ICON_MDI_BABY_FACE_OUTLINE "\xf3\xb0\xb9\xbd" // U+F0E7D
+#define ICON_MDI_BACKBURGER "\xf3\xb0\x81\xad" // U+F006D
+#define ICON_MDI_BACKSPACE "\xf3\xb0\x81\xae" // U+F006E
+#define ICON_MDI_BACKSPACE_OUTLINE "\xf3\xb0\xad\x9c" // U+F0B5C
+#define ICON_MDI_BACKSPACE_REVERSE "\xf3\xb0\xb9\xbe" // U+F0E7E
+#define ICON_MDI_BACKSPACE_REVERSE_OUTLINE "\xf3\xb0\xb9\xbf" // U+F0E7F
+#define ICON_MDI_BACKUP_RESTORE "\xf3\xb0\x81\xaf" // U+F006F
+#define ICON_MDI_BACTERIA "\xf3\xb0\xbb\x95" // U+F0ED5
+#define ICON_MDI_BACTERIA_OUTLINE "\xf3\xb0\xbb\x96" // U+F0ED6
+#define ICON_MDI_BADGE_ACCOUNT "\xf3\xb0\xb6\xa7" // U+F0DA7
+#define ICON_MDI_BADGE_ACCOUNT_ALERT "\xf3\xb0\xb6\xa8" // U+F0DA8
+#define ICON_MDI_BADGE_ACCOUNT_ALERT_OUTLINE "\xf3\xb0\xb6\xa9" // U+F0DA9
+#define ICON_MDI_BADGE_ACCOUNT_HORIZONTAL "\xf3\xb0\xb8\x8d" // U+F0E0D
+#define ICON_MDI_BADGE_ACCOUNT_HORIZONTAL_OUTLINE "\xf3\xb0\xb8\x8e" // U+F0E0E
+#define ICON_MDI_BADGE_ACCOUNT_OUTLINE "\xf3\xb0\xb6\xaa" // U+F0DAA
+#define ICON_MDI_BADMINTON "\xf3\xb0\xa1\x91" // U+F0851
+#define ICON_MDI_BAG_CARRY_ON "\xf3\xb0\xbc\xbb" // U+F0F3B
+#define ICON_MDI_BAG_CARRY_ON_CHECK "\xf3\xb0\xb5\xa5" // U+F0D65
+#define ICON_MDI_BAG_CARRY_ON_OFF "\xf3\xb0\xbc\xbc" // U+F0F3C
+#define ICON_MDI_BAG_CHECKED "\xf3\xb0\xbc\xbd" // U+F0F3D
+#define ICON_MDI_BAG_PERSONAL "\xf3\xb0\xb8\x90" // U+F0E10
+#define ICON_MDI_BAG_PERSONAL_OFF "\xf3\xb0\xb8\x91" // U+F0E11
+#define ICON_MDI_BAG_PERSONAL_OFF_OUTLINE "\xf3\xb0\xb8\x92" // U+F0E12
+#define ICON_MDI_BAG_PERSONAL_OUTLINE "\xf3\xb0\xb8\x93" // U+F0E13
+#define ICON_MDI_BAG_PERSONAL_PLUS "\xf3\xb1\xb2\xa4" // U+F1CA4
+#define ICON_MDI_BAG_PERSONAL_PLUS_OUTLINE "\xf3\xb1\xb2\xa5" // U+F1CA5
+#define ICON_MDI_BAG_PERSONAL_TAG "\xf3\xb1\xac\x8c" // U+F1B0C
+#define ICON_MDI_BAG_PERSONAL_TAG_OUTLINE "\xf3\xb1\xac\x8d" // U+F1B0D
+#define ICON_MDI_BAG_SUITCASE "\xf3\xb1\x96\x8b" // U+F158B
+#define ICON_MDI_BAG_SUITCASE_OFF "\xf3\xb1\x96\x8d" // U+F158D
+#define ICON_MDI_BAG_SUITCASE_OFF_OUTLINE "\xf3\xb1\x96\x8e" // U+F158E
+#define ICON_MDI_BAG_SUITCASE_OUTLINE "\xf3\xb1\x96\x8c" // U+F158C
+#define ICON_MDI_BAGUETTE "\xf3\xb0\xbc\xbe" // U+F0F3E
+#define ICON_MDI_BALCONY "\xf3\xb1\xa0\x97" // U+F1817
+#define ICON_MDI_BALLOON "\xf3\xb0\xa8\xa6" // U+F0A26
+#define ICON_MDI_BALLOT "\xf3\xb0\xa7\x89" // U+F09C9
+#define ICON_MDI_BALLOT_OUTLINE "\xf3\xb0\xa7\x8a" // U+F09CA
+#define ICON_MDI_BALLOT_RECOUNT "\xf3\xb0\xb0\xb9" // U+F0C39
+#define ICON_MDI_BALLOT_RECOUNT_OUTLINE "\xf3\xb0\xb0\xba" // U+F0C3A
+#define ICON_MDI_BANDAGE "\xf3\xb0\xb6\xaf" // U+F0DAF
+#define ICON_MDI_BANK "\xf3\xb0\x81\xb0" // U+F0070
+#define ICON_MDI_BANK_CHECK "\xf3\xb1\x99\x95" // U+F1655
+#define ICON_MDI_BANK_CIRCLE "\xf3\xb1\xb0\x83" // U+F1C03
+#define ICON_MDI_BANK_CIRCLE_OUTLINE "\xf3\xb1\xb0\x84" // U+F1C04
+#define ICON_MDI_BANK_MINUS "\xf3\xb0\xb6\xb0" // U+F0DB0
+#define ICON_MDI_BANK_OFF "\xf3\xb1\x99\x96" // U+F1656
+#define ICON_MDI_BANK_OFF_OUTLINE "\xf3\xb1\x99\x97" // U+F1657
+#define ICON_MDI_BANK_OUTLINE "\xf3\xb0\xba\x80" // U+F0E80
+#define ICON_MDI_BANK_PLUS "\xf3\xb0\xb6\xb1" // U+F0DB1
+#define ICON_MDI_BANK_REMOVE "\xf3\xb0\xb6\xb2" // U+F0DB2
+#define ICON_MDI_BANK_TRANSFER "\xf3\xb0\xa8\xa7" // U+F0A27
+#define ICON_MDI_BANK_TRANSFER_IN "\xf3\xb0\xa8\xa8" // U+F0A28
+#define ICON_MDI_BANK_TRANSFER_OUT "\xf3\xb0\xa8\xa9" // U+F0A29
+#define ICON_MDI_BARCODE "\xf3\xb0\x81\xb1" // U+F0071
+#define ICON_MDI_BARCODE_OFF "\xf3\xb1\x88\xb6" // U+F1236
+#define ICON_MDI_BARCODE_SCAN "\xf3\xb0\x81\xb2" // U+F0072
+#define ICON_MDI_BARLEY "\xf3\xb0\x81\xb3" // U+F0073
+#define ICON_MDI_BARLEY_OFF "\xf3\xb0\xad\x9d" // U+F0B5D
+#define ICON_MDI_BARN "\xf3\xb0\xad\x9e" // U+F0B5E
+#define ICON_MDI_BARREL "\xf3\xb0\x81\xb4" // U+F0074
+#define ICON_MDI_BARREL_OUTLINE "\xf3\xb1\xa8\xa8" // U+F1A28
+#define ICON_MDI_BASEBALL "\xf3\xb0\xa1\x92" // U+F0852
+#define ICON_MDI_BASEBALL_BAT "\xf3\xb0\xa1\x93" // U+F0853
+#define ICON_MDI_BASEBALL_DIAMOND "\xf3\xb1\x97\xac" // U+F15EC
+#define ICON_MDI_BASEBALL_DIAMOND_OUTLINE "\xf3\xb1\x97\xad" // U+F15ED
+#define ICON_MDI_BASEBALL_OUTLINE "\xf3\xb1\xb1\x9a" // U+F1C5A
+#define ICON_MDI_BASH "\xf3\xb1\x86\x83" // U+F1183
+#define ICON_MDI_BASKET "\xf3\xb0\x81\xb6" // U+F0076
+#define ICON_MDI_BASKET_CHECK "\xf3\xb1\xa3\xa5" // U+F18E5
+#define ICON_MDI_BASKET_CHECK_OUTLINE "\xf3\xb1\xa3\xa6" // U+F18E6
+#define ICON_MDI_BASKET_FILL "\xf3\xb0\x81\xb7" // U+F0077
+#define ICON_MDI_BASKET_MINUS "\xf3\xb1\x94\xa3" // U+F1523
+#define ICON_MDI_BASKET_MINUS_OUTLINE "\xf3\xb1\x94\xa4" // U+F1524
+#define ICON_MDI_BASKET_OFF "\xf3\xb1\x94\xa5" // U+F1525
+#define ICON_MDI_BASKET_OFF_OUTLINE "\xf3\xb1\x94\xa6" // U+F1526
+#define ICON_MDI_BASKET_OUTLINE "\xf3\xb1\x86\x81" // U+F1181
+#define ICON_MDI_BASKET_PLUS "\xf3\xb1\x94\xa7" // U+F1527
+#define ICON_MDI_BASKET_PLUS_OUTLINE "\xf3\xb1\x94\xa8" // U+F1528
+#define ICON_MDI_BASKET_REMOVE "\xf3\xb1\x94\xa9" // U+F1529
+#define ICON_MDI_BASKET_REMOVE_OUTLINE "\xf3\xb1\x94\xaa" // U+F152A
+#define ICON_MDI_BASKET_UNFILL "\xf3\xb0\x81\xb8" // U+F0078
+#define ICON_MDI_BASKETBALL "\xf3\xb0\xa0\x86" // U+F0806
+#define ICON_MDI_BASKETBALL_HOOP "\xf3\xb0\xb0\xbb" // U+F0C3B
+#define ICON_MDI_BASKETBALL_HOOP_OUTLINE "\xf3\xb0\xb0\xbc" // U+F0C3C
+#define ICON_MDI_BAT "\xf3\xb0\xad\x9f" // U+F0B5F
+#define ICON_MDI_BATHTUB "\xf3\xb1\xa0\x98" // U+F1818
+#define ICON_MDI_BATHTUB_OUTLINE "\xf3\xb1\xa0\x99" // U+F1819
+#define ICON_MDI_BATTERY "\xf3\xb0\x81\xb9" // U+F0079
+#define ICON_MDI_BATTERY_10 "\xf3\xb0\x81\xba" // U+F007A
+#define ICON_MDI_BATTERY_10_BLUETOOTH "\xf3\xb0\xa4\xbe" // U+F093E
+#define ICON_MDI_BATTERY_20 "\xf3\xb0\x81\xbb" // U+F007B
+#define ICON_MDI_BATTERY_20_BLUETOOTH "\xf3\xb0\xa4\xbf" // U+F093F
+#define ICON_MDI_BATTERY_30 "\xf3\xb0\x81\xbc" // U+F007C
+#define ICON_MDI_BATTERY_30_BLUETOOTH "\xf3\xb0\xa5\x80" // U+F0940
+#define ICON_MDI_BATTERY_40 "\xf3\xb0\x81\xbd" // U+F007D
+#define ICON_MDI_BATTERY_40_BLUETOOTH "\xf3\xb0\xa5\x81" // U+F0941
+#define ICON_MDI_BATTERY_50 "\xf3\xb0\x81\xbe" // U+F007E
+#define ICON_MDI_BATTERY_50_BLUETOOTH "\xf3\xb0\xa5\x82" // U+F0942
+#define ICON_MDI_BATTERY_60 "\xf3\xb0\x81\xbf" // U+F007F
+#define ICON_MDI_BATTERY_60_BLUETOOTH "\xf3\xb0\xa5\x83" // U+F0943
+#define ICON_MDI_BATTERY_70 "\xf3\xb0\x82\x80" // U+F0080
+#define ICON_MDI_BATTERY_70_BLUETOOTH "\xf3\xb0\xa5\x84" // U+F0944
+#define ICON_MDI_BATTERY_80 "\xf3\xb0\x82\x81" // U+F0081
+#define ICON_MDI_BATTERY_80_BLUETOOTH "\xf3\xb0\xa5\x85" // U+F0945
+#define ICON_MDI_BATTERY_90 "\xf3\xb0\x82\x82" // U+F0082
+#define ICON_MDI_BATTERY_90_BLUETOOTH "\xf3\xb0\xa5\x86" // U+F0946
+#define ICON_MDI_BATTERY_ALERT "\xf3\xb0\x82\x83" // U+F0083
+#define ICON_MDI_BATTERY_ALERT_BLUETOOTH "\xf3\xb0\xa5\x87" // U+F0947
+#define ICON_MDI_BATTERY_ALERT_VARIANT "\xf3\xb1\x83\x8c" // U+F10CC
+#define ICON_MDI_BATTERY_ALERT_VARIANT_OUTLINE "\xf3\xb1\x83\x8d" // U+F10CD
+#define ICON_MDI_BATTERY_ARROW_DOWN "\xf3\xb1\x9f\x9e" // U+F17DE
+#define ICON_MDI_BATTERY_ARROW_DOWN_OUTLINE "\xf3\xb1\x9f\x9f" // U+F17DF
+#define ICON_MDI_BATTERY_ARROW_UP "\xf3\xb1\x9f\xa0" // U+F17E0
+#define ICON_MDI_BATTERY_ARROW_UP_OUTLINE "\xf3\xb1\x9f\xa1" // U+F17E1
+#define ICON_MDI_BATTERY_BLUETOOTH "\xf3\xb0\xa5\x88" // U+F0948
+#define ICON_MDI_BATTERY_BLUETOOTH_VARIANT "\xf3\xb0\xa5\x89" // U+F0949
+#define ICON_MDI_BATTERY_CHARGING "\xf3\xb0\x82\x84" // U+F0084
+#define ICON_MDI_BATTERY_CHARGING_10 "\xf3\xb0\xa2\x9c" // U+F089C
+#define ICON_MDI_BATTERY_CHARGING_100 "\xf3\xb0\x82\x85" // U+F0085
+#define ICON_MDI_BATTERY_CHARGING_20 "\xf3\xb0\x82\x86" // U+F0086
+#define ICON_MDI_BATTERY_CHARGING_30 "\xf3\xb0\x82\x87" // U+F0087
+#define ICON_MDI_BATTERY_CHARGING_40 "\xf3\xb0\x82\x88" // U+F0088
+#define ICON_MDI_BATTERY_CHARGING_50 "\xf3\xb0\xa2\x9d" // U+F089D
+#define ICON_MDI_BATTERY_CHARGING_60 "\xf3\xb0\x82\x89" // U+F0089
+#define ICON_MDI_BATTERY_CHARGING_70 "\xf3\xb0\xa2\x9e" // U+F089E
+#define ICON_MDI_BATTERY_CHARGING_80 "\xf3\xb0\x82\x8a" // U+F008A
+#define ICON_MDI_BATTERY_CHARGING_90 "\xf3\xb0\x82\x8b" // U+F008B
+#define ICON_MDI_BATTERY_CHARGING_HIGH "\xf3\xb1\x8a\xa6" // U+F12A6
+#define ICON_MDI_BATTERY_CHARGING_LOW "\xf3\xb1\x8a\xa4" // U+F12A4
+#define ICON_MDI_BATTERY_CHARGING_MEDIUM "\xf3\xb1\x8a\xa5" // U+F12A5
+#define ICON_MDI_BATTERY_CHARGING_OUTLINE "\xf3\xb0\xa2\x9f" // U+F089F
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS "\xf3\xb0\xa0\x87" // U+F0807
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_10 "\xf3\xb0\xa0\x88" // U+F0808
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_20 "\xf3\xb0\xa0\x89" // U+F0809
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_30 "\xf3\xb0\xa0\x8a" // U+F080A
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_40 "\xf3\xb0\xa0\x8b" // U+F080B
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_50 "\xf3\xb0\xa0\x8c" // U+F080C
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_60 "\xf3\xb0\xa0\x8d" // U+F080D
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_70 "\xf3\xb0\xa0\x8e" // U+F080E
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_80 "\xf3\xb0\xa0\x8f" // U+F080F
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_90 "\xf3\xb0\xa0\x90" // U+F0810
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_ALERT "\xf3\xb0\xa0\x91" // U+F0811
+#define ICON_MDI_BATTERY_CHARGING_WIRELESS_OUTLINE "\xf3\xb0\xa0\x92" // U+F0812
+#define ICON_MDI_BATTERY_CHECK "\xf3\xb1\x9f\xa2" // U+F17E2
+#define ICON_MDI_BATTERY_CHECK_OUTLINE "\xf3\xb1\x9f\xa3" // U+F17E3
+#define ICON_MDI_BATTERY_CLOCK "\xf3\xb1\xa7\xa5" // U+F19E5
+#define ICON_MDI_BATTERY_CLOCK_OUTLINE "\xf3\xb1\xa7\xa6" // U+F19E6
+#define ICON_MDI_BATTERY_HEART "\xf3\xb1\x88\x8f" // U+F120F
+#define ICON_MDI_BATTERY_HEART_OUTLINE "\xf3\xb1\x88\x90" // U+F1210
+#define ICON_MDI_BATTERY_HEART_VARIANT "\xf3\xb1\x88\x91" // U+F1211
+#define ICON_MDI_BATTERY_HIGH "\xf3\xb1\x8a\xa3" // U+F12A3
+#define ICON_MDI_BATTERY_LOCK "\xf3\xb1\x9e\x9c" // U+F179C
+#define ICON_MDI_BATTERY_LOCK_OPEN "\xf3\xb1\x9e\x9d" // U+F179D
+#define ICON_MDI_BATTERY_LOW "\xf3\xb1\x8a\xa1" // U+F12A1
+#define ICON_MDI_BATTERY_MEDIUM "\xf3\xb1\x8a\xa2" // U+F12A2
+#define ICON_MDI_BATTERY_MINUS "\xf3\xb1\x9f\xa4" // U+F17E4
+#define ICON_MDI_BATTERY_MINUS_OUTLINE "\xf3\xb1\x9f\xa5" // U+F17E5
+#define ICON_MDI_BATTERY_MINUS_VARIANT "\xf3\xb0\x82\x8c" // U+F008C
+#define ICON_MDI_BATTERY_NEGATIVE "\xf3\xb0\x82\x8d" // U+F008D
+#define ICON_MDI_BATTERY_OFF "\xf3\xb1\x89\x9d" // U+F125D
+#define ICON_MDI_BATTERY_OFF_OUTLINE "\xf3\xb1\x89\x9e" // U+F125E
+#define ICON_MDI_BATTERY_OUTLINE "\xf3\xb0\x82\x8e" // U+F008E
+#define ICON_MDI_BATTERY_PLUS "\xf3\xb1\x9f\xa6" // U+F17E6
+#define ICON_MDI_BATTERY_PLUS_OUTLINE "\xf3\xb1\x9f\xa7" // U+F17E7
+#define ICON_MDI_BATTERY_PLUS_VARIANT "\xf3\xb0\x82\x8f" // U+F008F
+#define ICON_MDI_BATTERY_POSITIVE "\xf3\xb0\x82\x90" // U+F0090
+#define ICON_MDI_BATTERY_REMOVE "\xf3\xb1\x9f\xa8" // U+F17E8
+#define ICON_MDI_BATTERY_REMOVE_OUTLINE "\xf3\xb1\x9f\xa9" // U+F17E9
+#define ICON_MDI_BATTERY_SYNC "\xf3\xb1\xa0\xb4" // U+F1834
+#define ICON_MDI_BATTERY_SYNC_OUTLINE "\xf3\xb1\xa0\xb5" // U+F1835
+#define ICON_MDI_BATTERY_UNKNOWN "\xf3\xb0\x82\x91" // U+F0091
+#define ICON_MDI_BATTERY_UNKNOWN_BLUETOOTH "\xf3\xb0\xa5\x8a" // U+F094A
+#define ICON_MDI_BEACH "\xf3\xb0\x82\x92" // U+F0092
+#define ICON_MDI_BEAKER "\xf3\xb0\xb3\xaa" // U+F0CEA
+#define ICON_MDI_BEAKER_ALERT "\xf3\xb1\x88\xa9" // U+F1229
+#define ICON_MDI_BEAKER_ALERT_OUTLINE "\xf3\xb1\x88\xaa" // U+F122A
+#define ICON_MDI_BEAKER_CHECK "\xf3\xb1\x88\xab" // U+F122B
+#define ICON_MDI_BEAKER_CHECK_OUTLINE "\xf3\xb1\x88\xac" // U+F122C
+#define ICON_MDI_BEAKER_MINUS "\xf3\xb1\x88\xad" // U+F122D
+#define ICON_MDI_BEAKER_MINUS_OUTLINE "\xf3\xb1\x88\xae" // U+F122E
+#define ICON_MDI_BEAKER_OUTLINE "\xf3\xb0\x9a\x90" // U+F0690
+#define ICON_MDI_BEAKER_PLUS "\xf3\xb1\x88\xaf" // U+F122F
+#define ICON_MDI_BEAKER_PLUS_OUTLINE "\xf3\xb1\x88\xb0" // U+F1230
+#define ICON_MDI_BEAKER_QUESTION "\xf3\xb1\x88\xb1" // U+F1231
+#define ICON_MDI_BEAKER_QUESTION_OUTLINE "\xf3\xb1\x88\xb2" // U+F1232
+#define ICON_MDI_BEAKER_REMOVE "\xf3\xb1\x88\xb3" // U+F1233
+#define ICON_MDI_BEAKER_REMOVE_OUTLINE "\xf3\xb1\x88\xb4" // U+F1234
+#define ICON_MDI_BED "\xf3\xb0\x8b\xa3" // U+F02E3
+#define ICON_MDI_BED_CLOCK "\xf3\xb1\xae\x94" // U+F1B94
+#define ICON_MDI_BED_DOUBLE "\xf3\xb0\xbf\x94" // U+F0FD4
+#define ICON_MDI_BED_DOUBLE_OUTLINE "\xf3\xb0\xbf\x93" // U+F0FD3
+#define ICON_MDI_BED_EMPTY "\xf3\xb0\xa2\xa0" // U+F08A0
+#define ICON_MDI_BED_KING "\xf3\xb0\xbf\x92" // U+F0FD2
+#define ICON_MDI_BED_KING_OUTLINE "\xf3\xb0\xbf\x91" // U+F0FD1
+#define ICON_MDI_BED_OUTLINE "\xf3\xb0\x82\x99" // U+F0099
+#define ICON_MDI_BED_QUEEN "\xf3\xb0\xbf\x90" // U+F0FD0
+#define ICON_MDI_BED_QUEEN_OUTLINE "\xf3\xb0\xbf\x9b" // U+F0FDB
+#define ICON_MDI_BED_SINGLE "\xf3\xb1\x81\xad" // U+F106D
+#define ICON_MDI_BED_SINGLE_OUTLINE "\xf3\xb1\x81\xae" // U+F106E
+#define ICON_MDI_BEE "\xf3\xb0\xbe\xa1" // U+F0FA1
+#define ICON_MDI_BEE_FLOWER "\xf3\xb0\xbe\xa2" // U+F0FA2
+#define ICON_MDI_BEEHIVE_OFF_OUTLINE "\xf3\xb1\x8f\xad" // U+F13ED
+#define ICON_MDI_BEEHIVE_OUTLINE "\xf3\xb1\x83\x8e" // U+F10CE
+#define ICON_MDI_BEEKEEPER "\xf3\xb1\x93\xa2" // U+F14E2
+#define ICON_MDI_BEER "\xf3\xb0\x82\x98" // U+F0098
+#define ICON_MDI_BEER_OUTLINE "\xf3\xb1\x8c\x8c" // U+F130C
+#define ICON_MDI_BELL "\xf3\xb0\x82\x9a" // U+F009A
+#define ICON_MDI_BELL_ALERT "\xf3\xb0\xb5\x99" // U+F0D59
+#define ICON_MDI_BELL_ALERT_OUTLINE "\xf3\xb0\xba\x81" // U+F0E81
+#define ICON_MDI_BELL_BADGE "\xf3\xb1\x85\xab" // U+F116B
+#define ICON_MDI_BELL_BADGE_OUTLINE "\xf3\xb0\x85\xb8" // U+F0178
+#define ICON_MDI_BELL_CANCEL "\xf3\xb1\x8f\xa7" // U+F13E7
+#define ICON_MDI_BELL_CANCEL_OUTLINE "\xf3\xb1\x8f\xa8" // U+F13E8
+#define ICON_MDI_BELL_CHECK "\xf3\xb1\x87\xa5" // U+F11E5
+#define ICON_MDI_BELL_CHECK_OUTLINE "\xf3\xb1\x87\xa6" // U+F11E6
+#define ICON_MDI_BELL_CIRCLE "\xf3\xb0\xb5\x9a" // U+F0D5A
+#define ICON_MDI_BELL_CIRCLE_OUTLINE "\xf3\xb0\xb5\x9b" // U+F0D5B
+#define ICON_MDI_BELL_COG "\xf3\xb1\xa8\xa9" // U+F1A29
+#define ICON_MDI_BELL_COG_OUTLINE "\xf3\xb1\xa8\xaa" // U+F1A2A
+#define ICON_MDI_BELL_MINUS "\xf3\xb1\x8f\xa9" // U+F13E9
+#define ICON_MDI_BELL_MINUS_OUTLINE "\xf3\xb1\x8f\xaa" // U+F13EA
+#define ICON_MDI_BELL_OFF "\xf3\xb0\x82\x9b" // U+F009B
+#define ICON_MDI_BELL_OFF_OUTLINE "\xf3\xb0\xaa\x91" // U+F0A91
+#define ICON_MDI_BELL_OUTLINE "\xf3\xb0\x82\x9c" // U+F009C
+#define ICON_MDI_BELL_PLUS "\xf3\xb0\x82\x9d" // U+F009D
+#define ICON_MDI_BELL_PLUS_OUTLINE "\xf3\xb0\xaa\x92" // U+F0A92
+#define ICON_MDI_BELL_REMOVE "\xf3\xb1\x8f\xab" // U+F13EB
+#define ICON_MDI_BELL_REMOVE_OUTLINE "\xf3\xb1\x8f\xac" // U+F13EC
+#define ICON_MDI_BELL_RING "\xf3\xb0\x82\x9e" // U+F009E
+#define ICON_MDI_BELL_RING_OUTLINE "\xf3\xb0\x82\x9f" // U+F009F
+#define ICON_MDI_BELL_SLEEP "\xf3\xb0\x82\xa0" // U+F00A0
+#define ICON_MDI_BELL_SLEEP_OUTLINE "\xf3\xb0\xaa\x93" // U+F0A93
+#define ICON_MDI_BENCH "\xf3\xb1\xb0\xa1" // U+F1C21
+#define ICON_MDI_BENCH_BACK "\xf3\xb1\xb0\xa2" // U+F1C22
+#define ICON_MDI_BETA "\xf3\xb0\x82\xa1" // U+F00A1
+#define ICON_MDI_BETAMAX "\xf3\xb0\xa7\x8b" // U+F09CB
+#define ICON_MDI_BIATHLON "\xf3\xb0\xb8\x94" // U+F0E14
+#define ICON_MDI_BICYCLE "\xf3\xb1\x82\x9c" // U+F109C
+#define ICON_MDI_BICYCLE_BASKET "\xf3\xb1\x88\xb5" // U+F1235
+#define ICON_MDI_BICYCLE_CARGO "\xf3\xb1\xa2\x9c" // U+F189C
+#define ICON_MDI_BICYCLE_ELECTRIC "\xf3\xb1\x96\xb4" // U+F15B4
+#define ICON_MDI_BICYCLE_PENNY_FARTHING "\xf3\xb1\x97\xa9" // U+F15E9
+#define ICON_MDI_BIKE "\xf3\xb0\x82\xa3" // U+F00A3
+#define ICON_MDI_BIKE_FAST "\xf3\xb1\x84\x9f" // U+F111F
+#define ICON_MDI_BIKE_PEDAL "\xf3\xb1\xb0\xa3" // U+F1C23
+#define ICON_MDI_BIKE_PEDAL_CLIPLESS "\xf3\xb1\xb0\xa4" // U+F1C24
+#define ICON_MDI_BIKE_PEDAL_MOUNTAIN "\xf3\xb1\xb0\xa5" // U+F1C25
+#define ICON_MDI_BILLBOARD "\xf3\xb1\x80\x90" // U+F1010
+#define ICON_MDI_BILLIARDS "\xf3\xb0\xad\xa1" // U+F0B61
+#define ICON_MDI_BILLIARDS_RACK "\xf3\xb0\xad\xa2" // U+F0B62
+#define ICON_MDI_BINOCULARS "\xf3\xb0\x82\xa5" // U+F00A5
+#define ICON_MDI_BIO "\xf3\xb0\x82\xa6" // U+F00A6
+#define ICON_MDI_BIOHAZARD "\xf3\xb0\x82\xa7" // U+F00A7
+#define ICON_MDI_BIRD "\xf3\xb1\x97\x86" // U+F15C6
+#define ICON_MDI_BITBUCKET "\xf3\xb0\x82\xa8" // U+F00A8
+#define ICON_MDI_BITCOIN "\xf3\xb0\xa0\x93" // U+F0813
+#define ICON_MDI_BLACK_MESA "\xf3\xb0\x82\xa9" // U+F00A9
+#define ICON_MDI_BLENDER "\xf3\xb0\xb3\xab" // U+F0CEB
+#define ICON_MDI_BLENDER_OUTLINE "\xf3\xb1\xa0\x9a" // U+F181A
+#define ICON_MDI_BLENDER_SOFTWARE "\xf3\xb0\x82\xab" // U+F00AB
+#define ICON_MDI_BLINDS "\xf3\xb0\x82\xac" // U+F00AC
+#define ICON_MDI_BLINDS_HORIZONTAL "\xf3\xb1\xa8\xab" // U+F1A2B
+#define ICON_MDI_BLINDS_HORIZONTAL_CLOSED "\xf3\xb1\xa8\xac" // U+F1A2C
+#define ICON_MDI_BLINDS_OPEN "\xf3\xb1\x80\x91" // U+F1011
+#define ICON_MDI_BLINDS_VERTICAL "\xf3\xb1\xa8\xad" // U+F1A2D
+#define ICON_MDI_BLINDS_VERTICAL_CLOSED "\xf3\xb1\xa8\xae" // U+F1A2E
+#define ICON_MDI_BLOCK_HELPER "\xf3\xb0\x82\xad" // U+F00AD
+#define ICON_MDI_BLOOD_BAG "\xf3\xb0\xb3\xac" // U+F0CEC
+#define ICON_MDI_BLUETOOTH "\xf3\xb0\x82\xaf" // U+F00AF
+#define ICON_MDI_BLUETOOTH_AUDIO "\xf3\xb0\x82\xb0" // U+F00B0
+#define ICON_MDI_BLUETOOTH_CONNECT "\xf3\xb0\x82\xb1" // U+F00B1
+#define ICON_MDI_BLUETOOTH_OFF "\xf3\xb0\x82\xb2" // U+F00B2
+#define ICON_MDI_BLUETOOTH_SETTINGS "\xf3\xb0\x82\xb3" // U+F00B3
+#define ICON_MDI_BLUETOOTH_TRANSFER "\xf3\xb0\x82\xb4" // U+F00B4
+#define ICON_MDI_BLUR "\xf3\xb0\x82\xb5" // U+F00B5
+#define ICON_MDI_BLUR_LINEAR "\xf3\xb0\x82\xb6" // U+F00B6
+#define ICON_MDI_BLUR_OFF "\xf3\xb0\x82\xb7" // U+F00B7
+#define ICON_MDI_BLUR_RADIAL "\xf3\xb0\x82\xb8" // U+F00B8
+#define ICON_MDI_BOLT "\xf3\xb0\xb6\xb3" // U+F0DB3
+#define ICON_MDI_BOMB "\xf3\xb0\x9a\x91" // U+F0691
+#define ICON_MDI_BOMB_OFF "\xf3\xb0\x9b\x85" // U+F06C5
+#define ICON_MDI_BONE "\xf3\xb0\x82\xb9" // U+F00B9
+#define ICON_MDI_BONE_OFF "\xf3\xb1\xa7\xa0" // U+F19E0
+#define ICON_MDI_BOOK "\xf3\xb0\x82\xba" // U+F00BA
+#define ICON_MDI_BOOK_ACCOUNT "\xf3\xb1\x8e\xad" // U+F13AD
+#define ICON_MDI_BOOK_ACCOUNT_OUTLINE "\xf3\xb1\x8e\xae" // U+F13AE
+#define ICON_MDI_BOOK_ALERT "\xf3\xb1\x99\xbc" // U+F167C
+#define ICON_MDI_BOOK_ALERT_OUTLINE "\xf3\xb1\x99\xbd" // U+F167D
+#define ICON_MDI_BOOK_ALPHABET "\xf3\xb0\x98\x9d" // U+F061D
+#define ICON_MDI_BOOK_ARROW_DOWN "\xf3\xb1\x99\xbe" // U+F167E
+#define ICON_MDI_BOOK_ARROW_DOWN_OUTLINE "\xf3\xb1\x99\xbf" // U+F167F
+#define ICON_MDI_BOOK_ARROW_LEFT "\xf3\xb1\x9a\x80" // U+F1680
+#define ICON_MDI_BOOK_ARROW_LEFT_OUTLINE "\xf3\xb1\x9a\x81" // U+F1681
+#define ICON_MDI_BOOK_ARROW_RIGHT "\xf3\xb1\x9a\x82" // U+F1682
+#define ICON_MDI_BOOK_ARROW_RIGHT_OUTLINE "\xf3\xb1\x9a\x83" // U+F1683
+#define ICON_MDI_BOOK_ARROW_UP "\xf3\xb1\x9a\x84" // U+F1684
+#define ICON_MDI_BOOK_ARROW_UP_OUTLINE "\xf3\xb1\x9a\x85" // U+F1685
+#define ICON_MDI_BOOK_CANCEL "\xf3\xb1\x9a\x86" // U+F1686
+#define ICON_MDI_BOOK_CANCEL_OUTLINE "\xf3\xb1\x9a\x87" // U+F1687
+#define ICON_MDI_BOOK_CHECK "\xf3\xb1\x93\xb3" // U+F14F3
+#define ICON_MDI_BOOK_CHECK_OUTLINE "\xf3\xb1\x93\xb4" // U+F14F4
+#define ICON_MDI_BOOK_CLOCK "\xf3\xb1\x9a\x88" // U+F1688
+#define ICON_MDI_BOOK_CLOCK_OUTLINE "\xf3\xb1\x9a\x89" // U+F1689
+#define ICON_MDI_BOOK_COG "\xf3\xb1\x9a\x8a" // U+F168A
+#define ICON_MDI_BOOK_COG_OUTLINE "\xf3\xb1\x9a\x8b" // U+F168B
+#define ICON_MDI_BOOK_CROSS "\xf3\xb0\x82\xa2" // U+F00A2
+#define ICON_MDI_BOOK_EDIT "\xf3\xb1\x9a\x8c" // U+F168C
+#define ICON_MDI_BOOK_EDIT_OUTLINE "\xf3\xb1\x9a\x8d" // U+F168D
+#define ICON_MDI_BOOK_EDUCATION "\xf3\xb1\x9b\x89" // U+F16C9
+#define ICON_MDI_BOOK_EDUCATION_OUTLINE "\xf3\xb1\x9b\x8a" // U+F16CA
+#define ICON_MDI_BOOK_HEART "\xf3\xb1\xa8\x9d" // U+F1A1D
+#define ICON_MDI_BOOK_HEART_OUTLINE "\xf3\xb1\xa8\x9e" // U+F1A1E
+#define ICON_MDI_BOOK_INFORMATION_VARIANT "\xf3\xb1\x81\xaf" // U+F106F
+#define ICON_MDI_BOOK_LOCK "\xf3\xb0\x9e\x9a" // U+F079A
+#define ICON_MDI_BOOK_LOCK_OPEN "\xf3\xb0\x9e\x9b" // U+F079B
+#define ICON_MDI_BOOK_LOCK_OPEN_OUTLINE "\xf3\xb1\x9a\x8e" // U+F168E
+#define ICON_MDI_BOOK_LOCK_OUTLINE "\xf3\xb1\x9a\x8f" // U+F168F
+#define ICON_MDI_BOOK_MARKER "\xf3\xb1\x9a\x90" // U+F1690
+#define ICON_MDI_BOOK_MARKER_OUTLINE "\xf3\xb1\x9a\x91" // U+F1691
+#define ICON_MDI_BOOK_MINUS "\xf3\xb0\x97\x99" // U+F05D9
+#define ICON_MDI_BOOK_MINUS_MULTIPLE "\xf3\xb0\xaa\x94" // U+F0A94
+#define ICON_MDI_BOOK_MINUS_MULTIPLE_OUTLINE "\xf3\xb0\xa4\x8b" // U+F090B
+#define ICON_MDI_BOOK_MINUS_OUTLINE "\xf3\xb1\x9a\x92" // U+F1692
+#define ICON_MDI_BOOK_MULTIPLE "\xf3\xb0\x82\xbb" // U+F00BB
+#define ICON_MDI_BOOK_MULTIPLE_OUTLINE "\xf3\xb0\x90\xb6" // U+F0436
+#define ICON_MDI_BOOK_MUSIC "\xf3\xb0\x81\xa7" // U+F0067
+#define ICON_MDI_BOOK_MUSIC_OUTLINE "\xf3\xb1\x9a\x93" // U+F1693
+#define ICON_MDI_BOOK_OFF "\xf3\xb1\x9a\x94" // U+F1694
+#define ICON_MDI_BOOK_OFF_OUTLINE "\xf3\xb1\x9a\x95" // U+F1695
+#define ICON_MDI_BOOK_OPEN "\xf3\xb0\x82\xbd" // U+F00BD
+#define ICON_MDI_BOOK_OPEN_BLANK_VARIANT "\xf3\xb0\x82\xbe" // U+F00BE
+#define ICON_MDI_BOOK_OPEN_OUTLINE "\xf3\xb0\xad\xa3" // U+F0B63
+#define ICON_MDI_BOOK_OPEN_PAGE_VARIANT "\xf3\xb0\x97\x9a" // U+F05DA
+#define ICON_MDI_BOOK_OPEN_PAGE_VARIANT_OUTLINE "\xf3\xb1\x97\x96" // U+F15D6
+#define ICON_MDI_BOOK_OPEN_VARIANT "\xf3\xb1\x93\xb7" // U+F14F7
+#define ICON_MDI_BOOK_OUTLINE "\xf3\xb0\xad\xa4" // U+F0B64
+#define ICON_MDI_BOOK_PLAY "\xf3\xb0\xba\x82" // U+F0E82
+#define ICON_MDI_BOOK_PLAY_OUTLINE "\xf3\xb0\xba\x83" // U+F0E83
+#define ICON_MDI_BOOK_PLUS "\xf3\xb0\x97\x9b" // U+F05DB
+#define ICON_MDI_BOOK_PLUS_MULTIPLE "\xf3\xb0\xaa\x95" // U+F0A95
+#define ICON_MDI_BOOK_PLUS_MULTIPLE_OUTLINE "\xf3\xb0\xab\x9e" // U+F0ADE
+#define ICON_MDI_BOOK_PLUS_OUTLINE "\xf3\xb1\x9a\x96" // U+F1696
+#define ICON_MDI_BOOK_REFRESH "\xf3\xb1\x9a\x97" // U+F1697
+#define ICON_MDI_BOOK_REFRESH_OUTLINE "\xf3\xb1\x9a\x98" // U+F1698
+#define ICON_MDI_BOOK_REMOVE "\xf3\xb0\xaa\x97" // U+F0A97
+#define ICON_MDI_BOOK_REMOVE_MULTIPLE "\xf3\xb0\xaa\x96" // U+F0A96
+#define ICON_MDI_BOOK_REMOVE_MULTIPLE_OUTLINE "\xf3\xb0\x93\x8a" // U+F04CA
+#define ICON_MDI_BOOK_REMOVE_OUTLINE "\xf3\xb1\x9a\x99" // U+F1699
+#define ICON_MDI_BOOK_SEARCH "\xf3\xb0\xba\x84" // U+F0E84
+#define ICON_MDI_BOOK_SEARCH_OUTLINE "\xf3\xb0\xba\x85" // U+F0E85
+#define ICON_MDI_BOOK_SETTINGS "\xf3\xb1\x9a\x9a" // U+F169A
+#define ICON_MDI_BOOK_SETTINGS_OUTLINE "\xf3\xb1\x9a\x9b" // U+F169B
+#define ICON_MDI_BOOK_SYNC "\xf3\xb1\x9a\x9c" // U+F169C
+#define ICON_MDI_BOOK_SYNC_OUTLINE "\xf3\xb1\x9b\x88" // U+F16C8
+#define ICON_MDI_BOOK_VARIANT "\xf3\xb0\x82\xbf" // U+F00BF
+#define ICON_MDI_BOOKMARK "\xf3\xb0\x83\x80" // U+F00C0
+#define ICON_MDI_BOOKMARK_BOX "\xf3\xb1\xad\xb5" // U+F1B75
+#define ICON_MDI_BOOKMARK_BOX_MULTIPLE "\xf3\xb1\xa5\xac" // U+F196C
+#define ICON_MDI_BOOKMARK_BOX_MULTIPLE_OUTLINE "\xf3\xb1\xa5\xad" // U+F196D
+#define ICON_MDI_BOOKMARK_BOX_OUTLINE "\xf3\xb1\xad\xb6" // U+F1B76
+#define ICON_MDI_BOOKMARK_CHECK "\xf3\xb0\x83\x81" // U+F00C1
+#define ICON_MDI_BOOKMARK_CHECK_OUTLINE "\xf3\xb1\x8d\xbb" // U+F137B
+#define ICON_MDI_BOOKMARK_MINUS "\xf3\xb0\xa7\x8c" // U+F09CC
+#define ICON_MDI_BOOKMARK_MINUS_OUTLINE "\xf3\xb0\xa7\x8d" // U+F09CD
+#define ICON_MDI_BOOKMARK_MULTIPLE "\xf3\xb0\xb8\x95" // U+F0E15
+#define ICON_MDI_BOOKMARK_MULTIPLE_OUTLINE "\xf3\xb0\xb8\x96" // U+F0E16
+#define ICON_MDI_BOOKMARK_MUSIC "\xf3\xb0\x83\x82" // U+F00C2
+#define ICON_MDI_BOOKMARK_MUSIC_OUTLINE "\xf3\xb1\x8d\xb9" // U+F1379
+#define ICON_MDI_BOOKMARK_OFF "\xf3\xb0\xa7\x8e" // U+F09CE
+#define ICON_MDI_BOOKMARK_OFF_OUTLINE "\xf3\xb0\xa7\x8f" // U+F09CF
+#define ICON_MDI_BOOKMARK_OUTLINE "\xf3\xb0\x83\x83" // U+F00C3
+#define ICON_MDI_BOOKMARK_PLUS "\xf3\xb0\x83\x85" // U+F00C5
+#define ICON_MDI_BOOKMARK_PLUS_OUTLINE "\xf3\xb0\x83\x84" // U+F00C4
+#define ICON_MDI_BOOKMARK_REMOVE "\xf3\xb0\x83\x86" // U+F00C6
+#define ICON_MDI_BOOKMARK_REMOVE_OUTLINE "\xf3\xb1\x8d\xba" // U+F137A
+#define ICON_MDI_BOOKSHELF "\xf3\xb1\x89\x9f" // U+F125F
+#define ICON_MDI_BOOM_GATE "\xf3\xb0\xba\x86" // U+F0E86
+#define ICON_MDI_BOOM_GATE_ALERT "\xf3\xb0\xba\x87" // U+F0E87
+#define ICON_MDI_BOOM_GATE_ALERT_OUTLINE "\xf3\xb0\xba\x88" // U+F0E88
+#define ICON_MDI_BOOM_GATE_ARROW_DOWN "\xf3\xb0\xba\x89" // U+F0E89
+#define ICON_MDI_BOOM_GATE_ARROW_DOWN_OUTLINE "\xf3\xb0\xba\x8a" // U+F0E8A
+#define ICON_MDI_BOOM_GATE_ARROW_UP "\xf3\xb0\xba\x8c" // U+F0E8C
+#define ICON_MDI_BOOM_GATE_ARROW_UP_OUTLINE "\xf3\xb0\xba\x8d" // U+F0E8D
+#define ICON_MDI_BOOM_GATE_OUTLINE "\xf3\xb0\xba\x8b" // U+F0E8B
+#define ICON_MDI_BOOM_GATE_UP "\xf3\xb1\x9f\xb9" // U+F17F9
+#define ICON_MDI_BOOM_GATE_UP_OUTLINE "\xf3\xb1\x9f\xba" // U+F17FA
+#define ICON_MDI_BOOMBOX "\xf3\xb0\x97\x9c" // U+F05DC
+#define ICON_MDI_BOOMERANG "\xf3\xb1\x83\x8f" // U+F10CF
+#define ICON_MDI_BOOTSTRAP "\xf3\xb0\x9b\x86" // U+F06C6
+#define ICON_MDI_BORDER_ALL "\xf3\xb0\x83\x87" // U+F00C7
+#define ICON_MDI_BORDER_ALL_VARIANT "\xf3\xb0\xa2\xa1" // U+F08A1
+#define ICON_MDI_BORDER_BOTTOM "\xf3\xb0\x83\x88" // U+F00C8
+#define ICON_MDI_BORDER_BOTTOM_VARIANT "\xf3\xb0\xa2\xa2" // U+F08A2
+#define ICON_MDI_BORDER_COLOR "\xf3\xb0\x83\x89" // U+F00C9
+#define ICON_MDI_BORDER_HORIZONTAL "\xf3\xb0\x83\x8a" // U+F00CA
+#define ICON_MDI_BORDER_INSIDE "\xf3\xb0\x83\x8b" // U+F00CB
+#define ICON_MDI_BORDER_LEFT "\xf3\xb0\x83\x8c" // U+F00CC
+#define ICON_MDI_BORDER_LEFT_VARIANT "\xf3\xb0\xa2\xa3" // U+F08A3
+#define ICON_MDI_BORDER_NONE "\xf3\xb0\x83\x8d" // U+F00CD
+#define ICON_MDI_BORDER_NONE_VARIANT "\xf3\xb0\xa2\xa4" // U+F08A4
+#define ICON_MDI_BORDER_OUTSIDE "\xf3\xb0\x83\x8e" // U+F00CE
+#define ICON_MDI_BORDER_RADIUS "\xf3\xb1\xab\xb4" // U+F1AF4
+#define ICON_MDI_BORDER_RIGHT "\xf3\xb0\x83\x8f" // U+F00CF
+#define ICON_MDI_BORDER_RIGHT_VARIANT "\xf3\xb0\xa2\xa5" // U+F08A5
+#define ICON_MDI_BORDER_STYLE "\xf3\xb0\x83\x90" // U+F00D0
+#define ICON_MDI_BORDER_TOP "\xf3\xb0\x83\x91" // U+F00D1
+#define ICON_MDI_BORDER_TOP_VARIANT "\xf3\xb0\xa2\xa6" // U+F08A6
+#define ICON_MDI_BORDER_VERTICAL "\xf3\xb0\x83\x92" // U+F00D2
+#define ICON_MDI_BOTTLE_SODA "\xf3\xb1\x81\xb0" // U+F1070
+#define ICON_MDI_BOTTLE_SODA_CLASSIC "\xf3\xb1\x81\xb1" // U+F1071
+#define ICON_MDI_BOTTLE_SODA_CLASSIC_OUTLINE "\xf3\xb1\x8d\xa3" // U+F1363
+#define ICON_MDI_BOTTLE_SODA_OUTLINE "\xf3\xb1\x81\xb2" // U+F1072
+#define ICON_MDI_BOTTLE_TONIC "\xf3\xb1\x84\xae" // U+F112E
+#define ICON_MDI_BOTTLE_TONIC_OUTLINE "\xf3\xb1\x84\xaf" // U+F112F
+#define ICON_MDI_BOTTLE_TONIC_PLUS "\xf3\xb1\x84\xb0" // U+F1130
+#define ICON_MDI_BOTTLE_TONIC_PLUS_OUTLINE "\xf3\xb1\x84\xb1" // U+F1131
+#define ICON_MDI_BOTTLE_TONIC_SKULL "\xf3\xb1\x84\xb2" // U+F1132
+#define ICON_MDI_BOTTLE_TONIC_SKULL_OUTLINE "\xf3\xb1\x84\xb3" // U+F1133
+#define ICON_MDI_BOTTLE_WINE "\xf3\xb0\xa1\x94" // U+F0854
+#define ICON_MDI_BOTTLE_WINE_OUTLINE "\xf3\xb1\x8c\x90" // U+F1310
+#define ICON_MDI_BOW_ARROW "\xf3\xb1\xa1\x81" // U+F1841
+#define ICON_MDI_BOW_TIE "\xf3\xb0\x99\xb8" // U+F0678
+#define ICON_MDI_BOWL "\xf3\xb0\x8a\x8e" // U+F028E
+#define ICON_MDI_BOWL_MIX "\xf3\xb0\x98\x97" // U+F0617
+#define ICON_MDI_BOWL_MIX_OUTLINE "\xf3\xb0\x8b\xa4" // U+F02E4
+#define ICON_MDI_BOWL_OUTLINE "\xf3\xb0\x8a\xa9" // U+F02A9
+#define ICON_MDI_BOWLING "\xf3\xb0\x83\x93" // U+F00D3
+#define ICON_MDI_BOX "\xf3\xb0\x83\x94" // U+F00D4
+#define ICON_MDI_BOX_CUTTER "\xf3\xb0\x83\x95" // U+F00D5
+#define ICON_MDI_BOX_CUTTER_OFF "\xf3\xb0\xad\x8a" // U+F0B4A
+#define ICON_MDI_BOX_SHADOW "\xf3\xb0\x98\xb7" // U+F0637
+#define ICON_MDI_BOXING_GLOVE "\xf3\xb0\xad\xa5" // U+F0B65
+#define ICON_MDI_BRAILLE "\xf3\xb0\xa7\x90" // U+F09D0
+#define ICON_MDI_BRAIN "\xf3\xb0\xa7\x91" // U+F09D1
+#define ICON_MDI_BREAD_SLICE "\xf3\xb0\xb3\xae" // U+F0CEE
+#define ICON_MDI_BREAD_SLICE_OUTLINE "\xf3\xb0\xb3\xaf" // U+F0CEF
+#define ICON_MDI_BRIDGE "\xf3\xb0\x98\x98" // U+F0618
+#define ICON_MDI_BRIEFCASE "\xf3\xb0\x83\x96" // U+F00D6
+#define ICON_MDI_BRIEFCASE_ACCOUNT "\xf3\xb0\xb3\xb0" // U+F0CF0
+#define ICON_MDI_BRIEFCASE_ACCOUNT_OUTLINE "\xf3\xb0\xb3\xb1" // U+F0CF1
+#define ICON_MDI_BRIEFCASE_ARROW_LEFT_RIGHT "\xf3\xb1\xaa\x8d" // U+F1A8D
+#define ICON_MDI_BRIEFCASE_ARROW_LEFT_RIGHT_OUTLINE "\xf3\xb1\xaa\x8e" // U+F1A8E
+#define ICON_MDI_BRIEFCASE_ARROW_UP_DOWN "\xf3\xb1\xaa\x8f" // U+F1A8F
+#define ICON_MDI_BRIEFCASE_ARROW_UP_DOWN_OUTLINE "\xf3\xb1\xaa\x90" // U+F1A90
+#define ICON_MDI_BRIEFCASE_CHECK "\xf3\xb0\x83\x97" // U+F00D7
+#define ICON_MDI_BRIEFCASE_CHECK_OUTLINE "\xf3\xb1\x8c\x9e" // U+F131E
+#define ICON_MDI_BRIEFCASE_CLOCK "\xf3\xb1\x83\x90" // U+F10D0
+#define ICON_MDI_BRIEFCASE_CLOCK_OUTLINE "\xf3\xb1\x83\x91" // U+F10D1
+#define ICON_MDI_BRIEFCASE_DOWNLOAD "\xf3\xb0\x83\x98" // U+F00D8
+#define ICON_MDI_BRIEFCASE_DOWNLOAD_OUTLINE "\xf3\xb0\xb0\xbd" // U+F0C3D
+#define ICON_MDI_BRIEFCASE_EDIT "\xf3\xb0\xaa\x98" // U+F0A98
+#define ICON_MDI_BRIEFCASE_EDIT_OUTLINE "\xf3\xb0\xb0\xbe" // U+F0C3E
+#define ICON_MDI_BRIEFCASE_EYE "\xf3\xb1\x9f\x99" // U+F17D9
+#define ICON_MDI_BRIEFCASE_EYE_OUTLINE "\xf3\xb1\x9f\x9a" // U+F17DA
+#define ICON_MDI_BRIEFCASE_MINUS "\xf3\xb0\xa8\xaa" // U+F0A2A
+#define ICON_MDI_BRIEFCASE_MINUS_OUTLINE "\xf3\xb0\xb0\xbf" // U+F0C3F
+#define ICON_MDI_BRIEFCASE_OFF "\xf3\xb1\x99\x98" // U+F1658
+#define ICON_MDI_BRIEFCASE_OFF_OUTLINE "\xf3\xb1\x99\x99" // U+F1659
+#define ICON_MDI_BRIEFCASE_OUTLINE "\xf3\xb0\xa0\x94" // U+F0814
+#define ICON_MDI_BRIEFCASE_PLUS "\xf3\xb0\xa8\xab" // U+F0A2B
+#define ICON_MDI_BRIEFCASE_PLUS_OUTLINE "\xf3\xb0\xb1\x80" // U+F0C40
+#define ICON_MDI_BRIEFCASE_REMOVE "\xf3\xb0\xa8\xac" // U+F0A2C
+#define ICON_MDI_BRIEFCASE_REMOVE_OUTLINE "\xf3\xb0\xb1\x81" // U+F0C41
+#define ICON_MDI_BRIEFCASE_SEARCH "\xf3\xb0\xa8\xad" // U+F0A2D
+#define ICON_MDI_BRIEFCASE_SEARCH_OUTLINE "\xf3\xb0\xb1\x82" // U+F0C42
+#define ICON_MDI_BRIEFCASE_UPLOAD "\xf3\xb0\x83\x99" // U+F00D9
+#define ICON_MDI_BRIEFCASE_UPLOAD_OUTLINE "\xf3\xb0\xb1\x83" // U+F0C43
+#define ICON_MDI_BRIEFCASE_VARIANT "\xf3\xb1\x92\x94" // U+F1494
+#define ICON_MDI_BRIEFCASE_VARIANT_OFF "\xf3\xb1\x99\x9a" // U+F165A
+#define ICON_MDI_BRIEFCASE_VARIANT_OFF_OUTLINE "\xf3\xb1\x99\x9b" // U+F165B
+#define ICON_MDI_BRIEFCASE_VARIANT_OUTLINE "\xf3\xb1\x92\x95" // U+F1495
+#define ICON_MDI_BRIGHTNESS_1 "\xf3\xb0\x83\x9a" // U+F00DA
+#define ICON_MDI_BRIGHTNESS_2 "\xf3\xb0\x83\x9b" // U+F00DB
+#define ICON_MDI_BRIGHTNESS_3 "\xf3\xb0\x83\x9c" // U+F00DC
+#define ICON_MDI_BRIGHTNESS_4 "\xf3\xb0\x83\x9d" // U+F00DD
+#define ICON_MDI_BRIGHTNESS_5 "\xf3\xb0\x83\x9e" // U+F00DE
+#define ICON_MDI_BRIGHTNESS_6 "\xf3\xb0\x83\x9f" // U+F00DF
+#define ICON_MDI_BRIGHTNESS_7 "\xf3\xb0\x83\xa0" // U+F00E0
+#define ICON_MDI_BRIGHTNESS_AUTO "\xf3\xb0\x83\xa1" // U+F00E1
+#define ICON_MDI_BRIGHTNESS_PERCENT "\xf3\xb0\xb3\xb2" // U+F0CF2
+#define ICON_MDI_BROADCAST "\xf3\xb1\x9c\xa0" // U+F1720
+#define ICON_MDI_BROADCAST_OFF "\xf3\xb1\x9c\xa1" // U+F1721
+#define ICON_MDI_BROOM "\xf3\xb0\x83\xa2" // U+F00E2
+#define ICON_MDI_BRUSH "\xf3\xb0\x83\xa3" // U+F00E3
+#define ICON_MDI_BRUSH_OFF "\xf3\xb1\x9d\xb1" // U+F1771
+#define ICON_MDI_BRUSH_OUTLINE "\xf3\xb1\xa8\x8d" // U+F1A0D
+#define ICON_MDI_BRUSH_VARIANT "\xf3\xb1\xa0\x93" // U+F1813
+#define ICON_MDI_BUCKET "\xf3\xb1\x90\x95" // U+F1415
+#define ICON_MDI_BUCKET_OUTLINE "\xf3\xb1\x90\x96" // U+F1416
+#define ICON_MDI_BUFFET "\xf3\xb0\x95\xb8" // U+F0578
+#define ICON_MDI_BUG "\xf3\xb0\x83\xa4" // U+F00E4
+#define ICON_MDI_BUG_CHECK "\xf3\xb0\xa8\xae" // U+F0A2E
+#define ICON_MDI_BUG_CHECK_OUTLINE "\xf3\xb0\xa8\xaf" // U+F0A2F
+#define ICON_MDI_BUG_OUTLINE "\xf3\xb0\xa8\xb0" // U+F0A30
+#define ICON_MDI_BUG_PAUSE "\xf3\xb1\xab\xb5" // U+F1AF5
+#define ICON_MDI_BUG_PAUSE_OUTLINE "\xf3\xb1\xab\xb6" // U+F1AF6
+#define ICON_MDI_BUG_PLAY "\xf3\xb1\xab\xb7" // U+F1AF7
+#define ICON_MDI_BUG_PLAY_OUTLINE "\xf3\xb1\xab\xb8" // U+F1AF8
+#define ICON_MDI_BUG_STOP "\xf3\xb1\xab\xb9" // U+F1AF9
+#define ICON_MDI_BUG_STOP_OUTLINE "\xf3\xb1\xab\xba" // U+F1AFA
+#define ICON_MDI_BUGLE "\xf3\xb0\xb6\xb4" // U+F0DB4
+#define ICON_MDI_BULKHEAD_LIGHT "\xf3\xb1\xa8\xaf" // U+F1A2F
+#define ICON_MDI_BULLDOZER "\xf3\xb0\xac\xa2" // U+F0B22
+#define ICON_MDI_BULLET "\xf3\xb0\xb3\xb3" // U+F0CF3
+#define ICON_MDI_BULLETIN_BOARD "\xf3\xb0\x83\xa5" // U+F00E5
+#define ICON_MDI_BULLHORN "\xf3\xb0\x83\xa6" // U+F00E6
+#define ICON_MDI_BULLHORN_OUTLINE "\xf3\xb0\xac\xa3" // U+F0B23
+#define ICON_MDI_BULLHORN_VARIANT "\xf3\xb1\xa5\xae" // U+F196E
+#define ICON_MDI_BULLHORN_VARIANT_OUTLINE "\xf3\xb1\xa5\xaf" // U+F196F
+#define ICON_MDI_BULLSEYE "\xf3\xb0\x97\x9d" // U+F05DD
+#define ICON_MDI_BULLSEYE_ARROW "\xf3\xb0\xa3\x89" // U+F08C9
+#define ICON_MDI_BULMA "\xf3\xb1\x8b\xa7" // U+F12E7
+#define ICON_MDI_BUNK_BED "\xf3\xb1\x8c\x82" // U+F1302
+#define ICON_MDI_BUNK_BED_OUTLINE "\xf3\xb0\x82\x97" // U+F0097
+#define ICON_MDI_BUS "\xf3\xb0\x83\xa7" // U+F00E7
+#define ICON_MDI_BUS_ALERT "\xf3\xb0\xaa\x99" // U+F0A99
+#define ICON_MDI_BUS_ARTICULATED_END "\xf3\xb0\x9e\x9c" // U+F079C
+#define ICON_MDI_BUS_ARTICULATED_FRONT "\xf3\xb0\x9e\x9d" // U+F079D
+#define ICON_MDI_BUS_CLOCK "\xf3\xb0\xa3\x8a" // U+F08CA
+#define ICON_MDI_BUS_DOUBLE_DECKER "\xf3\xb0\x9e\x9e" // U+F079E
+#define ICON_MDI_BUS_ELECTRIC "\xf3\xb1\xa4\x9d" // U+F191D
+#define ICON_MDI_BUS_MARKER "\xf3\xb1\x88\x92" // U+F1212
+#define ICON_MDI_BUS_MULTIPLE "\xf3\xb0\xbc\xbf" // U+F0F3F
+#define ICON_MDI_BUS_SCHOOL "\xf3\xb0\x9e\x9f" // U+F079F
+#define ICON_MDI_BUS_SIDE "\xf3\xb0\x9e\xa0" // U+F07A0
+#define ICON_MDI_BUS_SIGN "\xf3\xb1\xb3\x81" // U+F1CC1
+#define ICON_MDI_BUS_STOP "\xf3\xb1\x80\x92" // U+F1012
+#define ICON_MDI_BUS_STOP_COVERED "\xf3\xb1\x80\x93" // U+F1013
+#define ICON_MDI_BUS_STOP_UNCOVERED "\xf3\xb1\x80\x94" // U+F1014
+#define ICON_MDI_BUS_WRENCH "\xf3\xb1\xb3\x82" // U+F1CC2
+#define ICON_MDI_BUTTERFLY "\xf3\xb1\x96\x89" // U+F1589
+#define ICON_MDI_BUTTERFLY_OUTLINE "\xf3\xb1\x96\x8a" // U+F158A
+#define ICON_MDI_BUTTON_CURSOR "\xf3\xb1\xad\x8f" // U+F1B4F
+#define ICON_MDI_BUTTON_POINTER "\xf3\xb1\xad\x90" // U+F1B50
+#define ICON_MDI_CABIN_A_FRAME "\xf3\xb1\xa2\x8c" // U+F188C
+#define ICON_MDI_CABLE_DATA "\xf3\xb1\x8e\x94" // U+F1394
+#define ICON_MDI_CACHED "\xf3\xb0\x83\xa8" // U+F00E8
+#define ICON_MDI_CACTUS "\xf3\xb0\xb6\xb5" // U+F0DB5
+#define ICON_MDI_CAKE "\xf3\xb0\x83\xa9" // U+F00E9
+#define ICON_MDI_CAKE_LAYERED "\xf3\xb0\x83\xaa" // U+F00EA
+#define ICON_MDI_CAKE_VARIANT "\xf3\xb0\x83\xab" // U+F00EB
+#define ICON_MDI_CAKE_VARIANT_OUTLINE "\xf3\xb1\x9f\xb0" // U+F17F0
+#define ICON_MDI_CALCULATOR "\xf3\xb0\x83\xac" // U+F00EC
+#define ICON_MDI_CALCULATOR_VARIANT "\xf3\xb0\xaa\x9a" // U+F0A9A
+#define ICON_MDI_CALCULATOR_VARIANT_OUTLINE "\xf3\xb1\x96\xa6" // U+F15A6
+#define ICON_MDI_CALENDAR "\xf3\xb0\x83\xad" // U+F00ED
+#define ICON_MDI_CALENDAR_ACCOUNT "\xf3\xb0\xbb\x97" // U+F0ED7
+#define ICON_MDI_CALENDAR_ACCOUNT_OUTLINE "\xf3\xb0\xbb\x98" // U+F0ED8
+#define ICON_MDI_CALENDAR_ALERT "\xf3\xb0\xa8\xb1" // U+F0A31
+#define ICON_MDI_CALENDAR_ALERT_OUTLINE "\xf3\xb1\xad\xa2" // U+F1B62
+#define ICON_MDI_CALENDAR_ARROW_LEFT "\xf3\xb1\x84\xb4" // U+F1134
+#define ICON_MDI_CALENDAR_ARROW_RIGHT "\xf3\xb1\x84\xb5" // U+F1135
+#define ICON_MDI_CALENDAR_BADGE "\xf3\xb1\xae\x9d" // U+F1B9D
+#define ICON_MDI_CALENDAR_BADGE_OUTLINE "\xf3\xb1\xae\x9e" // U+F1B9E
+#define ICON_MDI_CALENDAR_BLANK "\xf3\xb0\x83\xae" // U+F00EE
+#define ICON_MDI_CALENDAR_BLANK_MULTIPLE "\xf3\xb1\x81\xb3" // U+F1073
+#define ICON_MDI_CALENDAR_BLANK_OUTLINE "\xf3\xb0\xad\xa6" // U+F0B66
+#define ICON_MDI_CALENDAR_CHECK "\xf3\xb0\x83\xaf" // U+F00EF
+#define ICON_MDI_CALENDAR_CHECK_OUTLINE "\xf3\xb0\xb1\x84" // U+F0C44
+#define ICON_MDI_CALENDAR_CLOCK "\xf3\xb0\x83\xb0" // U+F00F0
+#define ICON_MDI_CALENDAR_CLOCK_OUTLINE "\xf3\xb1\x9b\xa1" // U+F16E1
+#define ICON_MDI_CALENDAR_COLLAPSE_HORIZONTAL "\xf3\xb1\xa2\x9d" // U+F189D
+#define ICON_MDI_CALENDAR_COLLAPSE_HORIZONTAL_OUTLINE "\xf3\xb1\xad\xa3" // U+F1B63
+#define ICON_MDI_CALENDAR_CURSOR "\xf3\xb1\x95\xbb" // U+F157B
+#define ICON_MDI_CALENDAR_CURSOR_OUTLINE "\xf3\xb1\xad\xa4" // U+F1B64
+#define ICON_MDI_CALENDAR_EDIT "\xf3\xb0\xa2\xa7" // U+F08A7
+#define ICON_MDI_CALENDAR_EDIT_OUTLINE "\xf3\xb1\xad\xa5" // U+F1B65
+#define ICON_MDI_CALENDAR_END "\xf3\xb1\x99\xac" // U+F166C
+#define ICON_MDI_CALENDAR_END_OUTLINE "\xf3\xb1\xad\xa6" // U+F1B66
+#define ICON_MDI_CALENDAR_EXPAND_HORIZONTAL "\xf3\xb1\xa2\x9e" // U+F189E
+#define ICON_MDI_CALENDAR_EXPAND_HORIZONTAL_OUTLINE "\xf3\xb1\xad\xa7" // U+F1B67
+#define ICON_MDI_CALENDAR_EXPORT "\xf3\xb0\xac\xa4" // U+F0B24
+#define ICON_MDI_CALENDAR_EXPORT_OUTLINE "\xf3\xb1\xad\xa8" // U+F1B68
+#define ICON_MDI_CALENDAR_FILTER "\xf3\xb1\xa8\xb2" // U+F1A32
+#define ICON_MDI_CALENDAR_FILTER_OUTLINE "\xf3\xb1\xa8\xb3" // U+F1A33
+#define ICON_MDI_CALENDAR_HEART "\xf3\xb0\xa7\x92" // U+F09D2
+#define ICON_MDI_CALENDAR_HEART_OUTLINE "\xf3\xb1\xad\xa9" // U+F1B69
+#define ICON_MDI_CALENDAR_IMPORT "\xf3\xb0\xac\xa5" // U+F0B25
+#define ICON_MDI_CALENDAR_IMPORT_OUTLINE "\xf3\xb1\xad\xaa" // U+F1B6A
+#define ICON_MDI_CALENDAR_LOCK "\xf3\xb1\x99\x81" // U+F1641
+#define ICON_MDI_CALENDAR_LOCK_OPEN "\xf3\xb1\xad\x9b" // U+F1B5B
+#define ICON_MDI_CALENDAR_LOCK_OPEN_OUTLINE "\xf3\xb1\xad\x9c" // U+F1B5C
+#define ICON_MDI_CALENDAR_LOCK_OUTLINE "\xf3\xb1\x99\x82" // U+F1642
+#define ICON_MDI_CALENDAR_MINUS "\xf3\xb0\xb5\x9c" // U+F0D5C
+#define ICON_MDI_CALENDAR_MINUS_OUTLINE "\xf3\xb1\xad\xab" // U+F1B6B
+#define ICON_MDI_CALENDAR_MONTH "\xf3\xb0\xb8\x97" // U+F0E17
+#define ICON_MDI_CALENDAR_MONTH_OUTLINE "\xf3\xb0\xb8\x98" // U+F0E18
+#define ICON_MDI_CALENDAR_MULTIPLE "\xf3\xb0\x83\xb1" // U+F00F1
+#define ICON_MDI_CALENDAR_MULTIPLE_CHECK "\xf3\xb0\x83\xb2" // U+F00F2
+#define ICON_MDI_CALENDAR_MULTISELECT "\xf3\xb0\xa8\xb2" // U+F0A32
+#define ICON_MDI_CALENDAR_MULTISELECT_OUTLINE "\xf3\xb1\xad\x95" // U+F1B55
+#define ICON_MDI_CALENDAR_OUTLINE "\xf3\xb0\xad\xa7" // U+F0B67
+#define ICON_MDI_CALENDAR_PLUS "\xf3\xb0\x83\xb3" // U+F00F3
+#define ICON_MDI_CALENDAR_PLUS_OUTLINE "\xf3\xb1\xad\xac" // U+F1B6C
+#define ICON_MDI_CALENDAR_QUESTION "\xf3\xb0\x9a\x92" // U+F0692
+#define ICON_MDI_CALENDAR_QUESTION_OUTLINE "\xf3\xb1\xad\xad" // U+F1B6D
+#define ICON_MDI_CALENDAR_RANGE "\xf3\xb0\x99\xb9" // U+F0679
+#define ICON_MDI_CALENDAR_RANGE_OUTLINE "\xf3\xb0\xad\xa8" // U+F0B68
+#define ICON_MDI_CALENDAR_REFRESH "\xf3\xb0\x87\xa1" // U+F01E1
+#define ICON_MDI_CALENDAR_REFRESH_OUTLINE "\xf3\xb0\x88\x83" // U+F0203
+#define ICON_MDI_CALENDAR_REMOVE "\xf3\xb0\x83\xb4" // U+F00F4
+#define ICON_MDI_CALENDAR_REMOVE_OUTLINE "\xf3\xb0\xb1\x85" // U+F0C45
+#define ICON_MDI_CALENDAR_SEARCH "\xf3\xb0\xa5\x8c" // U+F094C
+#define ICON_MDI_CALENDAR_SEARCH_OUTLINE "\xf3\xb1\xad\xae" // U+F1B6E
+#define ICON_MDI_CALENDAR_STAR "\xf3\xb0\xa7\x93" // U+F09D3
+#define ICON_MDI_CALENDAR_STAR_FOUR_POINTS "\xf3\xb1\xb0\x9f" // U+F1C1F
+#define ICON_MDI_CALENDAR_STAR_OUTLINE "\xf3\xb1\xad\x93" // U+F1B53
+#define ICON_MDI_CALENDAR_START "\xf3\xb1\x99\xad" // U+F166D
+#define ICON_MDI_CALENDAR_START_OUTLINE "\xf3\xb1\xad\xaf" // U+F1B6F
+#define ICON_MDI_CALENDAR_SYNC "\xf3\xb0\xba\x8e" // U+F0E8E
+#define ICON_MDI_CALENDAR_SYNC_OUTLINE "\xf3\xb0\xba\x8f" // U+F0E8F
+#define ICON_MDI_CALENDAR_TEXT "\xf3\xb0\x83\xb5" // U+F00F5
+#define ICON_MDI_CALENDAR_TEXT_OUTLINE "\xf3\xb0\xb1\x86" // U+F0C46
+#define ICON_MDI_CALENDAR_TODAY "\xf3\xb0\x83\xb6" // U+F00F6
+#define ICON_MDI_CALENDAR_TODAY_OUTLINE "\xf3\xb1\xa8\xb0" // U+F1A30
+#define ICON_MDI_CALENDAR_WEEK "\xf3\xb0\xa8\xb3" // U+F0A33
+#define ICON_MDI_CALENDAR_WEEK_BEGIN "\xf3\xb0\xa8\xb4" // U+F0A34
+#define ICON_MDI_CALENDAR_WEEK_BEGIN_OUTLINE "\xf3\xb1\xa8\xb1" // U+F1A31
+#define ICON_MDI_CALENDAR_WEEK_OUTLINE "\xf3\xb1\xa8\xb4" // U+F1A34
+#define ICON_MDI_CALENDAR_WEEKEND "\xf3\xb0\xbb\x99" // U+F0ED9
+#define ICON_MDI_CALENDAR_WEEKEND_OUTLINE "\xf3\xb0\xbb\x9a" // U+F0EDA
+#define ICON_MDI_CALL_MADE "\xf3\xb0\x83\xb7" // U+F00F7
+#define ICON_MDI_CALL_MERGE "\xf3\xb0\x83\xb8" // U+F00F8
+#define ICON_MDI_CALL_MISSED "\xf3\xb0\x83\xb9" // U+F00F9
+#define ICON_MDI_CALL_RECEIVED "\xf3\xb0\x83\xba" // U+F00FA
+#define ICON_MDI_CALL_SPLIT "\xf3\xb0\x83\xbb" // U+F00FB
+#define ICON_MDI_CAMCORDER "\xf3\xb0\x83\xbc" // U+F00FC
+#define ICON_MDI_CAMCORDER_OFF "\xf3\xb0\x83\xbf" // U+F00FF
+#define ICON_MDI_CAMERA "\xf3\xb0\x84\x80" // U+F0100
+#define ICON_MDI_CAMERA_ACCOUNT "\xf3\xb0\xa3\x8b" // U+F08CB
+#define ICON_MDI_CAMERA_BURST "\xf3\xb0\x9a\x93" // U+F0693
+#define ICON_MDI_CAMERA_CONTROL "\xf3\xb0\xad\xa9" // U+F0B69
+#define ICON_MDI_CAMERA_DOCUMENT "\xf3\xb1\xa1\xb1" // U+F1871
+#define ICON_MDI_CAMERA_DOCUMENT_OFF "\xf3\xb1\xa1\xb2" // U+F1872
+#define ICON_MDI_CAMERA_ENHANCE "\xf3\xb0\x84\x81" // U+F0101
+#define ICON_MDI_CAMERA_ENHANCE_OUTLINE "\xf3\xb0\xad\xaa" // U+F0B6A
+#define ICON_MDI_CAMERA_FLIP "\xf3\xb1\x97\x99" // U+F15D9
+#define ICON_MDI_CAMERA_FLIP_OUTLINE "\xf3\xb1\x97\x9a" // U+F15DA
+#define ICON_MDI_CAMERA_FRONT "\xf3\xb0\x84\x82" // U+F0102
+#define ICON_MDI_CAMERA_FRONT_VARIANT "\xf3\xb0\x84\x83" // U+F0103
+#define ICON_MDI_CAMERA_GOPRO "\xf3\xb0\x9e\xa1" // U+F07A1
+#define ICON_MDI_CAMERA_IMAGE "\xf3\xb0\xa3\x8c" // U+F08CC
+#define ICON_MDI_CAMERA_IRIS "\xf3\xb0\x84\x84" // U+F0104
+#define ICON_MDI_CAMERA_LOCK "\xf3\xb1\xa8\x94" // U+F1A14
+#define ICON_MDI_CAMERA_LOCK_OPEN "\xf3\xb1\xb0\x8d" // U+F1C0D
+#define ICON_MDI_CAMERA_LOCK_OPEN_OUTLINE "\xf3\xb1\xb0\x8e" // U+F1C0E
+#define ICON_MDI_CAMERA_LOCK_OUTLINE "\xf3\xb1\xa8\x95" // U+F1A15
+#define ICON_MDI_CAMERA_MARKER "\xf3\xb1\xa6\xa7" // U+F19A7
+#define ICON_MDI_CAMERA_MARKER_OUTLINE "\xf3\xb1\xa6\xa8" // U+F19A8
+#define ICON_MDI_CAMERA_METERING_CENTER "\xf3\xb0\x9e\xa2" // U+F07A2
+#define ICON_MDI_CAMERA_METERING_MATRIX "\xf3\xb0\x9e\xa3" // U+F07A3
+#define ICON_MDI_CAMERA_METERING_PARTIAL "\xf3\xb0\x9e\xa4" // U+F07A4
+#define ICON_MDI_CAMERA_METERING_SPOT "\xf3\xb0\x9e\xa5" // U+F07A5
+#define ICON_MDI_CAMERA_OFF "\xf3\xb0\x97\x9f" // U+F05DF
+#define ICON_MDI_CAMERA_OFF_OUTLINE "\xf3\xb1\xa6\xbf" // U+F19BF
+#define ICON_MDI_CAMERA_OUTLINE "\xf3\xb0\xb5\x9d" // U+F0D5D
+#define ICON_MDI_CAMERA_PARTY_MODE "\xf3\xb0\x84\x85" // U+F0105
+#define ICON_MDI_CAMERA_PLUS "\xf3\xb0\xbb\x9b" // U+F0EDB
+#define ICON_MDI_CAMERA_PLUS_OUTLINE "\xf3\xb0\xbb\x9c" // U+F0EDC
+#define ICON_MDI_CAMERA_REAR "\xf3\xb0\x84\x86" // U+F0106
+#define ICON_MDI_CAMERA_REAR_VARIANT "\xf3\xb0\x84\x87" // U+F0107
+#define ICON_MDI_CAMERA_RETAKE "\xf3\xb0\xb8\x99" // U+F0E19
+#define ICON_MDI_CAMERA_RETAKE_OUTLINE "\xf3\xb0\xb8\x9a" // U+F0E1A
+#define ICON_MDI_CAMERA_SWITCH "\xf3\xb0\x84\x88" // U+F0108
+#define ICON_MDI_CAMERA_SWITCH_OUTLINE "\xf3\xb0\xa1\x8a" // U+F084A
+#define ICON_MDI_CAMERA_TIMER "\xf3\xb0\x84\x89" // U+F0109
+#define ICON_MDI_CAMERA_WIRELESS "\xf3\xb0\xb6\xb6" // U+F0DB6
+#define ICON_MDI_CAMERA_WIRELESS_OUTLINE "\xf3\xb0\xb6\xb7" // U+F0DB7
+#define ICON_MDI_CAMPFIRE "\xf3\xb0\xbb\x9d" // U+F0EDD
+#define ICON_MDI_CANCEL "\xf3\xb0\x9c\xba" // U+F073A
+#define ICON_MDI_CANDELABRA "\xf3\xb1\x9f\x92" // U+F17D2
+#define ICON_MDI_CANDELABRA_FIRE "\xf3\xb1\x9f\x93" // U+F17D3
+#define ICON_MDI_CANDLE "\xf3\xb0\x97\xa2" // U+F05E2
+#define ICON_MDI_CANDY "\xf3\xb1\xa5\xb0" // U+F1970
+#define ICON_MDI_CANDY_OFF "\xf3\xb1\xa5\xb1" // U+F1971
+#define ICON_MDI_CANDY_OFF_OUTLINE "\xf3\xb1\xa5\xb2" // U+F1972
+#define ICON_MDI_CANDY_OUTLINE "\xf3\xb1\xa5\xb3" // U+F1973
+#define ICON_MDI_CANDYCANE "\xf3\xb0\x84\x8a" // U+F010A
+#define ICON_MDI_CANNABIS "\xf3\xb0\x9e\xa6" // U+F07A6
+#define ICON_MDI_CANNABIS_OFF "\xf3\xb1\x99\xae" // U+F166E
+#define ICON_MDI_CAPS_LOCK "\xf3\xb0\xaa\x9b" // U+F0A9B
+#define ICON_MDI_CAR "\xf3\xb0\x84\x8b" // U+F010B
+#define ICON_MDI_CAR_2_PLUS "\xf3\xb1\x80\x95" // U+F1015
+#define ICON_MDI_CAR_3_PLUS "\xf3\xb1\x80\x96" // U+F1016
+#define ICON_MDI_CAR_ARROW_LEFT "\xf3\xb1\x8e\xb2" // U+F13B2
+#define ICON_MDI_CAR_ARROW_RIGHT "\xf3\xb1\x8e\xb3" // U+F13B3
+#define ICON_MDI_CAR_BACK "\xf3\xb0\xb8\x9b" // U+F0E1B
+#define ICON_MDI_CAR_BATTERY "\xf3\xb0\x84\x8c" // U+F010C
+#define ICON_MDI_CAR_BRAKE_ABS "\xf3\xb0\xb1\x87" // U+F0C47
+#define ICON_MDI_CAR_BRAKE_ALERT "\xf3\xb0\xb1\x88" // U+F0C48
+#define ICON_MDI_CAR_BRAKE_FLUID_LEVEL "\xf3\xb1\xa4\x89" // U+F1909
+#define ICON_MDI_CAR_BRAKE_HOLD "\xf3\xb0\xb5\x9e" // U+F0D5E
+#define ICON_MDI_CAR_BRAKE_LOW_PRESSURE "\xf3\xb1\xa4\x8a" // U+F190A
+#define ICON_MDI_CAR_BRAKE_PARKING "\xf3\xb0\xb5\x9f" // U+F0D5F
+#define ICON_MDI_CAR_BRAKE_RETARDER "\xf3\xb1\x80\x97" // U+F1017
+#define ICON_MDI_CAR_BRAKE_TEMPERATURE "\xf3\xb1\xa4\x8b" // U+F190B
+#define ICON_MDI_CAR_BRAKE_WORN_LININGS "\xf3\xb1\xa4\x8c" // U+F190C
+#define ICON_MDI_CAR_CHILD_SEAT "\xf3\xb0\xbe\xa3" // U+F0FA3
+#define ICON_MDI_CAR_CLOCK "\xf3\xb1\xa5\xb4" // U+F1974
+#define ICON_MDI_CAR_CLUTCH "\xf3\xb1\x80\x98" // U+F1018
+#define ICON_MDI_CAR_COG "\xf3\xb1\x8f\x8c" // U+F13CC
+#define ICON_MDI_CAR_CONNECTED "\xf3\xb0\x84\x8d" // U+F010D
+#define ICON_MDI_CAR_CONVERTIBLE "\xf3\xb0\x9e\xa7" // U+F07A7
+#define ICON_MDI_CAR_COOLANT_LEVEL "\xf3\xb1\x80\x99" // U+F1019
+#define ICON_MDI_CAR_CRUISE_CONTROL "\xf3\xb0\xb5\xa0" // U+F0D60
+#define ICON_MDI_CAR_DEFROST_FRONT "\xf3\xb0\xb5\xa1" // U+F0D61
+#define ICON_MDI_CAR_DEFROST_REAR "\xf3\xb0\xb5\xa2" // U+F0D62
+#define ICON_MDI_CAR_DOOR "\xf3\xb0\xad\xab" // U+F0B6B
+#define ICON_MDI_CAR_DOOR_LOCK "\xf3\xb1\x82\x9d" // U+F109D
+#define ICON_MDI_CAR_DOOR_LOCK_OPEN "\xf3\xb1\xb2\x81" // U+F1C81
+#define ICON_MDI_CAR_ELECTRIC "\xf3\xb0\xad\xac" // U+F0B6C
+#define ICON_MDI_CAR_ELECTRIC_OUTLINE "\xf3\xb1\x96\xb5" // U+F15B5
+#define ICON_MDI_CAR_EMERGENCY "\xf3\xb1\x98\x8f" // U+F160F
+#define ICON_MDI_CAR_ESP "\xf3\xb0\xb1\x89" // U+F0C49
+#define ICON_MDI_CAR_ESTATE "\xf3\xb0\x9e\xa8" // U+F07A8
+#define ICON_MDI_CAR_HATCHBACK "\xf3\xb0\x9e\xa9" // U+F07A9
+#define ICON_MDI_CAR_INFO "\xf3\xb1\x86\xbe" // U+F11BE
+#define ICON_MDI_CAR_KEY "\xf3\xb0\xad\xad" // U+F0B6D
+#define ICON_MDI_CAR_LIFTED_PICKUP "\xf3\xb1\x94\xad" // U+F152D
+#define ICON_MDI_CAR_LIGHT_ALERT "\xf3\xb1\xa4\x8d" // U+F190D
+#define ICON_MDI_CAR_LIGHT_DIMMED "\xf3\xb0\xb1\x8a" // U+F0C4A
+#define ICON_MDI_CAR_LIGHT_FOG "\xf3\xb0\xb1\x8b" // U+F0C4B
+#define ICON_MDI_CAR_LIGHT_HIGH "\xf3\xb0\xb1\x8c" // U+F0C4C
+#define ICON_MDI_CAR_LIMOUSINE "\xf3\xb0\xa3\x8d" // U+F08CD
+#define ICON_MDI_CAR_MULTIPLE "\xf3\xb0\xad\xae" // U+F0B6E
+#define ICON_MDI_CAR_OFF "\xf3\xb0\xb8\x9c" // U+F0E1C
+#define ICON_MDI_CAR_OUTLINE "\xf3\xb1\x93\xad" // U+F14ED
+#define ICON_MDI_CAR_PARKING_LIGHTS "\xf3\xb0\xb5\xa3" // U+F0D63
+#define ICON_MDI_CAR_PICKUP "\xf3\xb0\x9e\xaa" // U+F07AA
+#define ICON_MDI_CAR_SEARCH "\xf3\xb1\xae\x8d" // U+F1B8D
+#define ICON_MDI_CAR_SEARCH_OUTLINE "\xf3\xb1\xae\x8e" // U+F1B8E
+#define ICON_MDI_CAR_SEAT "\xf3\xb0\xbe\xa4" // U+F0FA4
+#define ICON_MDI_CAR_SEAT_COOLER "\xf3\xb0\xbe\xa5" // U+F0FA5
+#define ICON_MDI_CAR_SEAT_HEATER "\xf3\xb0\xbe\xa6" // U+F0FA6
+#define ICON_MDI_CAR_SELECT "\xf3\xb1\xa1\xb9" // U+F1879
+#define ICON_MDI_CAR_SETTINGS "\xf3\xb1\x8f\x8d" // U+F13CD
+#define ICON_MDI_CAR_SHIFT_PATTERN "\xf3\xb0\xbd\x80" // U+F0F40
+#define ICON_MDI_CAR_SIDE "\xf3\xb0\x9e\xab" // U+F07AB
+#define ICON_MDI_CAR_SPEED_LIMITER "\xf3\xb1\xa4\x8e" // U+F190E
+#define ICON_MDI_CAR_SPORTS "\xf3\xb0\x9e\xac" // U+F07AC
+#define ICON_MDI_CAR_TIRE_ALERT "\xf3\xb0\xb1\x8d" // U+F0C4D
+#define ICON_MDI_CAR_TRACTION_CONTROL "\xf3\xb0\xb5\xa4" // U+F0D64
+#define ICON_MDI_CAR_TURBOCHARGER "\xf3\xb1\x80\x9a" // U+F101A
+#define ICON_MDI_CAR_WASH "\xf3\xb0\x84\x8e" // U+F010E
+#define ICON_MDI_CAR_WINDSHIELD "\xf3\xb1\x80\x9b" // U+F101B
+#define ICON_MDI_CAR_WINDSHIELD_OUTLINE "\xf3\xb1\x80\x9c" // U+F101C
+#define ICON_MDI_CAR_WIRELESS "\xf3\xb1\xa1\xb8" // U+F1878
+#define ICON_MDI_CAR_WRENCH "\xf3\xb1\xa0\x94" // U+F1814
+#define ICON_MDI_CARABINER "\xf3\xb1\x93\x80" // U+F14C0
+#define ICON_MDI_CARAVAN "\xf3\xb0\x9e\xad" // U+F07AD
+#define ICON_MDI_CARD "\xf3\xb0\xad\xaf" // U+F0B6F
+#define ICON_MDI_CARD_ACCOUNT_DETAILS "\xf3\xb0\x97\x92" // U+F05D2
+#define ICON_MDI_CARD_ACCOUNT_DETAILS_OUTLINE "\xf3\xb0\xb6\xab" // U+F0DAB
+#define ICON_MDI_CARD_ACCOUNT_DETAILS_STAR "\xf3\xb0\x8a\xa3" // U+F02A3
+#define ICON_MDI_CARD_ACCOUNT_DETAILS_STAR_OUTLINE "\xf3\xb0\x9b\x9b" // U+F06DB
+#define ICON_MDI_CARD_ACCOUNT_MAIL "\xf3\xb0\x86\x8e" // U+F018E
+#define ICON_MDI_CARD_ACCOUNT_MAIL_OUTLINE "\xf3\xb0\xba\x98" // U+F0E98
+#define ICON_MDI_CARD_ACCOUNT_PHONE "\xf3\xb0\xba\x99" // U+F0E99
+#define ICON_MDI_CARD_ACCOUNT_PHONE_OUTLINE "\xf3\xb0\xba\x9a" // U+F0E9A
+#define ICON_MDI_CARD_BULLETED "\xf3\xb0\xad\xb0" // U+F0B70
+#define ICON_MDI_CARD_BULLETED_OFF "\xf3\xb0\xad\xb1" // U+F0B71
+#define ICON_MDI_CARD_BULLETED_OFF_OUTLINE "\xf3\xb0\xad\xb2" // U+F0B72
+#define ICON_MDI_CARD_BULLETED_OUTLINE "\xf3\xb0\xad\xb3" // U+F0B73
+#define ICON_MDI_CARD_BULLETED_SETTINGS "\xf3\xb0\xad\xb4" // U+F0B74
+#define ICON_MDI_CARD_BULLETED_SETTINGS_OUTLINE "\xf3\xb0\xad\xb5" // U+F0B75
+#define ICON_MDI_CARD_MINUS "\xf3\xb1\x98\x80" // U+F1600
+#define ICON_MDI_CARD_MINUS_OUTLINE "\xf3\xb1\x98\x81" // U+F1601
+#define ICON_MDI_CARD_MULTIPLE "\xf3\xb1\x9f\xb1" // U+F17F1
+#define ICON_MDI_CARD_MULTIPLE_OUTLINE "\xf3\xb1\x9f\xb2" // U+F17F2
+#define ICON_MDI_CARD_OFF "\xf3\xb1\x98\x82" // U+F1602
+#define ICON_MDI_CARD_OFF_OUTLINE "\xf3\xb1\x98\x83" // U+F1603
+#define ICON_MDI_CARD_OUTLINE "\xf3\xb0\xad\xb6" // U+F0B76
+#define ICON_MDI_CARD_PLUS "\xf3\xb1\x87\xbf" // U+F11FF
+#define ICON_MDI_CARD_PLUS_OUTLINE "\xf3\xb1\x88\x80" // U+F1200
+#define ICON_MDI_CARD_REMOVE "\xf3\xb1\x98\x84" // U+F1604
+#define ICON_MDI_CARD_REMOVE_OUTLINE "\xf3\xb1\x98\x85" // U+F1605
+#define ICON_MDI_CARD_SEARCH "\xf3\xb1\x81\xb4" // U+F1074
+#define ICON_MDI_CARD_SEARCH_OUTLINE "\xf3\xb1\x81\xb5" // U+F1075
+#define ICON_MDI_CARD_TEXT "\xf3\xb0\xad\xb7" // U+F0B77
+#define ICON_MDI_CARD_TEXT_OUTLINE "\xf3\xb0\xad\xb8" // U+F0B78
+#define ICON_MDI_CARDS "\xf3\xb0\x98\xb8" // U+F0638
+#define ICON_MDI_CARDS_CLUB "\xf3\xb0\xa3\x8e" // U+F08CE
+#define ICON_MDI_CARDS_CLUB_OUTLINE "\xf3\xb1\xa2\x9f" // U+F189F
+#define ICON_MDI_CARDS_DIAMOND "\xf3\xb0\xa3\x8f" // U+F08CF
+#define ICON_MDI_CARDS_DIAMOND_OUTLINE "\xf3\xb1\x80\x9d" // U+F101D
+#define ICON_MDI_CARDS_HEART "\xf3\xb0\xa3\x90" // U+F08D0
+#define ICON_MDI_CARDS_HEART_OUTLINE "\xf3\xb1\xa2\xa0" // U+F18A0
+#define ICON_MDI_CARDS_OUTLINE "\xf3\xb0\x98\xb9" // U+F0639
+#define ICON_MDI_CARDS_PLAYING "\xf3\xb1\xa2\xa1" // U+F18A1
+#define ICON_MDI_CARDS_PLAYING_CLUB "\xf3\xb1\xa2\xa2" // U+F18A2
+#define ICON_MDI_CARDS_PLAYING_CLUB_MULTIPLE "\xf3\xb1\xa2\xa3" // U+F18A3
+#define ICON_MDI_CARDS_PLAYING_CLUB_MULTIPLE_OUTLINE "\xf3\xb1\xa2\xa4" // U+F18A4
+#define ICON_MDI_CARDS_PLAYING_CLUB_OUTLINE "\xf3\xb1\xa2\xa5" // U+F18A5
+#define ICON_MDI_CARDS_PLAYING_DIAMOND "\xf3\xb1\xa2\xa6" // U+F18A6
+#define ICON_MDI_CARDS_PLAYING_DIAMOND_MULTIPLE "\xf3\xb1\xa2\xa7" // U+F18A7
+#define ICON_MDI_CARDS_PLAYING_DIAMOND_MULTIPLE_OUTLINE "\xf3\xb1\xa2\xa8" // U+F18A8
+#define ICON_MDI_CARDS_PLAYING_DIAMOND_OUTLINE "\xf3\xb1\xa2\xa9" // U+F18A9
+#define ICON_MDI_CARDS_PLAYING_HEART "\xf3\xb1\xa2\xaa" // U+F18AA
+#define ICON_MDI_CARDS_PLAYING_HEART_MULTIPLE "\xf3\xb1\xa2\xab" // U+F18AB
+#define ICON_MDI_CARDS_PLAYING_HEART_MULTIPLE_OUTLINE "\xf3\xb1\xa2\xac" // U+F18AC
+#define ICON_MDI_CARDS_PLAYING_HEART_OUTLINE "\xf3\xb1\xa2\xad" // U+F18AD
+#define ICON_MDI_CARDS_PLAYING_OUTLINE "\xf3\xb0\x98\xba" // U+F063A
+#define ICON_MDI_CARDS_PLAYING_SPADE "\xf3\xb1\xa2\xae" // U+F18AE
+#define ICON_MDI_CARDS_PLAYING_SPADE_MULTIPLE "\xf3\xb1\xa2\xaf" // U+F18AF
+#define ICON_MDI_CARDS_PLAYING_SPADE_MULTIPLE_OUTLINE "\xf3\xb1\xa2\xb0" // U+F18B0
+#define ICON_MDI_CARDS_PLAYING_SPADE_OUTLINE "\xf3\xb1\xa2\xb1" // U+F18B1
+#define ICON_MDI_CARDS_SPADE "\xf3\xb0\xa3\x91" // U+F08D1
+#define ICON_MDI_CARDS_SPADE_OUTLINE "\xf3\xb1\xa2\xb2" // U+F18B2
+#define ICON_MDI_CARDS_VARIANT "\xf3\xb0\x9b\x87" // U+F06C7
+#define ICON_MDI_CARROT "\xf3\xb0\x84\x8f" // U+F010F
+#define ICON_MDI_CART "\xf3\xb0\x84\x90" // U+F0110
+#define ICON_MDI_CART_ARROW_DOWN "\xf3\xb0\xb5\xa6" // U+F0D66
+#define ICON_MDI_CART_ARROW_RIGHT "\xf3\xb0\xb1\x8e" // U+F0C4E
+#define ICON_MDI_CART_ARROW_UP "\xf3\xb0\xb5\xa7" // U+F0D67
+#define ICON_MDI_CART_CHECK "\xf3\xb1\x97\xaa" // U+F15EA
+#define ICON_MDI_CART_HEART "\xf3\xb1\xa3\xa0" // U+F18E0
+#define ICON_MDI_CART_MINUS "\xf3\xb0\xb5\xa8" // U+F0D68
+#define ICON_MDI_CART_OFF "\xf3\xb0\x99\xab" // U+F066B
+#define ICON_MDI_CART_OUTLINE "\xf3\xb0\x84\x91" // U+F0111
+#define ICON_MDI_CART_PERCENT "\xf3\xb1\xae\xae" // U+F1BAE
+#define ICON_MDI_CART_PLUS "\xf3\xb0\x84\x92" // U+F0112
+#define ICON_MDI_CART_REMOVE "\xf3\xb0\xb5\xa9" // U+F0D69
+#define ICON_MDI_CART_VARIANT "\xf3\xb1\x97\xab" // U+F15EB
+#define ICON_MDI_CASE_SENSITIVE_ALT "\xf3\xb0\x84\x93" // U+F0113
+#define ICON_MDI_CASH "\xf3\xb0\x84\x94" // U+F0114
+#define ICON_MDI_CASH_100 "\xf3\xb0\x84\x95" // U+F0115
+#define ICON_MDI_CASH_CHECK "\xf3\xb1\x93\xae" // U+F14EE
+#define ICON_MDI_CASH_CLOCK "\xf3\xb1\xaa\x91" // U+F1A91
+#define ICON_MDI_CASH_EDIT "\xf3\xb1\xb2\xab" // U+F1CAB
+#define ICON_MDI_CASH_FAST "\xf3\xb1\xa1\x9c" // U+F185C
+#define ICON_MDI_CASH_LOCK "\xf3\xb1\x93\xaa" // U+F14EA
+#define ICON_MDI_CASH_LOCK_OPEN "\xf3\xb1\x93\xab" // U+F14EB
+#define ICON_MDI_CASH_MARKER "\xf3\xb0\xb6\xb8" // U+F0DB8
+#define ICON_MDI_CASH_MINUS "\xf3\xb1\x89\xa0" // U+F1260
+#define ICON_MDI_CASH_MULTIPLE "\xf3\xb0\x84\x96" // U+F0116
+#define ICON_MDI_CASH_OFF "\xf3\xb1\xb1\xb9" // U+F1C79
+#define ICON_MDI_CASH_PLUS "\xf3\xb1\x89\xa1" // U+F1261
+#define ICON_MDI_CASH_REFUND "\xf3\xb0\xaa\x9c" // U+F0A9C
+#define ICON_MDI_CASH_REGISTER "\xf3\xb0\xb3\xb4" // U+F0CF4
+#define ICON_MDI_CASH_REMOVE "\xf3\xb1\x89\xa2" // U+F1262
+#define ICON_MDI_CASH_SYNC "\xf3\xb1\xaa\x92" // U+F1A92
+#define ICON_MDI_CASSETTE "\xf3\xb0\xa7\x94" // U+F09D4
+#define ICON_MDI_CAST "\xf3\xb0\x84\x98" // U+F0118
+#define ICON_MDI_CAST_AUDIO "\xf3\xb1\x80\x9e" // U+F101E
+#define ICON_MDI_CAST_AUDIO_VARIANT "\xf3\xb1\x9d\x89" // U+F1749
+#define ICON_MDI_CAST_CONNECTED "\xf3\xb0\x84\x99" // U+F0119
+#define ICON_MDI_CAST_EDUCATION "\xf3\xb0\xb8\x9d" // U+F0E1D
+#define ICON_MDI_CAST_OFF "\xf3\xb0\x9e\x8a" // U+F078A
+#define ICON_MDI_CAST_VARIANT "\xf3\xb0\x80\x9f" // U+F001F
+#define ICON_MDI_CASTLE "\xf3\xb0\x84\x9a" // U+F011A
+#define ICON_MDI_CAT "\xf3\xb0\x84\x9b" // U+F011B
+#define ICON_MDI_CCTV "\xf3\xb0\x9e\xae" // U+F07AE
+#define ICON_MDI_CCTV_OFF "\xf3\xb1\xa1\x9f" // U+F185F
+#define ICON_MDI_CEILING_FAN "\xf3\xb1\x9e\x97" // U+F1797
+#define ICON_MDI_CEILING_FAN_LIGHT "\xf3\xb1\x9e\x98" // U+F1798
+#define ICON_MDI_CEILING_LIGHT "\xf3\xb0\x9d\xa9" // U+F0769
+#define ICON_MDI_CEILING_LIGHT_MULTIPLE "\xf3\xb1\xa3\x9d" // U+F18DD
+#define ICON_MDI_CEILING_LIGHT_MULTIPLE_OUTLINE "\xf3\xb1\xa3\x9e" // U+F18DE
+#define ICON_MDI_CEILING_LIGHT_OUTLINE "\xf3\xb1\x9f\x87" // U+F17C7
+#define ICON_MDI_CELLPHONE "\xf3\xb0\x84\x9c" // U+F011C
+#define ICON_MDI_CELLPHONE_ARROW_DOWN "\xf3\xb0\xa7\x95" // U+F09D5
+#define ICON_MDI_CELLPHONE_ARROW_DOWN_VARIANT "\xf3\xb1\xa7\x85" // U+F19C5
+#define ICON_MDI_CELLPHONE_BASIC "\xf3\xb0\x84\x9e" // U+F011E
+#define ICON_MDI_CELLPHONE_CHARGING "\xf3\xb1\x8e\x97" // U+F1397
+#define ICON_MDI_CELLPHONE_CHECK "\xf3\xb1\x9f\xbd" // U+F17FD
+#define ICON_MDI_CELLPHONE_COG "\xf3\xb0\xa5\x91" // U+F0951
+#define ICON_MDI_CELLPHONE_DOCK "\xf3\xb0\x84\x9f" // U+F011F
+#define ICON_MDI_CELLPHONE_INFORMATION "\xf3\xb0\xbd\x81" // U+F0F41
+#define ICON_MDI_CELLPHONE_KEY "\xf3\xb0\xa5\x8e" // U+F094E
+#define ICON_MDI_CELLPHONE_LINK "\xf3\xb0\x84\xa1" // U+F0121
+#define ICON_MDI_CELLPHONE_LINK_OFF "\xf3\xb0\x84\xa2" // U+F0122
+#define ICON_MDI_CELLPHONE_LOCK "\xf3\xb0\xa5\x8f" // U+F094F
+#define ICON_MDI_CELLPHONE_MARKER "\xf3\xb1\xa0\xba" // U+F183A
+#define ICON_MDI_CELLPHONE_MESSAGE "\xf3\xb0\xa3\x93" // U+F08D3
+#define ICON_MDI_CELLPHONE_MESSAGE_OFF "\xf3\xb1\x83\x92" // U+F10D2
+#define ICON_MDI_CELLPHONE_NFC "\xf3\xb0\xba\x90" // U+F0E90
+#define ICON_MDI_CELLPHONE_NFC_OFF "\xf3\xb1\x8b\x98" // U+F12D8
+#define ICON_MDI_CELLPHONE_OFF "\xf3\xb0\xa5\x90" // U+F0950
+#define ICON_MDI_CELLPHONE_PLAY "\xf3\xb1\x80\x9f" // U+F101F
+#define ICON_MDI_CELLPHONE_REMOVE "\xf3\xb0\xa5\x8d" // U+F094D
+#define ICON_MDI_CELLPHONE_SCREENSHOT "\xf3\xb0\xa8\xb5" // U+F0A35
+#define ICON_MDI_CELLPHONE_SETTINGS "\xf3\xb0\x84\xa3" // U+F0123
+#define ICON_MDI_CELLPHONE_SOUND "\xf3\xb0\xa5\x92" // U+F0952
+#define ICON_MDI_CELLPHONE_TEXT "\xf3\xb0\xa3\x92" // U+F08D2
+#define ICON_MDI_CELLPHONE_WIRELESS "\xf3\xb0\xa0\x95" // U+F0815
+#define ICON_MDI_CENTOS "\xf3\xb1\x84\x9a" // U+F111A
+#define ICON_MDI_CERTIFICATE "\xf3\xb0\x84\xa4" // U+F0124
+#define ICON_MDI_CERTIFICATE_OUTLINE "\xf3\xb1\x86\x88" // U+F1188
+#define ICON_MDI_CHAIR_ROLLING "\xf3\xb0\xbd\x88" // U+F0F48
+#define ICON_MDI_CHAIR_SCHOOL "\xf3\xb0\x84\xa5" // U+F0125
+#define ICON_MDI_CHANDELIER "\xf3\xb1\x9e\x93" // U+F1793
+#define ICON_MDI_CHARITY "\xf3\xb0\xb1\x8f" // U+F0C4F
+#define ICON_MDI_CHARITY_SEARCH "\xf3\xb1\xb2\x82" // U+F1C82
+#define ICON_MDI_CHART_ARC "\xf3\xb0\x84\xa6" // U+F0126
+#define ICON_MDI_CHART_AREASPLINE "\xf3\xb0\x84\xa7" // U+F0127
+#define ICON_MDI_CHART_AREASPLINE_VARIANT "\xf3\xb0\xba\x91" // U+F0E91
+#define ICON_MDI_CHART_BAR "\xf3\xb0\x84\xa8" // U+F0128
+#define ICON_MDI_CHART_BAR_STACKED "\xf3\xb0\x9d\xaa" // U+F076A
+#define ICON_MDI_CHART_BELL_CURVE "\xf3\xb0\xb1\x90" // U+F0C50
+#define ICON_MDI_CHART_BELL_CURVE_CUMULATIVE "\xf3\xb0\xbe\xa7" // U+F0FA7
+#define ICON_MDI_CHART_BOX "\xf3\xb1\x95\x8d" // U+F154D
+#define ICON_MDI_CHART_BOX_OUTLINE "\xf3\xb1\x95\x8e" // U+F154E
+#define ICON_MDI_CHART_BOX_PLUS_OUTLINE "\xf3\xb1\x95\x8f" // U+F154F
+#define ICON_MDI_CHART_BUBBLE "\xf3\xb0\x97\xa3" // U+F05E3
+#define ICON_MDI_CHART_DONUT "\xf3\xb0\x9e\xaf" // U+F07AF
+#define ICON_MDI_CHART_DONUT_VARIANT "\xf3\xb0\x9e\xb0" // U+F07B0
+#define ICON_MDI_CHART_GANTT "\xf3\xb0\x99\xac" // U+F066C
+#define ICON_MDI_CHART_HISTOGRAM "\xf3\xb0\x84\xa9" // U+F0129
+#define ICON_MDI_CHART_LINE "\xf3\xb0\x84\xaa" // U+F012A
+#define ICON_MDI_CHART_LINE_STACKED "\xf3\xb0\x9d\xab" // U+F076B
+#define ICON_MDI_CHART_LINE_VARIANT "\xf3\xb0\x9e\xb1" // U+F07B1
+#define ICON_MDI_CHART_MULTILINE "\xf3\xb0\xa3\x94" // U+F08D4
+#define ICON_MDI_CHART_MULTIPLE "\xf3\xb1\x88\x93" // U+F1213
+#define ICON_MDI_CHART_PIE "\xf3\xb0\x84\xab" // U+F012B
+#define ICON_MDI_CHART_PIE_OUTLINE "\xf3\xb1\xaf\x9f" // U+F1BDF
+#define ICON_MDI_CHART_PPF "\xf3\xb1\x8e\x80" // U+F1380
+#define ICON_MDI_CHART_SANKEY "\xf3\xb1\x87\x9f" // U+F11DF
+#define ICON_MDI_CHART_SANKEY_VARIANT "\xf3\xb1\x87\xa0" // U+F11E0
+#define ICON_MDI_CHART_SCATTER_PLOT "\xf3\xb0\xba\x92" // U+F0E92
+#define ICON_MDI_CHART_SCATTER_PLOT_HEXBIN "\xf3\xb0\x99\xad" // U+F066D
+#define ICON_MDI_CHART_TIMELINE "\xf3\xb0\x99\xae" // U+F066E
+#define ICON_MDI_CHART_TIMELINE_VARIANT "\xf3\xb0\xba\x93" // U+F0E93
+#define ICON_MDI_CHART_TIMELINE_VARIANT_SHIMMER "\xf3\xb1\x96\xb6" // U+F15B6
+#define ICON_MDI_CHART_TREE "\xf3\xb0\xba\x94" // U+F0E94
+#define ICON_MDI_CHART_WATERFALL "\xf3\xb1\xa4\x98" // U+F1918
+#define ICON_MDI_CHAT "\xf3\xb0\xad\xb9" // U+F0B79
+#define ICON_MDI_CHAT_ALERT "\xf3\xb0\xad\xba" // U+F0B7A
+#define ICON_MDI_CHAT_ALERT_OUTLINE "\xf3\xb1\x8b\x89" // U+F12C9
+#define ICON_MDI_CHAT_MINUS "\xf3\xb1\x90\x90" // U+F1410
+#define ICON_MDI_CHAT_MINUS_OUTLINE "\xf3\xb1\x90\x93" // U+F1413
+#define ICON_MDI_CHAT_OUTLINE "\xf3\xb0\xbb\x9e" // U+F0EDE
+#define ICON_MDI_CHAT_PLUS "\xf3\xb1\x90\x8f" // U+F140F
+#define ICON_MDI_CHAT_PLUS_OUTLINE "\xf3\xb1\x90\x92" // U+F1412
+#define ICON_MDI_CHAT_PROCESSING "\xf3\xb0\xad\xbb" // U+F0B7B
+#define ICON_MDI_CHAT_PROCESSING_OUTLINE "\xf3\xb1\x8b\x8a" // U+F12CA
+#define ICON_MDI_CHAT_QUESTION "\xf3\xb1\x9c\xb8" // U+F1738
+#define ICON_MDI_CHAT_QUESTION_OUTLINE "\xf3\xb1\x9c\xb9" // U+F1739
+#define ICON_MDI_CHAT_REMOVE "\xf3\xb1\x90\x91" // U+F1411
+#define ICON_MDI_CHAT_REMOVE_OUTLINE "\xf3\xb1\x90\x94" // U+F1414
+#define ICON_MDI_CHAT_SLEEP "\xf3\xb1\x8b\x91" // U+F12D1
+#define ICON_MDI_CHAT_SLEEP_OUTLINE "\xf3\xb1\x8b\x92" // U+F12D2
+#define ICON_MDI_CHECK "\xf3\xb0\x84\xac" // U+F012C
+#define ICON_MDI_CHECK_ALL "\xf3\xb0\x84\xad" // U+F012D
+#define ICON_MDI_CHECK_BOLD "\xf3\xb0\xb8\x9e" // U+F0E1E
+#define ICON_MDI_CHECK_CIRCLE "\xf3\xb0\x97\xa0" // U+F05E0
+#define ICON_MDI_CHECK_CIRCLE_OUTLINE "\xf3\xb0\x97\xa1" // U+F05E1
+#define ICON_MDI_CHECK_DECAGRAM "\xf3\xb0\x9e\x91" // U+F0791
+#define ICON_MDI_CHECK_DECAGRAM_OUTLINE "\xf3\xb1\x9d\x80" // U+F1740
+#define ICON_MDI_CHECK_NETWORK "\xf3\xb0\xb1\x93" // U+F0C53
+#define ICON_MDI_CHECK_NETWORK_OUTLINE "\xf3\xb0\xb1\x94" // U+F0C54
+#define ICON_MDI_CHECK_OUTLINE "\xf3\xb0\xa1\x95" // U+F0855
+#define ICON_MDI_CHECK_UNDERLINE "\xf3\xb0\xb8\x9f" // U+F0E1F
+#define ICON_MDI_CHECK_UNDERLINE_CIRCLE "\xf3\xb0\xb8\xa0" // U+F0E20
+#define ICON_MDI_CHECK_UNDERLINE_CIRCLE_OUTLINE "\xf3\xb0\xb8\xa1" // U+F0E21
+#define ICON_MDI_CHECKBOOK "\xf3\xb0\xaa\x9d" // U+F0A9D
+#define ICON_MDI_CHECKBOOK_ARROW_LEFT "\xf3\xb1\xb0\x9d" // U+F1C1D
+#define ICON_MDI_CHECKBOOK_ARROW_RIGHT "\xf3\xb1\xb0\x9e" // U+F1C1E
+#define ICON_MDI_CHECKBOX_BLANK "\xf3\xb0\x84\xae" // U+F012E
+#define ICON_MDI_CHECKBOX_BLANK_BADGE "\xf3\xb1\x85\xb6" // U+F1176
+#define ICON_MDI_CHECKBOX_BLANK_BADGE_OUTLINE "\xf3\xb0\x84\x97" // U+F0117
+#define ICON_MDI_CHECKBOX_BLANK_CIRCLE "\xf3\xb0\x84\xaf" // U+F012F
+#define ICON_MDI_CHECKBOX_BLANK_CIRCLE_OUTLINE "\xf3\xb0\x84\xb0" // U+F0130
+#define ICON_MDI_CHECKBOX_BLANK_OFF "\xf3\xb1\x8b\xac" // U+F12EC
+#define ICON_MDI_CHECKBOX_BLANK_OFF_OUTLINE "\xf3\xb1\x8b\xad" // U+F12ED
+#define ICON_MDI_CHECKBOX_BLANK_OUTLINE "\xf3\xb0\x84\xb1" // U+F0131
+#define ICON_MDI_CHECKBOX_INTERMEDIATE "\xf3\xb0\xa1\x96" // U+F0856
+#define ICON_MDI_CHECKBOX_INTERMEDIATE_VARIANT "\xf3\xb1\xad\x94" // U+F1B54
+#define ICON_MDI_CHECKBOX_MARKED "\xf3\xb0\x84\xb2" // U+F0132
+#define ICON_MDI_CHECKBOX_MARKED_CIRCLE "\xf3\xb0\x84\xb3" // U+F0133
+#define ICON_MDI_CHECKBOX_MARKED_CIRCLE_AUTO_OUTLINE "\xf3\xb1\xb0\xa6" // U+F1C26
+#define ICON_MDI_CHECKBOX_MARKED_CIRCLE_MINUS_OUTLINE "\xf3\xb1\xb0\xa7" // U+F1C27
+#define ICON_MDI_CHECKBOX_MARKED_CIRCLE_OUTLINE "\xf3\xb0\x84\xb4" // U+F0134
+#define ICON_MDI_CHECKBOX_MARKED_CIRCLE_PLUS_OUTLINE "\xf3\xb1\xa4\xa7" // U+F1927
+#define ICON_MDI_CHECKBOX_MARKED_OUTLINE "\xf3\xb0\x84\xb5" // U+F0135
+#define ICON_MDI_CHECKBOX_MULTIPLE_BLANK "\xf3\xb0\x84\xb6" // U+F0136
+#define ICON_MDI_CHECKBOX_MULTIPLE_BLANK_CIRCLE "\xf3\xb0\x98\xbb" // U+F063B
+#define ICON_MDI_CHECKBOX_MULTIPLE_BLANK_CIRCLE_OUTLINE "\xf3\xb0\x98\xbc" // U+F063C
+#define ICON_MDI_CHECKBOX_MULTIPLE_BLANK_OUTLINE "\xf3\xb0\x84\xb7" // U+F0137
+#define ICON_MDI_CHECKBOX_MULTIPLE_MARKED "\xf3\xb0\x84\xb8" // U+F0138
+#define ICON_MDI_CHECKBOX_MULTIPLE_MARKED_CIRCLE "\xf3\xb0\x98\xbd" // U+F063D
+#define ICON_MDI_CHECKBOX_MULTIPLE_MARKED_CIRCLE_OUTLINE "\xf3\xb0\x98\xbe" // U+F063E
+#define ICON_MDI_CHECKBOX_MULTIPLE_MARKED_OUTLINE "\xf3\xb0\x84\xb9" // U+F0139
+#define ICON_MDI_CHECKBOX_MULTIPLE_OUTLINE "\xf3\xb0\xb1\x91" // U+F0C51
+#define ICON_MDI_CHECKBOX_OUTLINE "\xf3\xb0\xb1\x92" // U+F0C52
+#define ICON_MDI_CHECKERBOARD "\xf3\xb0\x84\xba" // U+F013A
+#define ICON_MDI_CHECKERBOARD_MINUS "\xf3\xb1\x88\x82" // U+F1202
+#define ICON_MDI_CHECKERBOARD_PLUS "\xf3\xb1\x88\x81" // U+F1201
+#define ICON_MDI_CHECKERBOARD_REMOVE "\xf3\xb1\x88\x83" // U+F1203
+#define ICON_MDI_CHEESE "\xf3\xb1\x8a\xb9" // U+F12B9
+#define ICON_MDI_CHEESE_OFF "\xf3\xb1\x8f\xae" // U+F13EE
+#define ICON_MDI_CHEF_HAT "\xf3\xb0\xad\xbc" // U+F0B7C
+#define ICON_MDI_CHEMICAL_WEAPON "\xf3\xb0\x84\xbb" // U+F013B
+#define ICON_MDI_CHESS_BISHOP "\xf3\xb0\xa1\x9c" // U+F085C
+#define ICON_MDI_CHESS_KING "\xf3\xb0\xa1\x97" // U+F0857
+#define ICON_MDI_CHESS_KNIGHT "\xf3\xb0\xa1\x98" // U+F0858
+#define ICON_MDI_CHESS_PAWN "\xf3\xb0\xa1\x99" // U+F0859
+#define ICON_MDI_CHESS_QUEEN "\xf3\xb0\xa1\x9a" // U+F085A
+#define ICON_MDI_CHESS_ROOK "\xf3\xb0\xa1\x9b" // U+F085B
+#define ICON_MDI_CHEVRON_DOUBLE_DOWN "\xf3\xb0\x84\xbc" // U+F013C
+#define ICON_MDI_CHEVRON_DOUBLE_LEFT "\xf3\xb0\x84\xbd" // U+F013D
+#define ICON_MDI_CHEVRON_DOUBLE_RIGHT "\xf3\xb0\x84\xbe" // U+F013E
+#define ICON_MDI_CHEVRON_DOUBLE_UP "\xf3\xb0\x84\xbf" // U+F013F
+#define ICON_MDI_CHEVRON_DOWN "\xf3\xb0\x85\x80" // U+F0140
+#define ICON_MDI_CHEVRON_DOWN_BOX "\xf3\xb0\xa7\x96" // U+F09D6
+#define ICON_MDI_CHEVRON_DOWN_BOX_OUTLINE "\xf3\xb0\xa7\x97" // U+F09D7
+#define ICON_MDI_CHEVRON_DOWN_CIRCLE "\xf3\xb0\xac\xa6" // U+F0B26
+#define ICON_MDI_CHEVRON_DOWN_CIRCLE_OUTLINE "\xf3\xb0\xac\xa7" // U+F0B27
+#define ICON_MDI_CHEVRON_LEFT "\xf3\xb0\x85\x81" // U+F0141
+#define ICON_MDI_CHEVRON_LEFT_BOX "\xf3\xb0\xa7\x98" // U+F09D8
+#define ICON_MDI_CHEVRON_LEFT_BOX_OUTLINE "\xf3\xb0\xa7\x99" // U+F09D9
+#define ICON_MDI_CHEVRON_LEFT_CIRCLE "\xf3\xb0\xac\xa8" // U+F0B28
+#define ICON_MDI_CHEVRON_LEFT_CIRCLE_OUTLINE "\xf3\xb0\xac\xa9" // U+F0B29
+#define ICON_MDI_CHEVRON_RIGHT "\xf3\xb0\x85\x82" // U+F0142
+#define ICON_MDI_CHEVRON_RIGHT_BOX "\xf3\xb0\xa7\x9a" // U+F09DA
+#define ICON_MDI_CHEVRON_RIGHT_BOX_OUTLINE "\xf3\xb0\xa7\x9b" // U+F09DB
+#define ICON_MDI_CHEVRON_RIGHT_CIRCLE "\xf3\xb0\xac\xaa" // U+F0B2A
+#define ICON_MDI_CHEVRON_RIGHT_CIRCLE_OUTLINE "\xf3\xb0\xac\xab" // U+F0B2B
+#define ICON_MDI_CHEVRON_TRIPLE_DOWN "\xf3\xb0\xb6\xb9" // U+F0DB9
+#define ICON_MDI_CHEVRON_TRIPLE_LEFT "\xf3\xb0\xb6\xba" // U+F0DBA
+#define ICON_MDI_CHEVRON_TRIPLE_RIGHT "\xf3\xb0\xb6\xbb" // U+F0DBB
+#define ICON_MDI_CHEVRON_TRIPLE_UP "\xf3\xb0\xb6\xbc" // U+F0DBC
+#define ICON_MDI_CHEVRON_UP "\xf3\xb0\x85\x83" // U+F0143
+#define ICON_MDI_CHEVRON_UP_BOX "\xf3\xb0\xa7\x9c" // U+F09DC
+#define ICON_MDI_CHEVRON_UP_BOX_OUTLINE "\xf3\xb0\xa7\x9d" // U+F09DD
+#define ICON_MDI_CHEVRON_UP_CIRCLE "\xf3\xb0\xac\xac" // U+F0B2C
+#define ICON_MDI_CHEVRON_UP_CIRCLE_OUTLINE "\xf3\xb0\xac\xad" // U+F0B2D
+#define ICON_MDI_CHILI_ALERT "\xf3\xb1\x9f\xaa" // U+F17EA
+#define ICON_MDI_CHILI_ALERT_OUTLINE "\xf3\xb1\x9f\xab" // U+F17EB
+#define ICON_MDI_CHILI_HOT "\xf3\xb0\x9e\xb2" // U+F07B2
+#define ICON_MDI_CHILI_HOT_OUTLINE "\xf3\xb1\x9f\xac" // U+F17EC
+#define ICON_MDI_CHILI_MEDIUM "\xf3\xb0\x9e\xb3" // U+F07B3
+#define ICON_MDI_CHILI_MEDIUM_OUTLINE "\xf3\xb1\x9f\xad" // U+F17ED
+#define ICON_MDI_CHILI_MILD "\xf3\xb0\x9e\xb4" // U+F07B4
+#define ICON_MDI_CHILI_MILD_OUTLINE "\xf3\xb1\x9f\xae" // U+F17EE
+#define ICON_MDI_CHILI_OFF "\xf3\xb1\x91\xa7" // U+F1467
+#define ICON_MDI_CHILI_OFF_OUTLINE "\xf3\xb1\x9f\xaf" // U+F17EF
+#define ICON_MDI_CHIP "\xf3\xb0\x98\x9a" // U+F061A
+#define ICON_MDI_CHURCH "\xf3\xb0\x85\x84" // U+F0144
+#define ICON_MDI_CHURCH_OUTLINE "\xf3\xb1\xac\x82" // U+F1B02
+#define ICON_MDI_CIGAR "\xf3\xb1\x86\x89" // U+F1189
+#define ICON_MDI_CIGAR_OFF "\xf3\xb1\x90\x9b" // U+F141B
+#define ICON_MDI_CIRCLE "\xf3\xb0\x9d\xa5" // U+F0765
+#define ICON_MDI_CIRCLE_BOX "\xf3\xb1\x97\x9c" // U+F15DC
+#define ICON_MDI_CIRCLE_BOX_OUTLINE "\xf3\xb1\x97\x9d" // U+F15DD
+#define ICON_MDI_CIRCLE_DOUBLE "\xf3\xb0\xba\x95" // U+F0E95
+#define ICON_MDI_CIRCLE_EDIT_OUTLINE "\xf3\xb0\xa3\x95" // U+F08D5
+#define ICON_MDI_CIRCLE_EXPAND "\xf3\xb0\xba\x96" // U+F0E96
+#define ICON_MDI_CIRCLE_HALF "\xf3\xb1\x8e\x95" // U+F1395
+#define ICON_MDI_CIRCLE_HALF_FULL "\xf3\xb1\x8e\x96" // U+F1396
+#define ICON_MDI_CIRCLE_MEDIUM "\xf3\xb0\xa7\x9e" // U+F09DE
+#define ICON_MDI_CIRCLE_MULTIPLE "\xf3\xb0\xac\xb8" // U+F0B38
+#define ICON_MDI_CIRCLE_MULTIPLE_OUTLINE "\xf3\xb0\x9a\x95" // U+F0695
+#define ICON_MDI_CIRCLE_OFF_OUTLINE "\xf3\xb1\x83\x93" // U+F10D3
+#define ICON_MDI_CIRCLE_OPACITY "\xf3\xb1\xa1\x93" // U+F1853
+#define ICON_MDI_CIRCLE_OUTLINE "\xf3\xb0\x9d\xa6" // U+F0766
+#define ICON_MDI_CIRCLE_SLICE_1 "\xf3\xb0\xaa\x9e" // U+F0A9E
+#define ICON_MDI_CIRCLE_SLICE_2 "\xf3\xb0\xaa\x9f" // U+F0A9F
+#define ICON_MDI_CIRCLE_SLICE_3 "\xf3\xb0\xaa\xa0" // U+F0AA0
+#define ICON_MDI_CIRCLE_SLICE_4 "\xf3\xb0\xaa\xa1" // U+F0AA1
+#define ICON_MDI_CIRCLE_SLICE_5 "\xf3\xb0\xaa\xa2" // U+F0AA2
+#define ICON_MDI_CIRCLE_SLICE_6 "\xf3\xb0\xaa\xa3" // U+F0AA3
+#define ICON_MDI_CIRCLE_SLICE_7 "\xf3\xb0\xaa\xa4" // U+F0AA4
+#define ICON_MDI_CIRCLE_SLICE_8 "\xf3\xb0\xaa\xa5" // U+F0AA5
+#define ICON_MDI_CIRCLE_SMALL "\xf3\xb0\xa7\x9f" // U+F09DF
+#define ICON_MDI_CIRCULAR_SAW "\xf3\xb0\xb8\xa2" // U+F0E22
+#define ICON_MDI_CITY "\xf3\xb0\x85\x86" // U+F0146
+#define ICON_MDI_CITY_SWITCH "\xf3\xb1\xb0\xa8" // U+F1C28
+#define ICON_MDI_CITY_VARIANT "\xf3\xb0\xa8\xb6" // U+F0A36
+#define ICON_MDI_CITY_VARIANT_OUTLINE "\xf3\xb0\xa8\xb7" // U+F0A37
+#define ICON_MDI_CLIPBOARD "\xf3\xb0\x85\x87" // U+F0147
+#define ICON_MDI_CLIPBOARD_ACCOUNT "\xf3\xb0\x85\x88" // U+F0148
+#define ICON_MDI_CLIPBOARD_ACCOUNT_OUTLINE "\xf3\xb0\xb1\x95" // U+F0C55
+#define ICON_MDI_CLIPBOARD_ALERT "\xf3\xb0\x85\x89" // U+F0149
+#define ICON_MDI_CLIPBOARD_ALERT_OUTLINE "\xf3\xb0\xb3\xb7" // U+F0CF7
+#define ICON_MDI_CLIPBOARD_ARROW_DOWN "\xf3\xb0\x85\x8a" // U+F014A
+#define ICON_MDI_CLIPBOARD_ARROW_DOWN_OUTLINE "\xf3\xb0\xb1\x96" // U+F0C56
+#define ICON_MDI_CLIPBOARD_ARROW_LEFT "\xf3\xb0\x85\x8b" // U+F014B
+#define ICON_MDI_CLIPBOARD_ARROW_LEFT_OUTLINE "\xf3\xb0\xb3\xb8" // U+F0CF8
+#define ICON_MDI_CLIPBOARD_ARROW_RIGHT "\xf3\xb0\xb3\xb9" // U+F0CF9
+#define ICON_MDI_CLIPBOARD_ARROW_RIGHT_OUTLINE "\xf3\xb0\xb3\xba" // U+F0CFA
+#define ICON_MDI_CLIPBOARD_ARROW_UP "\xf3\xb0\xb1\x97" // U+F0C57
+#define ICON_MDI_CLIPBOARD_ARROW_UP_OUTLINE "\xf3\xb0\xb1\x98" // U+F0C58
+#define ICON_MDI_CLIPBOARD_CHECK "\xf3\xb0\x85\x8e" // U+F014E
+#define ICON_MDI_CLIPBOARD_CHECK_MULTIPLE "\xf3\xb1\x89\xa3" // U+F1263
+#define ICON_MDI_CLIPBOARD_CHECK_MULTIPLE_OUTLINE "\xf3\xb1\x89\xa4" // U+F1264
+#define ICON_MDI_CLIPBOARD_CHECK_OUTLINE "\xf3\xb0\xa2\xa8" // U+F08A8
+#define ICON_MDI_CLIPBOARD_CLOCK "\xf3\xb1\x9b\xa2" // U+F16E2
+#define ICON_MDI_CLIPBOARD_CLOCK_OUTLINE "\xf3\xb1\x9b\xa3" // U+F16E3
+#define ICON_MDI_CLIPBOARD_EDIT "\xf3\xb1\x93\xa5" // U+F14E5
+#define ICON_MDI_CLIPBOARD_EDIT_OUTLINE "\xf3\xb1\x93\xa6" // U+F14E6
+#define ICON_MDI_CLIPBOARD_FILE "\xf3\xb1\x89\xa5" // U+F1265
+#define ICON_MDI_CLIPBOARD_FILE_OUTLINE "\xf3\xb1\x89\xa6" // U+F1266
+#define ICON_MDI_CLIPBOARD_FLOW "\xf3\xb0\x9b\x88" // U+F06C8
+#define ICON_MDI_CLIPBOARD_FLOW_OUTLINE "\xf3\xb1\x84\x97" // U+F1117
+#define ICON_MDI_CLIPBOARD_LIST "\xf3\xb1\x83\x94" // U+F10D4
+#define ICON_MDI_CLIPBOARD_LIST_OUTLINE "\xf3\xb1\x83\x95" // U+F10D5
+#define ICON_MDI_CLIPBOARD_MINUS "\xf3\xb1\x98\x98" // U+F1618
+#define ICON_MDI_CLIPBOARD_MINUS_OUTLINE "\xf3\xb1\x98\x99" // U+F1619
+#define ICON_MDI_CLIPBOARD_MULTIPLE "\xf3\xb1\x89\xa7" // U+F1267
+#define ICON_MDI_CLIPBOARD_MULTIPLE_OUTLINE "\xf3\xb1\x89\xa8" // U+F1268
+#define ICON_MDI_CLIPBOARD_OFF "\xf3\xb1\x98\x9a" // U+F161A
+#define ICON_MDI_CLIPBOARD_OFF_OUTLINE "\xf3\xb1\x98\x9b" // U+F161B
+#define ICON_MDI_CLIPBOARD_OUTLINE "\xf3\xb0\x85\x8c" // U+F014C
+#define ICON_MDI_CLIPBOARD_PLAY "\xf3\xb0\xb1\x99" // U+F0C59
+#define ICON_MDI_CLIPBOARD_PLAY_MULTIPLE "\xf3\xb1\x89\xa9" // U+F1269
+#define ICON_MDI_CLIPBOARD_PLAY_MULTIPLE_OUTLINE "\xf3\xb1\x89\xaa" // U+F126A
+#define ICON_MDI_CLIPBOARD_PLAY_OUTLINE "\xf3\xb0\xb1\x9a" // U+F0C5A
+#define ICON_MDI_CLIPBOARD_PLUS "\xf3\xb0\x9d\x91" // U+F0751
+#define ICON_MDI_CLIPBOARD_PLUS_OUTLINE "\xf3\xb1\x8c\x9f" // U+F131F
+#define ICON_MDI_CLIPBOARD_PULSE "\xf3\xb0\xa1\x9d" // U+F085D
+#define ICON_MDI_CLIPBOARD_PULSE_OUTLINE "\xf3\xb0\xa1\x9e" // U+F085E
+#define ICON_MDI_CLIPBOARD_REMOVE "\xf3\xb1\x98\x9c" // U+F161C
+#define ICON_MDI_CLIPBOARD_REMOVE_OUTLINE "\xf3\xb1\x98\x9d" // U+F161D
+#define ICON_MDI_CLIPBOARD_SEARCH "\xf3\xb1\x98\x9e" // U+F161E
+#define ICON_MDI_CLIPBOARD_SEARCH_OUTLINE "\xf3\xb1\x98\x9f" // U+F161F
+#define ICON_MDI_CLIPBOARD_TEXT "\xf3\xb0\x85\x8d" // U+F014D
+#define ICON_MDI_CLIPBOARD_TEXT_CLOCK "\xf3\xb1\xa3\xb9" // U+F18F9
+#define ICON_MDI_CLIPBOARD_TEXT_CLOCK_OUTLINE "\xf3\xb1\xa3\xba" // U+F18FA
+#define ICON_MDI_CLIPBOARD_TEXT_MULTIPLE "\xf3\xb1\x89\xab" // U+F126B
+#define ICON_MDI_CLIPBOARD_TEXT_MULTIPLE_OUTLINE "\xf3\xb1\x89\xac" // U+F126C
+#define ICON_MDI_CLIPBOARD_TEXT_OFF "\xf3\xb1\x98\xa0" // U+F1620
+#define ICON_MDI_CLIPBOARD_TEXT_OFF_OUTLINE "\xf3\xb1\x98\xa1" // U+F1621
+#define ICON_MDI_CLIPBOARD_TEXT_OUTLINE "\xf3\xb0\xa8\xb8" // U+F0A38
+#define ICON_MDI_CLIPBOARD_TEXT_PLAY "\xf3\xb0\xb1\x9b" // U+F0C5B
+#define ICON_MDI_CLIPBOARD_TEXT_PLAY_OUTLINE "\xf3\xb0\xb1\x9c" // U+F0C5C
+#define ICON_MDI_CLIPBOARD_TEXT_SEARCH "\xf3\xb1\x98\xa2" // U+F1622
+#define ICON_MDI_CLIPBOARD_TEXT_SEARCH_OUTLINE "\xf3\xb1\x98\xa3" // U+F1623
+#define ICON_MDI_CLIPPY "\xf3\xb0\x85\x8f" // U+F014F
+#define ICON_MDI_CLOCK "\xf3\xb0\xa5\x94" // U+F0954
+#define ICON_MDI_CLOCK_ALERT "\xf3\xb0\xa5\x95" // U+F0955
+#define ICON_MDI_CLOCK_ALERT_OUTLINE "\xf3\xb0\x97\x8e" // U+F05CE
+#define ICON_MDI_CLOCK_CHECK "\xf3\xb0\xbe\xa8" // U+F0FA8
+#define ICON_MDI_CLOCK_CHECK_OUTLINE "\xf3\xb0\xbe\xa9" // U+F0FA9
+#define ICON_MDI_CLOCK_DIGITAL "\xf3\xb0\xba\x97" // U+F0E97
+#define ICON_MDI_CLOCK_EDIT "\xf3\xb1\xa6\xba" // U+F19BA
+#define ICON_MDI_CLOCK_EDIT_OUTLINE "\xf3\xb1\xa6\xbb" // U+F19BB
+#define ICON_MDI_CLOCK_END "\xf3\xb0\x85\x91" // U+F0151
+#define ICON_MDI_CLOCK_FAST "\xf3\xb0\x85\x92" // U+F0152
+#define ICON_MDI_CLOCK_IN "\xf3\xb0\x85\x93" // U+F0153
+#define ICON_MDI_CLOCK_MINUS "\xf3\xb1\xa1\xa3" // U+F1863
+#define ICON_MDI_CLOCK_MINUS_OUTLINE "\xf3\xb1\xa1\xa4" // U+F1864
+#define ICON_MDI_CLOCK_OUT "\xf3\xb0\x85\x94" // U+F0154
+#define ICON_MDI_CLOCK_OUTLINE "\xf3\xb0\x85\x90" // U+F0150
+#define ICON_MDI_CLOCK_PLUS "\xf3\xb1\xa1\xa1" // U+F1861
+#define ICON_MDI_CLOCK_PLUS_OUTLINE "\xf3\xb1\xa1\xa2" // U+F1862
+#define ICON_MDI_CLOCK_REMOVE "\xf3\xb1\xa1\xa5" // U+F1865
+#define ICON_MDI_CLOCK_REMOVE_OUTLINE "\xf3\xb1\xa1\xa6" // U+F1866
+#define ICON_MDI_CLOCK_STAR_FOUR_POINTS "\xf3\xb1\xb0\xa9" // U+F1C29
+#define ICON_MDI_CLOCK_STAR_FOUR_POINTS_OUTLINE "\xf3\xb1\xb0\xaa" // U+F1C2A
+#define ICON_MDI_CLOCK_START "\xf3\xb0\x85\x95" // U+F0155
+#define ICON_MDI_CLOCK_TIME_EIGHT "\xf3\xb1\x91\x86" // U+F1446
+#define ICON_MDI_CLOCK_TIME_EIGHT_OUTLINE "\xf3\xb1\x91\x92" // U+F1452
+#define ICON_MDI_CLOCK_TIME_ELEVEN "\xf3\xb1\x91\x89" // U+F1449
+#define ICON_MDI_CLOCK_TIME_ELEVEN_OUTLINE "\xf3\xb1\x91\x95" // U+F1455
+#define ICON_MDI_CLOCK_TIME_FIVE "\xf3\xb1\x91\x83" // U+F1443
+#define ICON_MDI_CLOCK_TIME_FIVE_OUTLINE "\xf3\xb1\x91\x8f" // U+F144F
+#define ICON_MDI_CLOCK_TIME_FOUR "\xf3\xb1\x91\x82" // U+F1442
+#define ICON_MDI_CLOCK_TIME_FOUR_OUTLINE "\xf3\xb1\x91\x8e" // U+F144E
+#define ICON_MDI_CLOCK_TIME_NINE "\xf3\xb1\x91\x87" // U+F1447
+#define ICON_MDI_CLOCK_TIME_NINE_OUTLINE "\xf3\xb1\x91\x93" // U+F1453
+#define ICON_MDI_CLOCK_TIME_ONE "\xf3\xb1\x90\xbf" // U+F143F
+#define ICON_MDI_CLOCK_TIME_ONE_OUTLINE "\xf3\xb1\x91\x8b" // U+F144B
+#define ICON_MDI_CLOCK_TIME_SEVEN "\xf3\xb1\x91\x85" // U+F1445
+#define ICON_MDI_CLOCK_TIME_SEVEN_OUTLINE "\xf3\xb1\x91\x91" // U+F1451
+#define ICON_MDI_CLOCK_TIME_SIX "\xf3\xb1\x91\x84" // U+F1444
+#define ICON_MDI_CLOCK_TIME_SIX_OUTLINE "\xf3\xb1\x91\x90" // U+F1450
+#define ICON_MDI_CLOCK_TIME_TEN "\xf3\xb1\x91\x88" // U+F1448
+#define ICON_MDI_CLOCK_TIME_TEN_OUTLINE "\xf3\xb1\x91\x94" // U+F1454
+#define ICON_MDI_CLOCK_TIME_THREE "\xf3\xb1\x91\x81" // U+F1441
+#define ICON_MDI_CLOCK_TIME_THREE_OUTLINE "\xf3\xb1\x91\x8d" // U+F144D
+#define ICON_MDI_CLOCK_TIME_TWELVE "\xf3\xb1\x91\x8a" // U+F144A
+#define ICON_MDI_CLOCK_TIME_TWELVE_OUTLINE "\xf3\xb1\x91\x96" // U+F1456
+#define ICON_MDI_CLOCK_TIME_TWO "\xf3\xb1\x91\x80" // U+F1440
+#define ICON_MDI_CLOCK_TIME_TWO_OUTLINE "\xf3\xb1\x91\x8c" // U+F144C
+#define ICON_MDI_CLOSE "\xf3\xb0\x85\x96" // U+F0156
+#define ICON_MDI_CLOSE_BOX "\xf3\xb0\x85\x97" // U+F0157
+#define ICON_MDI_CLOSE_BOX_MULTIPLE "\xf3\xb0\xb1\x9d" // U+F0C5D
+#define ICON_MDI_CLOSE_BOX_MULTIPLE_OUTLINE "\xf3\xb0\xb1\x9e" // U+F0C5E
+#define ICON_MDI_CLOSE_BOX_OUTLINE "\xf3\xb0\x85\x98" // U+F0158
+#define ICON_MDI_CLOSE_CIRCLE "\xf3\xb0\x85\x99" // U+F0159
+#define ICON_MDI_CLOSE_CIRCLE_MULTIPLE "\xf3\xb0\x98\xaa" // U+F062A
+#define ICON_MDI_CLOSE_CIRCLE_MULTIPLE_OUTLINE "\xf3\xb0\xa2\x83" // U+F0883
+#define ICON_MDI_CLOSE_CIRCLE_OUTLINE "\xf3\xb0\x85\x9a" // U+F015A
+#define ICON_MDI_CLOSE_NETWORK "\xf3\xb0\x85\x9b" // U+F015B
+#define ICON_MDI_CLOSE_NETWORK_OUTLINE "\xf3\xb0\xb1\x9f" // U+F0C5F
+#define ICON_MDI_CLOSE_OCTAGON "\xf3\xb0\x85\x9c" // U+F015C
+#define ICON_MDI_CLOSE_OCTAGON_OUTLINE "\xf3\xb0\x85\x9d" // U+F015D
+#define ICON_MDI_CLOSE_OUTLINE "\xf3\xb0\x9b\x89" // U+F06C9
+#define ICON_MDI_CLOSE_THICK "\xf3\xb1\x8e\x98" // U+F1398
+#define ICON_MDI_CLOSED_CAPTION "\xf3\xb0\x85\x9e" // U+F015E
+#define ICON_MDI_CLOSED_CAPTION_OUTLINE "\xf3\xb0\xb6\xbd" // U+F0DBD
+#define ICON_MDI_CLOUD "\xf3\xb0\x85\x9f" // U+F015F
+#define ICON_MDI_CLOUD_ALERT "\xf3\xb0\xa7\xa0" // U+F09E0
+#define ICON_MDI_CLOUD_ALERT_OUTLINE "\xf3\xb1\xaf\xa0" // U+F1BE0
+#define ICON_MDI_CLOUD_ARROW_DOWN "\xf3\xb1\xaf\xa1" // U+F1BE1
+#define ICON_MDI_CLOUD_ARROW_DOWN_OUTLINE "\xf3\xb1\xaf\xa2" // U+F1BE2
+#define ICON_MDI_CLOUD_ARROW_LEFT "\xf3\xb1\xaf\xa3" // U+F1BE3
+#define ICON_MDI_CLOUD_ARROW_LEFT_OUTLINE "\xf3\xb1\xaf\xa4" // U+F1BE4
+#define ICON_MDI_CLOUD_ARROW_RIGHT "\xf3\xb1\xaf\xa5" // U+F1BE5
+#define ICON_MDI_CLOUD_ARROW_RIGHT_OUTLINE "\xf3\xb1\xaf\xa6" // U+F1BE6
+#define ICON_MDI_CLOUD_ARROW_UP "\xf3\xb1\xaf\xa7" // U+F1BE7
+#define ICON_MDI_CLOUD_ARROW_UP_OUTLINE "\xf3\xb1\xaf\xa8" // U+F1BE8
+#define ICON_MDI_CLOUD_BRACES "\xf3\xb0\x9e\xb5" // U+F07B5
+#define ICON_MDI_CLOUD_CANCEL "\xf3\xb1\xaf\xa9" // U+F1BE9
+#define ICON_MDI_CLOUD_CANCEL_OUTLINE "\xf3\xb1\xaf\xaa" // U+F1BEA
+#define ICON_MDI_CLOUD_CHECK "\xf3\xb1\xaf\xab" // U+F1BEB
+#define ICON_MDI_CLOUD_CHECK_OUTLINE "\xf3\xb1\xaf\xac" // U+F1BEC
+#define ICON_MDI_CLOUD_CHECK_VARIANT "\xf3\xb0\x85\xa0" // U+F0160
+#define ICON_MDI_CLOUD_CHECK_VARIANT_OUTLINE "\xf3\xb1\x8b\x8c" // U+F12CC
+#define ICON_MDI_CLOUD_CIRCLE "\xf3\xb0\x85\xa1" // U+F0161
+#define ICON_MDI_CLOUD_CIRCLE_OUTLINE "\xf3\xb1\xaf\xad" // U+F1BED
+#define ICON_MDI_CLOUD_CLOCK "\xf3\xb1\xaf\xae" // U+F1BEE
+#define ICON_MDI_CLOUD_CLOCK_OUTLINE "\xf3\xb1\xaf\xaf" // U+F1BEF
+#define ICON_MDI_CLOUD_COG "\xf3\xb1\xaf\xb0" // U+F1BF0
+#define ICON_MDI_CLOUD_COG_OUTLINE "\xf3\xb1\xaf\xb1" // U+F1BF1
+#define ICON_MDI_CLOUD_DOWNLOAD "\xf3\xb0\x85\xa2" // U+F0162
+#define ICON_MDI_CLOUD_DOWNLOAD_OUTLINE "\xf3\xb0\xad\xbd" // U+F0B7D
+#define ICON_MDI_CLOUD_KEY "\xf3\xb1\xb2\xa1" // U+F1CA1
+#define ICON_MDI_CLOUD_KEY_OUTLINE "\xf3\xb1\xb2\xa2" // U+F1CA2
+#define ICON_MDI_CLOUD_LOCK "\xf3\xb1\x87\xb1" // U+F11F1
+#define ICON_MDI_CLOUD_LOCK_OPEN "\xf3\xb1\xaf\xb2" // U+F1BF2
+#define ICON_MDI_CLOUD_LOCK_OPEN_OUTLINE "\xf3\xb1\xaf\xb3" // U+F1BF3
+#define ICON_MDI_CLOUD_LOCK_OUTLINE "\xf3\xb1\x87\xb2" // U+F11F2
+#define ICON_MDI_CLOUD_MINUS "\xf3\xb1\xaf\xb4" // U+F1BF4
+#define ICON_MDI_CLOUD_MINUS_OUTLINE "\xf3\xb1\xaf\xb5" // U+F1BF5
+#define ICON_MDI_CLOUD_OFF "\xf3\xb1\xaf\xb6" // U+F1BF6
+#define ICON_MDI_CLOUD_OFF_OUTLINE "\xf3\xb0\x85\xa4" // U+F0164
+#define ICON_MDI_CLOUD_OUTLINE "\xf3\xb0\x85\xa3" // U+F0163
+#define ICON_MDI_CLOUD_PERCENT "\xf3\xb1\xa8\xb5" // U+F1A35
+#define ICON_MDI_CLOUD_PERCENT_OUTLINE "\xf3\xb1\xa8\xb6" // U+F1A36
+#define ICON_MDI_CLOUD_PLUS "\xf3\xb1\xaf\xb7" // U+F1BF7
+#define ICON_MDI_CLOUD_PLUS_OUTLINE "\xf3\xb1\xaf\xb8" // U+F1BF8
+#define ICON_MDI_CLOUD_PRINT "\xf3\xb0\x85\xa5" // U+F0165
+#define ICON_MDI_CLOUD_PRINT_OUTLINE "\xf3\xb0\x85\xa6" // U+F0166
+#define ICON_MDI_CLOUD_QUESTION "\xf3\xb0\xa8\xb9" // U+F0A39
+#define ICON_MDI_CLOUD_QUESTION_OUTLINE "\xf3\xb1\xaf\xb9" // U+F1BF9
+#define ICON_MDI_CLOUD_REFRESH "\xf3\xb1\xaf\xba" // U+F1BFA
+#define ICON_MDI_CLOUD_REFRESH_OUTLINE "\xf3\xb1\xaf\xbb" // U+F1BFB
+#define ICON_MDI_CLOUD_REFRESH_VARIANT "\xf3\xb0\x94\xaa" // U+F052A
+#define ICON_MDI_CLOUD_REFRESH_VARIANT_OUTLINE "\xf3\xb1\xaf\xbc" // U+F1BFC
+#define ICON_MDI_CLOUD_REMOVE "\xf3\xb1\xaf\xbd" // U+F1BFD
+#define ICON_MDI_CLOUD_REMOVE_OUTLINE "\xf3\xb1\xaf\xbe" // U+F1BFE
+#define ICON_MDI_CLOUD_SEARCH "\xf3\xb0\xa5\x96" // U+F0956
+#define ICON_MDI_CLOUD_SEARCH_OUTLINE "\xf3\xb0\xa5\x97" // U+F0957
+#define ICON_MDI_CLOUD_SYNC "\xf3\xb0\x98\xbf" // U+F063F
+#define ICON_MDI_CLOUD_SYNC_OUTLINE "\xf3\xb1\x8b\x96" // U+F12D6
+#define ICON_MDI_CLOUD_TAGS "\xf3\xb0\x9e\xb6" // U+F07B6
+#define ICON_MDI_CLOUD_UPLOAD "\xf3\xb0\x85\xa7" // U+F0167
+#define ICON_MDI_CLOUD_UPLOAD_OUTLINE "\xf3\xb0\xad\xbe" // U+F0B7E
+#define ICON_MDI_CLOUDS "\xf3\xb1\xae\x95" // U+F1B95
+#define ICON_MDI_CLOVER "\xf3\xb0\xa0\x96" // U+F0816
+#define ICON_MDI_CLOVER_OUTLINE "\xf3\xb1\xb1\xa2" // U+F1C62
+#define ICON_MDI_COACH_LAMP "\xf3\xb1\x80\xa0" // U+F1020
+#define ICON_MDI_COACH_LAMP_VARIANT "\xf3\xb1\xa8\xb7" // U+F1A37
+#define ICON_MDI_COAT_RACK "\xf3\xb1\x82\x9e" // U+F109E
+#define ICON_MDI_CODE_ARRAY "\xf3\xb0\x85\xa8" // U+F0168
+#define ICON_MDI_CODE_BLOCK_BRACES "\xf3\xb1\xb2\x83" // U+F1C83
+#define ICON_MDI_CODE_BLOCK_BRACKETS "\xf3\xb1\xb2\x84" // U+F1C84
+#define ICON_MDI_CODE_BLOCK_PARENTHESES "\xf3\xb1\xb2\x85" // U+F1C85
+#define ICON_MDI_CODE_BLOCK_TAGS "\xf3\xb1\xb2\x86" // U+F1C86
+#define ICON_MDI_CODE_BRACES "\xf3\xb0\x85\xa9" // U+F0169
+#define ICON_MDI_CODE_BRACES_BOX "\xf3\xb1\x83\x96" // U+F10D6
+#define ICON_MDI_CODE_BRACKETS "\xf3\xb0\x85\xaa" // U+F016A
+#define ICON_MDI_CODE_EQUAL "\xf3\xb0\x85\xab" // U+F016B
+#define ICON_MDI_CODE_GREATER_THAN "\xf3\xb0\x85\xac" // U+F016C
+#define ICON_MDI_CODE_GREATER_THAN_OR_EQUAL "\xf3\xb0\x85\xad" // U+F016D
+#define ICON_MDI_CODE_JSON "\xf3\xb0\x98\xa6" // U+F0626
+#define ICON_MDI_CODE_LESS_THAN "\xf3\xb0\x85\xae" // U+F016E
+#define ICON_MDI_CODE_LESS_THAN_OR_EQUAL "\xf3\xb0\x85\xaf" // U+F016F
+#define ICON_MDI_CODE_NOT_EQUAL "\xf3\xb0\x85\xb0" // U+F0170
+#define ICON_MDI_CODE_NOT_EQUAL_VARIANT "\xf3\xb0\x85\xb1" // U+F0171
+#define ICON_MDI_CODE_PARENTHESES "\xf3\xb0\x85\xb2" // U+F0172
+#define ICON_MDI_CODE_PARENTHESES_BOX "\xf3\xb1\x83\x97" // U+F10D7
+#define ICON_MDI_CODE_STRING "\xf3\xb0\x85\xb3" // U+F0173
+#define ICON_MDI_CODE_TAGS "\xf3\xb0\x85\xb4" // U+F0174
+#define ICON_MDI_CODE_TAGS_CHECK "\xf3\xb0\x9a\x94" // U+F0694
+#define ICON_MDI_CODEPEN "\xf3\xb0\x85\xb5" // U+F0175
+#define ICON_MDI_COFFEE "\xf3\xb0\x85\xb6" // U+F0176
+#define ICON_MDI_COFFEE_MAKER "\xf3\xb1\x82\x9f" // U+F109F
+#define ICON_MDI_COFFEE_MAKER_CHECK "\xf3\xb1\xa4\xb1" // U+F1931
+#define ICON_MDI_COFFEE_MAKER_CHECK_OUTLINE "\xf3\xb1\xa4\xb2" // U+F1932
+#define ICON_MDI_COFFEE_MAKER_OUTLINE "\xf3\xb1\xa0\x9b" // U+F181B
+#define ICON_MDI_COFFEE_OFF "\xf3\xb0\xbe\xaa" // U+F0FAA
+#define ICON_MDI_COFFEE_OFF_OUTLINE "\xf3\xb0\xbe\xab" // U+F0FAB
+#define ICON_MDI_COFFEE_OUTLINE "\xf3\xb0\x9b\x8a" // U+F06CA
+#define ICON_MDI_COFFEE_TO_GO "\xf3\xb0\x85\xb7" // U+F0177
+#define ICON_MDI_COFFEE_TO_GO_OUTLINE "\xf3\xb1\x8c\x8e" // U+F130E
+#define ICON_MDI_COFFIN "\xf3\xb0\xad\xbf" // U+F0B7F
+#define ICON_MDI_COG "\xf3\xb0\x92\x93" // U+F0493
+#define ICON_MDI_COG_BOX "\xf3\xb0\x92\x94" // U+F0494
+#define ICON_MDI_COG_CLOCKWISE "\xf3\xb1\x87\x9d" // U+F11DD
+#define ICON_MDI_COG_COUNTERCLOCKWISE "\xf3\xb1\x87\x9e" // U+F11DE
+#define ICON_MDI_COG_OFF "\xf3\xb1\x8f\x8e" // U+F13CE
+#define ICON_MDI_COG_OFF_OUTLINE "\xf3\xb1\x8f\x8f" // U+F13CF
+#define ICON_MDI_COG_OUTLINE "\xf3\xb0\xa2\xbb" // U+F08BB
+#define ICON_MDI_COG_PAUSE "\xf3\xb1\xa4\xb3" // U+F1933
+#define ICON_MDI_COG_PAUSE_OUTLINE "\xf3\xb1\xa4\xb4" // U+F1934
+#define ICON_MDI_COG_PLAY "\xf3\xb1\xa4\xb5" // U+F1935
+#define ICON_MDI_COG_PLAY_OUTLINE "\xf3\xb1\xa4\xb6" // U+F1936
+#define ICON_MDI_COG_REFRESH "\xf3\xb1\x91\x9e" // U+F145E
+#define ICON_MDI_COG_REFRESH_OUTLINE "\xf3\xb1\x91\x9f" // U+F145F
+#define ICON_MDI_COG_STOP "\xf3\xb1\xa4\xb7" // U+F1937
+#define ICON_MDI_COG_STOP_OUTLINE "\xf3\xb1\xa4\xb8" // U+F1938
+#define ICON_MDI_COG_SYNC "\xf3\xb1\x91\xa0" // U+F1460
+#define ICON_MDI_COG_SYNC_OUTLINE "\xf3\xb1\x91\xa1" // U+F1461
+#define ICON_MDI_COG_TRANSFER "\xf3\xb1\x81\x9b" // U+F105B
+#define ICON_MDI_COG_TRANSFER_OUTLINE "\xf3\xb1\x81\x9c" // U+F105C
+#define ICON_MDI_COGS "\xf3\xb0\xa3\x96" // U+F08D6
+#define ICON_MDI_COLLAGE "\xf3\xb0\x99\x80" // U+F0640
+#define ICON_MDI_COLLAPSE_ALL "\xf3\xb0\xaa\xa6" // U+F0AA6
+#define ICON_MDI_COLLAPSE_ALL_OUTLINE "\xf3\xb0\xaa\xa7" // U+F0AA7
+#define ICON_MDI_COLOR_HELPER "\xf3\xb0\x85\xb9" // U+F0179
+#define ICON_MDI_COMMA "\xf3\xb0\xb8\xa3" // U+F0E23
+#define ICON_MDI_COMMA_BOX "\xf3\xb0\xb8\xab" // U+F0E2B
+#define ICON_MDI_COMMA_BOX_OUTLINE "\xf3\xb0\xb8\xa4" // U+F0E24
+#define ICON_MDI_COMMA_CIRCLE "\xf3\xb0\xb8\xa5" // U+F0E25
+#define ICON_MDI_COMMA_CIRCLE_OUTLINE "\xf3\xb0\xb8\xa6" // U+F0E26
+#define ICON_MDI_COMMENT "\xf3\xb0\x85\xba" // U+F017A
+#define ICON_MDI_COMMENT_ACCOUNT "\xf3\xb0\x85\xbb" // U+F017B
+#define ICON_MDI_COMMENT_ACCOUNT_OUTLINE "\xf3\xb0\x85\xbc" // U+F017C
+#define ICON_MDI_COMMENT_ALERT "\xf3\xb0\x85\xbd" // U+F017D
+#define ICON_MDI_COMMENT_ALERT_OUTLINE "\xf3\xb0\x85\xbe" // U+F017E
+#define ICON_MDI_COMMENT_ARROW_LEFT "\xf3\xb0\xa7\xa1" // U+F09E1
+#define ICON_MDI_COMMENT_ARROW_LEFT_OUTLINE "\xf3\xb0\xa7\xa2" // U+F09E2
+#define ICON_MDI_COMMENT_ARROW_RIGHT "\xf3\xb0\xa7\xa3" // U+F09E3
+#define ICON_MDI_COMMENT_ARROW_RIGHT_OUTLINE "\xf3\xb0\xa7\xa4" // U+F09E4
+#define ICON_MDI_COMMENT_BOOKMARK "\xf3\xb1\x96\xae" // U+F15AE
+#define ICON_MDI_COMMENT_BOOKMARK_OUTLINE "\xf3\xb1\x96\xaf" // U+F15AF
+#define ICON_MDI_COMMENT_CHECK "\xf3\xb0\x85\xbf" // U+F017F
+#define ICON_MDI_COMMENT_CHECK_OUTLINE "\xf3\xb0\x86\x80" // U+F0180
+#define ICON_MDI_COMMENT_EDIT "\xf3\xb1\x86\xbf" // U+F11BF
+#define ICON_MDI_COMMENT_EDIT_OUTLINE "\xf3\xb1\x8b\x84" // U+F12C4
+#define ICON_MDI_COMMENT_EYE "\xf3\xb0\xa8\xba" // U+F0A3A
+#define ICON_MDI_COMMENT_EYE_OUTLINE "\xf3\xb0\xa8\xbb" // U+F0A3B
+#define ICON_MDI_COMMENT_FLASH "\xf3\xb1\x96\xb0" // U+F15B0
+#define ICON_MDI_COMMENT_FLASH_OUTLINE "\xf3\xb1\x96\xb1" // U+F15B1
+#define ICON_MDI_COMMENT_MINUS "\xf3\xb1\x97\x9f" // U+F15DF
+#define ICON_MDI_COMMENT_MINUS_OUTLINE "\xf3\xb1\x97\xa0" // U+F15E0
+#define ICON_MDI_COMMENT_MULTIPLE "\xf3\xb0\xa1\x9f" // U+F085F
+#define ICON_MDI_COMMENT_MULTIPLE_OUTLINE "\xf3\xb0\x86\x81" // U+F0181
+#define ICON_MDI_COMMENT_OFF "\xf3\xb1\x97\xa1" // U+F15E1
+#define ICON_MDI_COMMENT_OFF_OUTLINE "\xf3\xb1\x97\xa2" // U+F15E2
+#define ICON_MDI_COMMENT_OUTLINE "\xf3\xb0\x86\x82" // U+F0182
+#define ICON_MDI_COMMENT_PLUS "\xf3\xb0\xa7\xa5" // U+F09E5
+#define ICON_MDI_COMMENT_PLUS_OUTLINE "\xf3\xb0\x86\x83" // U+F0183
+#define ICON_MDI_COMMENT_PROCESSING "\xf3\xb0\x86\x84" // U+F0184
+#define ICON_MDI_COMMENT_PROCESSING_OUTLINE "\xf3\xb0\x86\x85" // U+F0185
+#define ICON_MDI_COMMENT_QUESTION "\xf3\xb0\xa0\x97" // U+F0817
+#define ICON_MDI_COMMENT_QUESTION_OUTLINE "\xf3\xb0\x86\x86" // U+F0186
+#define ICON_MDI_COMMENT_QUOTE "\xf3\xb1\x80\xa1" // U+F1021
+#define ICON_MDI_COMMENT_QUOTE_OUTLINE "\xf3\xb1\x80\xa2" // U+F1022
+#define ICON_MDI_COMMENT_REMOVE "\xf3\xb0\x97\x9e" // U+F05DE
+#define ICON_MDI_COMMENT_REMOVE_OUTLINE "\xf3\xb0\x86\x87" // U+F0187
+#define ICON_MDI_COMMENT_SEARCH "\xf3\xb0\xa8\xbc" // U+F0A3C
+#define ICON_MDI_COMMENT_SEARCH_OUTLINE "\xf3\xb0\xa8\xbd" // U+F0A3D
+#define ICON_MDI_COMMENT_TEXT "\xf3\xb0\x86\x88" // U+F0188
+#define ICON_MDI_COMMENT_TEXT_MULTIPLE "\xf3\xb0\xa1\xa0" // U+F0860
+#define ICON_MDI_COMMENT_TEXT_MULTIPLE_OUTLINE "\xf3\xb0\xa1\xa1" // U+F0861
+#define ICON_MDI_COMMENT_TEXT_OUTLINE "\xf3\xb0\x86\x89" // U+F0189
+#define ICON_MDI_COMPARE "\xf3\xb0\x86\x8a" // U+F018A
+#define ICON_MDI_COMPARE_HORIZONTAL "\xf3\xb1\x92\x92" // U+F1492
+#define ICON_MDI_COMPARE_REMOVE "\xf3\xb1\xa2\xb3" // U+F18B3
+#define ICON_MDI_COMPARE_VERTICAL "\xf3\xb1\x92\x93" // U+F1493
+#define ICON_MDI_COMPASS "\xf3\xb0\x86\x8b" // U+F018B
+#define ICON_MDI_COMPASS_OFF "\xf3\xb0\xae\x80" // U+F0B80
+#define ICON_MDI_COMPASS_OFF_OUTLINE "\xf3\xb0\xae\x81" // U+F0B81
+#define ICON_MDI_COMPASS_OUTLINE "\xf3\xb0\x86\x8c" // U+F018C
+#define ICON_MDI_COMPASS_ROSE "\xf3\xb1\x8e\x82" // U+F1382
+#define ICON_MDI_COMPOST "\xf3\xb1\xa8\xb8" // U+F1A38
+#define ICON_MDI_CONE "\xf3\xb1\xa5\x8c" // U+F194C
+#define ICON_MDI_CONE_OFF "\xf3\xb1\xa5\x8d" // U+F194D
+#define ICON_MDI_CONNECTION "\xf3\xb1\x98\x96" // U+F1616
+#define ICON_MDI_CONSOLE "\xf3\xb0\x86\x8d" // U+F018D
+#define ICON_MDI_CONSOLE_LINE "\xf3\xb0\x9e\xb7" // U+F07B7
+#define ICON_MDI_CONSOLE_NETWORK "\xf3\xb0\xa2\xa9" // U+F08A9
+#define ICON_MDI_CONSOLE_NETWORK_OUTLINE "\xf3\xb0\xb1\xa0" // U+F0C60
+#define ICON_MDI_CONSOLIDATE "\xf3\xb1\x83\x98" // U+F10D8
+#define ICON_MDI_CONTACTLESS_PAYMENT "\xf3\xb0\xb5\xaa" // U+F0D6A
+#define ICON_MDI_CONTACTLESS_PAYMENT_CIRCLE "\xf3\xb0\x8c\xa1" // U+F0321
+#define ICON_MDI_CONTACTLESS_PAYMENT_CIRCLE_OUTLINE "\xf3\xb0\x90\x88" // U+F0408
+#define ICON_MDI_CONTACTS "\xf3\xb0\x9b\x8b" // U+F06CB
+#define ICON_MDI_CONTACTS_OUTLINE "\xf3\xb0\x96\xb8" // U+F05B8
+#define ICON_MDI_CONTAIN "\xf3\xb0\xa8\xbe" // U+F0A3E
+#define ICON_MDI_CONTAIN_END "\xf3\xb0\xa8\xbf" // U+F0A3F
+#define ICON_MDI_CONTAIN_START "\xf3\xb0\xa9\x80" // U+F0A40
+#define ICON_MDI_CONTENT_COPY "\xf3\xb0\x86\x8f" // U+F018F
+#define ICON_MDI_CONTENT_CUT "\xf3\xb0\x86\x90" // U+F0190
+#define ICON_MDI_CONTENT_DUPLICATE "\xf3\xb0\x86\x91" // U+F0191
+#define ICON_MDI_CONTENT_PASTE "\xf3\xb0\x86\x92" // U+F0192
+#define ICON_MDI_CONTENT_SAVE "\xf3\xb0\x86\x93" // U+F0193
+#define ICON_MDI_CONTENT_SAVE_ALERT "\xf3\xb0\xbd\x82" // U+F0F42
+#define ICON_MDI_CONTENT_SAVE_ALERT_OUTLINE "\xf3\xb0\xbd\x83" // U+F0F43
+#define ICON_MDI_CONTENT_SAVE_ALL "\xf3\xb0\x86\x94" // U+F0194
+#define ICON_MDI_CONTENT_SAVE_ALL_OUTLINE "\xf3\xb0\xbd\x84" // U+F0F44
+#define ICON_MDI_CONTENT_SAVE_CHECK "\xf3\xb1\xa3\xaa" // U+F18EA
+#define ICON_MDI_CONTENT_SAVE_CHECK_OUTLINE "\xf3\xb1\xa3\xab" // U+F18EB
+#define ICON_MDI_CONTENT_SAVE_COG "\xf3\xb1\x91\x9b" // U+F145B
+#define ICON_MDI_CONTENT_SAVE_COG_OUTLINE "\xf3\xb1\x91\x9c" // U+F145C
+#define ICON_MDI_CONTENT_SAVE_EDIT "\xf3\xb0\xb3\xbb" // U+F0CFB
+#define ICON_MDI_CONTENT_SAVE_EDIT_OUTLINE "\xf3\xb0\xb3\xbc" // U+F0CFC
+#define ICON_MDI_CONTENT_SAVE_MINUS "\xf3\xb1\xad\x83" // U+F1B43
+#define ICON_MDI_CONTENT_SAVE_MINUS_OUTLINE "\xf3\xb1\xad\x84" // U+F1B44
+#define ICON_MDI_CONTENT_SAVE_MOVE "\xf3\xb0\xb8\xa7" // U+F0E27
+#define ICON_MDI_CONTENT_SAVE_MOVE_OUTLINE "\xf3\xb0\xb8\xa8" // U+F0E28
+#define ICON_MDI_CONTENT_SAVE_OFF "\xf3\xb1\x99\x83" // U+F1643
+#define ICON_MDI_CONTENT_SAVE_OFF_OUTLINE "\xf3\xb1\x99\x84" // U+F1644
+#define ICON_MDI_CONTENT_SAVE_OUTLINE "\xf3\xb0\xa0\x98" // U+F0818
+#define ICON_MDI_CONTENT_SAVE_PLUS "\xf3\xb1\xad\x81" // U+F1B41
+#define ICON_MDI_CONTENT_SAVE_PLUS_OUTLINE "\xf3\xb1\xad\x82" // U+F1B42
+#define ICON_MDI_CONTENT_SAVE_SETTINGS "\xf3\xb0\x98\x9b" // U+F061B
+#define ICON_MDI_CONTENT_SAVE_SETTINGS_OUTLINE "\xf3\xb0\xac\xae" // U+F0B2E
+#define ICON_MDI_CONTRAST "\xf3\xb0\x86\x95" // U+F0195
+#define ICON_MDI_CONTRAST_BOX "\xf3\xb0\x86\x96" // U+F0196
+#define ICON_MDI_CONTRAST_CIRCLE "\xf3\xb0\x86\x97" // U+F0197
+#define ICON_MDI_CONTROLLER "\xf3\xb0\x8a\xb4" // U+F02B4
+#define ICON_MDI_CONTROLLER_CLASSIC "\xf3\xb0\xae\x82" // U+F0B82
+#define ICON_MDI_CONTROLLER_CLASSIC_OUTLINE "\xf3\xb0\xae\x83" // U+F0B83
+#define ICON_MDI_CONTROLLER_OFF "\xf3\xb0\x8a\xb5" // U+F02B5
+#define ICON_MDI_COOKIE "\xf3\xb0\x86\x98" // U+F0198
+#define ICON_MDI_COOKIE_ALERT "\xf3\xb1\x9b\x90" // U+F16D0
+#define ICON_MDI_COOKIE_ALERT_OUTLINE "\xf3\xb1\x9b\x91" // U+F16D1
+#define ICON_MDI_COOKIE_CHECK "\xf3\xb1\x9b\x92" // U+F16D2
+#define ICON_MDI_COOKIE_CHECK_OUTLINE "\xf3\xb1\x9b\x93" // U+F16D3
+#define ICON_MDI_COOKIE_CLOCK "\xf3\xb1\x9b\xa4" // U+F16E4
+#define ICON_MDI_COOKIE_CLOCK_OUTLINE "\xf3\xb1\x9b\xa5" // U+F16E5
+#define ICON_MDI_COOKIE_COG "\xf3\xb1\x9b\x94" // U+F16D4
+#define ICON_MDI_COOKIE_COG_OUTLINE "\xf3\xb1\x9b\x95" // U+F16D5
+#define ICON_MDI_COOKIE_EDIT "\xf3\xb1\x9b\xa6" // U+F16E6
+#define ICON_MDI_COOKIE_EDIT_OUTLINE "\xf3\xb1\x9b\xa7" // U+F16E7
+#define ICON_MDI_COOKIE_LOCK "\xf3\xb1\x9b\xa8" // U+F16E8
+#define ICON_MDI_COOKIE_LOCK_OUTLINE "\xf3\xb1\x9b\xa9" // U+F16E9
+#define ICON_MDI_COOKIE_MINUS "\xf3\xb1\x9b\x9a" // U+F16DA
+#define ICON_MDI_COOKIE_MINUS_OUTLINE "\xf3\xb1\x9b\x9b" // U+F16DB
+#define ICON_MDI_COOKIE_OFF "\xf3\xb1\x9b\xaa" // U+F16EA
+#define ICON_MDI_COOKIE_OFF_OUTLINE "\xf3\xb1\x9b\xab" // U+F16EB
+#define ICON_MDI_COOKIE_OUTLINE "\xf3\xb1\x9b\x9e" // U+F16DE
+#define ICON_MDI_COOKIE_PLUS "\xf3\xb1\x9b\x96" // U+F16D6
+#define ICON_MDI_COOKIE_PLUS_OUTLINE "\xf3\xb1\x9b\x97" // U+F16D7
+#define ICON_MDI_COOKIE_REFRESH "\xf3\xb1\x9b\xac" // U+F16EC
+#define ICON_MDI_COOKIE_REFRESH_OUTLINE "\xf3\xb1\x9b\xad" // U+F16ED
+#define ICON_MDI_COOKIE_REMOVE "\xf3\xb1\x9b\x98" // U+F16D8
+#define ICON_MDI_COOKIE_REMOVE_OUTLINE "\xf3\xb1\x9b\x99" // U+F16D9
+#define ICON_MDI_COOKIE_SETTINGS "\xf3\xb1\x9b\x9c" // U+F16DC
+#define ICON_MDI_COOKIE_SETTINGS_OUTLINE "\xf3\xb1\x9b\x9d" // U+F16DD
+#define ICON_MDI_COOLANT_TEMPERATURE "\xf3\xb0\x8f\x88" // U+F03C8
+#define ICON_MDI_COPYLEFT "\xf3\xb1\xa4\xb9" // U+F1939
+#define ICON_MDI_COPYRIGHT "\xf3\xb0\x97\xa6" // U+F05E6
+#define ICON_MDI_CORDOVA "\xf3\xb0\xa5\x98" // U+F0958
+#define ICON_MDI_CORN "\xf3\xb0\x9e\xb8" // U+F07B8
+#define ICON_MDI_CORN_OFF "\xf3\xb1\x8f\xaf" // U+F13EF
+#define ICON_MDI_COSINE_WAVE "\xf3\xb1\x91\xb9" // U+F1479
+#define ICON_MDI_COUNTER "\xf3\xb0\x86\x99" // U+F0199
+#define ICON_MDI_COUNTERTOP "\xf3\xb1\xa0\x9c" // U+F181C
+#define ICON_MDI_COUNTERTOP_OUTLINE "\xf3\xb1\xa0\x9d" // U+F181D
+#define ICON_MDI_COW "\xf3\xb0\x86\x9a" // U+F019A
+#define ICON_MDI_COW_OFF "\xf3\xb1\xa3\xbc" // U+F18FC
+#define ICON_MDI_CPU_32_BIT "\xf3\xb0\xbb\x9f" // U+F0EDF
+#define ICON_MDI_CPU_64_BIT "\xf3\xb0\xbb\xa0" // U+F0EE0
+#define ICON_MDI_CRADLE "\xf3\xb1\xa6\x8b" // U+F198B
+#define ICON_MDI_CRADLE_OUTLINE "\xf3\xb1\xa6\x91" // U+F1991
+#define ICON_MDI_CRANE "\xf3\xb0\xa1\xa2" // U+F0862
+#define ICON_MDI_CREATION "\xf3\xb0\x99\xb4" // U+F0674
+#define ICON_MDI_CREATION_OUTLINE "\xf3\xb1\xb0\xab" // U+F1C2B
+#define ICON_MDI_CREATIVE_COMMONS "\xf3\xb0\xb5\xab" // U+F0D6B
+#define ICON_MDI_CREDIT_CARD "\xf3\xb0\xbf\xaf" // U+F0FEF
+#define ICON_MDI_CREDIT_CARD_CHECK "\xf3\xb1\x8f\x90" // U+F13D0
+#define ICON_MDI_CREDIT_CARD_CHECK_OUTLINE "\xf3\xb1\x8f\x91" // U+F13D1
+#define ICON_MDI_CREDIT_CARD_CHIP "\xf3\xb1\xa4\x8f" // U+F190F
+#define ICON_MDI_CREDIT_CARD_CHIP_OUTLINE "\xf3\xb1\xa4\x90" // U+F1910
+#define ICON_MDI_CREDIT_CARD_CLOCK "\xf3\xb0\xbb\xa1" // U+F0EE1
+#define ICON_MDI_CREDIT_CARD_CLOCK_OUTLINE "\xf3\xb0\xbb\xa2" // U+F0EE2
+#define ICON_MDI_CREDIT_CARD_EDIT "\xf3\xb1\x9f\x97" // U+F17D7
+#define ICON_MDI_CREDIT_CARD_EDIT_OUTLINE "\xf3\xb1\x9f\x98" // U+F17D8
+#define ICON_MDI_CREDIT_CARD_FAST "\xf3\xb1\xa4\x91" // U+F1911
+#define ICON_MDI_CREDIT_CARD_FAST_OUTLINE "\xf3\xb1\xa4\x92" // U+F1912
+#define ICON_MDI_CREDIT_CARD_LOCK "\xf3\xb1\xa3\xa7" // U+F18E7
+#define ICON_MDI_CREDIT_CARD_LOCK_OUTLINE "\xf3\xb1\xa3\xa8" // U+F18E8
+#define ICON_MDI_CREDIT_CARD_MARKER "\xf3\xb0\x9a\xa8" // U+F06A8
+#define ICON_MDI_CREDIT_CARD_MARKER_OUTLINE "\xf3\xb0\xb6\xbe" // U+F0DBE
+#define ICON_MDI_CREDIT_CARD_MINUS "\xf3\xb0\xbe\xac" // U+F0FAC
+#define ICON_MDI_CREDIT_CARD_MINUS_OUTLINE "\xf3\xb0\xbe\xad" // U+F0FAD
+#define ICON_MDI_CREDIT_CARD_MULTIPLE "\xf3\xb0\xbf\xb0" // U+F0FF0
+#define ICON_MDI_CREDIT_CARD_MULTIPLE_OUTLINE "\xf3\xb0\x86\x9c" // U+F019C
+#define ICON_MDI_CREDIT_CARD_OFF "\xf3\xb0\xbf\xb1" // U+F0FF1
+#define ICON_MDI_CREDIT_CARD_OFF_OUTLINE "\xf3\xb0\x97\xa4" // U+F05E4
+#define ICON_MDI_CREDIT_CARD_OUTLINE "\xf3\xb0\x86\x9b" // U+F019B
+#define ICON_MDI_CREDIT_CARD_PLUS "\xf3\xb0\xbf\xb2" // U+F0FF2
+#define ICON_MDI_CREDIT_CARD_PLUS_OUTLINE "\xf3\xb0\x99\xb6" // U+F0676
+#define ICON_MDI_CREDIT_CARD_REFRESH "\xf3\xb1\x99\x85" // U+F1645
+#define ICON_MDI_CREDIT_CARD_REFRESH_OUTLINE "\xf3\xb1\x99\x86" // U+F1646
+#define ICON_MDI_CREDIT_CARD_REFUND "\xf3\xb0\xbf\xb3" // U+F0FF3
+#define ICON_MDI_CREDIT_CARD_REFUND_OUTLINE "\xf3\xb0\xaa\xa8" // U+F0AA8
+#define ICON_MDI_CREDIT_CARD_REMOVE "\xf3\xb0\xbe\xae" // U+F0FAE
+#define ICON_MDI_CREDIT_CARD_REMOVE_OUTLINE "\xf3\xb0\xbe\xaf" // U+F0FAF
+#define ICON_MDI_CREDIT_CARD_SCAN "\xf3\xb0\xbf\xb4" // U+F0FF4
+#define ICON_MDI_CREDIT_CARD_SCAN_OUTLINE "\xf3\xb0\x86\x9d" // U+F019D
+#define ICON_MDI_CREDIT_CARD_SEARCH "\xf3\xb1\x99\x87" // U+F1647
+#define ICON_MDI_CREDIT_CARD_SEARCH_OUTLINE "\xf3\xb1\x99\x88" // U+F1648
+#define ICON_MDI_CREDIT_CARD_SETTINGS "\xf3\xb0\xbf\xb5" // U+F0FF5
+#define ICON_MDI_CREDIT_CARD_SETTINGS_OUTLINE "\xf3\xb0\xa3\x97" // U+F08D7
+#define ICON_MDI_CREDIT_CARD_SYNC "\xf3\xb1\x99\x89" // U+F1649
+#define ICON_MDI_CREDIT_CARD_SYNC_OUTLINE "\xf3\xb1\x99\x8a" // U+F164A
+#define ICON_MDI_CREDIT_CARD_WIRELESS "\xf3\xb0\xa0\x82" // U+F0802
+#define ICON_MDI_CREDIT_CARD_WIRELESS_OFF "\xf3\xb0\x95\xba" // U+F057A
+#define ICON_MDI_CREDIT_CARD_WIRELESS_OFF_OUTLINE "\xf3\xb0\x95\xbb" // U+F057B
+#define ICON_MDI_CREDIT_CARD_WIRELESS_OUTLINE "\xf3\xb0\xb5\xac" // U+F0D6C
+#define ICON_MDI_CRICKET "\xf3\xb0\xb5\xad" // U+F0D6D
+#define ICON_MDI_CROP "\xf3\xb0\x86\x9e" // U+F019E
+#define ICON_MDI_CROP_FREE "\xf3\xb0\x86\x9f" // U+F019F
+#define ICON_MDI_CROP_LANDSCAPE "\xf3\xb0\x86\xa0" // U+F01A0
+#define ICON_MDI_CROP_PORTRAIT "\xf3\xb0\x86\xa1" // U+F01A1
+#define ICON_MDI_CROP_ROTATE "\xf3\xb0\x9a\x96" // U+F0696
+#define ICON_MDI_CROP_SQUARE "\xf3\xb0\x86\xa2" // U+F01A2
+#define ICON_MDI_CROSS "\xf3\xb0\xa5\x93" // U+F0953
+#define ICON_MDI_CROSS_BOLNISI "\xf3\xb0\xb3\xad" // U+F0CED
+#define ICON_MDI_CROSS_CELTIC "\xf3\xb0\xb3\xb5" // U+F0CF5
+#define ICON_MDI_CROSS_OUTLINE "\xf3\xb0\xb3\xb6" // U+F0CF6
+#define ICON_MDI_CROSSHAIRS "\xf3\xb0\x86\xa3" // U+F01A3
+#define ICON_MDI_CROSSHAIRS_GPS "\xf3\xb0\x86\xa4" // U+F01A4
+#define ICON_MDI_CROSSHAIRS_OFF "\xf3\xb0\xbd\x85" // U+F0F45
+#define ICON_MDI_CROSSHAIRS_QUESTION "\xf3\xb1\x84\xb6" // U+F1136
+#define ICON_MDI_CROWD "\xf3\xb1\xa5\xb5" // U+F1975
+#define ICON_MDI_CROWN "\xf3\xb0\x86\xa5" // U+F01A5
+#define ICON_MDI_CROWN_CIRCLE "\xf3\xb1\x9f\x9c" // U+F17DC
+#define ICON_MDI_CROWN_CIRCLE_OUTLINE "\xf3\xb1\x9f\x9d" // U+F17DD
+#define ICON_MDI_CROWN_OUTLINE "\xf3\xb1\x87\x90" // U+F11D0
+#define ICON_MDI_CRYENGINE "\xf3\xb0\xa5\x99" // U+F0959
+#define ICON_MDI_CRYSTAL_BALL "\xf3\xb0\xac\xaf" // U+F0B2F
+#define ICON_MDI_CUBE "\xf3\xb0\x86\xa6" // U+F01A6
+#define ICON_MDI_CUBE_OFF "\xf3\xb1\x90\x9c" // U+F141C
+#define ICON_MDI_CUBE_OFF_OUTLINE "\xf3\xb1\x90\x9d" // U+F141D
+#define ICON_MDI_CUBE_OUTLINE "\xf3\xb0\x86\xa7" // U+F01A7
+#define ICON_MDI_CUBE_SCAN "\xf3\xb0\xae\x84" // U+F0B84
+#define ICON_MDI_CUBE_SEND "\xf3\xb0\x86\xa8" // U+F01A8
+#define ICON_MDI_CUBE_UNFOLDED "\xf3\xb0\x86\xa9" // U+F01A9
+#define ICON_MDI_CUP "\xf3\xb0\x86\xaa" // U+F01AA
+#define ICON_MDI_CUP_OFF "\xf3\xb0\x97\xa5" // U+F05E5
+#define ICON_MDI_CUP_OFF_OUTLINE "\xf3\xb1\x8d\xbd" // U+F137D
+#define ICON_MDI_CUP_OUTLINE "\xf3\xb1\x8c\x8f" // U+F130F
+#define ICON_MDI_CUP_WATER "\xf3\xb0\x86\xab" // U+F01AB
+#define ICON_MDI_CUPBOARD "\xf3\xb0\xbd\x86" // U+F0F46
+#define ICON_MDI_CUPBOARD_OUTLINE "\xf3\xb0\xbd\x87" // U+F0F47
+#define ICON_MDI_CUPCAKE "\xf3\xb0\xa5\x9a" // U+F095A
+#define ICON_MDI_CURLING "\xf3\xb0\xa1\xa3" // U+F0863
+#define ICON_MDI_CURRENCY_BDT "\xf3\xb0\xa1\xa4" // U+F0864
+#define ICON_MDI_CURRENCY_BRL "\xf3\xb0\xae\x85" // U+F0B85
+#define ICON_MDI_CURRENCY_BTC "\xf3\xb0\x86\xac" // U+F01AC
+#define ICON_MDI_CURRENCY_CNY "\xf3\xb0\x9e\xba" // U+F07BA
+#define ICON_MDI_CURRENCY_ETH "\xf3\xb0\x9e\xbb" // U+F07BB
+#define ICON_MDI_CURRENCY_EUR "\xf3\xb0\x86\xad" // U+F01AD
+#define ICON_MDI_CURRENCY_EUR_OFF "\xf3\xb1\x8c\x95" // U+F1315
+#define ICON_MDI_CURRENCY_FRA "\xf3\xb1\xa8\xb9" // U+F1A39
+#define ICON_MDI_CURRENCY_GBP "\xf3\xb0\x86\xae" // U+F01AE
+#define ICON_MDI_CURRENCY_ILS "\xf3\xb0\xb1\xa1" // U+F0C61
+#define ICON_MDI_CURRENCY_INR "\xf3\xb0\x86\xaf" // U+F01AF
+#define ICON_MDI_CURRENCY_JPY "\xf3\xb0\x9e\xbc" // U+F07BC
+#define ICON_MDI_CURRENCY_KRW "\xf3\xb0\x9e\xbd" // U+F07BD
+#define ICON_MDI_CURRENCY_KZT "\xf3\xb0\xa1\xa5" // U+F0865
+#define ICON_MDI_CURRENCY_MNT "\xf3\xb1\x94\x92" // U+F1512
+#define ICON_MDI_CURRENCY_NGN "\xf3\xb0\x86\xb0" // U+F01B0
+#define ICON_MDI_CURRENCY_PHP "\xf3\xb0\xa7\xa6" // U+F09E6
+#define ICON_MDI_CURRENCY_RIAL "\xf3\xb0\xba\x9c" // U+F0E9C
+#define ICON_MDI_CURRENCY_RUB "\xf3\xb0\x86\xb1" // U+F01B1
+#define ICON_MDI_CURRENCY_RUPEE "\xf3\xb1\xa5\xb6" // U+F1976
+#define ICON_MDI_CURRENCY_SIGN "\xf3\xb0\x9e\xbe" // U+F07BE
+#define ICON_MDI_CURRENCY_THB "\xf3\xb1\xb0\x85" // U+F1C05
+#define ICON_MDI_CURRENCY_TRY "\xf3\xb0\x86\xb2" // U+F01B2
+#define ICON_MDI_CURRENCY_TWD "\xf3\xb0\x9e\xbf" // U+F07BF
+#define ICON_MDI_CURRENCY_UAH "\xf3\xb1\xae\x9b" // U+F1B9B
+#define ICON_MDI_CURRENCY_USD "\xf3\xb0\x87\x81" // U+F01C1
+#define ICON_MDI_CURRENCY_USD_OFF "\xf3\xb0\x99\xba" // U+F067A
+#define ICON_MDI_CURRENT_AC "\xf3\xb1\x92\x80" // U+F1480
+#define ICON_MDI_CURRENT_DC "\xf3\xb0\xa5\x9c" // U+F095C
+#define ICON_MDI_CURSOR_DEFAULT "\xf3\xb0\x87\x80" // U+F01C0
+#define ICON_MDI_CURSOR_DEFAULT_CLICK "\xf3\xb0\xb3\xbd" // U+F0CFD
+#define ICON_MDI_CURSOR_DEFAULT_CLICK_OUTLINE "\xf3\xb0\xb3\xbe" // U+F0CFE
+#define ICON_MDI_CURSOR_DEFAULT_GESTURE "\xf3\xb1\x84\xa7" // U+F1127
+#define ICON_MDI_CURSOR_DEFAULT_GESTURE_OUTLINE "\xf3\xb1\x84\xa8" // U+F1128
+#define ICON_MDI_CURSOR_DEFAULT_OUTLINE "\xf3\xb0\x86\xbf" // U+F01BF
+#define ICON_MDI_CURSOR_MOVE "\xf3\xb0\x86\xbe" // U+F01BE
+#define ICON_MDI_CURSOR_POINTER "\xf3\xb0\x86\xbd" // U+F01BD
+#define ICON_MDI_CURSOR_TEXT "\xf3\xb0\x97\xa7" // U+F05E7
+#define ICON_MDI_CURTAINS "\xf3\xb1\xa1\x86" // U+F1846
+#define ICON_MDI_CURTAINS_CLOSED "\xf3\xb1\xa1\x87" // U+F1847
+#define ICON_MDI_CYLINDER "\xf3\xb1\xa5\x8e" // U+F194E
+#define ICON_MDI_CYLINDER_OFF "\xf3\xb1\xa5\x8f" // U+F194F
+#define ICON_MDI_DANCE_BALLROOM "\xf3\xb1\x97\xbb" // U+F15FB
+#define ICON_MDI_DANCE_POLE "\xf3\xb1\x95\xb8" // U+F1578
+#define ICON_MDI_DATA_MATRIX "\xf3\xb1\x94\xbc" // U+F153C
+#define ICON_MDI_DATA_MATRIX_EDIT "\xf3\xb1\x94\xbd" // U+F153D
+#define ICON_MDI_DATA_MATRIX_MINUS "\xf3\xb1\x94\xbe" // U+F153E
+#define ICON_MDI_DATA_MATRIX_PLUS "\xf3\xb1\x94\xbf" // U+F153F
+#define ICON_MDI_DATA_MATRIX_REMOVE "\xf3\xb1\x95\x80" // U+F1540
+#define ICON_MDI_DATA_MATRIX_SCAN "\xf3\xb1\x95\x81" // U+F1541
+#define ICON_MDI_DATABASE "\xf3\xb0\x86\xbc" // U+F01BC
+#define ICON_MDI_DATABASE_ALERT "\xf3\xb1\x98\xba" // U+F163A
+#define ICON_MDI_DATABASE_ALERT_OUTLINE "\xf3\xb1\x98\xa4" // U+F1624
+#define ICON_MDI_DATABASE_ARROW_DOWN "\xf3\xb1\x98\xbb" // U+F163B
+#define ICON_MDI_DATABASE_ARROW_DOWN_OUTLINE "\xf3\xb1\x98\xa5" // U+F1625
+#define ICON_MDI_DATABASE_ARROW_LEFT "\xf3\xb1\x98\xbc" // U+F163C
+#define ICON_MDI_DATABASE_ARROW_LEFT_OUTLINE "\xf3\xb1\x98\xa6" // U+F1626
+#define ICON_MDI_DATABASE_ARROW_RIGHT "\xf3\xb1\x98\xbd" // U+F163D
+#define ICON_MDI_DATABASE_ARROW_RIGHT_OUTLINE "\xf3\xb1\x98\xa7" // U+F1627
+#define ICON_MDI_DATABASE_ARROW_UP "\xf3\xb1\x98\xbe" // U+F163E
+#define ICON_MDI_DATABASE_ARROW_UP_OUTLINE "\xf3\xb1\x98\xa8" // U+F1628
+#define ICON_MDI_DATABASE_CHECK "\xf3\xb0\xaa\xa9" // U+F0AA9
+#define ICON_MDI_DATABASE_CHECK_OUTLINE "\xf3\xb1\x98\xa9" // U+F1629
+#define ICON_MDI_DATABASE_CLOCK "\xf3\xb1\x98\xbf" // U+F163F
+#define ICON_MDI_DATABASE_CLOCK_OUTLINE "\xf3\xb1\x98\xaa" // U+F162A
+#define ICON_MDI_DATABASE_COG "\xf3\xb1\x99\x8b" // U+F164B
+#define ICON_MDI_DATABASE_COG_OUTLINE "\xf3\xb1\x99\x8c" // U+F164C
+#define ICON_MDI_DATABASE_EDIT "\xf3\xb0\xae\x86" // U+F0B86
+#define ICON_MDI_DATABASE_EDIT_OUTLINE "\xf3\xb1\x98\xab" // U+F162B
+#define ICON_MDI_DATABASE_EXPORT "\xf3\xb0\xa5\x9e" // U+F095E
+#define ICON_MDI_DATABASE_EXPORT_OUTLINE "\xf3\xb1\x98\xac" // U+F162C
+#define ICON_MDI_DATABASE_EYE "\xf3\xb1\xa4\x9f" // U+F191F
+#define ICON_MDI_DATABASE_EYE_OFF "\xf3\xb1\xa4\xa0" // U+F1920
+#define ICON_MDI_DATABASE_EYE_OFF_OUTLINE "\xf3\xb1\xa4\xa1" // U+F1921
+#define ICON_MDI_DATABASE_EYE_OUTLINE "\xf3\xb1\xa4\xa2" // U+F1922
+#define ICON_MDI_DATABASE_IMPORT "\xf3\xb0\xa5\x9d" // U+F095D
+#define ICON_MDI_DATABASE_IMPORT_OUTLINE "\xf3\xb1\x98\xad" // U+F162D
+#define ICON_MDI_DATABASE_LOCK "\xf3\xb0\xaa\xaa" // U+F0AAA
+#define ICON_MDI_DATABASE_LOCK_OUTLINE "\xf3\xb1\x98\xae" // U+F162E
+#define ICON_MDI_DATABASE_MARKER "\xf3\xb1\x8b\xb6" // U+F12F6
+#define ICON_MDI_DATABASE_MARKER_OUTLINE "\xf3\xb1\x98\xaf" // U+F162F
+#define ICON_MDI_DATABASE_MINUS "\xf3\xb0\x86\xbb" // U+F01BB
+#define ICON_MDI_DATABASE_MINUS_OUTLINE "\xf3\xb1\x98\xb0" // U+F1630
+#define ICON_MDI_DATABASE_OFF "\xf3\xb1\x99\x80" // U+F1640
+#define ICON_MDI_DATABASE_OFF_OUTLINE "\xf3\xb1\x98\xb1" // U+F1631
+#define ICON_MDI_DATABASE_OUTLINE "\xf3\xb1\x98\xb2" // U+F1632
+#define ICON_MDI_DATABASE_PLUS "\xf3\xb0\x86\xba" // U+F01BA
+#define ICON_MDI_DATABASE_PLUS_OUTLINE "\xf3\xb1\x98\xb3" // U+F1633
+#define ICON_MDI_DATABASE_REFRESH "\xf3\xb0\x97\x82" // U+F05C2
+#define ICON_MDI_DATABASE_REFRESH_OUTLINE "\xf3\xb1\x98\xb4" // U+F1634
+#define ICON_MDI_DATABASE_REMOVE "\xf3\xb0\xb4\x80" // U+F0D00
+#define ICON_MDI_DATABASE_REMOVE_OUTLINE "\xf3\xb1\x98\xb5" // U+F1635
+#define ICON_MDI_DATABASE_SEARCH "\xf3\xb0\xa1\xa6" // U+F0866
+#define ICON_MDI_DATABASE_SEARCH_OUTLINE "\xf3\xb1\x98\xb6" // U+F1636
+#define ICON_MDI_DATABASE_SETTINGS "\xf3\xb0\xb4\x81" // U+F0D01
+#define ICON_MDI_DATABASE_SETTINGS_OUTLINE "\xf3\xb1\x98\xb7" // U+F1637
+#define ICON_MDI_DATABASE_SYNC "\xf3\xb0\xb3\xbf" // U+F0CFF
+#define ICON_MDI_DATABASE_SYNC_OUTLINE "\xf3\xb1\x98\xb8" // U+F1638
+#define ICON_MDI_DEATH_STAR "\xf3\xb0\xa3\x98" // U+F08D8
+#define ICON_MDI_DEATH_STAR_VARIANT "\xf3\xb0\xa3\x99" // U+F08D9
+#define ICON_MDI_DEATHLY_HALLOWS "\xf3\xb0\xae\x87" // U+F0B87
+#define ICON_MDI_DEBIAN "\xf3\xb0\xa3\x9a" // U+F08DA
+#define ICON_MDI_DEBUG_STEP_INTO "\xf3\xb0\x86\xb9" // U+F01B9
+#define ICON_MDI_DEBUG_STEP_OUT "\xf3\xb0\x86\xb8" // U+F01B8
+#define ICON_MDI_DEBUG_STEP_OVER "\xf3\xb0\x86\xb7" // U+F01B7
+#define ICON_MDI_DECAGRAM "\xf3\xb0\x9d\xac" // U+F076C
+#define ICON_MDI_DECAGRAM_OUTLINE "\xf3\xb0\x9d\xad" // U+F076D
+#define ICON_MDI_DECIMAL "\xf3\xb1\x82\xa1" // U+F10A1
+#define ICON_MDI_DECIMAL_COMMA "\xf3\xb1\x82\xa2" // U+F10A2
+#define ICON_MDI_DECIMAL_COMMA_DECREASE "\xf3\xb1\x82\xa3" // U+F10A3
+#define ICON_MDI_DECIMAL_COMMA_INCREASE "\xf3\xb1\x82\xa4" // U+F10A4
+#define ICON_MDI_DECIMAL_DECREASE "\xf3\xb0\x86\xb6" // U+F01B6
+#define ICON_MDI_DECIMAL_INCREASE "\xf3\xb0\x86\xb5" // U+F01B5
+#define ICON_MDI_DELETE "\xf3\xb0\x86\xb4" // U+F01B4
+#define ICON_MDI_DELETE_ALERT "\xf3\xb1\x82\xa5" // U+F10A5
+#define ICON_MDI_DELETE_ALERT_OUTLINE "\xf3\xb1\x82\xa6" // U+F10A6
+#define ICON_MDI_DELETE_CIRCLE "\xf3\xb0\x9a\x83" // U+F0683
+#define ICON_MDI_DELETE_CIRCLE_OUTLINE "\xf3\xb0\xae\x88" // U+F0B88
+#define ICON_MDI_DELETE_CLOCK "\xf3\xb1\x95\x96" // U+F1556
+#define ICON_MDI_DELETE_CLOCK_OUTLINE "\xf3\xb1\x95\x97" // U+F1557
+#define ICON_MDI_DELETE_EMPTY "\xf3\xb0\x9b\x8c" // U+F06CC
+#define ICON_MDI_DELETE_EMPTY_OUTLINE "\xf3\xb0\xba\x9d" // U+F0E9D
+#define ICON_MDI_DELETE_FOREVER "\xf3\xb0\x97\xa8" // U+F05E8
+#define ICON_MDI_DELETE_FOREVER_OUTLINE "\xf3\xb0\xae\x89" // U+F0B89
+#define ICON_MDI_DELETE_OFF "\xf3\xb1\x82\xa7" // U+F10A7
+#define ICON_MDI_DELETE_OFF_OUTLINE "\xf3\xb1\x82\xa8" // U+F10A8
+#define ICON_MDI_DELETE_OUTLINE "\xf3\xb0\xa7\xa7" // U+F09E7
+#define ICON_MDI_DELETE_RESTORE "\xf3\xb0\xa0\x99" // U+F0819
+#define ICON_MDI_DELETE_SWEEP "\xf3\xb0\x97\xa9" // U+F05E9
+#define ICON_MDI_DELETE_SWEEP_OUTLINE "\xf3\xb0\xb1\xa2" // U+F0C62
+#define ICON_MDI_DELETE_VARIANT "\xf3\xb0\x86\xb3" // U+F01B3
+#define ICON_MDI_DELTA "\xf3\xb0\x87\x82" // U+F01C2
+#define ICON_MDI_DESK "\xf3\xb1\x88\xb9" // U+F1239
+#define ICON_MDI_DESK_LAMP "\xf3\xb0\xa5\x9f" // U+F095F
+#define ICON_MDI_DESK_LAMP_OFF "\xf3\xb1\xac\x9f" // U+F1B1F
+#define ICON_MDI_DESK_LAMP_ON "\xf3\xb1\xac\xa0" // U+F1B20
+#define ICON_MDI_DESKPHONE "\xf3\xb0\x87\x83" // U+F01C3
+#define ICON_MDI_DESKTOP_CLASSIC "\xf3\xb0\x9f\x80" // U+F07C0
+#define ICON_MDI_DESKTOP_TOWER "\xf3\xb0\x87\x85" // U+F01C5
+#define ICON_MDI_DESKTOP_TOWER_MONITOR "\xf3\xb0\xaa\xab" // U+F0AAB
+#define ICON_MDI_DETAILS "\xf3\xb0\x87\x86" // U+F01C6
+#define ICON_MDI_DEV_TO "\xf3\xb0\xb5\xae" // U+F0D6E
+#define ICON_MDI_DEVELOPER_BOARD "\xf3\xb0\x9a\x97" // U+F0697
+#define ICON_MDI_DEVIANTART "\xf3\xb0\x87\x87" // U+F01C7
+#define ICON_MDI_DEVICES "\xf3\xb0\xbe\xb0" // U+F0FB0
+#define ICON_MDI_DHARMACHAKRA "\xf3\xb0\xa5\x8b" // U+F094B
+#define ICON_MDI_DIABETES "\xf3\xb1\x84\xa6" // U+F1126
+#define ICON_MDI_DIALPAD "\xf3\xb0\x98\x9c" // U+F061C
+#define ICON_MDI_DIAMETER "\xf3\xb0\xb1\xa3" // U+F0C63
+#define ICON_MDI_DIAMETER_OUTLINE "\xf3\xb0\xb1\xa4" // U+F0C64
+#define ICON_MDI_DIAMETER_VARIANT "\xf3\xb0\xb1\xa5" // U+F0C65
+#define ICON_MDI_DIAMOND "\xf3\xb0\xae\x8a" // U+F0B8A
+#define ICON_MDI_DIAMOND_OUTLINE "\xf3\xb0\xae\x8b" // U+F0B8B
+#define ICON_MDI_DIAMOND_STONE "\xf3\xb0\x87\x88" // U+F01C8
+#define ICON_MDI_DICE_1 "\xf3\xb0\x87\x8a" // U+F01CA
+#define ICON_MDI_DICE_1_OUTLINE "\xf3\xb1\x85\x8a" // U+F114A
+#define ICON_MDI_DICE_2 "\xf3\xb0\x87\x8b" // U+F01CB
+#define ICON_MDI_DICE_2_OUTLINE "\xf3\xb1\x85\x8b" // U+F114B
+#define ICON_MDI_DICE_3 "\xf3\xb0\x87\x8c" // U+F01CC
+#define ICON_MDI_DICE_3_OUTLINE "\xf3\xb1\x85\x8c" // U+F114C
+#define ICON_MDI_DICE_4 "\xf3\xb0\x87\x8d" // U+F01CD
+#define ICON_MDI_DICE_4_OUTLINE "\xf3\xb1\x85\x8d" // U+F114D
+#define ICON_MDI_DICE_5 "\xf3\xb0\x87\x8e" // U+F01CE
+#define ICON_MDI_DICE_5_OUTLINE "\xf3\xb1\x85\x8e" // U+F114E
+#define ICON_MDI_DICE_6 "\xf3\xb0\x87\x8f" // U+F01CF
+#define ICON_MDI_DICE_6_OUTLINE "\xf3\xb1\x85\x8f" // U+F114F
+#define ICON_MDI_DICE_D10 "\xf3\xb1\x85\x93" // U+F1153
+#define ICON_MDI_DICE_D10_OUTLINE "\xf3\xb0\x9d\xaf" // U+F076F
+#define ICON_MDI_DICE_D12 "\xf3\xb1\x85\x94" // U+F1154
+#define ICON_MDI_DICE_D12_OUTLINE "\xf3\xb0\xa1\xa7" // U+F0867
+#define ICON_MDI_DICE_D20 "\xf3\xb1\x85\x95" // U+F1155
+#define ICON_MDI_DICE_D20_OUTLINE "\xf3\xb0\x97\xaa" // U+F05EA
+#define ICON_MDI_DICE_D4 "\xf3\xb1\x85\x90" // U+F1150
+#define ICON_MDI_DICE_D4_OUTLINE "\xf3\xb0\x97\xab" // U+F05EB
+#define ICON_MDI_DICE_D6 "\xf3\xb1\x85\x91" // U+F1151
+#define ICON_MDI_DICE_D6_OUTLINE "\xf3\xb0\x97\xad" // U+F05ED
+#define ICON_MDI_DICE_D8 "\xf3\xb1\x85\x92" // U+F1152
+#define ICON_MDI_DICE_D8_OUTLINE "\xf3\xb0\x97\xac" // U+F05EC
+#define ICON_MDI_DICE_MULTIPLE "\xf3\xb0\x9d\xae" // U+F076E
+#define ICON_MDI_DICE_MULTIPLE_OUTLINE "\xf3\xb1\x85\x96" // U+F1156
+#define ICON_MDI_DIGITAL_OCEAN "\xf3\xb1\x88\xb7" // U+F1237
+#define ICON_MDI_DIP_SWITCH "\xf3\xb0\x9f\x81" // U+F07C1
+#define ICON_MDI_DIRECTIONS "\xf3\xb0\x87\x90" // U+F01D0
+#define ICON_MDI_DIRECTIONS_FORK "\xf3\xb0\x99\x81" // U+F0641
+#define ICON_MDI_DISC "\xf3\xb0\x97\xae" // U+F05EE
+#define ICON_MDI_DISC_ALERT "\xf3\xb0\x87\x91" // U+F01D1
+#define ICON_MDI_DISC_PLAYER "\xf3\xb0\xa5\xa0" // U+F0960
+#define ICON_MDI_DISHWASHER "\xf3\xb0\xaa\xac" // U+F0AAC
+#define ICON_MDI_DISHWASHER_ALERT "\xf3\xb1\x86\xb8" // U+F11B8
+#define ICON_MDI_DISHWASHER_OFF "\xf3\xb1\x86\xb9" // U+F11B9
+#define ICON_MDI_DISQUS "\xf3\xb0\x87\x92" // U+F01D2
+#define ICON_MDI_DISTRIBUTE_HORIZONTAL_CENTER "\xf3\xb1\x87\x89" // U+F11C9
+#define ICON_MDI_DISTRIBUTE_HORIZONTAL_LEFT "\xf3\xb1\x87\x88" // U+F11C8
+#define ICON_MDI_DISTRIBUTE_HORIZONTAL_RIGHT "\xf3\xb1\x87\x8a" // U+F11CA
+#define ICON_MDI_DISTRIBUTE_VERTICAL_BOTTOM "\xf3\xb1\x87\x8b" // U+F11CB
+#define ICON_MDI_DISTRIBUTE_VERTICAL_CENTER "\xf3\xb1\x87\x8c" // U+F11CC
+#define ICON_MDI_DISTRIBUTE_VERTICAL_TOP "\xf3\xb1\x87\x8d" // U+F11CD
+#define ICON_MDI_DIVERSIFY "\xf3\xb1\xa1\xb7" // U+F1877
+#define ICON_MDI_DIVING "\xf3\xb1\xa5\xb7" // U+F1977
+#define ICON_MDI_DIVING_FLIPPERS "\xf3\xb0\xb6\xbf" // U+F0DBF
+#define ICON_MDI_DIVING_HELMET "\xf3\xb0\xb7\x80" // U+F0DC0
+#define ICON_MDI_DIVING_SCUBA "\xf3\xb1\xad\xb7" // U+F1B77
+#define ICON_MDI_DIVING_SCUBA_FLAG "\xf3\xb0\xb7\x82" // U+F0DC2
+#define ICON_MDI_DIVING_SCUBA_MASK "\xf3\xb0\xb7\x81" // U+F0DC1
+#define ICON_MDI_DIVING_SCUBA_TANK "\xf3\xb0\xb7\x83" // U+F0DC3
+#define ICON_MDI_DIVING_SCUBA_TANK_MULTIPLE "\xf3\xb0\xb7\x84" // U+F0DC4
+#define ICON_MDI_DIVING_SNORKEL "\xf3\xb0\xb7\x85" // U+F0DC5
+#define ICON_MDI_DIVISION "\xf3\xb0\x87\x94" // U+F01D4
+#define ICON_MDI_DIVISION_BOX "\xf3\xb0\x87\x95" // U+F01D5
+#define ICON_MDI_DLNA "\xf3\xb0\xa9\x81" // U+F0A41
+#define ICON_MDI_DNA "\xf3\xb0\x9a\x84" // U+F0684
+#define ICON_MDI_DNS "\xf3\xb0\x87\x96" // U+F01D6
+#define ICON_MDI_DNS_OUTLINE "\xf3\xb0\xae\x8c" // U+F0B8C
+#define ICON_MDI_DOCK_BOTTOM "\xf3\xb1\x82\xa9" // U+F10A9
+#define ICON_MDI_DOCK_LEFT "\xf3\xb1\x82\xaa" // U+F10AA
+#define ICON_MDI_DOCK_RIGHT "\xf3\xb1\x82\xab" // U+F10AB
+#define ICON_MDI_DOCK_TOP "\xf3\xb1\x94\x93" // U+F1513
+#define ICON_MDI_DOCK_WINDOW "\xf3\xb1\x82\xac" // U+F10AC
+#define ICON_MDI_DOCKER "\xf3\xb0\xa1\xa8" // U+F0868
+#define ICON_MDI_DOCTOR "\xf3\xb0\xa9\x82" // U+F0A42
+#define ICON_MDI_DOG "\xf3\xb0\xa9\x83" // U+F0A43
+#define ICON_MDI_DOG_SERVICE "\xf3\xb0\xaa\xad" // U+F0AAD
+#define ICON_MDI_DOG_SIDE "\xf3\xb0\xa9\x84" // U+F0A44
+#define ICON_MDI_DOG_SIDE_OFF "\xf3\xb1\x9b\xae" // U+F16EE
+#define ICON_MDI_DOLBY "\xf3\xb0\x9a\xb3" // U+F06B3
+#define ICON_MDI_DOLLY "\xf3\xb0\xba\x9e" // U+F0E9E
+#define ICON_MDI_DOLPHIN "\xf3\xb1\xa2\xb4" // U+F18B4
+#define ICON_MDI_DOMAIN "\xf3\xb0\x87\x97" // U+F01D7
+#define ICON_MDI_DOMAIN_OFF "\xf3\xb0\xb5\xaf" // U+F0D6F
+#define ICON_MDI_DOMAIN_PLUS "\xf3\xb1\x82\xad" // U+F10AD
+#define ICON_MDI_DOMAIN_REMOVE "\xf3\xb1\x82\xae" // U+F10AE
+#define ICON_MDI_DOMAIN_SWITCH "\xf3\xb1\xb0\xac" // U+F1C2C
+#define ICON_MDI_DOME_LIGHT "\xf3\xb1\x90\x9e" // U+F141E
+#define ICON_MDI_DOMINO_MASK "\xf3\xb1\x80\xa3" // U+F1023
+#define ICON_MDI_DONKEY "\xf3\xb0\x9f\x82" // U+F07C2
+#define ICON_MDI_DOOR "\xf3\xb0\xa0\x9a" // U+F081A
+#define ICON_MDI_DOOR_CLOSED "\xf3\xb0\xa0\x9b" // U+F081B
+#define ICON_MDI_DOOR_CLOSED_CANCEL "\xf3\xb1\xb2\x93" // U+F1C93
+#define ICON_MDI_DOOR_CLOSED_LOCK "\xf3\xb1\x82\xaf" // U+F10AF
+#define ICON_MDI_DOOR_OPEN "\xf3\xb0\xa0\x9c" // U+F081C
+#define ICON_MDI_DOOR_SLIDING "\xf3\xb1\xa0\x9e" // U+F181E
+#define ICON_MDI_DOOR_SLIDING_LOCK "\xf3\xb1\xa0\x9f" // U+F181F
+#define ICON_MDI_DOOR_SLIDING_OPEN "\xf3\xb1\xa0\xa0" // U+F1820
+#define ICON_MDI_DOORBELL "\xf3\xb1\x8b\xa6" // U+F12E6
+#define ICON_MDI_DOORBELL_VIDEO "\xf3\xb0\xa1\xa9" // U+F0869
+#define ICON_MDI_DOT_NET "\xf3\xb0\xaa\xae" // U+F0AAE
+#define ICON_MDI_DOTS_CIRCLE "\xf3\xb1\xa5\xb8" // U+F1978
+#define ICON_MDI_DOTS_GRID "\xf3\xb1\x97\xbc" // U+F15FC
+#define ICON_MDI_DOTS_HEXAGON "\xf3\xb1\x97\xbf" // U+F15FF
+#define ICON_MDI_DOTS_HORIZONTAL "\xf3\xb0\x87\x98" // U+F01D8
+#define ICON_MDI_DOTS_HORIZONTAL_CIRCLE "\xf3\xb0\x9f\x83" // U+F07C3
+#define ICON_MDI_DOTS_HORIZONTAL_CIRCLE_OUTLINE "\xf3\xb0\xae\x8d" // U+F0B8D
+#define ICON_MDI_DOTS_SQUARE "\xf3\xb1\x97\xbd" // U+F15FD
+#define ICON_MDI_DOTS_TRIANGLE "\xf3\xb1\x97\xbe" // U+F15FE
+#define ICON_MDI_DOTS_VERTICAL "\xf3\xb0\x87\x99" // U+F01D9
+#define ICON_MDI_DOTS_VERTICAL_CIRCLE "\xf3\xb0\x9f\x84" // U+F07C4
+#define ICON_MDI_DOTS_VERTICAL_CIRCLE_OUTLINE "\xf3\xb0\xae\x8e" // U+F0B8E
+#define ICON_MDI_DOWNLOAD "\xf3\xb0\x87\x9a" // U+F01DA
+#define ICON_MDI_DOWNLOAD_BOX "\xf3\xb1\x91\xa2" // U+F1462
+#define ICON_MDI_DOWNLOAD_BOX_OUTLINE "\xf3\xb1\x91\xa3" // U+F1463
+#define ICON_MDI_DOWNLOAD_CIRCLE "\xf3\xb1\x91\xa4" // U+F1464
+#define ICON_MDI_DOWNLOAD_CIRCLE_OUTLINE "\xf3\xb1\x91\xa5" // U+F1465
+#define ICON_MDI_DOWNLOAD_LOCK "\xf3\xb1\x8c\xa0" // U+F1320
+#define ICON_MDI_DOWNLOAD_LOCK_OUTLINE "\xf3\xb1\x8c\xa1" // U+F1321
+#define ICON_MDI_DOWNLOAD_MULTIPLE "\xf3\xb0\xa7\xa9" // U+F09E9
+#define ICON_MDI_DOWNLOAD_NETWORK "\xf3\xb0\x9b\xb4" // U+F06F4
+#define ICON_MDI_DOWNLOAD_NETWORK_OUTLINE "\xf3\xb0\xb1\xa6" // U+F0C66
+#define ICON_MDI_DOWNLOAD_OFF "\xf3\xb1\x82\xb0" // U+F10B0
+#define ICON_MDI_DOWNLOAD_OFF_OUTLINE "\xf3\xb1\x82\xb1" // U+F10B1
+#define ICON_MDI_DOWNLOAD_OUTLINE "\xf3\xb0\xae\x8f" // U+F0B8F
+#define ICON_MDI_DRAG "\xf3\xb0\x87\x9b" // U+F01DB
+#define ICON_MDI_DRAG_HORIZONTAL "\xf3\xb0\x87\x9c" // U+F01DC
+#define ICON_MDI_DRAG_HORIZONTAL_VARIANT "\xf3\xb1\x8b\xb0" // U+F12F0
+#define ICON_MDI_DRAG_VARIANT "\xf3\xb0\xae\x90" // U+F0B90
+#define ICON_MDI_DRAG_VERTICAL "\xf3\xb0\x87\x9d" // U+F01DD
+#define ICON_MDI_DRAG_VERTICAL_VARIANT "\xf3\xb1\x8b\xb1" // U+F12F1
+#define ICON_MDI_DRAMA_MASKS "\xf3\xb0\xb4\x82" // U+F0D02
+#define ICON_MDI_DRAW "\xf3\xb0\xbd\x89" // U+F0F49
+#define ICON_MDI_DRAW_PEN "\xf3\xb1\xa6\xb9" // U+F19B9
+#define ICON_MDI_DRAWING "\xf3\xb0\x87\x9e" // U+F01DE
+#define ICON_MDI_DRAWING_BOX "\xf3\xb0\x87\x9f" // U+F01DF
+#define ICON_MDI_DRESSER "\xf3\xb0\xbd\x8a" // U+F0F4A
+#define ICON_MDI_DRESSER_OUTLINE "\xf3\xb0\xbd\x8b" // U+F0F4B
+#define ICON_MDI_DRONE "\xf3\xb0\x87\xa2" // U+F01E2
+#define ICON_MDI_DROPBOX "\xf3\xb0\x87\xa3" // U+F01E3
+#define ICON_MDI_DRUPAL "\xf3\xb0\x87\xa4" // U+F01E4
+#define ICON_MDI_DUCK "\xf3\xb0\x87\xa5" // U+F01E5
+#define ICON_MDI_DUMBBELL "\xf3\xb0\x87\xa6" // U+F01E6
+#define ICON_MDI_DUMP_TRUCK "\xf3\xb0\xb1\xa7" // U+F0C67
+#define ICON_MDI_EAR_HEARING "\xf3\xb0\x9f\x85" // U+F07C5
+#define ICON_MDI_EAR_HEARING_LOOP "\xf3\xb1\xab\xae" // U+F1AEE
+#define ICON_MDI_EAR_HEARING_OFF "\xf3\xb0\xa9\x85" // U+F0A45
+#define ICON_MDI_EARBUDS "\xf3\xb1\xa1\x8f" // U+F184F
+#define ICON_MDI_EARBUDS_OFF "\xf3\xb1\xa1\x90" // U+F1850
+#define ICON_MDI_EARBUDS_OFF_OUTLINE "\xf3\xb1\xa1\x91" // U+F1851
+#define ICON_MDI_EARBUDS_OUTLINE "\xf3\xb1\xa1\x92" // U+F1852
+#define ICON_MDI_EARTH "\xf3\xb0\x87\xa7" // U+F01E7
+#define ICON_MDI_EARTH_ARROW_DOWN "\xf3\xb1\xb2\x87" // U+F1C87
+#define ICON_MDI_EARTH_ARROW_LEFT "\xf3\xb1\xb2\x88" // U+F1C88
+#define ICON_MDI_EARTH_ARROW_RIGHT "\xf3\xb1\x8c\x91" // U+F1311
+#define ICON_MDI_EARTH_ARROW_UP "\xf3\xb1\xb2\x89" // U+F1C89
+#define ICON_MDI_EARTH_BOX "\xf3\xb0\x9b\x8d" // U+F06CD
+#define ICON_MDI_EARTH_BOX_MINUS "\xf3\xb1\x90\x87" // U+F1407
+#define ICON_MDI_EARTH_BOX_OFF "\xf3\xb0\x9b\x8e" // U+F06CE
+#define ICON_MDI_EARTH_BOX_PLUS "\xf3\xb1\x90\x86" // U+F1406
+#define ICON_MDI_EARTH_BOX_REMOVE "\xf3\xb1\x90\x88" // U+F1408
+#define ICON_MDI_EARTH_MINUS "\xf3\xb1\x90\x84" // U+F1404
+#define ICON_MDI_EARTH_OFF "\xf3\xb0\x87\xa8" // U+F01E8
+#define ICON_MDI_EARTH_PLUS "\xf3\xb1\x90\x83" // U+F1403
+#define ICON_MDI_EARTH_REMOVE "\xf3\xb1\x90\x85" // U+F1405
+#define ICON_MDI_EGG "\xf3\xb0\xaa\xaf" // U+F0AAF
+#define ICON_MDI_EGG_EASTER "\xf3\xb0\xaa\xb0" // U+F0AB0
+#define ICON_MDI_EGG_FRIED "\xf3\xb1\xa1\x8a" // U+F184A
+#define ICON_MDI_EGG_OFF "\xf3\xb1\x8f\xb0" // U+F13F0
+#define ICON_MDI_EGG_OFF_OUTLINE "\xf3\xb1\x8f\xb1" // U+F13F1
+#define ICON_MDI_EGG_OUTLINE "\xf3\xb1\x8f\xb2" // U+F13F2
+#define ICON_MDI_EIFFEL_TOWER "\xf3\xb1\x95\xab" // U+F156B
+#define ICON_MDI_EIGHT_TRACK "\xf3\xb0\xa7\xaa" // U+F09EA
+#define ICON_MDI_EJECT "\xf3\xb0\x87\xaa" // U+F01EA
+#define ICON_MDI_EJECT_CIRCLE "\xf3\xb1\xac\xa3" // U+F1B23
+#define ICON_MDI_EJECT_CIRCLE_OUTLINE "\xf3\xb1\xac\xa4" // U+F1B24
+#define ICON_MDI_EJECT_OUTLINE "\xf3\xb0\xae\x91" // U+F0B91
+#define ICON_MDI_ELECTRIC_SWITCH "\xf3\xb0\xba\x9f" // U+F0E9F
+#define ICON_MDI_ELECTRIC_SWITCH_CLOSED "\xf3\xb1\x83\x99" // U+F10D9
+#define ICON_MDI_ELECTRON_FRAMEWORK "\xf3\xb1\x80\xa4" // U+F1024
+#define ICON_MDI_ELEPHANT "\xf3\xb0\x9f\x86" // U+F07C6
+#define ICON_MDI_ELEVATION_DECLINE "\xf3\xb0\x87\xab" // U+F01EB
+#define ICON_MDI_ELEVATION_RISE "\xf3\xb0\x87\xac" // U+F01EC
+#define ICON_MDI_ELEVATOR "\xf3\xb0\x87\xad" // U+F01ED
+#define ICON_MDI_ELEVATOR_DOWN "\xf3\xb1\x8b\x82" // U+F12C2
+#define ICON_MDI_ELEVATOR_PASSENGER "\xf3\xb1\x8e\x81" // U+F1381
+#define ICON_MDI_ELEVATOR_PASSENGER_OFF "\xf3\xb1\xa5\xb9" // U+F1979
+#define ICON_MDI_ELEVATOR_PASSENGER_OFF_OUTLINE "\xf3\xb1\xa5\xba" // U+F197A
+#define ICON_MDI_ELEVATOR_PASSENGER_OUTLINE "\xf3\xb1\xa5\xbb" // U+F197B
+#define ICON_MDI_ELEVATOR_UP "\xf3\xb1\x8b\x81" // U+F12C1
+#define ICON_MDI_ELLIPSE "\xf3\xb0\xba\xa0" // U+F0EA0
+#define ICON_MDI_ELLIPSE_OUTLINE "\xf3\xb0\xba\xa1" // U+F0EA1
+#define ICON_MDI_EMAIL "\xf3\xb0\x87\xae" // U+F01EE
+#define ICON_MDI_EMAIL_ALERT "\xf3\xb0\x9b\x8f" // U+F06CF
+#define ICON_MDI_EMAIL_ALERT_OUTLINE "\xf3\xb0\xb5\x82" // U+F0D42
+#define ICON_MDI_EMAIL_ARROW_LEFT "\xf3\xb1\x83\x9a" // U+F10DA
+#define ICON_MDI_EMAIL_ARROW_LEFT_OUTLINE "\xf3\xb1\x83\x9b" // U+F10DB
+#define ICON_MDI_EMAIL_ARROW_RIGHT "\xf3\xb1\x83\x9c" // U+F10DC
+#define ICON_MDI_EMAIL_ARROW_RIGHT_OUTLINE "\xf3\xb1\x83\x9d" // U+F10DD
+#define ICON_MDI_EMAIL_BOX "\xf3\xb0\xb4\x83" // U+F0D03
+#define ICON_MDI_EMAIL_CHECK "\xf3\xb0\xaa\xb1" // U+F0AB1
+#define ICON_MDI_EMAIL_CHECK_OUTLINE "\xf3\xb0\xaa\xb2" // U+F0AB2
+#define ICON_MDI_EMAIL_EDIT "\xf3\xb0\xbb\xa3" // U+F0EE3
+#define ICON_MDI_EMAIL_EDIT_OUTLINE "\xf3\xb0\xbb\xa4" // U+F0EE4
+#define ICON_MDI_EMAIL_FAST "\xf3\xb1\xa1\xaf" // U+F186F
+#define ICON_MDI_EMAIL_FAST_OUTLINE "\xf3\xb1\xa1\xb0" // U+F1870
+#define ICON_MDI_EMAIL_HEART_OUTLINE "\xf3\xb1\xb1\x9b" // U+F1C5B
+#define ICON_MDI_EMAIL_LOCK "\xf3\xb0\x87\xb1" // U+F01F1
+#define ICON_MDI_EMAIL_LOCK_OUTLINE "\xf3\xb1\xad\xa1" // U+F1B61
+#define ICON_MDI_EMAIL_MARK_AS_UNREAD "\xf3\xb0\xae\x92" // U+F0B92
+#define ICON_MDI_EMAIL_MINUS "\xf3\xb0\xbb\xa5" // U+F0EE5
+#define ICON_MDI_EMAIL_MINUS_OUTLINE "\xf3\xb0\xbb\xa6" // U+F0EE6
+#define ICON_MDI_EMAIL_MULTIPLE "\xf3\xb0\xbb\xa7" // U+F0EE7
+#define ICON_MDI_EMAIL_MULTIPLE_OUTLINE "\xf3\xb0\xbb\xa8" // U+F0EE8
+#define ICON_MDI_EMAIL_NEWSLETTER "\xf3\xb0\xbe\xb1" // U+F0FB1
+#define ICON_MDI_EMAIL_OFF "\xf3\xb1\x8f\xa3" // U+F13E3
+#define ICON_MDI_EMAIL_OFF_OUTLINE "\xf3\xb1\x8f\xa4" // U+F13E4
+#define ICON_MDI_EMAIL_OPEN "\xf3\xb0\x87\xaf" // U+F01EF
+#define ICON_MDI_EMAIL_OPEN_HEART_OUTLINE "\xf3\xb1\xb1\x9c" // U+F1C5C
+#define ICON_MDI_EMAIL_OPEN_MULTIPLE "\xf3\xb0\xbb\xa9" // U+F0EE9
+#define ICON_MDI_EMAIL_OPEN_MULTIPLE_OUTLINE "\xf3\xb0\xbb\xaa" // U+F0EEA
+#define ICON_MDI_EMAIL_OPEN_OUTLINE "\xf3\xb0\x97\xaf" // U+F05EF
+#define ICON_MDI_EMAIL_OUTLINE "\xf3\xb0\x87\xb0" // U+F01F0
+#define ICON_MDI_EMAIL_PLUS "\xf3\xb0\xa7\xab" // U+F09EB
+#define ICON_MDI_EMAIL_PLUS_OUTLINE "\xf3\xb0\xa7\xac" // U+F09EC
+#define ICON_MDI_EMAIL_REMOVE "\xf3\xb1\x99\xa1" // U+F1661
+#define ICON_MDI_EMAIL_REMOVE_OUTLINE "\xf3\xb1\x99\xa2" // U+F1662
+#define ICON_MDI_EMAIL_SEAL "\xf3\xb1\xa5\x9b" // U+F195B
+#define ICON_MDI_EMAIL_SEAL_OUTLINE "\xf3\xb1\xa5\x9c" // U+F195C
+#define ICON_MDI_EMAIL_SEARCH "\xf3\xb0\xa5\xa1" // U+F0961
+#define ICON_MDI_EMAIL_SEARCH_OUTLINE "\xf3\xb0\xa5\xa2" // U+F0962
+#define ICON_MDI_EMAIL_SYNC "\xf3\xb1\x8b\x87" // U+F12C7
+#define ICON_MDI_EMAIL_SYNC_OUTLINE "\xf3\xb1\x8b\x88" // U+F12C8
+#define ICON_MDI_EMAIL_VARIANT "\xf3\xb0\x97\xb0" // U+F05F0
+#define ICON_MDI_EMBER "\xf3\xb0\xac\xb0" // U+F0B30
+#define ICON_MDI_EMBY "\xf3\xb0\x9a\xb4" // U+F06B4
+#define ICON_MDI_EMOTICON "\xf3\xb0\xb1\xa8" // U+F0C68
+#define ICON_MDI_EMOTICON_ANGRY "\xf3\xb0\xb1\xa9" // U+F0C69
+#define ICON_MDI_EMOTICON_ANGRY_OUTLINE "\xf3\xb0\xb1\xaa" // U+F0C6A
+#define ICON_MDI_EMOTICON_CONFUSED "\xf3\xb1\x83\x9e" // U+F10DE
+#define ICON_MDI_EMOTICON_CONFUSED_OUTLINE "\xf3\xb1\x83\x9f" // U+F10DF
+#define ICON_MDI_EMOTICON_COOL "\xf3\xb0\xb1\xab" // U+F0C6B
+#define ICON_MDI_EMOTICON_COOL_OUTLINE "\xf3\xb0\x87\xb3" // U+F01F3
+#define ICON_MDI_EMOTICON_CRY "\xf3\xb0\xb1\xac" // U+F0C6C
+#define ICON_MDI_EMOTICON_CRY_OUTLINE "\xf3\xb0\xb1\xad" // U+F0C6D
+#define ICON_MDI_EMOTICON_DEAD "\xf3\xb0\xb1\xae" // U+F0C6E
+#define ICON_MDI_EMOTICON_DEAD_OUTLINE "\xf3\xb0\x9a\x9b" // U+F069B
+#define ICON_MDI_EMOTICON_DEVIL "\xf3\xb0\xb1\xaf" // U+F0C6F
+#define ICON_MDI_EMOTICON_DEVIL_OUTLINE "\xf3\xb0\x87\xb4" // U+F01F4
+#define ICON_MDI_EMOTICON_EXCITED "\xf3\xb0\xb1\xb0" // U+F0C70
+#define ICON_MDI_EMOTICON_EXCITED_OUTLINE "\xf3\xb0\x9a\x9c" // U+F069C
+#define ICON_MDI_EMOTICON_FROWN "\xf3\xb0\xbd\x8c" // U+F0F4C
+#define ICON_MDI_EMOTICON_FROWN_OUTLINE "\xf3\xb0\xbd\x8d" // U+F0F4D
+#define ICON_MDI_EMOTICON_HAPPY "\xf3\xb0\xb1\xb1" // U+F0C71
+#define ICON_MDI_EMOTICON_HAPPY_OUTLINE "\xf3\xb0\x87\xb5" // U+F01F5
+#define ICON_MDI_EMOTICON_KISS "\xf3\xb0\xb1\xb2" // U+F0C72
+#define ICON_MDI_EMOTICON_KISS_OUTLINE "\xf3\xb0\xb1\xb3" // U+F0C73
+#define ICON_MDI_EMOTICON_LOL "\xf3\xb1\x88\x94" // U+F1214
+#define ICON_MDI_EMOTICON_LOL_OUTLINE "\xf3\xb1\x88\x95" // U+F1215
+#define ICON_MDI_EMOTICON_MINUS "\xf3\xb1\xb2\xb2" // U+F1CB2
+#define ICON_MDI_EMOTICON_MINUS_OUTLINE "\xf3\xb1\xb2\xb3" // U+F1CB3
+#define ICON_MDI_EMOTICON_NEUTRAL "\xf3\xb0\xb1\xb4" // U+F0C74
+#define ICON_MDI_EMOTICON_NEUTRAL_OUTLINE "\xf3\xb0\x87\xb6" // U+F01F6
+#define ICON_MDI_EMOTICON_OUTLINE "\xf3\xb0\x87\xb2" // U+F01F2
+#define ICON_MDI_EMOTICON_PLUS "\xf3\xb1\xb2\xb4" // U+F1CB4
+#define ICON_MDI_EMOTICON_PLUS_OUTLINE "\xf3\xb1\xb2\xb5" // U+F1CB5
+#define ICON_MDI_EMOTICON_POOP "\xf3\xb0\x87\xb7" // U+F01F7
+#define ICON_MDI_EMOTICON_POOP_OUTLINE "\xf3\xb0\xb1\xb5" // U+F0C75
+#define ICON_MDI_EMOTICON_REMOVE "\xf3\xb1\xb2\xb6" // U+F1CB6
+#define ICON_MDI_EMOTICON_REMOVE_OUTLINE "\xf3\xb1\xb2\xb7" // U+F1CB7
+#define ICON_MDI_EMOTICON_SAD "\xf3\xb0\xb1\xb6" // U+F0C76
+#define ICON_MDI_EMOTICON_SAD_OUTLINE "\xf3\xb0\x87\xb8" // U+F01F8
+#define ICON_MDI_EMOTICON_SICK "\xf3\xb1\x95\xbc" // U+F157C
+#define ICON_MDI_EMOTICON_SICK_OUTLINE "\xf3\xb1\x95\xbd" // U+F157D
+#define ICON_MDI_EMOTICON_TONGUE "\xf3\xb0\x87\xb9" // U+F01F9
+#define ICON_MDI_EMOTICON_TONGUE_OUTLINE "\xf3\xb0\xb1\xb7" // U+F0C77
+#define ICON_MDI_EMOTICON_WINK "\xf3\xb0\xb1\xb8" // U+F0C78
+#define ICON_MDI_EMOTICON_WINK_OUTLINE "\xf3\xb0\xb1\xb9" // U+F0C79
+#define ICON_MDI_ENGINE "\xf3\xb0\x87\xba" // U+F01FA
+#define ICON_MDI_ENGINE_OFF "\xf3\xb0\xa9\x86" // U+F0A46
+#define ICON_MDI_ENGINE_OFF_OUTLINE "\xf3\xb0\xa9\x87" // U+F0A47
+#define ICON_MDI_ENGINE_OUTLINE "\xf3\xb0\x87\xbb" // U+F01FB
+#define ICON_MDI_EPSILON "\xf3\xb1\x83\xa0" // U+F10E0
+#define ICON_MDI_EQUAL "\xf3\xb0\x87\xbc" // U+F01FC
+#define ICON_MDI_EQUAL_BOX "\xf3\xb0\x87\xbd" // U+F01FD
+#define ICON_MDI_EQUALIZER "\xf3\xb0\xba\xa2" // U+F0EA2
+#define ICON_MDI_EQUALIZER_OUTLINE "\xf3\xb0\xba\xa3" // U+F0EA3
+#define ICON_MDI_ERASER "\xf3\xb0\x87\xbe" // U+F01FE
+#define ICON_MDI_ERASER_VARIANT "\xf3\xb0\x99\x82" // U+F0642
+#define ICON_MDI_ESCALATOR "\xf3\xb0\x87\xbf" // U+F01FF
+#define ICON_MDI_ESCALATOR_BOX "\xf3\xb1\x8e\x99" // U+F1399
+#define ICON_MDI_ESCALATOR_DOWN "\xf3\xb1\x8b\x80" // U+F12C0
+#define ICON_MDI_ESCALATOR_UP "\xf3\xb1\x8a\xbf" // U+F12BF
+#define ICON_MDI_ESLINT "\xf3\xb0\xb1\xba" // U+F0C7A
+#define ICON_MDI_ET "\xf3\xb0\xaa\xb3" // U+F0AB3
+#define ICON_MDI_ETHEREUM "\xf3\xb0\xa1\xaa" // U+F086A
+#define ICON_MDI_ETHERNET "\xf3\xb0\x88\x80" // U+F0200
+#define ICON_MDI_ETHERNET_CABLE "\xf3\xb0\x88\x81" // U+F0201
+#define ICON_MDI_ETHERNET_CABLE_OFF "\xf3\xb0\x88\x82" // U+F0202
+#define ICON_MDI_EV_PLUG_CCS1 "\xf3\xb1\x94\x99" // U+F1519
+#define ICON_MDI_EV_PLUG_CCS2 "\xf3\xb1\x94\x9a" // U+F151A
+#define ICON_MDI_EV_PLUG_CHADEMO "\xf3\xb1\x94\x9b" // U+F151B
+#define ICON_MDI_EV_PLUG_TESLA "\xf3\xb1\x94\x9c" // U+F151C
+#define ICON_MDI_EV_PLUG_TYPE1 "\xf3\xb1\x94\x9d" // U+F151D
+#define ICON_MDI_EV_PLUG_TYPE2 "\xf3\xb1\x94\x9e" // U+F151E
+#define ICON_MDI_EV_STATION "\xf3\xb0\x97\xb1" // U+F05F1
+#define ICON_MDI_EVERNOTE "\xf3\xb0\x88\x84" // U+F0204
+#define ICON_MDI_EXCAVATOR "\xf3\xb1\x80\xa5" // U+F1025
+#define ICON_MDI_EXCLAMATION "\xf3\xb0\x88\x85" // U+F0205
+#define ICON_MDI_EXCLAMATION_THICK "\xf3\xb1\x88\xb8" // U+F1238
+#define ICON_MDI_EXIT_RUN "\xf3\xb0\xa9\x88" // U+F0A48
+#define ICON_MDI_EXIT_TO_APP "\xf3\xb0\x88\x86" // U+F0206
+#define ICON_MDI_EXPAND_ALL "\xf3\xb0\xaa\xb4" // U+F0AB4
+#define ICON_MDI_EXPAND_ALL_OUTLINE "\xf3\xb0\xaa\xb5" // U+F0AB5
+#define ICON_MDI_EXPANSION_CARD "\xf3\xb0\xa2\xae" // U+F08AE
+#define ICON_MDI_EXPANSION_CARD_VARIANT "\xf3\xb0\xbe\xb2" // U+F0FB2
+#define ICON_MDI_EXPONENT "\xf3\xb0\xa5\xa3" // U+F0963
+#define ICON_MDI_EXPONENT_BOX "\xf3\xb0\xa5\xa4" // U+F0964
+#define ICON_MDI_EXPORT "\xf3\xb0\x88\x87" // U+F0207
+#define ICON_MDI_EXPORT_VARIANT "\xf3\xb0\xae\x93" // U+F0B93
+#define ICON_MDI_EYE "\xf3\xb0\x88\x88" // U+F0208
+#define ICON_MDI_EYE_ARROW_LEFT "\xf3\xb1\xa3\xbd" // U+F18FD
+#define ICON_MDI_EYE_ARROW_LEFT_OUTLINE "\xf3\xb1\xa3\xbe" // U+F18FE
+#define ICON_MDI_EYE_ARROW_RIGHT "\xf3\xb1\xa3\xbf" // U+F18FF
+#define ICON_MDI_EYE_ARROW_RIGHT_OUTLINE "\xf3\xb1\xa4\x80" // U+F1900
+#define ICON_MDI_EYE_CHECK "\xf3\xb0\xb4\x84" // U+F0D04
+#define ICON_MDI_EYE_CHECK_OUTLINE "\xf3\xb0\xb4\x85" // U+F0D05
+#define ICON_MDI_EYE_CIRCLE "\xf3\xb0\xae\x94" // U+F0B94
+#define ICON_MDI_EYE_CIRCLE_OUTLINE "\xf3\xb0\xae\x95" // U+F0B95
+#define ICON_MDI_EYE_CLOSED "\xf3\xb1\xb2\xa3" // U+F1CA3
+#define ICON_MDI_EYE_LOCK "\xf3\xb1\xb0\x86" // U+F1C06
+#define ICON_MDI_EYE_LOCK_OPEN "\xf3\xb1\xb0\x87" // U+F1C07
+#define ICON_MDI_EYE_LOCK_OPEN_OUTLINE "\xf3\xb1\xb0\x88" // U+F1C08
+#define ICON_MDI_EYE_LOCK_OUTLINE "\xf3\xb1\xb0\x89" // U+F1C09
+#define ICON_MDI_EYE_MINUS "\xf3\xb1\x80\xa6" // U+F1026
+#define ICON_MDI_EYE_MINUS_OUTLINE "\xf3\xb1\x80\xa7" // U+F1027
+#define ICON_MDI_EYE_OFF "\xf3\xb0\x88\x89" // U+F0209
+#define ICON_MDI_EYE_OFF_OUTLINE "\xf3\xb0\x9b\x91" // U+F06D1
+#define ICON_MDI_EYE_OUTLINE "\xf3\xb0\x9b\x90" // U+F06D0
+#define ICON_MDI_EYE_PLUS "\xf3\xb0\xa1\xab" // U+F086B
+#define ICON_MDI_EYE_PLUS_OUTLINE "\xf3\xb0\xa1\xac" // U+F086C
+#define ICON_MDI_EYE_REFRESH "\xf3\xb1\xa5\xbc" // U+F197C
+#define ICON_MDI_EYE_REFRESH_OUTLINE "\xf3\xb1\xa5\xbd" // U+F197D
+#define ICON_MDI_EYE_REMOVE "\xf3\xb1\x97\xa3" // U+F15E3
+#define ICON_MDI_EYE_REMOVE_OUTLINE "\xf3\xb1\x97\xa4" // U+F15E4
+#define ICON_MDI_EYE_SETTINGS "\xf3\xb0\xa1\xad" // U+F086D
+#define ICON_MDI_EYE_SETTINGS_OUTLINE "\xf3\xb0\xa1\xae" // U+F086E
+#define ICON_MDI_EYEDROPPER "\xf3\xb0\x88\x8a" // U+F020A
+#define ICON_MDI_EYEDROPPER_MINUS "\xf3\xb1\x8f\x9d" // U+F13DD
+#define ICON_MDI_EYEDROPPER_OFF "\xf3\xb1\x8f\x9f" // U+F13DF
+#define ICON_MDI_EYEDROPPER_PLUS "\xf3\xb1\x8f\x9c" // U+F13DC
+#define ICON_MDI_EYEDROPPER_REMOVE "\xf3\xb1\x8f\x9e" // U+F13DE
+#define ICON_MDI_EYEDROPPER_VARIANT "\xf3\xb0\x88\x8b" // U+F020B
+#define ICON_MDI_FACE_AGENT "\xf3\xb0\xb5\xb0" // U+F0D70
+#define ICON_MDI_FACE_MAN "\xf3\xb0\x99\x83" // U+F0643
+#define ICON_MDI_FACE_MAN_OUTLINE "\xf3\xb0\xae\x96" // U+F0B96
+#define ICON_MDI_FACE_MAN_PROFILE "\xf3\xb0\x99\x84" // U+F0644
+#define ICON_MDI_FACE_MAN_SHIMMER "\xf3\xb1\x97\x8c" // U+F15CC
+#define ICON_MDI_FACE_MAN_SHIMMER_OUTLINE "\xf3\xb1\x97\x8d" // U+F15CD
+#define ICON_MDI_FACE_MASK "\xf3\xb1\x96\x86" // U+F1586
+#define ICON_MDI_FACE_MASK_OUTLINE "\xf3\xb1\x96\x87" // U+F1587
+#define ICON_MDI_FACE_RECOGNITION "\xf3\xb0\xb1\xbb" // U+F0C7B
+#define ICON_MDI_FACE_WOMAN "\xf3\xb1\x81\xb7" // U+F1077
+#define ICON_MDI_FACE_WOMAN_OUTLINE "\xf3\xb1\x81\xb8" // U+F1078
+#define ICON_MDI_FACE_WOMAN_PROFILE "\xf3\xb1\x81\xb6" // U+F1076
+#define ICON_MDI_FACE_WOMAN_SHIMMER "\xf3\xb1\x97\x8e" // U+F15CE
+#define ICON_MDI_FACE_WOMAN_SHIMMER_OUTLINE "\xf3\xb1\x97\x8f" // U+F15CF
+#define ICON_MDI_FACEBOOK "\xf3\xb0\x88\x8c" // U+F020C
+#define ICON_MDI_FACEBOOK_GAMING "\xf3\xb0\x9f\x9d" // U+F07DD
+#define ICON_MDI_FACEBOOK_MESSENGER "\xf3\xb0\x88\x8e" // U+F020E
+#define ICON_MDI_FACEBOOK_WORKPLACE "\xf3\xb0\xac\xb1" // U+F0B31
+#define ICON_MDI_FACTORY "\xf3\xb0\x88\x8f" // U+F020F
+#define ICON_MDI_FAMILY_TREE "\xf3\xb1\x98\x8e" // U+F160E
+#define ICON_MDI_FAN "\xf3\xb0\x88\x90" // U+F0210
+#define ICON_MDI_FAN_ALERT "\xf3\xb1\x91\xac" // U+F146C
+#define ICON_MDI_FAN_AUTO "\xf3\xb1\x9c\x9d" // U+F171D
+#define ICON_MDI_FAN_CHEVRON_DOWN "\xf3\xb1\x91\xad" // U+F146D
+#define ICON_MDI_FAN_CHEVRON_UP "\xf3\xb1\x91\xae" // U+F146E
+#define ICON_MDI_FAN_CLOCK "\xf3\xb1\xa8\xba" // U+F1A3A
+#define ICON_MDI_FAN_MINUS "\xf3\xb1\x91\xb0" // U+F1470
+#define ICON_MDI_FAN_OFF "\xf3\xb0\xa0\x9d" // U+F081D
+#define ICON_MDI_FAN_PLUS "\xf3\xb1\x91\xaf" // U+F146F
+#define ICON_MDI_FAN_REMOVE "\xf3\xb1\x91\xb1" // U+F1471
+#define ICON_MDI_FAN_SPEED_1 "\xf3\xb1\x91\xb2" // U+F1472
+#define ICON_MDI_FAN_SPEED_2 "\xf3\xb1\x91\xb3" // U+F1473
+#define ICON_MDI_FAN_SPEED_3 "\xf3\xb1\x91\xb4" // U+F1474
+#define ICON_MDI_FAST_FORWARD "\xf3\xb0\x88\x91" // U+F0211
+#define ICON_MDI_FAST_FORWARD_10 "\xf3\xb0\xb5\xb1" // U+F0D71
+#define ICON_MDI_FAST_FORWARD_15 "\xf3\xb1\xa4\xba" // U+F193A
+#define ICON_MDI_FAST_FORWARD_30 "\xf3\xb0\xb4\x86" // U+F0D06
+#define ICON_MDI_FAST_FORWARD_45 "\xf3\xb1\xac\x92" // U+F1B12
+#define ICON_MDI_FAST_FORWARD_5 "\xf3\xb1\x87\xb8" // U+F11F8
+#define ICON_MDI_FAST_FORWARD_60 "\xf3\xb1\x98\x8b" // U+F160B
+#define ICON_MDI_FAST_FORWARD_OUTLINE "\xf3\xb0\x9b\x92" // U+F06D2
+#define ICON_MDI_FAUCET "\xf3\xb1\xac\xa9" // U+F1B29
+#define ICON_MDI_FAUCET_VARIANT "\xf3\xb1\xac\xaa" // U+F1B2A
+#define ICON_MDI_FAX "\xf3\xb0\x88\x92" // U+F0212
+#define ICON_MDI_FEATHER "\xf3\xb0\x9b\x93" // U+F06D3
+#define ICON_MDI_FEATURE_SEARCH "\xf3\xb0\xa9\x89" // U+F0A49
+#define ICON_MDI_FEATURE_SEARCH_OUTLINE "\xf3\xb0\xa9\x8a" // U+F0A4A
+#define ICON_MDI_FEDORA "\xf3\xb0\xa3\x9b" // U+F08DB
+#define ICON_MDI_FENCE "\xf3\xb1\x9e\x9a" // U+F179A
+#define ICON_MDI_FENCE_ELECTRIC "\xf3\xb1\x9f\xb6" // U+F17F6
+#define ICON_MDI_FENCING "\xf3\xb1\x93\x81" // U+F14C1
+#define ICON_MDI_FERRIS_WHEEL "\xf3\xb0\xba\xa4" // U+F0EA4
+#define ICON_MDI_FERRY "\xf3\xb0\x88\x93" // U+F0213
+#define ICON_MDI_FILE "\xf3\xb0\x88\x94" // U+F0214
+#define ICON_MDI_FILE_ACCOUNT "\xf3\xb0\x9c\xbb" // U+F073B
+#define ICON_MDI_FILE_ACCOUNT_OUTLINE "\xf3\xb1\x80\xa8" // U+F1028
+#define ICON_MDI_FILE_ALERT "\xf3\xb0\xa9\x8b" // U+F0A4B
+#define ICON_MDI_FILE_ALERT_OUTLINE "\xf3\xb0\xa9\x8c" // U+F0A4C
+#define ICON_MDI_FILE_ARROW_LEFT_RIGHT "\xf3\xb1\xaa\x93" // U+F1A93
+#define ICON_MDI_FILE_ARROW_LEFT_RIGHT_OUTLINE "\xf3\xb1\xaa\x94" // U+F1A94
+#define ICON_MDI_FILE_ARROW_UP_DOWN "\xf3\xb1\xaa\x95" // U+F1A95
+#define ICON_MDI_FILE_ARROW_UP_DOWN_OUTLINE "\xf3\xb1\xaa\x96" // U+F1A96
+#define ICON_MDI_FILE_CABINET "\xf3\xb0\xaa\xb6" // U+F0AB6
+#define ICON_MDI_FILE_CAD "\xf3\xb0\xbb\xab" // U+F0EEB
+#define ICON_MDI_FILE_CAD_BOX "\xf3\xb0\xbb\xac" // U+F0EEC
+#define ICON_MDI_FILE_CANCEL "\xf3\xb0\xb7\x86" // U+F0DC6
+#define ICON_MDI_FILE_CANCEL_OUTLINE "\xf3\xb0\xb7\x87" // U+F0DC7
+#define ICON_MDI_FILE_CERTIFICATE "\xf3\xb1\x86\x86" // U+F1186
+#define ICON_MDI_FILE_CERTIFICATE_OUTLINE "\xf3\xb1\x86\x87" // U+F1187
+#define ICON_MDI_FILE_CHART "\xf3\xb0\x88\x95" // U+F0215
+#define ICON_MDI_FILE_CHART_CHECK "\xf3\xb1\xa7\x86" // U+F19C6
+#define ICON_MDI_FILE_CHART_CHECK_OUTLINE "\xf3\xb1\xa7\x87" // U+F19C7
+#define ICON_MDI_FILE_CHART_OUTLINE "\xf3\xb1\x80\xa9" // U+F1029
+#define ICON_MDI_FILE_CHECK "\xf3\xb0\x88\x96" // U+F0216
+#define ICON_MDI_FILE_CHECK_OUTLINE "\xf3\xb0\xb8\xa9" // U+F0E29
+#define ICON_MDI_FILE_CLOCK "\xf3\xb1\x8b\xa1" // U+F12E1
+#define ICON_MDI_FILE_CLOCK_OUTLINE "\xf3\xb1\x8b\xa2" // U+F12E2
+#define ICON_MDI_FILE_CLOUD "\xf3\xb0\x88\x97" // U+F0217
+#define ICON_MDI_FILE_CLOUD_OUTLINE "\xf3\xb1\x80\xaa" // U+F102A
+#define ICON_MDI_FILE_CODE "\xf3\xb0\x88\xae" // U+F022E
+#define ICON_MDI_FILE_CODE_OUTLINE "\xf3\xb1\x80\xab" // U+F102B
+#define ICON_MDI_FILE_COG "\xf3\xb1\x81\xbb" // U+F107B
+#define ICON_MDI_FILE_COG_OUTLINE "\xf3\xb1\x81\xbc" // U+F107C
+#define ICON_MDI_FILE_COMPARE "\xf3\xb0\xa2\xaa" // U+F08AA
+#define ICON_MDI_FILE_DELIMITED "\xf3\xb0\x88\x98" // U+F0218
+#define ICON_MDI_FILE_DELIMITED_OUTLINE "\xf3\xb0\xba\xa5" // U+F0EA5
+#define ICON_MDI_FILE_DOCUMENT "\xf3\xb0\x88\x99" // U+F0219
+#define ICON_MDI_FILE_DOCUMENT_ALERT "\xf3\xb1\xaa\x97" // U+F1A97
+#define ICON_MDI_FILE_DOCUMENT_ALERT_OUTLINE "\xf3\xb1\xaa\x98" // U+F1A98
+#define ICON_MDI_FILE_DOCUMENT_ARROW_RIGHT "\xf3\xb1\xb0\x8f" // U+F1C0F
+#define ICON_MDI_FILE_DOCUMENT_ARROW_RIGHT_OUTLINE "\xf3\xb1\xb0\x90" // U+F1C10
+#define ICON_MDI_FILE_DOCUMENT_CHECK "\xf3\xb1\xaa\x99" // U+F1A99
+#define ICON_MDI_FILE_DOCUMENT_CHECK_OUTLINE "\xf3\xb1\xaa\x9a" // U+F1A9A
+#define ICON_MDI_FILE_DOCUMENT_EDIT "\xf3\xb0\xb7\x88" // U+F0DC8
+#define ICON_MDI_FILE_DOCUMENT_EDIT_OUTLINE "\xf3\xb0\xb7\x89" // U+F0DC9
+#define ICON_MDI_FILE_DOCUMENT_MINUS "\xf3\xb1\xaa\x9b" // U+F1A9B
+#define ICON_MDI_FILE_DOCUMENT_MINUS_OUTLINE "\xf3\xb1\xaa\x9c" // U+F1A9C
+#define ICON_MDI_FILE_DOCUMENT_MULTIPLE "\xf3\xb1\x94\x97" // U+F1517
+#define ICON_MDI_FILE_DOCUMENT_MULTIPLE_OUTLINE "\xf3\xb1\x94\x98" // U+F1518
+#define ICON_MDI_FILE_DOCUMENT_OUTLINE "\xf3\xb0\xa7\xae" // U+F09EE
+#define ICON_MDI_FILE_DOCUMENT_PLUS "\xf3\xb1\xaa\x9d" // U+F1A9D
+#define ICON_MDI_FILE_DOCUMENT_PLUS_OUTLINE "\xf3\xb1\xaa\x9e" // U+F1A9E
+#define ICON_MDI_FILE_DOCUMENT_REFRESH "\xf3\xb1\xb1\xba" // U+F1C7A
+#define ICON_MDI_FILE_DOCUMENT_REFRESH_OUTLINE "\xf3\xb1\xb1\xbb" // U+F1C7B
+#define ICON_MDI_FILE_DOCUMENT_REMOVE "\xf3\xb1\xaa\x9f" // U+F1A9F
+#define ICON_MDI_FILE_DOCUMENT_REMOVE_OUTLINE "\xf3\xb1\xaa\xa0" // U+F1AA0
+#define ICON_MDI_FILE_DOWNLOAD "\xf3\xb0\xa5\xa5" // U+F0965
+#define ICON_MDI_FILE_DOWNLOAD_OUTLINE "\xf3\xb0\xa5\xa6" // U+F0966
+#define ICON_MDI_FILE_EDIT "\xf3\xb1\x87\xa7" // U+F11E7
+#define ICON_MDI_FILE_EDIT_OUTLINE "\xf3\xb1\x87\xa8" // U+F11E8
+#define ICON_MDI_FILE_EXCEL "\xf3\xb0\x88\x9b" // U+F021B
+#define ICON_MDI_FILE_EXCEL_BOX "\xf3\xb0\x88\x9c" // U+F021C
+#define ICON_MDI_FILE_EXCEL_BOX_OUTLINE "\xf3\xb1\x80\xac" // U+F102C
+#define ICON_MDI_FILE_EXCEL_OUTLINE "\xf3\xb1\x80\xad" // U+F102D
+#define ICON_MDI_FILE_EXPORT "\xf3\xb0\x88\x9d" // U+F021D
+#define ICON_MDI_FILE_EXPORT_OUTLINE "\xf3\xb1\x80\xae" // U+F102E
+#define ICON_MDI_FILE_EYE "\xf3\xb0\xb7\x8a" // U+F0DCA
+#define ICON_MDI_FILE_EYE_OUTLINE "\xf3\xb0\xb7\x8b" // U+F0DCB
+#define ICON_MDI_FILE_FIND "\xf3\xb0\x88\x9e" // U+F021E
+#define ICON_MDI_FILE_FIND_OUTLINE "\xf3\xb0\xae\x97" // U+F0B97
+#define ICON_MDI_FILE_GIF_BOX "\xf3\xb0\xb5\xb8" // U+F0D78
+#define ICON_MDI_FILE_HIDDEN "\xf3\xb0\x98\x93" // U+F0613
+#define ICON_MDI_FILE_IMAGE "\xf3\xb0\x88\x9f" // U+F021F
+#define ICON_MDI_FILE_IMAGE_MARKER "\xf3\xb1\x9d\xb2" // U+F1772
+#define ICON_MDI_FILE_IMAGE_MARKER_OUTLINE "\xf3\xb1\x9d\xb3" // U+F1773
+#define ICON_MDI_FILE_IMAGE_MINUS "\xf3\xb1\xa4\xbb" // U+F193B
+#define ICON_MDI_FILE_IMAGE_MINUS_OUTLINE "\xf3\xb1\xa4\xbc" // U+F193C
+#define ICON_MDI_FILE_IMAGE_OUTLINE "\xf3\xb0\xba\xb0" // U+F0EB0
+#define ICON_MDI_FILE_IMAGE_PLUS "\xf3\xb1\xa4\xbd" // U+F193D
+#define ICON_MDI_FILE_IMAGE_PLUS_OUTLINE "\xf3\xb1\xa4\xbe" // U+F193E
+#define ICON_MDI_FILE_IMAGE_REMOVE "\xf3\xb1\xa4\xbf" // U+F193F
+#define ICON_MDI_FILE_IMAGE_REMOVE_OUTLINE "\xf3\xb1\xa5\x80" // U+F1940
+#define ICON_MDI_FILE_IMPORT "\xf3\xb0\x88\xa0" // U+F0220
+#define ICON_MDI_FILE_IMPORT_OUTLINE "\xf3\xb1\x80\xaf" // U+F102F
+#define ICON_MDI_FILE_JPG_BOX "\xf3\xb0\x88\xa5" // U+F0225
+#define ICON_MDI_FILE_KEY "\xf3\xb1\x86\x84" // U+F1184
+#define ICON_MDI_FILE_KEY_OUTLINE "\xf3\xb1\x86\x85" // U+F1185
+#define ICON_MDI_FILE_LINK "\xf3\xb1\x85\xb7" // U+F1177
+#define ICON_MDI_FILE_LINK_OUTLINE "\xf3\xb1\x85\xb8" // U+F1178
+#define ICON_MDI_FILE_LOCK "\xf3\xb0\x88\xa1" // U+F0221
+#define ICON_MDI_FILE_LOCK_OPEN "\xf3\xb1\xa7\x88" // U+F19C8
+#define ICON_MDI_FILE_LOCK_OPEN_OUTLINE "\xf3\xb1\xa7\x89" // U+F19C9
+#define ICON_MDI_FILE_LOCK_OUTLINE "\xf3\xb1\x80\xb0" // U+F1030
+#define ICON_MDI_FILE_MARKER "\xf3\xb1\x9d\xb4" // U+F1774
+#define ICON_MDI_FILE_MARKER_OUTLINE "\xf3\xb1\x9d\xb5" // U+F1775
+#define ICON_MDI_FILE_MINUS "\xf3\xb1\xaa\xa1" // U+F1AA1
+#define ICON_MDI_FILE_MINUS_OUTLINE "\xf3\xb1\xaa\xa2" // U+F1AA2
+#define ICON_MDI_FILE_MOVE "\xf3\xb0\xaa\xb9" // U+F0AB9
+#define ICON_MDI_FILE_MOVE_OUTLINE "\xf3\xb1\x80\xb1" // U+F1031
+#define ICON_MDI_FILE_MULTIPLE "\xf3\xb0\x88\xa2" // U+F0222
+#define ICON_MDI_FILE_MULTIPLE_OUTLINE "\xf3\xb1\x80\xb2" // U+F1032
+#define ICON_MDI_FILE_MUSIC "\xf3\xb0\x88\xa3" // U+F0223
+#define ICON_MDI_FILE_MUSIC_OUTLINE "\xf3\xb0\xb8\xaa" // U+F0E2A
+#define ICON_MDI_FILE_OUTLINE "\xf3\xb0\x88\xa4" // U+F0224
+#define ICON_MDI_FILE_PDF_BOX "\xf3\xb0\x88\xa6" // U+F0226
+#define ICON_MDI_FILE_PERCENT "\xf3\xb0\xa0\x9e" // U+F081E
+#define ICON_MDI_FILE_PERCENT_OUTLINE "\xf3\xb1\x80\xb3" // U+F1033
+#define ICON_MDI_FILE_PHONE "\xf3\xb1\x85\xb9" // U+F1179
+#define ICON_MDI_FILE_PHONE_OUTLINE "\xf3\xb1\x85\xba" // U+F117A
+#define ICON_MDI_FILE_PLUS "\xf3\xb0\x9d\x92" // U+F0752
+#define ICON_MDI_FILE_PLUS_OUTLINE "\xf3\xb0\xbb\xad" // U+F0EED
+#define ICON_MDI_FILE_PNG_BOX "\xf3\xb0\xb8\xad" // U+F0E2D
+#define ICON_MDI_FILE_POWERPOINT "\xf3\xb0\x88\xa7" // U+F0227
+#define ICON_MDI_FILE_POWERPOINT_BOX "\xf3\xb0\x88\xa8" // U+F0228
+#define ICON_MDI_FILE_POWERPOINT_BOX_OUTLINE "\xf3\xb1\x80\xb4" // U+F1034
+#define ICON_MDI_FILE_POWERPOINT_OUTLINE "\xf3\xb1\x80\xb5" // U+F1035
+#define ICON_MDI_FILE_PRESENTATION_BOX "\xf3\xb0\x88\xa9" // U+F0229
+#define ICON_MDI_FILE_QUESTION "\xf3\xb0\xa1\xaf" // U+F086F
+#define ICON_MDI_FILE_QUESTION_OUTLINE "\xf3\xb1\x80\xb6" // U+F1036
+#define ICON_MDI_FILE_REFRESH "\xf3\xb0\xa4\x98" // U+F0918
+#define ICON_MDI_FILE_REFRESH_OUTLINE "\xf3\xb0\x95\x81" // U+F0541
+#define ICON_MDI_FILE_REMOVE "\xf3\xb0\xae\x98" // U+F0B98
+#define ICON_MDI_FILE_REMOVE_OUTLINE "\xf3\xb1\x80\xb7" // U+F1037
+#define ICON_MDI_FILE_REPLACE "\xf3\xb0\xac\xb2" // U+F0B32
+#define ICON_MDI_FILE_REPLACE_OUTLINE "\xf3\xb0\xac\xb3" // U+F0B33
+#define ICON_MDI_FILE_RESTORE "\xf3\xb0\x99\xb0" // U+F0670
+#define ICON_MDI_FILE_RESTORE_OUTLINE "\xf3\xb1\x80\xb8" // U+F1038
+#define ICON_MDI_FILE_ROTATE_LEFT "\xf3\xb1\xa8\xbb" // U+F1A3B
+#define ICON_MDI_FILE_ROTATE_LEFT_OUTLINE "\xf3\xb1\xa8\xbc" // U+F1A3C
+#define ICON_MDI_FILE_ROTATE_RIGHT "\xf3\xb1\xa8\xbd" // U+F1A3D
+#define ICON_MDI_FILE_ROTATE_RIGHT_OUTLINE "\xf3\xb1\xa8\xbe" // U+F1A3E
+#define ICON_MDI_FILE_SEARCH "\xf3\xb0\xb1\xbc" // U+F0C7C
+#define ICON_MDI_FILE_SEARCH_OUTLINE "\xf3\xb0\xb1\xbd" // U+F0C7D
+#define ICON_MDI_FILE_SEND "\xf3\xb0\x88\xaa" // U+F022A
+#define ICON_MDI_FILE_SEND_OUTLINE "\xf3\xb1\x80\xb9" // U+F1039
+#define ICON_MDI_FILE_SETTINGS "\xf3\xb1\x81\xb9" // U+F1079
+#define ICON_MDI_FILE_SETTINGS_OUTLINE "\xf3\xb1\x81\xba" // U+F107A
+#define ICON_MDI_FILE_SIGN "\xf3\xb1\xa7\x83" // U+F19C3
+#define ICON_MDI_FILE_STAR "\xf3\xb1\x80\xba" // U+F103A
+#define ICON_MDI_FILE_STAR_FOUR_POINTS "\xf3\xb1\xb0\xad" // U+F1C2D
+#define ICON_MDI_FILE_STAR_FOUR_POINTS_OUTLINE "\xf3\xb1\xb0\xae" // U+F1C2E
+#define ICON_MDI_FILE_STAR_OUTLINE "\xf3\xb1\x80\xbb" // U+F103B
+#define ICON_MDI_FILE_SWAP "\xf3\xb0\xbe\xb4" // U+F0FB4
+#define ICON_MDI_FILE_SWAP_OUTLINE "\xf3\xb0\xbe\xb5" // U+F0FB5
+#define ICON_MDI_FILE_SYNC "\xf3\xb1\x88\x96" // U+F1216
+#define ICON_MDI_FILE_SYNC_OUTLINE "\xf3\xb1\x88\x97" // U+F1217
+#define ICON_MDI_FILE_TABLE "\xf3\xb0\xb1\xbe" // U+F0C7E
+#define ICON_MDI_FILE_TABLE_BOX "\xf3\xb1\x83\xa1" // U+F10E1
+#define ICON_MDI_FILE_TABLE_BOX_MULTIPLE "\xf3\xb1\x83\xa2" // U+F10E2
+#define ICON_MDI_FILE_TABLE_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x83\xa3" // U+F10E3
+#define ICON_MDI_FILE_TABLE_BOX_OUTLINE "\xf3\xb1\x83\xa4" // U+F10E4
+#define ICON_MDI_FILE_TABLE_OUTLINE "\xf3\xb0\xb1\xbf" // U+F0C7F
+#define ICON_MDI_FILE_TREE "\xf3\xb0\x99\x85" // U+F0645
+#define ICON_MDI_FILE_TREE_OUTLINE "\xf3\xb1\x8f\x92" // U+F13D2
+#define ICON_MDI_FILE_UNDO "\xf3\xb0\xa3\x9c" // U+F08DC
+#define ICON_MDI_FILE_UNDO_OUTLINE "\xf3\xb1\x80\xbc" // U+F103C
+#define ICON_MDI_FILE_UPLOAD "\xf3\xb0\xa9\x8d" // U+F0A4D
+#define ICON_MDI_FILE_UPLOAD_OUTLINE "\xf3\xb0\xa9\x8e" // U+F0A4E
+#define ICON_MDI_FILE_VIDEO "\xf3\xb0\x88\xab" // U+F022B
+#define ICON_MDI_FILE_VIDEO_OUTLINE "\xf3\xb0\xb8\xac" // U+F0E2C
+#define ICON_MDI_FILE_WORD "\xf3\xb0\x88\xac" // U+F022C
+#define ICON_MDI_FILE_WORD_BOX "\xf3\xb0\x88\xad" // U+F022D
+#define ICON_MDI_FILE_WORD_BOX_OUTLINE "\xf3\xb1\x80\xbd" // U+F103D
+#define ICON_MDI_FILE_WORD_OUTLINE "\xf3\xb1\x80\xbe" // U+F103E
+#define ICON_MDI_FILE_XML_BOX "\xf3\xb1\xad\x8b" // U+F1B4B
+#define ICON_MDI_FILM "\xf3\xb0\x88\xaf" // U+F022F
+#define ICON_MDI_FILMSTRIP "\xf3\xb0\x88\xb0" // U+F0230
+#define ICON_MDI_FILMSTRIP_BOX "\xf3\xb0\x8c\xb2" // U+F0332
+#define ICON_MDI_FILMSTRIP_BOX_MULTIPLE "\xf3\xb0\xb4\x98" // U+F0D18
+#define ICON_MDI_FILMSTRIP_OFF "\xf3\xb0\x88\xb1" // U+F0231
+#define ICON_MDI_FILTER "\xf3\xb0\x88\xb2" // U+F0232
+#define ICON_MDI_FILTER_CHECK "\xf3\xb1\xa3\xac" // U+F18EC
+#define ICON_MDI_FILTER_CHECK_OUTLINE "\xf3\xb1\xa3\xad" // U+F18ED
+#define ICON_MDI_FILTER_COG "\xf3\xb1\xaa\xa3" // U+F1AA3
+#define ICON_MDI_FILTER_COG_OUTLINE "\xf3\xb1\xaa\xa4" // U+F1AA4
+#define ICON_MDI_FILTER_MENU "\xf3\xb1\x83\xa5" // U+F10E5
+#define ICON_MDI_FILTER_MENU_OUTLINE "\xf3\xb1\x83\xa6" // U+F10E6
+#define ICON_MDI_FILTER_MINUS "\xf3\xb0\xbb\xae" // U+F0EEE
+#define ICON_MDI_FILTER_MINUS_OUTLINE "\xf3\xb0\xbb\xaf" // U+F0EEF
+#define ICON_MDI_FILTER_MULTIPLE "\xf3\xb1\xa8\xbf" // U+F1A3F
+#define ICON_MDI_FILTER_MULTIPLE_OUTLINE "\xf3\xb1\xa9\x80" // U+F1A40
+#define ICON_MDI_FILTER_OFF "\xf3\xb1\x93\xaf" // U+F14EF
+#define ICON_MDI_FILTER_OFF_OUTLINE "\xf3\xb1\x93\xb0" // U+F14F0
+#define ICON_MDI_FILTER_OUTLINE "\xf3\xb0\x88\xb3" // U+F0233
+#define ICON_MDI_FILTER_PLUS "\xf3\xb0\xbb\xb0" // U+F0EF0
+#define ICON_MDI_FILTER_PLUS_OUTLINE "\xf3\xb0\xbb\xb1" // U+F0EF1
+#define ICON_MDI_FILTER_REMOVE "\xf3\xb0\x88\xb4" // U+F0234
+#define ICON_MDI_FILTER_REMOVE_OUTLINE "\xf3\xb0\x88\xb5" // U+F0235
+#define ICON_MDI_FILTER_SETTINGS "\xf3\xb1\xaa\xa5" // U+F1AA5
+#define ICON_MDI_FILTER_SETTINGS_OUTLINE "\xf3\xb1\xaa\xa6" // U+F1AA6
+#define ICON_MDI_FILTER_VARIANT "\xf3\xb0\x88\xb6" // U+F0236
+#define ICON_MDI_FILTER_VARIANT_MINUS "\xf3\xb1\x84\x92" // U+F1112
+#define ICON_MDI_FILTER_VARIANT_PLUS "\xf3\xb1\x84\x93" // U+F1113
+#define ICON_MDI_FILTER_VARIANT_REMOVE "\xf3\xb1\x80\xbf" // U+F103F
+#define ICON_MDI_FINANCE "\xf3\xb0\xa0\x9f" // U+F081F
+#define ICON_MDI_FIND_REPLACE "\xf3\xb0\x9b\x94" // U+F06D4
+#define ICON_MDI_FINGERPRINT "\xf3\xb0\x88\xb7" // U+F0237
+#define ICON_MDI_FINGERPRINT_OFF "\xf3\xb0\xba\xb1" // U+F0EB1
+#define ICON_MDI_FIRE "\xf3\xb0\x88\xb8" // U+F0238
+#define ICON_MDI_FIRE_ALERT "\xf3\xb1\x97\x97" // U+F15D7
+#define ICON_MDI_FIRE_CIRCLE "\xf3\xb1\xa0\x87" // U+F1807
+#define ICON_MDI_FIRE_EXTINGUISHER "\xf3\xb0\xbb\xb2" // U+F0EF2
+#define ICON_MDI_FIRE_HYDRANT "\xf3\xb1\x84\xb7" // U+F1137
+#define ICON_MDI_FIRE_HYDRANT_ALERT "\xf3\xb1\x84\xb8" // U+F1138
+#define ICON_MDI_FIRE_HYDRANT_OFF "\xf3\xb1\x84\xb9" // U+F1139
+#define ICON_MDI_FIRE_OFF "\xf3\xb1\x9c\xa2" // U+F1722
+#define ICON_MDI_FIRE_STATION "\xf3\xb1\xb3\x83" // U+F1CC3
+#define ICON_MDI_FIRE_TRUCK "\xf3\xb0\xa2\xab" // U+F08AB
+#define ICON_MDI_FIREBASE "\xf3\xb0\xa5\xa7" // U+F0967
+#define ICON_MDI_FIREFOX "\xf3\xb0\x88\xb9" // U+F0239
+#define ICON_MDI_FIREPLACE "\xf3\xb0\xb8\xae" // U+F0E2E
+#define ICON_MDI_FIREPLACE_OFF "\xf3\xb0\xb8\xaf" // U+F0E2F
+#define ICON_MDI_FIREWIRE "\xf3\xb0\x96\xbe" // U+F05BE
+#define ICON_MDI_FIREWORK "\xf3\xb0\xb8\xb0" // U+F0E30
+#define ICON_MDI_FIREWORK_OFF "\xf3\xb1\x9c\xa3" // U+F1723
+#define ICON_MDI_FISH "\xf3\xb0\x88\xba" // U+F023A
+#define ICON_MDI_FISH_OFF "\xf3\xb1\x8f\xb3" // U+F13F3
+#define ICON_MDI_FISHBOWL "\xf3\xb0\xbb\xb3" // U+F0EF3
+#define ICON_MDI_FISHBOWL_OUTLINE "\xf3\xb0\xbb\xb4" // U+F0EF4
+#define ICON_MDI_FIT_TO_PAGE "\xf3\xb0\xbb\xb5" // U+F0EF5
+#define ICON_MDI_FIT_TO_PAGE_OUTLINE "\xf3\xb0\xbb\xb6" // U+F0EF6
+#define ICON_MDI_FIT_TO_SCREEN "\xf3\xb1\xa3\xb4" // U+F18F4
+#define ICON_MDI_FIT_TO_SCREEN_OUTLINE "\xf3\xb1\xa3\xb5" // U+F18F5
+#define ICON_MDI_FLAG "\xf3\xb0\x88\xbb" // U+F023B
+#define ICON_MDI_FLAG_CHECKERED "\xf3\xb0\x88\xbc" // U+F023C
+#define ICON_MDI_FLAG_MINUS "\xf3\xb0\xae\x99" // U+F0B99
+#define ICON_MDI_FLAG_MINUS_OUTLINE "\xf3\xb1\x82\xb2" // U+F10B2
+#define ICON_MDI_FLAG_OFF "\xf3\xb1\xa3\xae" // U+F18EE
+#define ICON_MDI_FLAG_OFF_OUTLINE "\xf3\xb1\xa3\xaf" // U+F18EF
+#define ICON_MDI_FLAG_OUTLINE "\xf3\xb0\x88\xbd" // U+F023D
+#define ICON_MDI_FLAG_PLUS "\xf3\xb0\xae\x9a" // U+F0B9A
+#define ICON_MDI_FLAG_PLUS_OUTLINE "\xf3\xb1\x82\xb3" // U+F10B3
+#define ICON_MDI_FLAG_REMOVE "\xf3\xb0\xae\x9b" // U+F0B9B
+#define ICON_MDI_FLAG_REMOVE_OUTLINE "\xf3\xb1\x82\xb4" // U+F10B4
+#define ICON_MDI_FLAG_TRIANGLE "\xf3\xb0\x88\xbf" // U+F023F
+#define ICON_MDI_FLAG_VARIANT "\xf3\xb0\x89\x80" // U+F0240
+#define ICON_MDI_FLAG_VARIANT_MINUS "\xf3\xb1\xae\xb4" // U+F1BB4
+#define ICON_MDI_FLAG_VARIANT_MINUS_OUTLINE "\xf3\xb1\xae\xb5" // U+F1BB5
+#define ICON_MDI_FLAG_VARIANT_OFF "\xf3\xb1\xae\xb0" // U+F1BB0
+#define ICON_MDI_FLAG_VARIANT_OFF_OUTLINE "\xf3\xb1\xae\xb1" // U+F1BB1
+#define ICON_MDI_FLAG_VARIANT_OUTLINE "\xf3\xb0\x88\xbe" // U+F023E
+#define ICON_MDI_FLAG_VARIANT_PLUS "\xf3\xb1\xae\xb2" // U+F1BB2
+#define ICON_MDI_FLAG_VARIANT_PLUS_OUTLINE "\xf3\xb1\xae\xb3" // U+F1BB3
+#define ICON_MDI_FLAG_VARIANT_REMOVE "\xf3\xb1\xae\xb6" // U+F1BB6
+#define ICON_MDI_FLAG_VARIANT_REMOVE_OUTLINE "\xf3\xb1\xae\xb7" // U+F1BB7
+#define ICON_MDI_FLARE "\xf3\xb0\xb5\xb2" // U+F0D72
+#define ICON_MDI_FLASH "\xf3\xb0\x89\x81" // U+F0241
+#define ICON_MDI_FLASH_ALERT "\xf3\xb0\xbb\xb7" // U+F0EF7
+#define ICON_MDI_FLASH_ALERT_OUTLINE "\xf3\xb0\xbb\xb8" // U+F0EF8
+#define ICON_MDI_FLASH_AUTO "\xf3\xb0\x89\x82" // U+F0242
+#define ICON_MDI_FLASH_OFF "\xf3\xb0\x89\x83" // U+F0243
+#define ICON_MDI_FLASH_OFF_OUTLINE "\xf3\xb1\xad\x85" // U+F1B45
+#define ICON_MDI_FLASH_OUTLINE "\xf3\xb0\x9b\x95" // U+F06D5
+#define ICON_MDI_FLASH_RED_EYE "\xf3\xb0\x99\xbb" // U+F067B
+#define ICON_MDI_FLASH_TRIANGLE "\xf3\xb1\xac\x9d" // U+F1B1D
+#define ICON_MDI_FLASH_TRIANGLE_OUTLINE "\xf3\xb1\xac\x9e" // U+F1B1E
+#define ICON_MDI_FLASHLIGHT "\xf3\xb0\x89\x84" // U+F0244
+#define ICON_MDI_FLASHLIGHT_OFF "\xf3\xb0\x89\x85" // U+F0245
+#define ICON_MDI_FLASK "\xf3\xb0\x82\x93" // U+F0093
+#define ICON_MDI_FLASK_EMPTY "\xf3\xb0\x82\x94" // U+F0094
+#define ICON_MDI_FLASK_EMPTY_MINUS "\xf3\xb1\x88\xba" // U+F123A
+#define ICON_MDI_FLASK_EMPTY_MINUS_OUTLINE "\xf3\xb1\x88\xbb" // U+F123B
+#define ICON_MDI_FLASK_EMPTY_OFF "\xf3\xb1\x8f\xb4" // U+F13F4
+#define ICON_MDI_FLASK_EMPTY_OFF_OUTLINE "\xf3\xb1\x8f\xb5" // U+F13F5
+#define ICON_MDI_FLASK_EMPTY_OUTLINE "\xf3\xb0\x82\x95" // U+F0095
+#define ICON_MDI_FLASK_EMPTY_PLUS "\xf3\xb1\x88\xbc" // U+F123C
+#define ICON_MDI_FLASK_EMPTY_PLUS_OUTLINE "\xf3\xb1\x88\xbd" // U+F123D
+#define ICON_MDI_FLASK_EMPTY_REMOVE "\xf3\xb1\x88\xbe" // U+F123E
+#define ICON_MDI_FLASK_EMPTY_REMOVE_OUTLINE "\xf3\xb1\x88\xbf" // U+F123F
+#define ICON_MDI_FLASK_MINUS "\xf3\xb1\x89\x80" // U+F1240
+#define ICON_MDI_FLASK_MINUS_OUTLINE "\xf3\xb1\x89\x81" // U+F1241
+#define ICON_MDI_FLASK_OFF "\xf3\xb1\x8f\xb6" // U+F13F6
+#define ICON_MDI_FLASK_OFF_OUTLINE "\xf3\xb1\x8f\xb7" // U+F13F7
+#define ICON_MDI_FLASK_OUTLINE "\xf3\xb0\x82\x96" // U+F0096
+#define ICON_MDI_FLASK_PLUS "\xf3\xb1\x89\x82" // U+F1242
+#define ICON_MDI_FLASK_PLUS_OUTLINE "\xf3\xb1\x89\x83" // U+F1243
+#define ICON_MDI_FLASK_REMOVE "\xf3\xb1\x89\x84" // U+F1244
+#define ICON_MDI_FLASK_REMOVE_OUTLINE "\xf3\xb1\x89\x85" // U+F1245
+#define ICON_MDI_FLASK_ROUND_BOTTOM "\xf3\xb1\x89\x8b" // U+F124B
+#define ICON_MDI_FLASK_ROUND_BOTTOM_EMPTY "\xf3\xb1\x89\x8c" // U+F124C
+#define ICON_MDI_FLASK_ROUND_BOTTOM_EMPTY_OUTLINE "\xf3\xb1\x89\x8d" // U+F124D
+#define ICON_MDI_FLASK_ROUND_BOTTOM_OUTLINE "\xf3\xb1\x89\x8e" // U+F124E
+#define ICON_MDI_FLEUR_DE_LIS "\xf3\xb1\x8c\x83" // U+F1303
+#define ICON_MDI_FLIP_HORIZONTAL "\xf3\xb1\x83\xa7" // U+F10E7
+#define ICON_MDI_FLIP_TO_BACK "\xf3\xb0\x89\x87" // U+F0247
+#define ICON_MDI_FLIP_TO_FRONT "\xf3\xb0\x89\x88" // U+F0248
+#define ICON_MDI_FLIP_VERTICAL "\xf3\xb1\x83\xa8" // U+F10E8
+#define ICON_MDI_FLOOR_LAMP "\xf3\xb0\xa3\x9d" // U+F08DD
+#define ICON_MDI_FLOOR_LAMP_DUAL "\xf3\xb1\x81\x80" // U+F1040
+#define ICON_MDI_FLOOR_LAMP_DUAL_OUTLINE "\xf3\xb1\x9f\x8e" // U+F17CE
+#define ICON_MDI_FLOOR_LAMP_OUTLINE "\xf3\xb1\x9f\x88" // U+F17C8
+#define ICON_MDI_FLOOR_LAMP_TORCHIERE "\xf3\xb1\x9d\x87" // U+F1747
+#define ICON_MDI_FLOOR_LAMP_TORCHIERE_OUTLINE "\xf3\xb1\x9f\x96" // U+F17D6
+#define ICON_MDI_FLOOR_LAMP_TORCHIERE_VARIANT "\xf3\xb1\x81\x81" // U+F1041
+#define ICON_MDI_FLOOR_LAMP_TORCHIERE_VARIANT_OUTLINE "\xf3\xb1\x9f\x8f" // U+F17CF
+#define ICON_MDI_FLOOR_PLAN "\xf3\xb0\xa0\xa1" // U+F0821
+#define ICON_MDI_FLOPPY "\xf3\xb0\x89\x89" // U+F0249
+#define ICON_MDI_FLOPPY_VARIANT "\xf3\xb0\xa7\xaf" // U+F09EF
+#define ICON_MDI_FLOWER "\xf3\xb0\x89\x8a" // U+F024A
+#define ICON_MDI_FLOWER_OUTLINE "\xf3\xb0\xa7\xb0" // U+F09F0
+#define ICON_MDI_FLOWER_POLLEN "\xf3\xb1\xa2\x85" // U+F1885
+#define ICON_MDI_FLOWER_POLLEN_OUTLINE "\xf3\xb1\xa2\x86" // U+F1886
+#define ICON_MDI_FLOWER_POPPY "\xf3\xb0\xb4\x88" // U+F0D08
+#define ICON_MDI_FLOWER_TULIP "\xf3\xb0\xa7\xb1" // U+F09F1
+#define ICON_MDI_FLOWER_TULIP_OUTLINE "\xf3\xb0\xa7\xb2" // U+F09F2
+#define ICON_MDI_FOCUS_AUTO "\xf3\xb0\xbd\x8e" // U+F0F4E
+#define ICON_MDI_FOCUS_FIELD "\xf3\xb0\xbd\x8f" // U+F0F4F
+#define ICON_MDI_FOCUS_FIELD_HORIZONTAL "\xf3\xb0\xbd\x90" // U+F0F50
+#define ICON_MDI_FOCUS_FIELD_VERTICAL "\xf3\xb0\xbd\x91" // U+F0F51
+#define ICON_MDI_FOLDER "\xf3\xb0\x89\x8b" // U+F024B
+#define ICON_MDI_FOLDER_ACCOUNT "\xf3\xb0\x89\x8c" // U+F024C
+#define ICON_MDI_FOLDER_ACCOUNT_OUTLINE "\xf3\xb0\xae\x9c" // U+F0B9C
+#define ICON_MDI_FOLDER_ALERT "\xf3\xb0\xb7\x8c" // U+F0DCC
+#define ICON_MDI_FOLDER_ALERT_OUTLINE "\xf3\xb0\xb7\x8d" // U+F0DCD
+#define ICON_MDI_FOLDER_ARROW_DOWN "\xf3\xb1\xa7\xa8" // U+F19E8
+#define ICON_MDI_FOLDER_ARROW_DOWN_OUTLINE "\xf3\xb1\xa7\xa9" // U+F19E9
+#define ICON_MDI_FOLDER_ARROW_LEFT "\xf3\xb1\xa7\xaa" // U+F19EA
+#define ICON_MDI_FOLDER_ARROW_LEFT_OUTLINE "\xf3\xb1\xa7\xab" // U+F19EB
+#define ICON_MDI_FOLDER_ARROW_LEFT_RIGHT "\xf3\xb1\xa7\xac" // U+F19EC
+#define ICON_MDI_FOLDER_ARROW_LEFT_RIGHT_OUTLINE "\xf3\xb1\xa7\xad" // U+F19ED
+#define ICON_MDI_FOLDER_ARROW_RIGHT "\xf3\xb1\xa7\xae" // U+F19EE
+#define ICON_MDI_FOLDER_ARROW_RIGHT_OUTLINE "\xf3\xb1\xa7\xaf" // U+F19EF
+#define ICON_MDI_FOLDER_ARROW_UP "\xf3\xb1\xa7\xb0" // U+F19F0
+#define ICON_MDI_FOLDER_ARROW_UP_DOWN "\xf3\xb1\xa7\xb1" // U+F19F1
+#define ICON_MDI_FOLDER_ARROW_UP_DOWN_OUTLINE "\xf3\xb1\xa7\xb2" // U+F19F2
+#define ICON_MDI_FOLDER_ARROW_UP_OUTLINE "\xf3\xb1\xa7\xb3" // U+F19F3
+#define ICON_MDI_FOLDER_CANCEL "\xf3\xb1\xa7\xb4" // U+F19F4
+#define ICON_MDI_FOLDER_CANCEL_OUTLINE "\xf3\xb1\xa7\xb5" // U+F19F5
+#define ICON_MDI_FOLDER_CHECK "\xf3\xb1\xa5\xbe" // U+F197E
+#define ICON_MDI_FOLDER_CHECK_OUTLINE "\xf3\xb1\xa5\xbf" // U+F197F
+#define ICON_MDI_FOLDER_CLOCK "\xf3\xb0\xaa\xba" // U+F0ABA
+#define ICON_MDI_FOLDER_CLOCK_OUTLINE "\xf3\xb0\xaa\xbb" // U+F0ABB
+#define ICON_MDI_FOLDER_COG "\xf3\xb1\x81\xbf" // U+F107F
+#define ICON_MDI_FOLDER_COG_OUTLINE "\xf3\xb1\x82\x80" // U+F1080
+#define ICON_MDI_FOLDER_DOWNLOAD "\xf3\xb0\x89\x8d" // U+F024D
+#define ICON_MDI_FOLDER_DOWNLOAD_OUTLINE "\xf3\xb1\x83\xa9" // U+F10E9
+#define ICON_MDI_FOLDER_EDIT "\xf3\xb0\xa3\x9e" // U+F08DE
+#define ICON_MDI_FOLDER_EDIT_OUTLINE "\xf3\xb0\xb7\x8e" // U+F0DCE
+#define ICON_MDI_FOLDER_EYE "\xf3\xb1\x9e\x8a" // U+F178A
+#define ICON_MDI_FOLDER_EYE_OUTLINE "\xf3\xb1\x9e\x8b" // U+F178B
+#define ICON_MDI_FOLDER_FILE "\xf3\xb1\xa7\xb6" // U+F19F6
+#define ICON_MDI_FOLDER_FILE_OUTLINE "\xf3\xb1\xa7\xb7" // U+F19F7
+#define ICON_MDI_FOLDER_GOOGLE_DRIVE "\xf3\xb0\x89\x8e" // U+F024E
+#define ICON_MDI_FOLDER_HEART "\xf3\xb1\x83\xaa" // U+F10EA
+#define ICON_MDI_FOLDER_HEART_OUTLINE "\xf3\xb1\x83\xab" // U+F10EB
+#define ICON_MDI_FOLDER_HIDDEN "\xf3\xb1\x9e\x9e" // U+F179E
+#define ICON_MDI_FOLDER_HOME "\xf3\xb1\x82\xb5" // U+F10B5
+#define ICON_MDI_FOLDER_HOME_OUTLINE "\xf3\xb1\x82\xb6" // U+F10B6
+#define ICON_MDI_FOLDER_IMAGE "\xf3\xb0\x89\x8f" // U+F024F
+#define ICON_MDI_FOLDER_INFORMATION "\xf3\xb1\x82\xb7" // U+F10B7
+#define ICON_MDI_FOLDER_INFORMATION_OUTLINE "\xf3\xb1\x82\xb8" // U+F10B8
+#define ICON_MDI_FOLDER_KEY "\xf3\xb0\xa2\xac" // U+F08AC
+#define ICON_MDI_FOLDER_KEY_NETWORK "\xf3\xb0\xa2\xad" // U+F08AD
+#define ICON_MDI_FOLDER_KEY_NETWORK_OUTLINE "\xf3\xb0\xb2\x80" // U+F0C80
+#define ICON_MDI_FOLDER_KEY_OUTLINE "\xf3\xb1\x83\xac" // U+F10EC
+#define ICON_MDI_FOLDER_LOCK "\xf3\xb0\x89\x90" // U+F0250
+#define ICON_MDI_FOLDER_LOCK_OPEN "\xf3\xb0\x89\x91" // U+F0251
+#define ICON_MDI_FOLDER_LOCK_OPEN_OUTLINE "\xf3\xb1\xaa\xa7" // U+F1AA7
+#define ICON_MDI_FOLDER_LOCK_OUTLINE "\xf3\xb1\xaa\xa8" // U+F1AA8
+#define ICON_MDI_FOLDER_MARKER "\xf3\xb1\x89\xad" // U+F126D
+#define ICON_MDI_FOLDER_MARKER_OUTLINE "\xf3\xb1\x89\xae" // U+F126E
+#define ICON_MDI_FOLDER_MINUS "\xf3\xb1\xad\x89" // U+F1B49
+#define ICON_MDI_FOLDER_MINUS_OUTLINE "\xf3\xb1\xad\x8a" // U+F1B4A
+#define ICON_MDI_FOLDER_MOVE "\xf3\xb0\x89\x92" // U+F0252
+#define ICON_MDI_FOLDER_MOVE_OUTLINE "\xf3\xb1\x89\x86" // U+F1246
+#define ICON_MDI_FOLDER_MULTIPLE "\xf3\xb0\x89\x93" // U+F0253
+#define ICON_MDI_FOLDER_MULTIPLE_IMAGE "\xf3\xb0\x89\x94" // U+F0254
+#define ICON_MDI_FOLDER_MULTIPLE_OUTLINE "\xf3\xb0\x89\x95" // U+F0255
+#define ICON_MDI_FOLDER_MULTIPLE_PLUS "\xf3\xb1\x91\xbe" // U+F147E
+#define ICON_MDI_FOLDER_MULTIPLE_PLUS_OUTLINE "\xf3\xb1\x91\xbf" // U+F147F
+#define ICON_MDI_FOLDER_MUSIC "\xf3\xb1\x8d\x99" // U+F1359
+#define ICON_MDI_FOLDER_MUSIC_OUTLINE "\xf3\xb1\x8d\x9a" // U+F135A
+#define ICON_MDI_FOLDER_NETWORK "\xf3\xb0\xa1\xb0" // U+F0870
+#define ICON_MDI_FOLDER_NETWORK_OUTLINE "\xf3\xb0\xb2\x81" // U+F0C81
+#define ICON_MDI_FOLDER_OFF "\xf3\xb1\xa7\xb8" // U+F19F8
+#define ICON_MDI_FOLDER_OFF_OUTLINE "\xf3\xb1\xa7\xb9" // U+F19F9
+#define ICON_MDI_FOLDER_OPEN "\xf3\xb0\x9d\xb0" // U+F0770
+#define ICON_MDI_FOLDER_OPEN_OUTLINE "\xf3\xb0\xb7\x8f" // U+F0DCF
+#define ICON_MDI_FOLDER_OUTLINE "\xf3\xb0\x89\x96" // U+F0256
+#define ICON_MDI_FOLDER_PLAY "\xf3\xb1\xa7\xba" // U+F19FA
+#define ICON_MDI_FOLDER_PLAY_OUTLINE "\xf3\xb1\xa7\xbb" // U+F19FB
+#define ICON_MDI_FOLDER_PLUS "\xf3\xb0\x89\x97" // U+F0257
+#define ICON_MDI_FOLDER_PLUS_OUTLINE "\xf3\xb0\xae\x9d" // U+F0B9D
+#define ICON_MDI_FOLDER_POUND "\xf3\xb0\xb4\x89" // U+F0D09
+#define ICON_MDI_FOLDER_POUND_OUTLINE "\xf3\xb0\xb4\x8a" // U+F0D0A
+#define ICON_MDI_FOLDER_QUESTION "\xf3\xb1\xa7\x8a" // U+F19CA
+#define ICON_MDI_FOLDER_QUESTION_OUTLINE "\xf3\xb1\xa7\x8b" // U+F19CB
+#define ICON_MDI_FOLDER_REFRESH "\xf3\xb0\x9d\x89" // U+F0749
+#define ICON_MDI_FOLDER_REFRESH_OUTLINE "\xf3\xb0\x95\x82" // U+F0542
+#define ICON_MDI_FOLDER_REMOVE "\xf3\xb0\x89\x98" // U+F0258
+#define ICON_MDI_FOLDER_REMOVE_OUTLINE "\xf3\xb0\xae\x9e" // U+F0B9E
+#define ICON_MDI_FOLDER_SEARCH "\xf3\xb0\xa5\xa8" // U+F0968
+#define ICON_MDI_FOLDER_SEARCH_OUTLINE "\xf3\xb0\xa5\xa9" // U+F0969
+#define ICON_MDI_FOLDER_SETTINGS "\xf3\xb1\x81\xbd" // U+F107D
+#define ICON_MDI_FOLDER_SETTINGS_OUTLINE "\xf3\xb1\x81\xbe" // U+F107E
+#define ICON_MDI_FOLDER_STAR "\xf3\xb0\x9a\x9d" // U+F069D
+#define ICON_MDI_FOLDER_STAR_MULTIPLE "\xf3\xb1\x8f\x93" // U+F13D3
+#define ICON_MDI_FOLDER_STAR_MULTIPLE_OUTLINE "\xf3\xb1\x8f\x94" // U+F13D4
+#define ICON_MDI_FOLDER_STAR_OUTLINE "\xf3\xb0\xae\x9f" // U+F0B9F
+#define ICON_MDI_FOLDER_SWAP "\xf3\xb0\xbe\xb6" // U+F0FB6
+#define ICON_MDI_FOLDER_SWAP_OUTLINE "\xf3\xb0\xbe\xb7" // U+F0FB7
+#define ICON_MDI_FOLDER_SYNC "\xf3\xb0\xb4\x8b" // U+F0D0B
+#define ICON_MDI_FOLDER_SYNC_OUTLINE "\xf3\xb0\xb4\x8c" // U+F0D0C
+#define ICON_MDI_FOLDER_TABLE "\xf3\xb1\x8b\xa3" // U+F12E3
+#define ICON_MDI_FOLDER_TABLE_OUTLINE "\xf3\xb1\x8b\xa4" // U+F12E4
+#define ICON_MDI_FOLDER_TEXT "\xf3\xb0\xb2\x82" // U+F0C82
+#define ICON_MDI_FOLDER_TEXT_OUTLINE "\xf3\xb0\xb2\x83" // U+F0C83
+#define ICON_MDI_FOLDER_UPLOAD "\xf3\xb0\x89\x99" // U+F0259
+#define ICON_MDI_FOLDER_UPLOAD_OUTLINE "\xf3\xb1\x83\xad" // U+F10ED
+#define ICON_MDI_FOLDER_WRENCH "\xf3\xb1\xa7\xbc" // U+F19FC
+#define ICON_MDI_FOLDER_WRENCH_OUTLINE "\xf3\xb1\xa7\xbd" // U+F19FD
+#define ICON_MDI_FOLDER_ZIP "\xf3\xb0\x9b\xab" // U+F06EB
+#define ICON_MDI_FOLDER_ZIP_OUTLINE "\xf3\xb0\x9e\xb9" // U+F07B9
+#define ICON_MDI_FONT_AWESOME "\xf3\xb0\x80\xba" // U+F003A
+#define ICON_MDI_FOOD "\xf3\xb0\x89\x9a" // U+F025A
+#define ICON_MDI_FOOD_APPLE "\xf3\xb0\x89\x9b" // U+F025B
+#define ICON_MDI_FOOD_APPLE_OUTLINE "\xf3\xb0\xb2\x84" // U+F0C84
+#define ICON_MDI_FOOD_CROISSANT "\xf3\xb0\x9f\x88" // U+F07C8
+#define ICON_MDI_FOOD_DRUMSTICK "\xf3\xb1\x90\x9f" // U+F141F
+#define ICON_MDI_FOOD_DRUMSTICK_OFF "\xf3\xb1\x91\xa8" // U+F1468
+#define ICON_MDI_FOOD_DRUMSTICK_OFF_OUTLINE "\xf3\xb1\x91\xa9" // U+F1469
+#define ICON_MDI_FOOD_DRUMSTICK_OUTLINE "\xf3\xb1\x90\xa0" // U+F1420
+#define ICON_MDI_FOOD_FORK_DRINK "\xf3\xb0\x97\xb2" // U+F05F2
+#define ICON_MDI_FOOD_HALAL "\xf3\xb1\x95\xb2" // U+F1572
+#define ICON_MDI_FOOD_HOT_DOG "\xf3\xb1\xa1\x8b" // U+F184B
+#define ICON_MDI_FOOD_KOSHER "\xf3\xb1\x95\xb3" // U+F1573
+#define ICON_MDI_FOOD_OFF "\xf3\xb0\x97\xb3" // U+F05F3
+#define ICON_MDI_FOOD_OFF_OUTLINE "\xf3\xb1\xa4\x95" // U+F1915
+#define ICON_MDI_FOOD_OUTLINE "\xf3\xb1\xa4\x96" // U+F1916
+#define ICON_MDI_FOOD_STEAK "\xf3\xb1\x91\xaa" // U+F146A
+#define ICON_MDI_FOOD_STEAK_OFF "\xf3\xb1\x91\xab" // U+F146B
+#define ICON_MDI_FOOD_TAKEOUT_BOX "\xf3\xb1\xa0\xb6" // U+F1836
+#define ICON_MDI_FOOD_TAKEOUT_BOX_OUTLINE "\xf3\xb1\xa0\xb7" // U+F1837
+#define ICON_MDI_FOOD_TURKEY "\xf3\xb1\x9c\x9c" // U+F171C
+#define ICON_MDI_FOOD_VARIANT "\xf3\xb0\x89\x9c" // U+F025C
+#define ICON_MDI_FOOD_VARIANT_OFF "\xf3\xb1\x8f\xa5" // U+F13E5
+#define ICON_MDI_FOOT_PRINT "\xf3\xb0\xbd\x92" // U+F0F52
+#define ICON_MDI_FOOTBALL "\xf3\xb0\x89\x9d" // U+F025D
+#define ICON_MDI_FOOTBALL_AUSTRALIAN "\xf3\xb0\x89\x9e" // U+F025E
+#define ICON_MDI_FOOTBALL_HELMET "\xf3\xb0\x89\x9f" // U+F025F
+#define ICON_MDI_FOREST "\xf3\xb1\xa2\x97" // U+F1897
+#define ICON_MDI_FOREST_OUTLINE "\xf3\xb1\xb1\xa3" // U+F1C63
+#define ICON_MDI_FORKLIFT "\xf3\xb0\x9f\x89" // U+F07C9
+#define ICON_MDI_FORM_DROPDOWN "\xf3\xb1\x90\x80" // U+F1400
+#define ICON_MDI_FORM_SELECT "\xf3\xb1\x90\x81" // U+F1401
+#define ICON_MDI_FORM_TEXTAREA "\xf3\xb1\x82\x95" // U+F1095
+#define ICON_MDI_FORM_TEXTBOX "\xf3\xb0\x98\x8e" // U+F060E
+#define ICON_MDI_FORM_TEXTBOX_LOCK "\xf3\xb1\x8d\x9d" // U+F135D
+#define ICON_MDI_FORM_TEXTBOX_PASSWORD "\xf3\xb0\x9f\xb5" // U+F07F5
+#define ICON_MDI_FORMAT_ALIGN_BOTTOM "\xf3\xb0\x9d\x93" // U+F0753
+#define ICON_MDI_FORMAT_ALIGN_CENTER "\xf3\xb0\x89\xa0" // U+F0260
+#define ICON_MDI_FORMAT_ALIGN_JUSTIFY "\xf3\xb0\x89\xa1" // U+F0261
+#define ICON_MDI_FORMAT_ALIGN_LEFT "\xf3\xb0\x89\xa2" // U+F0262
+#define ICON_MDI_FORMAT_ALIGN_MIDDLE "\xf3\xb0\x9d\x94" // U+F0754
+#define ICON_MDI_FORMAT_ALIGN_RIGHT "\xf3\xb0\x89\xa3" // U+F0263
+#define ICON_MDI_FORMAT_ALIGN_TOP "\xf3\xb0\x9d\x95" // U+F0755
+#define ICON_MDI_FORMAT_ANNOTATION_MINUS "\xf3\xb0\xaa\xbc" // U+F0ABC
+#define ICON_MDI_FORMAT_ANNOTATION_PLUS "\xf3\xb0\x99\x86" // U+F0646
+#define ICON_MDI_FORMAT_BOLD "\xf3\xb0\x89\xa4" // U+F0264
+#define ICON_MDI_FORMAT_CLEAR "\xf3\xb0\x89\xa5" // U+F0265
+#define ICON_MDI_FORMAT_COLOR_FILL "\xf3\xb0\x89\xa6" // U+F0266
+#define ICON_MDI_FORMAT_COLOR_HIGHLIGHT "\xf3\xb0\xb8\xb1" // U+F0E31
+#define ICON_MDI_FORMAT_COLOR_MARKER_CANCEL "\xf3\xb1\x8c\x93" // U+F1313
+#define ICON_MDI_FORMAT_COLOR_TEXT "\xf3\xb0\x9a\x9e" // U+F069E
+#define ICON_MDI_FORMAT_COLUMNS "\xf3\xb0\xa3\x9f" // U+F08DF
+#define ICON_MDI_FORMAT_FLOAT_CENTER "\xf3\xb0\x89\xa7" // U+F0267
+#define ICON_MDI_FORMAT_FLOAT_LEFT "\xf3\xb0\x89\xa8" // U+F0268
+#define ICON_MDI_FORMAT_FLOAT_NONE "\xf3\xb0\x89\xa9" // U+F0269
+#define ICON_MDI_FORMAT_FLOAT_RIGHT "\xf3\xb0\x89\xaa" // U+F026A
+#define ICON_MDI_FORMAT_FONT "\xf3\xb0\x9b\x96" // U+F06D6
+#define ICON_MDI_FORMAT_FONT_SIZE_DECREASE "\xf3\xb0\xa7\xb3" // U+F09F3
+#define ICON_MDI_FORMAT_FONT_SIZE_INCREASE "\xf3\xb0\xa7\xb4" // U+F09F4
+#define ICON_MDI_FORMAT_HEADER_1 "\xf3\xb0\x89\xab" // U+F026B
+#define ICON_MDI_FORMAT_HEADER_2 "\xf3\xb0\x89\xac" // U+F026C
+#define ICON_MDI_FORMAT_HEADER_3 "\xf3\xb0\x89\xad" // U+F026D
+#define ICON_MDI_FORMAT_HEADER_4 "\xf3\xb0\x89\xae" // U+F026E
+#define ICON_MDI_FORMAT_HEADER_5 "\xf3\xb0\x89\xaf" // U+F026F
+#define ICON_MDI_FORMAT_HEADER_6 "\xf3\xb0\x89\xb0" // U+F0270
+#define ICON_MDI_FORMAT_HEADER_DECREASE "\xf3\xb0\x89\xb1" // U+F0271
+#define ICON_MDI_FORMAT_HEADER_EQUAL "\xf3\xb0\x89\xb2" // U+F0272
+#define ICON_MDI_FORMAT_HEADER_INCREASE "\xf3\xb0\x89\xb3" // U+F0273
+#define ICON_MDI_FORMAT_HEADER_POUND "\xf3\xb0\x89\xb4" // U+F0274
+#define ICON_MDI_FORMAT_HORIZONTAL_ALIGN_CENTER "\xf3\xb0\x98\x9e" // U+F061E
+#define ICON_MDI_FORMAT_HORIZONTAL_ALIGN_LEFT "\xf3\xb0\x98\x9f" // U+F061F
+#define ICON_MDI_FORMAT_HORIZONTAL_ALIGN_RIGHT "\xf3\xb0\x98\xa0" // U+F0620
+#define ICON_MDI_FORMAT_INDENT_DECREASE "\xf3\xb0\x89\xb5" // U+F0275
+#define ICON_MDI_FORMAT_INDENT_INCREASE "\xf3\xb0\x89\xb6" // U+F0276
+#define ICON_MDI_FORMAT_ITALIC "\xf3\xb0\x89\xb7" // U+F0277
+#define ICON_MDI_FORMAT_LETTER_CASE "\xf3\xb0\xac\xb4" // U+F0B34
+#define ICON_MDI_FORMAT_LETTER_CASE_LOWER "\xf3\xb0\xac\xb5" // U+F0B35
+#define ICON_MDI_FORMAT_LETTER_CASE_UPPER "\xf3\xb0\xac\xb6" // U+F0B36
+#define ICON_MDI_FORMAT_LETTER_ENDS_WITH "\xf3\xb0\xbe\xb8" // U+F0FB8
+#define ICON_MDI_FORMAT_LETTER_MATCHES "\xf3\xb0\xbe\xb9" // U+F0FB9
+#define ICON_MDI_FORMAT_LETTER_SPACING "\xf3\xb1\xa5\x96" // U+F1956
+#define ICON_MDI_FORMAT_LETTER_SPACING_VARIANT "\xf3\xb1\xab\xbb" // U+F1AFB
+#define ICON_MDI_FORMAT_LETTER_STARTS_WITH "\xf3\xb0\xbe\xba" // U+F0FBA
+#define ICON_MDI_FORMAT_LINE_HEIGHT "\xf3\xb1\xab\xbc" // U+F1AFC
+#define ICON_MDI_FORMAT_LINE_SPACING "\xf3\xb0\x89\xb8" // U+F0278
+#define ICON_MDI_FORMAT_LINE_STYLE "\xf3\xb0\x97\x88" // U+F05C8
+#define ICON_MDI_FORMAT_LINE_WEIGHT "\xf3\xb0\x97\x89" // U+F05C9
+#define ICON_MDI_FORMAT_LIST_BULLETED "\xf3\xb0\x89\xb9" // U+F0279
+#define ICON_MDI_FORMAT_LIST_BULLETED_SQUARE "\xf3\xb0\xb7\x90" // U+F0DD0
+#define ICON_MDI_FORMAT_LIST_BULLETED_TRIANGLE "\xf3\xb0\xba\xb2" // U+F0EB2
+#define ICON_MDI_FORMAT_LIST_BULLETED_TYPE "\xf3\xb0\x89\xba" // U+F027A
+#define ICON_MDI_FORMAT_LIST_CHECKBOX "\xf3\xb0\xa5\xaa" // U+F096A
+#define ICON_MDI_FORMAT_LIST_CHECKS "\xf3\xb0\x9d\x96" // U+F0756
+#define ICON_MDI_FORMAT_LIST_GROUP "\xf3\xb1\xa1\xa0" // U+F1860
+#define ICON_MDI_FORMAT_LIST_GROUP_PLUS "\xf3\xb1\xad\x96" // U+F1B56
+#define ICON_MDI_FORMAT_LIST_NUMBERED "\xf3\xb0\x89\xbb" // U+F027B
+#define ICON_MDI_FORMAT_LIST_NUMBERED_RTL "\xf3\xb0\xb4\x8d" // U+F0D0D
+#define ICON_MDI_FORMAT_LIST_TEXT "\xf3\xb1\x89\xaf" // U+F126F
+#define ICON_MDI_FORMAT_OVERLINE "\xf3\xb0\xba\xb3" // U+F0EB3
+#define ICON_MDI_FORMAT_PAGE_BREAK "\xf3\xb0\x9b\x97" // U+F06D7
+#define ICON_MDI_FORMAT_PAGE_SPLIT "\xf3\xb1\xa4\x97" // U+F1917
+#define ICON_MDI_FORMAT_PAINT "\xf3\xb0\x89\xbc" // U+F027C
+#define ICON_MDI_FORMAT_PARAGRAPH "\xf3\xb0\x89\xbd" // U+F027D
+#define ICON_MDI_FORMAT_PARAGRAPH_SPACING "\xf3\xb1\xab\xbd" // U+F1AFD
+#define ICON_MDI_FORMAT_PILCROW "\xf3\xb0\x9b\x98" // U+F06D8
+#define ICON_MDI_FORMAT_PILCROW_ARROW_LEFT "\xf3\xb0\x8a\x86" // U+F0286
+#define ICON_MDI_FORMAT_PILCROW_ARROW_RIGHT "\xf3\xb0\x8a\x85" // U+F0285
+#define ICON_MDI_FORMAT_QUOTE_CLOSE "\xf3\xb0\x89\xbe" // U+F027E
+#define ICON_MDI_FORMAT_QUOTE_CLOSE_OUTLINE "\xf3\xb1\x86\xa8" // U+F11A8
+#define ICON_MDI_FORMAT_QUOTE_OPEN "\xf3\xb0\x9d\x97" // U+F0757
+#define ICON_MDI_FORMAT_QUOTE_OPEN_OUTLINE "\xf3\xb1\x86\xa7" // U+F11A7
+#define ICON_MDI_FORMAT_ROTATE_90 "\xf3\xb0\x9a\xaa" // U+F06AA
+#define ICON_MDI_FORMAT_SECTION "\xf3\xb0\x9a\x9f" // U+F069F
+#define ICON_MDI_FORMAT_SIZE "\xf3\xb0\x89\xbf" // U+F027F
+#define ICON_MDI_FORMAT_STRIKETHROUGH "\xf3\xb0\x8a\x80" // U+F0280
+#define ICON_MDI_FORMAT_STRIKETHROUGH_VARIANT "\xf3\xb0\x8a\x81" // U+F0281
+#define ICON_MDI_FORMAT_SUBSCRIPT "\xf3\xb0\x8a\x82" // U+F0282
+#define ICON_MDI_FORMAT_SUPERSCRIPT "\xf3\xb0\x8a\x83" // U+F0283
+#define ICON_MDI_FORMAT_TEXT "\xf3\xb0\x8a\x84" // U+F0284
+#define ICON_MDI_FORMAT_TEXT_ROTATION_ANGLE_DOWN "\xf3\xb0\xbe\xbb" // U+F0FBB
+#define ICON_MDI_FORMAT_TEXT_ROTATION_ANGLE_UP "\xf3\xb0\xbe\xbc" // U+F0FBC
+#define ICON_MDI_FORMAT_TEXT_ROTATION_DOWN "\xf3\xb0\xb5\xb3" // U+F0D73
+#define ICON_MDI_FORMAT_TEXT_ROTATION_DOWN_VERTICAL "\xf3\xb0\xbe\xbd" // U+F0FBD
+#define ICON_MDI_FORMAT_TEXT_ROTATION_NONE "\xf3\xb0\xb5\xb4" // U+F0D74
+#define ICON_MDI_FORMAT_TEXT_ROTATION_UP "\xf3\xb0\xbe\xbe" // U+F0FBE
+#define ICON_MDI_FORMAT_TEXT_ROTATION_VERTICAL "\xf3\xb0\xbe\xbf" // U+F0FBF
+#define ICON_MDI_FORMAT_TEXT_VARIANT "\xf3\xb0\xb8\xb2" // U+F0E32
+#define ICON_MDI_FORMAT_TEXT_VARIANT_OUTLINE "\xf3\xb1\x94\x8f" // U+F150F
+#define ICON_MDI_FORMAT_TEXT_WRAPPING_CLIP "\xf3\xb0\xb4\x8e" // U+F0D0E
+#define ICON_MDI_FORMAT_TEXT_WRAPPING_OVERFLOW "\xf3\xb0\xb4\x8f" // U+F0D0F
+#define ICON_MDI_FORMAT_TEXT_WRAPPING_WRAP "\xf3\xb0\xb4\x90" // U+F0D10
+#define ICON_MDI_FORMAT_TEXTBOX "\xf3\xb0\xb4\x91" // U+F0D11
+#define ICON_MDI_FORMAT_TITLE "\xf3\xb0\x97\xb4" // U+F05F4
+#define ICON_MDI_FORMAT_UNDERLINE "\xf3\xb0\x8a\x87" // U+F0287
+#define ICON_MDI_FORMAT_UNDERLINE_WAVY "\xf3\xb1\xa3\xa9" // U+F18E9
+#define ICON_MDI_FORMAT_VERTICAL_ALIGN_BOTTOM "\xf3\xb0\x98\xa1" // U+F0621
+#define ICON_MDI_FORMAT_VERTICAL_ALIGN_CENTER "\xf3\xb0\x98\xa2" // U+F0622
+#define ICON_MDI_FORMAT_VERTICAL_ALIGN_TOP "\xf3\xb0\x98\xa3" // U+F0623
+#define ICON_MDI_FORMAT_WRAP_INLINE "\xf3\xb0\x8a\x88" // U+F0288
+#define ICON_MDI_FORMAT_WRAP_SQUARE "\xf3\xb0\x8a\x89" // U+F0289
+#define ICON_MDI_FORMAT_WRAP_TIGHT "\xf3\xb0\x8a\x8a" // U+F028A
+#define ICON_MDI_FORMAT_WRAP_TOP_BOTTOM "\xf3\xb0\x8a\x8b" // U+F028B
+#define ICON_MDI_FORUM "\xf3\xb0\x8a\x8c" // U+F028C
+#define ICON_MDI_FORUM_MINUS "\xf3\xb1\xaa\xa9" // U+F1AA9
+#define ICON_MDI_FORUM_MINUS_OUTLINE "\xf3\xb1\xaa\xaa" // U+F1AAA
+#define ICON_MDI_FORUM_OUTLINE "\xf3\xb0\xa0\xa2" // U+F0822
+#define ICON_MDI_FORUM_PLUS "\xf3\xb1\xaa\xab" // U+F1AAB
+#define ICON_MDI_FORUM_PLUS_OUTLINE "\xf3\xb1\xaa\xac" // U+F1AAC
+#define ICON_MDI_FORUM_REMOVE "\xf3\xb1\xaa\xad" // U+F1AAD
+#define ICON_MDI_FORUM_REMOVE_OUTLINE "\xf3\xb1\xaa\xae" // U+F1AAE
+#define ICON_MDI_FORWARD "\xf3\xb0\x8a\x8d" // U+F028D
+#define ICON_MDI_FORWARDBURGER "\xf3\xb0\xb5\xb5" // U+F0D75
+#define ICON_MDI_FOUNTAIN "\xf3\xb0\xa5\xab" // U+F096B
+#define ICON_MDI_FOUNTAIN_PEN "\xf3\xb0\xb4\x92" // U+F0D12
+#define ICON_MDI_FOUNTAIN_PEN_TIP "\xf3\xb0\xb4\x93" // U+F0D13
+#define ICON_MDI_FRACTION_ONE_HALF "\xf3\xb1\xa6\x92" // U+F1992
+#define ICON_MDI_FREEBSD "\xf3\xb0\xa3\xa0" // U+F08E0
+#define ICON_MDI_FRENCH_FRIES "\xf3\xb1\xa5\x97" // U+F1957
+#define ICON_MDI_FREQUENTLY_ASKED_QUESTIONS "\xf3\xb0\xba\xb4" // U+F0EB4
+#define ICON_MDI_FRIDGE "\xf3\xb0\x8a\x90" // U+F0290
+#define ICON_MDI_FRIDGE_ALERT "\xf3\xb1\x86\xb1" // U+F11B1
+#define ICON_MDI_FRIDGE_ALERT_OUTLINE "\xf3\xb1\x86\xb2" // U+F11B2
+#define ICON_MDI_FRIDGE_BOTTOM "\xf3\xb0\x8a\x92" // U+F0292
+#define ICON_MDI_FRIDGE_INDUSTRIAL "\xf3\xb1\x97\xae" // U+F15EE
+#define ICON_MDI_FRIDGE_INDUSTRIAL_ALERT "\xf3\xb1\x97\xaf" // U+F15EF
+#define ICON_MDI_FRIDGE_INDUSTRIAL_ALERT_OUTLINE "\xf3\xb1\x97\xb0" // U+F15F0
+#define ICON_MDI_FRIDGE_INDUSTRIAL_OFF "\xf3\xb1\x97\xb1" // U+F15F1
+#define ICON_MDI_FRIDGE_INDUSTRIAL_OFF_OUTLINE "\xf3\xb1\x97\xb2" // U+F15F2
+#define ICON_MDI_FRIDGE_INDUSTRIAL_OUTLINE "\xf3\xb1\x97\xb3" // U+F15F3
+#define ICON_MDI_FRIDGE_OFF "\xf3\xb1\x86\xaf" // U+F11AF
+#define ICON_MDI_FRIDGE_OFF_OUTLINE "\xf3\xb1\x86\xb0" // U+F11B0
+#define ICON_MDI_FRIDGE_OUTLINE "\xf3\xb0\x8a\x8f" // U+F028F
+#define ICON_MDI_FRIDGE_TOP "\xf3\xb0\x8a\x91" // U+F0291
+#define ICON_MDI_FRIDGE_VARIANT "\xf3\xb1\x97\xb4" // U+F15F4
+#define ICON_MDI_FRIDGE_VARIANT_ALERT "\xf3\xb1\x97\xb5" // U+F15F5
+#define ICON_MDI_FRIDGE_VARIANT_ALERT_OUTLINE "\xf3\xb1\x97\xb6" // U+F15F6
+#define ICON_MDI_FRIDGE_VARIANT_OFF "\xf3\xb1\x97\xb7" // U+F15F7
+#define ICON_MDI_FRIDGE_VARIANT_OFF_OUTLINE "\xf3\xb1\x97\xb8" // U+F15F8
+#define ICON_MDI_FRIDGE_VARIANT_OUTLINE "\xf3\xb1\x97\xb9" // U+F15F9
+#define ICON_MDI_FRUIT_CHERRIES "\xf3\xb1\x81\x82" // U+F1042
+#define ICON_MDI_FRUIT_CHERRIES_OFF "\xf3\xb1\x8f\xb8" // U+F13F8
+#define ICON_MDI_FRUIT_CITRUS "\xf3\xb1\x81\x83" // U+F1043
+#define ICON_MDI_FRUIT_CITRUS_OFF "\xf3\xb1\x8f\xb9" // U+F13F9
+#define ICON_MDI_FRUIT_GRAPES "\xf3\xb1\x81\x84" // U+F1044
+#define ICON_MDI_FRUIT_GRAPES_OUTLINE "\xf3\xb1\x81\x85" // U+F1045
+#define ICON_MDI_FRUIT_PEAR "\xf3\xb1\xa8\x8e" // U+F1A0E
+#define ICON_MDI_FRUIT_PINEAPPLE "\xf3\xb1\x81\x86" // U+F1046
+#define ICON_MDI_FRUIT_WATERMELON "\xf3\xb1\x81\x87" // U+F1047
+#define ICON_MDI_FUEL "\xf3\xb0\x9f\x8a" // U+F07CA
+#define ICON_MDI_FUEL_CELL "\xf3\xb1\xa2\xb5" // U+F18B5
+#define ICON_MDI_FULLSCREEN "\xf3\xb0\x8a\x93" // U+F0293
+#define ICON_MDI_FULLSCREEN_EXIT "\xf3\xb0\x8a\x94" // U+F0294
+#define ICON_MDI_FUNCTION "\xf3\xb0\x8a\x95" // U+F0295
+#define ICON_MDI_FUNCTION_VARIANT "\xf3\xb0\xa1\xb1" // U+F0871
+#define ICON_MDI_FURIGANA_HORIZONTAL "\xf3\xb1\x82\x81" // U+F1081
+#define ICON_MDI_FURIGANA_VERTICAL "\xf3\xb1\x82\x82" // U+F1082
+#define ICON_MDI_FUSE "\xf3\xb0\xb2\x85" // U+F0C85
+#define ICON_MDI_FUSE_ALERT "\xf3\xb1\x90\xad" // U+F142D
+#define ICON_MDI_FUSE_BLADE "\xf3\xb0\xb2\x86" // U+F0C86
+#define ICON_MDI_FUSE_OFF "\xf3\xb1\x90\xac" // U+F142C
+#define ICON_MDI_GAMEPAD "\xf3\xb0\x8a\x96" // U+F0296
+#define ICON_MDI_GAMEPAD_CIRCLE "\xf3\xb0\xb8\xb3" // U+F0E33
+#define ICON_MDI_GAMEPAD_CIRCLE_DOWN "\xf3\xb0\xb8\xb4" // U+F0E34
+#define ICON_MDI_GAMEPAD_CIRCLE_LEFT "\xf3\xb0\xb8\xb5" // U+F0E35
+#define ICON_MDI_GAMEPAD_CIRCLE_OUTLINE "\xf3\xb0\xb8\xb6" // U+F0E36
+#define ICON_MDI_GAMEPAD_CIRCLE_RIGHT "\xf3\xb0\xb8\xb7" // U+F0E37
+#define ICON_MDI_GAMEPAD_CIRCLE_UP "\xf3\xb0\xb8\xb8" // U+F0E38
+#define ICON_MDI_GAMEPAD_DOWN "\xf3\xb0\xb8\xb9" // U+F0E39
+#define ICON_MDI_GAMEPAD_LEFT "\xf3\xb0\xb8\xba" // U+F0E3A
+#define ICON_MDI_GAMEPAD_OUTLINE "\xf3\xb1\xa4\x99" // U+F1919
+#define ICON_MDI_GAMEPAD_RIGHT "\xf3\xb0\xb8\xbb" // U+F0E3B
+#define ICON_MDI_GAMEPAD_ROUND "\xf3\xb0\xb8\xbc" // U+F0E3C
+#define ICON_MDI_GAMEPAD_ROUND_DOWN "\xf3\xb0\xb8\xbd" // U+F0E3D
+#define ICON_MDI_GAMEPAD_ROUND_LEFT "\xf3\xb0\xb8\xbe" // U+F0E3E
+#define ICON_MDI_GAMEPAD_ROUND_OUTLINE "\xf3\xb0\xb8\xbf" // U+F0E3F
+#define ICON_MDI_GAMEPAD_ROUND_RIGHT "\xf3\xb0\xb9\x80" // U+F0E40
+#define ICON_MDI_GAMEPAD_ROUND_UP "\xf3\xb0\xb9\x81" // U+F0E41
+#define ICON_MDI_GAMEPAD_SQUARE "\xf3\xb0\xba\xb5" // U+F0EB5
+#define ICON_MDI_GAMEPAD_SQUARE_OUTLINE "\xf3\xb0\xba\xb6" // U+F0EB6
+#define ICON_MDI_GAMEPAD_UP "\xf3\xb0\xb9\x82" // U+F0E42
+#define ICON_MDI_GAMEPAD_VARIANT "\xf3\xb0\x8a\x97" // U+F0297
+#define ICON_MDI_GAMEPAD_VARIANT_OUTLINE "\xf3\xb0\xba\xb7" // U+F0EB7
+#define ICON_MDI_GAMMA "\xf3\xb1\x83\xae" // U+F10EE
+#define ICON_MDI_GANTRY_CRANE "\xf3\xb0\xb7\x91" // U+F0DD1
+#define ICON_MDI_GARAGE "\xf3\xb0\x9b\x99" // U+F06D9
+#define ICON_MDI_GARAGE_ALERT "\xf3\xb0\xa1\xb2" // U+F0872
+#define ICON_MDI_GARAGE_ALERT_VARIANT "\xf3\xb1\x8b\x95" // U+F12D5
+#define ICON_MDI_GARAGE_LOCK "\xf3\xb1\x9f\xbb" // U+F17FB
+#define ICON_MDI_GARAGE_OPEN "\xf3\xb0\x9b\x9a" // U+F06DA
+#define ICON_MDI_GARAGE_OPEN_VARIANT "\xf3\xb1\x8b\x94" // U+F12D4
+#define ICON_MDI_GARAGE_VARIANT "\xf3\xb1\x8b\x93" // U+F12D3
+#define ICON_MDI_GARAGE_VARIANT_LOCK "\xf3\xb1\x9f\xbc" // U+F17FC
+#define ICON_MDI_GAS_BURNER "\xf3\xb1\xa8\x9b" // U+F1A1B
+#define ICON_MDI_GAS_CYLINDER "\xf3\xb0\x99\x87" // U+F0647
+#define ICON_MDI_GAS_STATION "\xf3\xb0\x8a\x98" // U+F0298
+#define ICON_MDI_GAS_STATION_IN_USE "\xf3\xb1\xb3\x84" // U+F1CC4
+#define ICON_MDI_GAS_STATION_IN_USE_OUTLINE "\xf3\xb1\xb3\x85" // U+F1CC5
+#define ICON_MDI_GAS_STATION_OFF "\xf3\xb1\x90\x89" // U+F1409
+#define ICON_MDI_GAS_STATION_OFF_OUTLINE "\xf3\xb1\x90\x8a" // U+F140A
+#define ICON_MDI_GAS_STATION_OUTLINE "\xf3\xb0\xba\xb8" // U+F0EB8
+#define ICON_MDI_GATE "\xf3\xb0\x8a\x99" // U+F0299
+#define ICON_MDI_GATE_ALERT "\xf3\xb1\x9f\xb8" // U+F17F8
+#define ICON_MDI_GATE_AND "\xf3\xb0\xa3\xa1" // U+F08E1
+#define ICON_MDI_GATE_ARROW_LEFT "\xf3\xb1\x9f\xb7" // U+F17F7
+#define ICON_MDI_GATE_ARROW_RIGHT "\xf3\xb1\x85\xa9" // U+F1169
+#define ICON_MDI_GATE_BUFFER "\xf3\xb1\xab\xbe" // U+F1AFE
+#define ICON_MDI_GATE_NAND "\xf3\xb0\xa3\xa2" // U+F08E2
+#define ICON_MDI_GATE_NOR "\xf3\xb0\xa3\xa3" // U+F08E3
+#define ICON_MDI_GATE_NOT "\xf3\xb0\xa3\xa4" // U+F08E4
+#define ICON_MDI_GATE_OPEN "\xf3\xb1\x85\xaa" // U+F116A
+#define ICON_MDI_GATE_OR "\xf3\xb0\xa3\xa5" // U+F08E5
+#define ICON_MDI_GATE_XNOR "\xf3\xb0\xa3\xa6" // U+F08E6
+#define ICON_MDI_GATE_XOR "\xf3\xb0\xa3\xa7" // U+F08E7
+#define ICON_MDI_GATSBY "\xf3\xb0\xb9\x83" // U+F0E43
+#define ICON_MDI_GAUGE "\xf3\xb0\x8a\x9a" // U+F029A
+#define ICON_MDI_GAUGE_EMPTY "\xf3\xb0\xa1\xb3" // U+F0873
+#define ICON_MDI_GAUGE_FULL "\xf3\xb0\xa1\xb4" // U+F0874
+#define ICON_MDI_GAUGE_LOW "\xf3\xb0\xa1\xb5" // U+F0875
+#define ICON_MDI_GAVEL "\xf3\xb0\x8a\x9b" // U+F029B
+#define ICON_MDI_GENDER_FEMALE "\xf3\xb0\x8a\x9c" // U+F029C
+#define ICON_MDI_GENDER_MALE "\xf3\xb0\x8a\x9d" // U+F029D
+#define ICON_MDI_GENDER_MALE_FEMALE "\xf3\xb0\x8a\x9e" // U+F029E
+#define ICON_MDI_GENDER_MALE_FEMALE_VARIANT "\xf3\xb1\x84\xbf" // U+F113F
+#define ICON_MDI_GENDER_NON_BINARY "\xf3\xb1\x85\x80" // U+F1140
+#define ICON_MDI_GENDER_TRANSGENDER "\xf3\xb0\x8a\x9f" // U+F029F
+#define ICON_MDI_GENERATOR_MOBILE "\xf3\xb1\xb2\x8a" // U+F1C8A
+#define ICON_MDI_GENERATOR_PORTABLE "\xf3\xb1\xb2\x8b" // U+F1C8B
+#define ICON_MDI_GENERATOR_STATIONARY "\xf3\xb1\xb2\x8c" // U+F1C8C
+#define ICON_MDI_GENTOO "\xf3\xb0\xa3\xa8" // U+F08E8
+#define ICON_MDI_GESTURE "\xf3\xb0\x9f\x8b" // U+F07CB
+#define ICON_MDI_GESTURE_DOUBLE_TAP "\xf3\xb0\x9c\xbc" // U+F073C
+#define ICON_MDI_GESTURE_PINCH "\xf3\xb0\xaa\xbd" // U+F0ABD
+#define ICON_MDI_GESTURE_SPREAD "\xf3\xb0\xaa\xbe" // U+F0ABE
+#define ICON_MDI_GESTURE_SWIPE "\xf3\xb0\xb5\xb6" // U+F0D76
+#define ICON_MDI_GESTURE_SWIPE_DOWN "\xf3\xb0\x9c\xbd" // U+F073D
+#define ICON_MDI_GESTURE_SWIPE_HORIZONTAL "\xf3\xb0\xaa\xbf" // U+F0ABF
+#define ICON_MDI_GESTURE_SWIPE_LEFT "\xf3\xb0\x9c\xbe" // U+F073E
+#define ICON_MDI_GESTURE_SWIPE_RIGHT "\xf3\xb0\x9c\xbf" // U+F073F
+#define ICON_MDI_GESTURE_SWIPE_UP "\xf3\xb0\x9d\x80" // U+F0740
+#define ICON_MDI_GESTURE_SWIPE_VERTICAL "\xf3\xb0\xab\x80" // U+F0AC0
+#define ICON_MDI_GESTURE_TAP "\xf3\xb0\x9d\x81" // U+F0741
+#define ICON_MDI_GESTURE_TAP_BOX "\xf3\xb1\x8a\xa9" // U+F12A9
+#define ICON_MDI_GESTURE_TAP_BUTTON "\xf3\xb1\x8a\xa8" // U+F12A8
+#define ICON_MDI_GESTURE_TAP_HOLD "\xf3\xb0\xb5\xb7" // U+F0D77
+#define ICON_MDI_GESTURE_TWO_DOUBLE_TAP "\xf3\xb0\x9d\x82" // U+F0742
+#define ICON_MDI_GESTURE_TWO_TAP "\xf3\xb0\x9d\x83" // U+F0743
+#define ICON_MDI_GHOST "\xf3\xb0\x8a\xa0" // U+F02A0
+#define ICON_MDI_GHOST_OFF "\xf3\xb0\xa7\xb5" // U+F09F5
+#define ICON_MDI_GHOST_OFF_OUTLINE "\xf3\xb1\x99\x9c" // U+F165C
+#define ICON_MDI_GHOST_OUTLINE "\xf3\xb1\x99\x9d" // U+F165D
+#define ICON_MDI_GIFT "\xf3\xb0\xb9\x84" // U+F0E44
+#define ICON_MDI_GIFT_OFF "\xf3\xb1\x9b\xaf" // U+F16EF
+#define ICON_MDI_GIFT_OFF_OUTLINE "\xf3\xb1\x9b\xb0" // U+F16F0
+#define ICON_MDI_GIFT_OPEN "\xf3\xb1\x9b\xb1" // U+F16F1
+#define ICON_MDI_GIFT_OPEN_OUTLINE "\xf3\xb1\x9b\xb2" // U+F16F2
+#define ICON_MDI_GIFT_OUTLINE "\xf3\xb0\x8a\xa1" // U+F02A1
+#define ICON_MDI_GIT "\xf3\xb0\x8a\xa2" // U+F02A2
+#define ICON_MDI_GITHUB "\xf3\xb0\x8a\xa4" // U+F02A4
+#define ICON_MDI_GITLAB "\xf3\xb0\xae\xa0" // U+F0BA0
+#define ICON_MDI_GLASS_COCKTAIL "\xf3\xb0\x8d\x96" // U+F0356
+#define ICON_MDI_GLASS_COCKTAIL_OFF "\xf3\xb1\x97\xa6" // U+F15E6
+#define ICON_MDI_GLASS_FLUTE "\xf3\xb0\x8a\xa5" // U+F02A5
+#define ICON_MDI_GLASS_FRAGILE "\xf3\xb1\xa1\xb3" // U+F1873
+#define ICON_MDI_GLASS_MUG "\xf3\xb0\x8a\xa6" // U+F02A6
+#define ICON_MDI_GLASS_MUG_OFF "\xf3\xb1\x97\xa7" // U+F15E7
+#define ICON_MDI_GLASS_MUG_VARIANT "\xf3\xb1\x84\x96" // U+F1116
+#define ICON_MDI_GLASS_MUG_VARIANT_OFF "\xf3\xb1\x97\xa8" // U+F15E8
+#define ICON_MDI_GLASS_PINT_OUTLINE "\xf3\xb1\x8c\x8d" // U+F130D
+#define ICON_MDI_GLASS_STANGE "\xf3\xb0\x8a\xa7" // U+F02A7
+#define ICON_MDI_GLASS_TULIP "\xf3\xb0\x8a\xa8" // U+F02A8
+#define ICON_MDI_GLASS_WINE "\xf3\xb0\xa1\xb6" // U+F0876
+#define ICON_MDI_GLASSES "\xf3\xb0\x8a\xaa" // U+F02AA
+#define ICON_MDI_GLOBE_LIGHT "\xf3\xb0\x99\xaf" // U+F066F
+#define ICON_MDI_GLOBE_LIGHT_OUTLINE "\xf3\xb1\x8b\x97" // U+F12D7
+#define ICON_MDI_GLOBE_MODEL "\xf3\xb0\xa3\xa9" // U+F08E9
+#define ICON_MDI_GMAIL "\xf3\xb0\x8a\xab" // U+F02AB
+#define ICON_MDI_GNOME "\xf3\xb0\x8a\xac" // U+F02AC
+#define ICON_MDI_GO_KART "\xf3\xb0\xb5\xb9" // U+F0D79
+#define ICON_MDI_GO_KART_TRACK "\xf3\xb0\xb5\xba" // U+F0D7A
+#define ICON_MDI_GOG "\xf3\xb0\xae\xa1" // U+F0BA1
+#define ICON_MDI_GOLD "\xf3\xb1\x89\x8f" // U+F124F
+#define ICON_MDI_GOLF "\xf3\xb0\xa0\xa3" // U+F0823
+#define ICON_MDI_GOLF_CART "\xf3\xb1\x86\xa4" // U+F11A4
+#define ICON_MDI_GOLF_TEE "\xf3\xb1\x82\x83" // U+F1083
+#define ICON_MDI_GONDOLA "\xf3\xb0\x9a\x86" // U+F0686
+#define ICON_MDI_GOODREADS "\xf3\xb0\xb5\xbb" // U+F0D7B
+#define ICON_MDI_GOOGLE "\xf3\xb0\x8a\xad" // U+F02AD
+#define ICON_MDI_GOOGLE_ADS "\xf3\xb0\xb2\x87" // U+F0C87
+#define ICON_MDI_GOOGLE_ANALYTICS "\xf3\xb0\x9f\x8c" // U+F07CC
+#define ICON_MDI_GOOGLE_ASSISTANT "\xf3\xb0\x9f\x8d" // U+F07CD
+#define ICON_MDI_GOOGLE_CARDBOARD "\xf3\xb0\x8a\xae" // U+F02AE
+#define ICON_MDI_GOOGLE_CHROME "\xf3\xb0\x8a\xaf" // U+F02AF
+#define ICON_MDI_GOOGLE_CIRCLES "\xf3\xb0\x8a\xb0" // U+F02B0
+#define ICON_MDI_GOOGLE_CIRCLES_COMMUNITIES "\xf3\xb0\x8a\xb1" // U+F02B1
+#define ICON_MDI_GOOGLE_CIRCLES_EXTENDED "\xf3\xb0\x8a\xb2" // U+F02B2
+#define ICON_MDI_GOOGLE_CIRCLES_GROUP "\xf3\xb0\x8a\xb3" // U+F02B3
+#define ICON_MDI_GOOGLE_CLASSROOM "\xf3\xb0\x8b\x80" // U+F02C0
+#define ICON_MDI_GOOGLE_CLOUD "\xf3\xb1\x87\xb6" // U+F11F6
+#define ICON_MDI_GOOGLE_DOWNASAUR "\xf3\xb1\x8d\xa2" // U+F1362
+#define ICON_MDI_GOOGLE_DRIVE "\xf3\xb0\x8a\xb6" // U+F02B6
+#define ICON_MDI_GOOGLE_EARTH "\xf3\xb0\x8a\xb7" // U+F02B7
+#define ICON_MDI_GOOGLE_FIT "\xf3\xb0\xa5\xac" // U+F096C
+#define ICON_MDI_GOOGLE_GLASS "\xf3\xb0\x8a\xb8" // U+F02B8
+#define ICON_MDI_GOOGLE_HANGOUTS "\xf3\xb0\x8b\x89" // U+F02C9
+#define ICON_MDI_GOOGLE_KEEP "\xf3\xb0\x9b\x9c" // U+F06DC
+#define ICON_MDI_GOOGLE_LENS "\xf3\xb0\xa7\xb6" // U+F09F6
+#define ICON_MDI_GOOGLE_MAPS "\xf3\xb0\x97\xb5" // U+F05F5
+#define ICON_MDI_GOOGLE_MY_BUSINESS "\xf3\xb1\x81\x88" // U+F1048
+#define ICON_MDI_GOOGLE_NEARBY "\xf3\xb0\x8a\xb9" // U+F02B9
+#define ICON_MDI_GOOGLE_PLAY "\xf3\xb0\x8a\xbc" // U+F02BC
+#define ICON_MDI_GOOGLE_PLUS "\xf3\xb0\x8a\xbd" // U+F02BD
+#define ICON_MDI_GOOGLE_PODCAST "\xf3\xb0\xba\xb9" // U+F0EB9
+#define ICON_MDI_GOOGLE_SPREADSHEET "\xf3\xb0\xa7\xb7" // U+F09F7
+#define ICON_MDI_GOOGLE_STREET_VIEW "\xf3\xb0\xb2\x88" // U+F0C88
+#define ICON_MDI_GOOGLE_TRANSLATE "\xf3\xb0\x8a\xbf" // U+F02BF
+#define ICON_MDI_GRADIENT_HORIZONTAL "\xf3\xb1\x9d\x8a" // U+F174A
+#define ICON_MDI_GRADIENT_VERTICAL "\xf3\xb0\x9a\xa0" // U+F06A0
+#define ICON_MDI_GRAIN "\xf3\xb0\xb5\xbc" // U+F0D7C
+#define ICON_MDI_GRAPH "\xf3\xb1\x81\x89" // U+F1049
+#define ICON_MDI_GRAPH_OUTLINE "\xf3\xb1\x81\x8a" // U+F104A
+#define ICON_MDI_GRAPHQL "\xf3\xb0\xa1\xb7" // U+F0877
+#define ICON_MDI_GRASS "\xf3\xb1\x94\x90" // U+F1510
+#define ICON_MDI_GRAVE_STONE "\xf3\xb0\xae\xa2" // U+F0BA2
+#define ICON_MDI_GREASE_PENCIL "\xf3\xb0\x99\x88" // U+F0648
+#define ICON_MDI_GREATER_THAN "\xf3\xb0\xa5\xad" // U+F096D
+#define ICON_MDI_GREATER_THAN_OR_EQUAL "\xf3\xb0\xa5\xae" // U+F096E
+#define ICON_MDI_GREENHOUSE "\xf3\xb0\x80\xad" // U+F002D
+#define ICON_MDI_GRID "\xf3\xb0\x8b\x81" // U+F02C1
+#define ICON_MDI_GRID_LARGE "\xf3\xb0\x9d\x98" // U+F0758
+#define ICON_MDI_GRID_OFF "\xf3\xb0\x8b\x82" // U+F02C2
+#define ICON_MDI_GRILL "\xf3\xb0\xb9\x85" // U+F0E45
+#define ICON_MDI_GRILL_OUTLINE "\xf3\xb1\x86\x8a" // U+F118A
+#define ICON_MDI_GROUP "\xf3\xb0\x8b\x83" // U+F02C3
+#define ICON_MDI_GUITAR_ACOUSTIC "\xf3\xb0\x9d\xb1" // U+F0771
+#define ICON_MDI_GUITAR_ELECTRIC "\xf3\xb0\x8b\x84" // U+F02C4
+#define ICON_MDI_GUITAR_PICK "\xf3\xb0\x8b\x85" // U+F02C5
+#define ICON_MDI_GUITAR_PICK_OUTLINE "\xf3\xb0\x8b\x86" // U+F02C6
+#define ICON_MDI_GUY_FAWKES_MASK "\xf3\xb0\xa0\xa5" // U+F0825
+#define ICON_MDI_GYMNASTICS "\xf3\xb1\xa9\x81" // U+F1A41
+#define ICON_MDI_HAIL "\xf3\xb0\xab\x81" // U+F0AC1
+#define ICON_MDI_HAIR_DRYER "\xf3\xb1\x83\xaf" // U+F10EF
+#define ICON_MDI_HAIR_DRYER_OUTLINE "\xf3\xb1\x83\xb0" // U+F10F0
+#define ICON_MDI_HALLOWEEN "\xf3\xb0\xae\xa3" // U+F0BA3
+#define ICON_MDI_HAMBURGER "\xf3\xb0\x9a\x85" // U+F0685
+#define ICON_MDI_HAMBURGER_CHECK "\xf3\xb1\x9d\xb6" // U+F1776
+#define ICON_MDI_HAMBURGER_MINUS "\xf3\xb1\x9d\xb7" // U+F1777
+#define ICON_MDI_HAMBURGER_OFF "\xf3\xb1\x9d\xb8" // U+F1778
+#define ICON_MDI_HAMBURGER_PLUS "\xf3\xb1\x9d\xb9" // U+F1779
+#define ICON_MDI_HAMBURGER_REMOVE "\xf3\xb1\x9d\xba" // U+F177A
+#define ICON_MDI_HAMMER "\xf3\xb0\xa3\xaa" // U+F08EA
+#define ICON_MDI_HAMMER_SCREWDRIVER "\xf3\xb1\x8c\xa2" // U+F1322
+#define ICON_MDI_HAMMER_SICKLE "\xf3\xb1\xa2\x87" // U+F1887
+#define ICON_MDI_HAMMER_WRENCH "\xf3\xb1\x8c\xa3" // U+F1323
+#define ICON_MDI_HAND_BACK_LEFT "\xf3\xb0\xb9\x86" // U+F0E46
+#define ICON_MDI_HAND_BACK_LEFT_OFF "\xf3\xb1\xa0\xb0" // U+F1830
+#define ICON_MDI_HAND_BACK_LEFT_OFF_OUTLINE "\xf3\xb1\xa0\xb2" // U+F1832
+#define ICON_MDI_HAND_BACK_LEFT_OUTLINE "\xf3\xb1\xa0\xac" // U+F182C
+#define ICON_MDI_HAND_BACK_RIGHT "\xf3\xb0\xb9\x87" // U+F0E47
+#define ICON_MDI_HAND_BACK_RIGHT_OFF "\xf3\xb1\xa0\xb1" // U+F1831
+#define ICON_MDI_HAND_BACK_RIGHT_OFF_OUTLINE "\xf3\xb1\xa0\xb3" // U+F1833
+#define ICON_MDI_HAND_BACK_RIGHT_OUTLINE "\xf3\xb1\xa0\xad" // U+F182D
+#define ICON_MDI_HAND_CLAP "\xf3\xb1\xa5\x8b" // U+F194B
+#define ICON_MDI_HAND_CLAP_OFF "\xf3\xb1\xa9\x82" // U+F1A42
+#define ICON_MDI_HAND_COIN "\xf3\xb1\xa2\x8f" // U+F188F
+#define ICON_MDI_HAND_COIN_OUTLINE "\xf3\xb1\xa2\x90" // U+F1890
+#define ICON_MDI_HAND_CYCLE "\xf3\xb1\xae\x9c" // U+F1B9C
+#define ICON_MDI_HAND_EXTENDED "\xf3\xb1\xa2\xb6" // U+F18B6
+#define ICON_MDI_HAND_EXTENDED_OUTLINE "\xf3\xb1\xa2\xb7" // U+F18B7
+#define ICON_MDI_HAND_FRONT_LEFT "\xf3\xb1\xa0\xab" // U+F182B
+#define ICON_MDI_HAND_FRONT_LEFT_OUTLINE "\xf3\xb1\xa0\xae" // U+F182E
+#define ICON_MDI_HAND_FRONT_RIGHT "\xf3\xb0\xa9\x8f" // U+F0A4F
+#define ICON_MDI_HAND_FRONT_RIGHT_OUTLINE "\xf3\xb1\xa0\xaf" // U+F182F
+#define ICON_MDI_HAND_HEART "\xf3\xb1\x83\xb1" // U+F10F1
+#define ICON_MDI_HAND_HEART_OUTLINE "\xf3\xb1\x95\xbe" // U+F157E
+#define ICON_MDI_HAND_OKAY "\xf3\xb0\xa9\x90" // U+F0A50
+#define ICON_MDI_HAND_PEACE "\xf3\xb0\xa9\x91" // U+F0A51
+#define ICON_MDI_HAND_PEACE_VARIANT "\xf3\xb0\xa9\x92" // U+F0A52
+#define ICON_MDI_HAND_POINTING_DOWN "\xf3\xb0\xa9\x93" // U+F0A53
+#define ICON_MDI_HAND_POINTING_LEFT "\xf3\xb0\xa9\x94" // U+F0A54
+#define ICON_MDI_HAND_POINTING_RIGHT "\xf3\xb0\x8b\x87" // U+F02C7
+#define ICON_MDI_HAND_POINTING_UP "\xf3\xb0\xa9\x95" // U+F0A55
+#define ICON_MDI_HAND_SAW "\xf3\xb0\xb9\x88" // U+F0E48
+#define ICON_MDI_HAND_WASH "\xf3\xb1\x95\xbf" // U+F157F
+#define ICON_MDI_HAND_WASH_OUTLINE "\xf3\xb1\x96\x80" // U+F1580
+#define ICON_MDI_HAND_WATER "\xf3\xb1\x8e\x9f" // U+F139F
+#define ICON_MDI_HAND_WAVE "\xf3\xb1\xa0\xa1" // U+F1821
+#define ICON_MDI_HAND_WAVE_OUTLINE "\xf3\xb1\xa0\xa2" // U+F1822
+#define ICON_MDI_HANDBALL "\xf3\xb0\xbd\x93" // U+F0F53
+#define ICON_MDI_HANDCUFFS "\xf3\xb1\x84\xbe" // U+F113E
+#define ICON_MDI_HANDS_PRAY "\xf3\xb0\x95\xb9" // U+F0579
+#define ICON_MDI_HANDSHAKE "\xf3\xb1\x88\x98" // U+F1218
+#define ICON_MDI_HANDSHAKE_OUTLINE "\xf3\xb1\x96\xa1" // U+F15A1
+#define ICON_MDI_HANGER "\xf3\xb0\x8b\x88" // U+F02C8
+#define ICON_MDI_HARD_HAT "\xf3\xb0\xa5\xaf" // U+F096F
+#define ICON_MDI_HARDDISK "\xf3\xb0\x8b\x8a" // U+F02CA
+#define ICON_MDI_HARDDISK_PLUS "\xf3\xb1\x81\x8b" // U+F104B
+#define ICON_MDI_HARDDISK_REMOVE "\xf3\xb1\x81\x8c" // U+F104C
+#define ICON_MDI_HAT_FEDORA "\xf3\xb0\xae\xa4" // U+F0BA4
+#define ICON_MDI_HAZARD_LIGHTS "\xf3\xb0\xb2\x89" // U+F0C89
+#define ICON_MDI_HDMI_PORT "\xf3\xb1\xae\xb8" // U+F1BB8
+#define ICON_MDI_HDR "\xf3\xb0\xb5\xbd" // U+F0D7D
+#define ICON_MDI_HDR_OFF "\xf3\xb0\xb5\xbe" // U+F0D7E
+#define ICON_MDI_HEAD "\xf3\xb1\x8d\x9e" // U+F135E
+#define ICON_MDI_HEAD_ALERT "\xf3\xb1\x8c\xb8" // U+F1338
+#define ICON_MDI_HEAD_ALERT_OUTLINE "\xf3\xb1\x8c\xb9" // U+F1339
+#define ICON_MDI_HEAD_CHECK "\xf3\xb1\x8c\xba" // U+F133A
+#define ICON_MDI_HEAD_CHECK_OUTLINE "\xf3\xb1\x8c\xbb" // U+F133B
+#define ICON_MDI_HEAD_COG "\xf3\xb1\x8c\xbc" // U+F133C
+#define ICON_MDI_HEAD_COG_OUTLINE "\xf3\xb1\x8c\xbd" // U+F133D
+#define ICON_MDI_HEAD_DOTS_HORIZONTAL "\xf3\xb1\x8c\xbe" // U+F133E
+#define ICON_MDI_HEAD_DOTS_HORIZONTAL_OUTLINE "\xf3\xb1\x8c\xbf" // U+F133F
+#define ICON_MDI_HEAD_FLASH "\xf3\xb1\x8d\x80" // U+F1340
+#define ICON_MDI_HEAD_FLASH_OUTLINE "\xf3\xb1\x8d\x81" // U+F1341
+#define ICON_MDI_HEAD_HEART "\xf3\xb1\x8d\x82" // U+F1342
+#define ICON_MDI_HEAD_HEART_OUTLINE "\xf3\xb1\x8d\x83" // U+F1343
+#define ICON_MDI_HEAD_LIGHTBULB "\xf3\xb1\x8d\x84" // U+F1344
+#define ICON_MDI_HEAD_LIGHTBULB_OUTLINE "\xf3\xb1\x8d\x85" // U+F1345
+#define ICON_MDI_HEAD_MINUS "\xf3\xb1\x8d\x86" // U+F1346
+#define ICON_MDI_HEAD_MINUS_OUTLINE "\xf3\xb1\x8d\x87" // U+F1347
+#define ICON_MDI_HEAD_OUTLINE "\xf3\xb1\x8d\x9f" // U+F135F
+#define ICON_MDI_HEAD_PLUS "\xf3\xb1\x8d\x88" // U+F1348
+#define ICON_MDI_HEAD_PLUS_OUTLINE "\xf3\xb1\x8d\x89" // U+F1349
+#define ICON_MDI_HEAD_QUESTION "\xf3\xb1\x8d\x8a" // U+F134A
+#define ICON_MDI_HEAD_QUESTION_OUTLINE "\xf3\xb1\x8d\x8b" // U+F134B
+#define ICON_MDI_HEAD_REMOVE "\xf3\xb1\x8d\x8c" // U+F134C
+#define ICON_MDI_HEAD_REMOVE_OUTLINE "\xf3\xb1\x8d\x8d" // U+F134D
+#define ICON_MDI_HEAD_SNOWFLAKE "\xf3\xb1\x8d\x8e" // U+F134E
+#define ICON_MDI_HEAD_SNOWFLAKE_OUTLINE "\xf3\xb1\x8d\x8f" // U+F134F
+#define ICON_MDI_HEAD_SYNC "\xf3\xb1\x8d\x90" // U+F1350
+#define ICON_MDI_HEAD_SYNC_OUTLINE "\xf3\xb1\x8d\x91" // U+F1351
+#define ICON_MDI_HEADPHONES "\xf3\xb0\x8b\x8b" // U+F02CB
+#define ICON_MDI_HEADPHONES_BLUETOOTH "\xf3\xb0\xa5\xb0" // U+F0970
+#define ICON_MDI_HEADPHONES_BOX "\xf3\xb0\x8b\x8c" // U+F02CC
+#define ICON_MDI_HEADPHONES_OFF "\xf3\xb0\x9f\x8e" // U+F07CE
+#define ICON_MDI_HEADPHONES_SETTINGS "\xf3\xb0\x8b\x8d" // U+F02CD
+#define ICON_MDI_HEADSET "\xf3\xb0\x8b\x8e" // U+F02CE
+#define ICON_MDI_HEADSET_DOCK "\xf3\xb0\x8b\x8f" // U+F02CF
+#define ICON_MDI_HEADSET_OFF "\xf3\xb0\x8b\x90" // U+F02D0
+#define ICON_MDI_HEART "\xf3\xb0\x8b\x91" // U+F02D1
+#define ICON_MDI_HEART_BOX "\xf3\xb0\x8b\x92" // U+F02D2
+#define ICON_MDI_HEART_BOX_OUTLINE "\xf3\xb0\x8b\x93" // U+F02D3
+#define ICON_MDI_HEART_BROKEN "\xf3\xb0\x8b\x94" // U+F02D4
+#define ICON_MDI_HEART_BROKEN_OUTLINE "\xf3\xb0\xb4\x94" // U+F0D14
+#define ICON_MDI_HEART_CIRCLE "\xf3\xb0\xa5\xb1" // U+F0971
+#define ICON_MDI_HEART_CIRCLE_OUTLINE "\xf3\xb0\xa5\xb2" // U+F0972
+#define ICON_MDI_HEART_COG "\xf3\xb1\x99\xa3" // U+F1663
+#define ICON_MDI_HEART_COG_OUTLINE "\xf3\xb1\x99\xa4" // U+F1664
+#define ICON_MDI_HEART_FLASH "\xf3\xb0\xbb\xb9" // U+F0EF9
+#define ICON_MDI_HEART_HALF "\xf3\xb0\x9b\x9f" // U+F06DF
+#define ICON_MDI_HEART_HALF_FULL "\xf3\xb0\x9b\x9e" // U+F06DE
+#define ICON_MDI_HEART_HALF_OUTLINE "\xf3\xb0\x9b\xa0" // U+F06E0
+#define ICON_MDI_HEART_MINUS "\xf3\xb1\x90\xaf" // U+F142F
+#define ICON_MDI_HEART_MINUS_OUTLINE "\xf3\xb1\x90\xb2" // U+F1432
+#define ICON_MDI_HEART_MULTIPLE "\xf3\xb0\xa9\x96" // U+F0A56
+#define ICON_MDI_HEART_MULTIPLE_OUTLINE "\xf3\xb0\xa9\x97" // U+F0A57
+#define ICON_MDI_HEART_OFF "\xf3\xb0\x9d\x99" // U+F0759
+#define ICON_MDI_HEART_OFF_OUTLINE "\xf3\xb1\x90\xb4" // U+F1434
+#define ICON_MDI_HEART_OUTLINE "\xf3\xb0\x8b\x95" // U+F02D5
+#define ICON_MDI_HEART_PLUS "\xf3\xb1\x90\xae" // U+F142E
+#define ICON_MDI_HEART_PLUS_OUTLINE "\xf3\xb1\x90\xb1" // U+F1431
+#define ICON_MDI_HEART_PULSE "\xf3\xb0\x97\xb6" // U+F05F6
+#define ICON_MDI_HEART_REMOVE "\xf3\xb1\x90\xb0" // U+F1430
+#define ICON_MDI_HEART_REMOVE_OUTLINE "\xf3\xb1\x90\xb3" // U+F1433
+#define ICON_MDI_HEART_SEARCH "\xf3\xb1\xb2\x8d" // U+F1C8D
+#define ICON_MDI_HEART_SETTINGS "\xf3\xb1\x99\xa5" // U+F1665
+#define ICON_MDI_HEART_SETTINGS_OUTLINE "\xf3\xb1\x99\xa6" // U+F1666
+#define ICON_MDI_HEAT_PUMP "\xf3\xb1\xa9\x83" // U+F1A43
+#define ICON_MDI_HEAT_PUMP_OUTLINE "\xf3\xb1\xa9\x84" // U+F1A44
+#define ICON_MDI_HEAT_WAVE "\xf3\xb1\xa9\x85" // U+F1A45
+#define ICON_MDI_HEATING_COIL "\xf3\xb1\xaa\xaf" // U+F1AAF
+#define ICON_MDI_HELICOPTER "\xf3\xb0\xab\x82" // U+F0AC2
+#define ICON_MDI_HELP "\xf3\xb0\x8b\x96" // U+F02D6
+#define ICON_MDI_HELP_BOX "\xf3\xb0\x9e\x8b" // U+F078B
+#define ICON_MDI_HELP_BOX_MULTIPLE "\xf3\xb1\xb0\x8a" // U+F1C0A
+#define ICON_MDI_HELP_BOX_MULTIPLE_OUTLINE "\xf3\xb1\xb0\x8b" // U+F1C0B
+#define ICON_MDI_HELP_BOX_OUTLINE "\xf3\xb1\xb0\x8c" // U+F1C0C
+#define ICON_MDI_HELP_CIRCLE "\xf3\xb0\x8b\x97" // U+F02D7
+#define ICON_MDI_HELP_CIRCLE_OUTLINE "\xf3\xb0\x98\xa5" // U+F0625
+#define ICON_MDI_HELP_NETWORK "\xf3\xb0\x9b\xb5" // U+F06F5
+#define ICON_MDI_HELP_NETWORK_OUTLINE "\xf3\xb0\xb2\x8a" // U+F0C8A
+#define ICON_MDI_HELP_RHOMBUS "\xf3\xb0\xae\xa5" // U+F0BA5
+#define ICON_MDI_HELP_RHOMBUS_OUTLINE "\xf3\xb0\xae\xa6" // U+F0BA6
+#define ICON_MDI_HEXADECIMAL "\xf3\xb1\x8a\xa7" // U+F12A7
+#define ICON_MDI_HEXAGON "\xf3\xb0\x8b\x98" // U+F02D8
+#define ICON_MDI_HEXAGON_MULTIPLE "\xf3\xb0\x9b\xa1" // U+F06E1
+#define ICON_MDI_HEXAGON_MULTIPLE_OUTLINE "\xf3\xb1\x83\xb2" // U+F10F2
+#define ICON_MDI_HEXAGON_OUTLINE "\xf3\xb0\x8b\x99" // U+F02D9
+#define ICON_MDI_HEXAGON_SLICE_1 "\xf3\xb0\xab\x83" // U+F0AC3
+#define ICON_MDI_HEXAGON_SLICE_2 "\xf3\xb0\xab\x84" // U+F0AC4
+#define ICON_MDI_HEXAGON_SLICE_3 "\xf3\xb0\xab\x85" // U+F0AC5
+#define ICON_MDI_HEXAGON_SLICE_4 "\xf3\xb0\xab\x86" // U+F0AC6
+#define ICON_MDI_HEXAGON_SLICE_5 "\xf3\xb0\xab\x87" // U+F0AC7
+#define ICON_MDI_HEXAGON_SLICE_6 "\xf3\xb0\xab\x88" // U+F0AC8
+#define ICON_MDI_HEXAGRAM "\xf3\xb0\xab\x89" // U+F0AC9
+#define ICON_MDI_HEXAGRAM_OUTLINE "\xf3\xb0\xab\x8a" // U+F0ACA
+#define ICON_MDI_HIGH_DEFINITION "\xf3\xb0\x9f\x8f" // U+F07CF
+#define ICON_MDI_HIGH_DEFINITION_BOX "\xf3\xb0\xa1\xb8" // U+F0878
+#define ICON_MDI_HIGHWAY "\xf3\xb0\x97\xb7" // U+F05F7
+#define ICON_MDI_HIKING "\xf3\xb0\xb5\xbf" // U+F0D7F
+#define ICON_MDI_HISTORY "\xf3\xb0\x8b\x9a" // U+F02DA
+#define ICON_MDI_HOCKEY_PUCK "\xf3\xb0\xa1\xb9" // U+F0879
+#define ICON_MDI_HOCKEY_STICKS "\xf3\xb0\xa1\xba" // U+F087A
+#define ICON_MDI_HOLOLENS "\xf3\xb0\x8b\x9b" // U+F02DB
+#define ICON_MDI_HOME "\xf3\xb0\x8b\x9c" // U+F02DC
+#define ICON_MDI_HOME_ACCOUNT "\xf3\xb0\xa0\xa6" // U+F0826
+#define ICON_MDI_HOME_ALERT "\xf3\xb0\xa1\xbb" // U+F087B
+#define ICON_MDI_HOME_ALERT_OUTLINE "\xf3\xb1\x97\x90" // U+F15D0
+#define ICON_MDI_HOME_ANALYTICS "\xf3\xb0\xba\xba" // U+F0EBA
+#define ICON_MDI_HOME_ASSISTANT "\xf3\xb0\x9f\x90" // U+F07D0
+#define ICON_MDI_HOME_AUTOMATION "\xf3\xb0\x9f\x91" // U+F07D1
+#define ICON_MDI_HOME_BATTERY "\xf3\xb1\xa4\x81" // U+F1901
+#define ICON_MDI_HOME_BATTERY_OUTLINE "\xf3\xb1\xa4\x82" // U+F1902
+#define ICON_MDI_HOME_CIRCLE "\xf3\xb0\x9f\x92" // U+F07D2
+#define ICON_MDI_HOME_CIRCLE_OUTLINE "\xf3\xb1\x81\x8d" // U+F104D
+#define ICON_MDI_HOME_CITY "\xf3\xb0\xb4\x95" // U+F0D15
+#define ICON_MDI_HOME_CITY_OUTLINE "\xf3\xb0\xb4\x96" // U+F0D16
+#define ICON_MDI_HOME_CLOCK "\xf3\xb1\xa8\x92" // U+F1A12
+#define ICON_MDI_HOME_CLOCK_OUTLINE "\xf3\xb1\xa8\x93" // U+F1A13
+#define ICON_MDI_HOME_EDIT "\xf3\xb1\x85\x99" // U+F1159
+#define ICON_MDI_HOME_EDIT_OUTLINE "\xf3\xb1\x85\x9a" // U+F115A
+#define ICON_MDI_HOME_EXPORT_OUTLINE "\xf3\xb0\xbe\x9b" // U+F0F9B
+#define ICON_MDI_HOME_FLOOD "\xf3\xb0\xbb\xba" // U+F0EFA
+#define ICON_MDI_HOME_FLOOR_0 "\xf3\xb0\xb7\x92" // U+F0DD2
+#define ICON_MDI_HOME_FLOOR_1 "\xf3\xb0\xb6\x80" // U+F0D80
+#define ICON_MDI_HOME_FLOOR_2 "\xf3\xb0\xb6\x81" // U+F0D81
+#define ICON_MDI_HOME_FLOOR_3 "\xf3\xb0\xb6\x82" // U+F0D82
+#define ICON_MDI_HOME_FLOOR_A "\xf3\xb0\xb6\x83" // U+F0D83
+#define ICON_MDI_HOME_FLOOR_B "\xf3\xb0\xb6\x84" // U+F0D84
+#define ICON_MDI_HOME_FLOOR_G "\xf3\xb0\xb6\x85" // U+F0D85
+#define ICON_MDI_HOME_FLOOR_L "\xf3\xb0\xb6\x86" // U+F0D86
+#define ICON_MDI_HOME_FLOOR_NEGATIVE_1 "\xf3\xb0\xb7\x93" // U+F0DD3
+#define ICON_MDI_HOME_GROUP "\xf3\xb0\xb7\x94" // U+F0DD4
+#define ICON_MDI_HOME_GROUP_MINUS "\xf3\xb1\xa7\x81" // U+F19C1
+#define ICON_MDI_HOME_GROUP_PLUS "\xf3\xb1\xa7\x80" // U+F19C0
+#define ICON_MDI_HOME_GROUP_REMOVE "\xf3\xb1\xa7\x82" // U+F19C2
+#define ICON_MDI_HOME_HEART "\xf3\xb0\xa0\xa7" // U+F0827
+#define ICON_MDI_HOME_IMPORT_OUTLINE "\xf3\xb0\xbe\x9c" // U+F0F9C
+#define ICON_MDI_HOME_LIGHTBULB "\xf3\xb1\x89\x91" // U+F1251
+#define ICON_MDI_HOME_LIGHTBULB_OUTLINE "\xf3\xb1\x89\x92" // U+F1252
+#define ICON_MDI_HOME_LIGHTNING_BOLT "\xf3\xb1\xa4\x83" // U+F1903
+#define ICON_MDI_HOME_LIGHTNING_BOLT_OUTLINE "\xf3\xb1\xa4\x84" // U+F1904
+#define ICON_MDI_HOME_LOCK "\xf3\xb0\xa3\xab" // U+F08EB
+#define ICON_MDI_HOME_LOCK_OPEN "\xf3\xb0\xa3\xac" // U+F08EC
+#define ICON_MDI_HOME_MAP_MARKER "\xf3\xb0\x97\xb8" // U+F05F8
+#define ICON_MDI_HOME_MINUS "\xf3\xb0\xa5\xb4" // U+F0974
+#define ICON_MDI_HOME_MINUS_OUTLINE "\xf3\xb1\x8f\x95" // U+F13D5
+#define ICON_MDI_HOME_MODERN "\xf3\xb0\x8b\x9d" // U+F02DD
+#define ICON_MDI_HOME_OFF "\xf3\xb1\xa9\x86" // U+F1A46
+#define ICON_MDI_HOME_OFF_OUTLINE "\xf3\xb1\xa9\x87" // U+F1A47
+#define ICON_MDI_HOME_OUTLINE "\xf3\xb0\x9a\xa1" // U+F06A1
+#define ICON_MDI_HOME_PERCENT "\xf3\xb1\xb1\xbc" // U+F1C7C
+#define ICON_MDI_HOME_PERCENT_OUTLINE "\xf3\xb1\xb1\xbd" // U+F1C7D
+#define ICON_MDI_HOME_PLUS "\xf3\xb0\xa5\xb5" // U+F0975
+#define ICON_MDI_HOME_PLUS_OUTLINE "\xf3\xb1\x8f\x96" // U+F13D6
+#define ICON_MDI_HOME_REMOVE "\xf3\xb1\x89\x87" // U+F1247
+#define ICON_MDI_HOME_REMOVE_OUTLINE "\xf3\xb1\x8f\x97" // U+F13D7
+#define ICON_MDI_HOME_ROOF "\xf3\xb1\x84\xab" // U+F112B
+#define ICON_MDI_HOME_SEARCH "\xf3\xb1\x8e\xb0" // U+F13B0
+#define ICON_MDI_HOME_SEARCH_OUTLINE "\xf3\xb1\x8e\xb1" // U+F13B1
+#define ICON_MDI_HOME_SILO "\xf3\xb1\xae\xa0" // U+F1BA0
+#define ICON_MDI_HOME_SILO_OUTLINE "\xf3\xb1\xae\xa1" // U+F1BA1
+#define ICON_MDI_HOME_SOUND_IN "\xf3\xb1\xb0\xaf" // U+F1C2F
+#define ICON_MDI_HOME_SOUND_IN_OUTLINE "\xf3\xb1\xb0\xb0" // U+F1C30
+#define ICON_MDI_HOME_SOUND_OUT "\xf3\xb1\xb0\xb1" // U+F1C31
+#define ICON_MDI_HOME_SOUND_OUT_OUTLINE "\xf3\xb1\xb0\xb2" // U+F1C32
+#define ICON_MDI_HOME_SWITCH "\xf3\xb1\x9e\x94" // U+F1794
+#define ICON_MDI_HOME_SWITCH_OUTLINE "\xf3\xb1\x9e\x95" // U+F1795
+#define ICON_MDI_HOME_THERMOMETER "\xf3\xb0\xbd\x94" // U+F0F54
+#define ICON_MDI_HOME_THERMOMETER_OUTLINE "\xf3\xb0\xbd\x95" // U+F0F55
+#define ICON_MDI_HOME_VARIANT "\xf3\xb0\x8b\x9e" // U+F02DE
+#define ICON_MDI_HOME_VARIANT_OUTLINE "\xf3\xb0\xae\xa7" // U+F0BA7
+#define ICON_MDI_HOOK "\xf3\xb0\x9b\xa2" // U+F06E2
+#define ICON_MDI_HOOK_OFF "\xf3\xb0\x9b\xa3" // U+F06E3
+#define ICON_MDI_HOOP_HOUSE "\xf3\xb0\xb9\x96" // U+F0E56
+#define ICON_MDI_HOPS "\xf3\xb0\x8b\x9f" // U+F02DF
+#define ICON_MDI_HORIZONTAL_ROTATE_CLOCKWISE "\xf3\xb1\x83\xb3" // U+F10F3
+#define ICON_MDI_HORIZONTAL_ROTATE_COUNTERCLOCKWISE "\xf3\xb1\x83\xb4" // U+F10F4
+#define ICON_MDI_HORSE "\xf3\xb1\x96\xbf" // U+F15BF
+#define ICON_MDI_HORSE_HUMAN "\xf3\xb1\x97\x80" // U+F15C0
+#define ICON_MDI_HORSE_VARIANT "\xf3\xb1\x97\x81" // U+F15C1
+#define ICON_MDI_HORSE_VARIANT_FAST "\xf3\xb1\xa1\xae" // U+F186E
+#define ICON_MDI_HORSESHOE "\xf3\xb0\xa9\x98" // U+F0A58
+#define ICON_MDI_HOSPITAL "\xf3\xb0\xbf\xb6" // U+F0FF6
+#define ICON_MDI_HOSPITAL_BOX "\xf3\xb0\x8b\xa0" // U+F02E0
+#define ICON_MDI_HOSPITAL_BOX_OUTLINE "\xf3\xb0\xbf\xb7" // U+F0FF7
+#define ICON_MDI_HOSPITAL_BUILDING "\xf3\xb0\x8b\xa1" // U+F02E1
+#define ICON_MDI_HOSPITAL_MARKER "\xf3\xb0\x8b\xa2" // U+F02E2
+#define ICON_MDI_HOT_TUB "\xf3\xb0\xa0\xa8" // U+F0828
+#define ICON_MDI_HOURS_12 "\xf3\xb1\xb2\x94" // U+F1C94
+#define ICON_MDI_HOURS_24 "\xf3\xb1\x91\xb8" // U+F1478
+#define ICON_MDI_HUB "\xf3\xb1\xb2\x95" // U+F1C95
+#define ICON_MDI_HUB_OUTLINE "\xf3\xb1\xb2\x96" // U+F1C96
+#define ICON_MDI_HUBSPOT "\xf3\xb0\xb4\x97" // U+F0D17
+#define ICON_MDI_HULU "\xf3\xb0\xa0\xa9" // U+F0829
+#define ICON_MDI_HUMAN "\xf3\xb0\x8b\xa6" // U+F02E6
+#define ICON_MDI_HUMAN_BABY_CHANGING_TABLE "\xf3\xb1\x8e\x8b" // U+F138B
+#define ICON_MDI_HUMAN_CANE "\xf3\xb1\x96\x81" // U+F1581
+#define ICON_MDI_HUMAN_CAPACITY_DECREASE "\xf3\xb1\x96\x9b" // U+F159B
+#define ICON_MDI_HUMAN_CAPACITY_INCREASE "\xf3\xb1\x96\x9c" // U+F159C
+#define ICON_MDI_HUMAN_CHILD "\xf3\xb0\x8b\xa7" // U+F02E7
+#define ICON_MDI_HUMAN_DOLLY "\xf3\xb1\xa6\x80" // U+F1980
+#define ICON_MDI_HUMAN_EDIT "\xf3\xb1\x93\xa8" // U+F14E8
+#define ICON_MDI_HUMAN_FEMALE "\xf3\xb0\x99\x89" // U+F0649
+#define ICON_MDI_HUMAN_FEMALE_BOY "\xf3\xb0\xa9\x99" // U+F0A59
+#define ICON_MDI_HUMAN_FEMALE_DANCE "\xf3\xb1\x97\x89" // U+F15C9
+#define ICON_MDI_HUMAN_FEMALE_FEMALE "\xf3\xb0\xa9\x9a" // U+F0A5A
+#define ICON_MDI_HUMAN_FEMALE_FEMALE_CHILD "\xf3\xb1\xb2\x8e" // U+F1C8E
+#define ICON_MDI_HUMAN_FEMALE_GIRL "\xf3\xb0\xa9\x9b" // U+F0A5B
+#define ICON_MDI_HUMAN_GREETING "\xf3\xb1\x9f\x84" // U+F17C4
+#define ICON_MDI_HUMAN_GREETING_PROXIMITY "\xf3\xb1\x96\x9d" // U+F159D
+#define ICON_MDI_HUMAN_GREETING_VARIANT "\xf3\xb0\x99\x8a" // U+F064A
+#define ICON_MDI_HUMAN_HANDSDOWN "\xf3\xb0\x99\x8b" // U+F064B
+#define ICON_MDI_HUMAN_HANDSUP "\xf3\xb0\x99\x8c" // U+F064C
+#define ICON_MDI_HUMAN_MALE "\xf3\xb0\x99\x8d" // U+F064D
+#define ICON_MDI_HUMAN_MALE_BOARD "\xf3\xb0\xa2\x90" // U+F0890
+#define ICON_MDI_HUMAN_MALE_BOARD_POLL "\xf3\xb0\xa1\x86" // U+F0846
+#define ICON_MDI_HUMAN_MALE_BOY "\xf3\xb0\xa9\x9c" // U+F0A5C
+#define ICON_MDI_HUMAN_MALE_CHILD "\xf3\xb1\x8e\x8c" // U+F138C
+#define ICON_MDI_HUMAN_MALE_FEMALE "\xf3\xb0\x8b\xa8" // U+F02E8
+#define ICON_MDI_HUMAN_MALE_FEMALE_CHILD "\xf3\xb1\xa0\xa3" // U+F1823
+#define ICON_MDI_HUMAN_MALE_GIRL "\xf3\xb0\xa9\x9d" // U+F0A5D
+#define ICON_MDI_HUMAN_MALE_HEIGHT "\xf3\xb0\xbb\xbb" // U+F0EFB
+#define ICON_MDI_HUMAN_MALE_HEIGHT_VARIANT "\xf3\xb0\xbb\xbc" // U+F0EFC
+#define ICON_MDI_HUMAN_MALE_MALE "\xf3\xb0\xa9\x9e" // U+F0A5E
+#define ICON_MDI_HUMAN_MALE_MALE_CHILD "\xf3\xb1\xb2\x8f" // U+F1C8F
+#define ICON_MDI_HUMAN_NON_BINARY "\xf3\xb1\xa1\x88" // U+F1848
+#define ICON_MDI_HUMAN_PREGNANT "\xf3\xb0\x97\x8f" // U+F05CF
+#define ICON_MDI_HUMAN_QUEUE "\xf3\xb1\x95\xb1" // U+F1571
+#define ICON_MDI_HUMAN_SCOOTER "\xf3\xb1\x87\xa9" // U+F11E9
+#define ICON_MDI_HUMAN_WALKER "\xf3\xb1\xad\xb1" // U+F1B71
+#define ICON_MDI_HUMAN_WHEELCHAIR "\xf3\xb1\x8e\x8d" // U+F138D
+#define ICON_MDI_HUMAN_WHITE_CANE "\xf3\xb1\xa6\x81" // U+F1981
+#define ICON_MDI_HUMBLE_BUNDLE "\xf3\xb0\x9d\x84" // U+F0744
+#define ICON_MDI_HVAC "\xf3\xb1\x8d\x92" // U+F1352
+#define ICON_MDI_HVAC_OFF "\xf3\xb1\x96\x9e" // U+F159E
+#define ICON_MDI_HYDRAULIC_OIL_LEVEL "\xf3\xb1\x8c\xa4" // U+F1324
+#define ICON_MDI_HYDRAULIC_OIL_TEMPERATURE "\xf3\xb1\x8c\xa5" // U+F1325
+#define ICON_MDI_HYDRO_POWER "\xf3\xb1\x8b\xa5" // U+F12E5
+#define ICON_MDI_HYDROGEN_STATION "\xf3\xb1\xa2\x94" // U+F1894
+#define ICON_MDI_ICE_CREAM "\xf3\xb0\xa0\xaa" // U+F082A
+#define ICON_MDI_ICE_CREAM_OFF "\xf3\xb0\xb9\x92" // U+F0E52
+#define ICON_MDI_ICE_POP "\xf3\xb0\xbb\xbd" // U+F0EFD
+#define ICON_MDI_ID_CARD "\xf3\xb0\xbf\x80" // U+F0FC0
+#define ICON_MDI_IDENTIFIER "\xf3\xb0\xbb\xbe" // U+F0EFE
+#define ICON_MDI_IDEOGRAM_CJK "\xf3\xb1\x8c\xb1" // U+F1331
+#define ICON_MDI_IDEOGRAM_CJK_VARIANT "\xf3\xb1\x8c\xb2" // U+F1332
+#define ICON_MDI_IMAGE "\xf3\xb0\x8b\xa9" // U+F02E9
+#define ICON_MDI_IMAGE_ALBUM "\xf3\xb0\x8b\xaa" // U+F02EA
+#define ICON_MDI_IMAGE_AREA "\xf3\xb0\x8b\xab" // U+F02EB
+#define ICON_MDI_IMAGE_AREA_CLOSE "\xf3\xb0\x8b\xac" // U+F02EC
+#define ICON_MDI_IMAGE_AUTO_ADJUST "\xf3\xb0\xbf\x81" // U+F0FC1
+#define ICON_MDI_IMAGE_BROKEN "\xf3\xb0\x8b\xad" // U+F02ED
+#define ICON_MDI_IMAGE_BROKEN_VARIANT "\xf3\xb0\x8b\xae" // U+F02EE
+#define ICON_MDI_IMAGE_CHECK "\xf3\xb1\xac\xa5" // U+F1B25
+#define ICON_MDI_IMAGE_CHECK_OUTLINE "\xf3\xb1\xac\xa6" // U+F1B26
+#define ICON_MDI_IMAGE_EDIT "\xf3\xb1\x87\xa3" // U+F11E3
+#define ICON_MDI_IMAGE_EDIT_OUTLINE "\xf3\xb1\x87\xa4" // U+F11E4
+#define ICON_MDI_IMAGE_FILTER_BLACK_WHITE "\xf3\xb0\x8b\xb0" // U+F02F0
+#define ICON_MDI_IMAGE_FILTER_CENTER_FOCUS "\xf3\xb0\x8b\xb1" // U+F02F1
+#define ICON_MDI_IMAGE_FILTER_CENTER_FOCUS_STRONG "\xf3\xb0\xbb\xbf" // U+F0EFF
+#define ICON_MDI_IMAGE_FILTER_CENTER_FOCUS_STRONG_OUTLINE "\xf3\xb0\xbc\x80" // U+F0F00
+#define ICON_MDI_IMAGE_FILTER_CENTER_FOCUS_WEAK "\xf3\xb0\x8b\xb2" // U+F02F2
+#define ICON_MDI_IMAGE_FILTER_DRAMA "\xf3\xb0\x8b\xb3" // U+F02F3
+#define ICON_MDI_IMAGE_FILTER_DRAMA_OUTLINE "\xf3\xb1\xaf\xbf" // U+F1BFF
+#define ICON_MDI_IMAGE_FILTER_FRAMES "\xf3\xb0\x8b\xb4" // U+F02F4
+#define ICON_MDI_IMAGE_FILTER_HDR "\xf3\xb0\x8b\xb5" // U+F02F5
+#define ICON_MDI_IMAGE_FILTER_HDR_OUTLINE "\xf3\xb1\xb1\xa4" // U+F1C64
+#define ICON_MDI_IMAGE_FILTER_NONE "\xf3\xb0\x8b\xb6" // U+F02F6
+#define ICON_MDI_IMAGE_FILTER_TILT_SHIFT "\xf3\xb0\x8b\xb7" // U+F02F7
+#define ICON_MDI_IMAGE_FILTER_VINTAGE "\xf3\xb0\x8b\xb8" // U+F02F8
+#define ICON_MDI_IMAGE_FRAME "\xf3\xb0\xb9\x89" // U+F0E49
+#define ICON_MDI_IMAGE_LOCK "\xf3\xb1\xaa\xb0" // U+F1AB0
+#define ICON_MDI_IMAGE_LOCK_OUTLINE "\xf3\xb1\xaa\xb1" // U+F1AB1
+#define ICON_MDI_IMAGE_MARKER "\xf3\xb1\x9d\xbb" // U+F177B
+#define ICON_MDI_IMAGE_MARKER_OUTLINE "\xf3\xb1\x9d\xbc" // U+F177C
+#define ICON_MDI_IMAGE_MINUS "\xf3\xb1\x90\x99" // U+F1419
+#define ICON_MDI_IMAGE_MINUS_OUTLINE "\xf3\xb1\xad\x87" // U+F1B47
+#define ICON_MDI_IMAGE_MOVE "\xf3\xb0\xa7\xb8" // U+F09F8
+#define ICON_MDI_IMAGE_MULTIPLE "\xf3\xb0\x8b\xb9" // U+F02F9
+#define ICON_MDI_IMAGE_MULTIPLE_OUTLINE "\xf3\xb0\x8b\xaf" // U+F02EF
+#define ICON_MDI_IMAGE_OFF "\xf3\xb0\xa0\xab" // U+F082B
+#define ICON_MDI_IMAGE_OFF_OUTLINE "\xf3\xb1\x87\x91" // U+F11D1
+#define ICON_MDI_IMAGE_OUTLINE "\xf3\xb0\xa5\xb6" // U+F0976
+#define ICON_MDI_IMAGE_PLUS "\xf3\xb0\xa1\xbc" // U+F087C
+#define ICON_MDI_IMAGE_PLUS_OUTLINE "\xf3\xb1\xad\x86" // U+F1B46
+#define ICON_MDI_IMAGE_REFRESH "\xf3\xb1\xa7\xbe" // U+F19FE
+#define ICON_MDI_IMAGE_REFRESH_OUTLINE "\xf3\xb1\xa7\xbf" // U+F19FF
+#define ICON_MDI_IMAGE_REMOVE "\xf3\xb1\x90\x98" // U+F1418
+#define ICON_MDI_IMAGE_REMOVE_OUTLINE "\xf3\xb1\xad\x88" // U+F1B48
+#define ICON_MDI_IMAGE_SEARCH "\xf3\xb0\xa5\xb7" // U+F0977
+#define ICON_MDI_IMAGE_SEARCH_OUTLINE "\xf3\xb0\xa5\xb8" // U+F0978
+#define ICON_MDI_IMAGE_SIZE_SELECT_ACTUAL "\xf3\xb0\xb2\x8d" // U+F0C8D
+#define ICON_MDI_IMAGE_SIZE_SELECT_LARGE "\xf3\xb0\xb2\x8e" // U+F0C8E
+#define ICON_MDI_IMAGE_SIZE_SELECT_SMALL "\xf3\xb0\xb2\x8f" // U+F0C8F
+#define ICON_MDI_IMAGE_SYNC "\xf3\xb1\xa8\x80" // U+F1A00
+#define ICON_MDI_IMAGE_SYNC_OUTLINE "\xf3\xb1\xa8\x81" // U+F1A01
+#define ICON_MDI_IMAGE_TEXT "\xf3\xb1\x98\x8d" // U+F160D
+#define ICON_MDI_IMPORT "\xf3\xb0\x8b\xba" // U+F02FA
+#define ICON_MDI_INBOX "\xf3\xb0\x9a\x87" // U+F0687
+#define ICON_MDI_INBOX_ARROW_DOWN "\xf3\xb0\x8b\xbb" // U+F02FB
+#define ICON_MDI_INBOX_ARROW_DOWN_OUTLINE "\xf3\xb1\x89\xb0" // U+F1270
+#define ICON_MDI_INBOX_ARROW_UP "\xf3\xb0\x8f\x91" // U+F03D1
+#define ICON_MDI_INBOX_ARROW_UP_OUTLINE "\xf3\xb1\x89\xb1" // U+F1271
+#define ICON_MDI_INBOX_FULL "\xf3\xb1\x89\xb2" // U+F1272
+#define ICON_MDI_INBOX_FULL_OUTLINE "\xf3\xb1\x89\xb3" // U+F1273
+#define ICON_MDI_INBOX_MULTIPLE "\xf3\xb0\xa2\xb0" // U+F08B0
+#define ICON_MDI_INBOX_MULTIPLE_OUTLINE "\xf3\xb0\xae\xa8" // U+F0BA8
+#define ICON_MDI_INBOX_OUTLINE "\xf3\xb1\x89\xb4" // U+F1274
+#define ICON_MDI_INBOX_REMOVE "\xf3\xb1\x96\x9f" // U+F159F
+#define ICON_MDI_INBOX_REMOVE_OUTLINE "\xf3\xb1\x96\xa0" // U+F15A0
+#define ICON_MDI_INCOGNITO "\xf3\xb0\x97\xb9" // U+F05F9
+#define ICON_MDI_INCOGNITO_CIRCLE "\xf3\xb1\x90\xa1" // U+F1421
+#define ICON_MDI_INCOGNITO_CIRCLE_OFF "\xf3\xb1\x90\xa2" // U+F1422
+#define ICON_MDI_INCOGNITO_OFF "\xf3\xb0\x81\xb5" // U+F0075
+#define ICON_MDI_INDUCTION "\xf3\xb1\xa1\x8c" // U+F184C
+#define ICON_MDI_INFINITY "\xf3\xb0\x9b\xa4" // U+F06E4
+#define ICON_MDI_INFORMATION "\xf3\xb0\x8b\xbc" // U+F02FC
+#define ICON_MDI_INFORMATION_BOX "\xf3\xb1\xb1\xa5" // U+F1C65
+#define ICON_MDI_INFORMATION_BOX_OUTLINE "\xf3\xb1\xb1\xa6" // U+F1C66
+#define ICON_MDI_INFORMATION_OFF "\xf3\xb1\x9e\x8c" // U+F178C
+#define ICON_MDI_INFORMATION_OFF_OUTLINE "\xf3\xb1\x9e\x8d" // U+F178D
+#define ICON_MDI_INFORMATION_OUTLINE "\xf3\xb0\x8b\xbd" // U+F02FD
+#define ICON_MDI_INFORMATION_SLAB_BOX "\xf3\xb1\xb1\xa7" // U+F1C67
+#define ICON_MDI_INFORMATION_SLAB_BOX_OUTLINE "\xf3\xb1\xb1\xa8" // U+F1C68
+#define ICON_MDI_INFORMATION_SLAB_CIRCLE "\xf3\xb1\xb1\xa9" // U+F1C69
+#define ICON_MDI_INFORMATION_SLAB_CIRCLE_OUTLINE "\xf3\xb1\xb1\xaa" // U+F1C6A
+#define ICON_MDI_INFORMATION_SLAB_SYMBOL "\xf3\xb1\xb1\xab" // U+F1C6B
+#define ICON_MDI_INFORMATION_SYMBOL "\xf3\xb1\xb1\xac" // U+F1C6C
+#define ICON_MDI_INFORMATION_VARIANT "\xf3\xb0\x99\x8e" // U+F064E
+#define ICON_MDI_INFORMATION_VARIANT_BOX "\xf3\xb1\xb1\xad" // U+F1C6D
+#define ICON_MDI_INFORMATION_VARIANT_BOX_OUTLINE "\xf3\xb1\xb1\xae" // U+F1C6E
+#define ICON_MDI_INFORMATION_VARIANT_CIRCLE "\xf3\xb1\xb1\xaf" // U+F1C6F
+#define ICON_MDI_INFORMATION_VARIANT_CIRCLE_OUTLINE "\xf3\xb1\xb1\xb0" // U+F1C70
+#define ICON_MDI_INSTAGRAM "\xf3\xb0\x8b\xbe" // U+F02FE
+#define ICON_MDI_INSTRUMENT_TRIANGLE "\xf3\xb1\x81\x8e" // U+F104E
+#define ICON_MDI_INTEGRATED_CIRCUIT_CHIP "\xf3\xb1\xa4\x93" // U+F1913
+#define ICON_MDI_INVERT_COLORS "\xf3\xb0\x8c\x81" // U+F0301
+#define ICON_MDI_INVERT_COLORS_OFF "\xf3\xb0\xb9\x8a" // U+F0E4A
+#define ICON_MDI_IOBROKER "\xf3\xb1\x8b\xa8" // U+F12E8
+#define ICON_MDI_IP "\xf3\xb0\xa9\x9f" // U+F0A5F
+#define ICON_MDI_IP_NETWORK "\xf3\xb0\xa9\xa0" // U+F0A60
+#define ICON_MDI_IP_NETWORK_OUTLINE "\xf3\xb0\xb2\x90" // U+F0C90
+#define ICON_MDI_IP_OUTLINE "\xf3\xb1\xa6\x82" // U+F1982
+#define ICON_MDI_IPOD "\xf3\xb0\xb2\x91" // U+F0C91
+#define ICON_MDI_IRON "\xf3\xb1\xa0\xa4" // U+F1824
+#define ICON_MDI_IRON_BOARD "\xf3\xb1\xa0\xb8" // U+F1838
+#define ICON_MDI_IRON_OUTLINE "\xf3\xb1\xa0\xa5" // U+F1825
+#define ICON_MDI_ISLAND "\xf3\xb1\x81\x8f" // U+F104F
+#define ICON_MDI_ISLAND_VARIANT "\xf3\xb1\xb3\x86" // U+F1CC6
+#define ICON_MDI_IV_BAG "\xf3\xb1\x82\xb9" // U+F10B9
+#define ICON_MDI_JABBER "\xf3\xb0\xb7\x95" // U+F0DD5
+#define ICON_MDI_JEEPNEY "\xf3\xb0\x8c\x82" // U+F0302
+#define ICON_MDI_JELLYFISH "\xf3\xb0\xbc\x81" // U+F0F01
+#define ICON_MDI_JELLYFISH_OUTLINE "\xf3\xb0\xbc\x82" // U+F0F02
+#define ICON_MDI_JIRA "\xf3\xb0\x8c\x83" // U+F0303
+#define ICON_MDI_JQUERY "\xf3\xb0\xa1\xbd" // U+F087D
+#define ICON_MDI_JSFIDDLE "\xf3\xb0\x8c\x84" // U+F0304
+#define ICON_MDI_JUMP_ROPE "\xf3\xb1\x8b\xbf" // U+F12FF
+#define ICON_MDI_KABADDI "\xf3\xb0\xb6\x87" // U+F0D87
+#define ICON_MDI_KANGAROO "\xf3\xb1\x95\x98" // U+F1558
+#define ICON_MDI_KARATE "\xf3\xb0\xa0\xac" // U+F082C
+#define ICON_MDI_KAYAKING "\xf3\xb0\xa2\xaf" // U+F08AF
+#define ICON_MDI_KEG "\xf3\xb0\x8c\x85" // U+F0305
+#define ICON_MDI_KETTLE "\xf3\xb0\x97\xba" // U+F05FA
+#define ICON_MDI_KETTLE_ALERT "\xf3\xb1\x8c\x97" // U+F1317
+#define ICON_MDI_KETTLE_ALERT_OUTLINE "\xf3\xb1\x8c\x98" // U+F1318
+#define ICON_MDI_KETTLE_OFF "\xf3\xb1\x8c\x9b" // U+F131B
+#define ICON_MDI_KETTLE_OFF_OUTLINE "\xf3\xb1\x8c\x9c" // U+F131C
+#define ICON_MDI_KETTLE_OUTLINE "\xf3\xb0\xbd\x96" // U+F0F56
+#define ICON_MDI_KETTLE_POUR_OVER "\xf3\xb1\x9c\xbc" // U+F173C
+#define ICON_MDI_KETTLE_STEAM "\xf3\xb1\x8c\x99" // U+F1319
+#define ICON_MDI_KETTLE_STEAM_OUTLINE "\xf3\xb1\x8c\x9a" // U+F131A
+#define ICON_MDI_KETTLEBELL "\xf3\xb1\x8c\x80" // U+F1300
+#define ICON_MDI_KEY "\xf3\xb0\x8c\x86" // U+F0306
+#define ICON_MDI_KEY_ALERT "\xf3\xb1\xa6\x83" // U+F1983
+#define ICON_MDI_KEY_ALERT_OUTLINE "\xf3\xb1\xa6\x84" // U+F1984
+#define ICON_MDI_KEY_ARROW_RIGHT "\xf3\xb1\x8c\x92" // U+F1312
+#define ICON_MDI_KEY_CHAIN "\xf3\xb1\x95\xb4" // U+F1574
+#define ICON_MDI_KEY_CHAIN_VARIANT "\xf3\xb1\x95\xb5" // U+F1575
+#define ICON_MDI_KEY_CHANGE "\xf3\xb0\x8c\x87" // U+F0307
+#define ICON_MDI_KEY_LINK "\xf3\xb1\x86\x9f" // U+F119F
+#define ICON_MDI_KEY_MINUS "\xf3\xb0\x8c\x88" // U+F0308
+#define ICON_MDI_KEY_OUTLINE "\xf3\xb0\xb7\x96" // U+F0DD6
+#define ICON_MDI_KEY_PLUS "\xf3\xb0\x8c\x89" // U+F0309
+#define ICON_MDI_KEY_REMOVE "\xf3\xb0\x8c\x8a" // U+F030A
+#define ICON_MDI_KEY_STAR "\xf3\xb1\x86\x9e" // U+F119E
+#define ICON_MDI_KEY_VARIANT "\xf3\xb0\x8c\x8b" // U+F030B
+#define ICON_MDI_KEY_WIRELESS "\xf3\xb0\xbf\x82" // U+F0FC2
+#define ICON_MDI_KEYBOARD "\xf3\xb0\x8c\x8c" // U+F030C
+#define ICON_MDI_KEYBOARD_BACKSPACE "\xf3\xb0\x8c\x8d" // U+F030D
+#define ICON_MDI_KEYBOARD_CAPS "\xf3\xb0\x8c\x8e" // U+F030E
+#define ICON_MDI_KEYBOARD_CLOSE "\xf3\xb0\x8c\x8f" // U+F030F
+#define ICON_MDI_KEYBOARD_CLOSE_OUTLINE "\xf3\xb1\xb0\x80" // U+F1C00
+#define ICON_MDI_KEYBOARD_ESC "\xf3\xb1\x8a\xb7" // U+F12B7
+#define ICON_MDI_KEYBOARD_F1 "\xf3\xb1\x8a\xab" // U+F12AB
+#define ICON_MDI_KEYBOARD_F10 "\xf3\xb1\x8a\xb4" // U+F12B4
+#define ICON_MDI_KEYBOARD_F11 "\xf3\xb1\x8a\xb5" // U+F12B5
+#define ICON_MDI_KEYBOARD_F12 "\xf3\xb1\x8a\xb6" // U+F12B6
+#define ICON_MDI_KEYBOARD_F2 "\xf3\xb1\x8a\xac" // U+F12AC
+#define ICON_MDI_KEYBOARD_F3 "\xf3\xb1\x8a\xad" // U+F12AD
+#define ICON_MDI_KEYBOARD_F4 "\xf3\xb1\x8a\xae" // U+F12AE
+#define ICON_MDI_KEYBOARD_F5 "\xf3\xb1\x8a\xaf" // U+F12AF
+#define ICON_MDI_KEYBOARD_F6 "\xf3\xb1\x8a\xb0" // U+F12B0
+#define ICON_MDI_KEYBOARD_F7 "\xf3\xb1\x8a\xb1" // U+F12B1
+#define ICON_MDI_KEYBOARD_F8 "\xf3\xb1\x8a\xb2" // U+F12B2
+#define ICON_MDI_KEYBOARD_F9 "\xf3\xb1\x8a\xb3" // U+F12B3
+#define ICON_MDI_KEYBOARD_OFF "\xf3\xb0\x8c\x90" // U+F0310
+#define ICON_MDI_KEYBOARD_OFF_OUTLINE "\xf3\xb0\xb9\x8b" // U+F0E4B
+#define ICON_MDI_KEYBOARD_OUTLINE "\xf3\xb0\xa5\xbb" // U+F097B
+#define ICON_MDI_KEYBOARD_RETURN "\xf3\xb0\x8c\x91" // U+F0311
+#define ICON_MDI_KEYBOARD_SETTINGS "\xf3\xb0\xa7\xb9" // U+F09F9
+#define ICON_MDI_KEYBOARD_SETTINGS_OUTLINE "\xf3\xb0\xa7\xba" // U+F09FA
+#define ICON_MDI_KEYBOARD_SPACE "\xf3\xb1\x81\x90" // U+F1050
+#define ICON_MDI_KEYBOARD_TAB "\xf3\xb0\x8c\x92" // U+F0312
+#define ICON_MDI_KEYBOARD_TAB_REVERSE "\xf3\xb0\x8c\xa5" // U+F0325
+#define ICON_MDI_KEYBOARD_VARIANT "\xf3\xb0\x8c\x93" // U+F0313
+#define ICON_MDI_KHANDA "\xf3\xb1\x83\xbd" // U+F10FD
+#define ICON_MDI_KICKSTARTER "\xf3\xb0\x9d\x85" // U+F0745
+#define ICON_MDI_KITE "\xf3\xb1\xa6\x85" // U+F1985
+#define ICON_MDI_KITE_OUTLINE "\xf3\xb1\xa6\x86" // U+F1986
+#define ICON_MDI_KITESURFING "\xf3\xb1\x9d\x84" // U+F1744
+#define ICON_MDI_KLINGON "\xf3\xb1\x8d\x9b" // U+F135B
+#define ICON_MDI_KNIFE "\xf3\xb0\xa7\xbb" // U+F09FB
+#define ICON_MDI_KNIFE_MILITARY "\xf3\xb0\xa7\xbc" // U+F09FC
+#define ICON_MDI_KNOB "\xf3\xb1\xae\x96" // U+F1B96
+#define ICON_MDI_KOALA "\xf3\xb1\x9c\xbf" // U+F173F
+#define ICON_MDI_KODI "\xf3\xb0\x8c\x94" // U+F0314
+#define ICON_MDI_KUBERNETES "\xf3\xb1\x83\xbe" // U+F10FE
+#define ICON_MDI_LABEL "\xf3\xb0\x8c\x95" // U+F0315
+#define ICON_MDI_LABEL_MULTIPLE "\xf3\xb1\x8d\xb5" // U+F1375
+#define ICON_MDI_LABEL_MULTIPLE_OUTLINE "\xf3\xb1\x8d\xb6" // U+F1376
+#define ICON_MDI_LABEL_OFF "\xf3\xb0\xab\x8b" // U+F0ACB
+#define ICON_MDI_LABEL_OFF_OUTLINE "\xf3\xb0\xab\x8c" // U+F0ACC
+#define ICON_MDI_LABEL_OUTLINE "\xf3\xb0\x8c\x96" // U+F0316
+#define ICON_MDI_LABEL_PERCENT "\xf3\xb1\x8b\xaa" // U+F12EA
+#define ICON_MDI_LABEL_PERCENT_OUTLINE "\xf3\xb1\x8b\xab" // U+F12EB
+#define ICON_MDI_LABEL_VARIANT "\xf3\xb0\xab\x8d" // U+F0ACD
+#define ICON_MDI_LABEL_VARIANT_OUTLINE "\xf3\xb0\xab\x8e" // U+F0ACE
+#define ICON_MDI_LADDER "\xf3\xb1\x96\xa2" // U+F15A2
+#define ICON_MDI_LADYBUG "\xf3\xb0\xa0\xad" // U+F082D
+#define ICON_MDI_LAMBDA "\xf3\xb0\x98\xa7" // U+F0627
+#define ICON_MDI_LAMP "\xf3\xb0\x9a\xb5" // U+F06B5
+#define ICON_MDI_LAMP_OUTLINE "\xf3\xb1\x9f\x90" // U+F17D0
+#define ICON_MDI_LAMPS "\xf3\xb1\x95\xb6" // U+F1576
+#define ICON_MDI_LAMPS_OUTLINE "\xf3\xb1\x9f\x91" // U+F17D1
+#define ICON_MDI_LAN "\xf3\xb0\x8c\x97" // U+F0317
+#define ICON_MDI_LAN_CHECK "\xf3\xb1\x8a\xaa" // U+F12AA
+#define ICON_MDI_LAN_CONNECT "\xf3\xb0\x8c\x98" // U+F0318
+#define ICON_MDI_LAN_DISCONNECT "\xf3\xb0\x8c\x99" // U+F0319
+#define ICON_MDI_LAN_PENDING "\xf3\xb0\x8c\x9a" // U+F031A
+#define ICON_MDI_LAND_FIELDS "\xf3\xb1\xaa\xb2" // U+F1AB2
+#define ICON_MDI_LAND_PLOTS "\xf3\xb1\xaa\xb3" // U+F1AB3
+#define ICON_MDI_LAND_PLOTS_CIRCLE "\xf3\xb1\xaa\xb4" // U+F1AB4
+#define ICON_MDI_LAND_PLOTS_CIRCLE_VARIANT "\xf3\xb1\xaa\xb5" // U+F1AB5
+#define ICON_MDI_LAND_PLOTS_MARKER "\xf3\xb1\xb1\x9d" // U+F1C5D
+#define ICON_MDI_LAND_ROWS_HORIZONTAL "\xf3\xb1\xaa\xb6" // U+F1AB6
+#define ICON_MDI_LAND_ROWS_VERTICAL "\xf3\xb1\xaa\xb7" // U+F1AB7
+#define ICON_MDI_LANDSLIDE "\xf3\xb1\xa9\x88" // U+F1A48
+#define ICON_MDI_LANDSLIDE_OUTLINE "\xf3\xb1\xa9\x89" // U+F1A49
+#define ICON_MDI_LANGUAGE_C "\xf3\xb0\x99\xb1" // U+F0671
+#define ICON_MDI_LANGUAGE_CPP "\xf3\xb0\x99\xb2" // U+F0672
+#define ICON_MDI_LANGUAGE_CSHARP "\xf3\xb0\x8c\x9b" // U+F031B
+#define ICON_MDI_LANGUAGE_CSS3 "\xf3\xb0\x8c\x9c" // U+F031C
+#define ICON_MDI_LANGUAGE_FORTRAN "\xf3\xb1\x88\x9a" // U+F121A
+#define ICON_MDI_LANGUAGE_GO "\xf3\xb0\x9f\x93" // U+F07D3
+#define ICON_MDI_LANGUAGE_HASKELL "\xf3\xb0\xb2\x92" // U+F0C92
+#define ICON_MDI_LANGUAGE_HTML5 "\xf3\xb0\x8c\x9d" // U+F031D
+#define ICON_MDI_LANGUAGE_JAVA "\xf3\xb0\xac\xb7" // U+F0B37
+#define ICON_MDI_LANGUAGE_JAVASCRIPT "\xf3\xb0\x8c\x9e" // U+F031E
+#define ICON_MDI_LANGUAGE_KOTLIN "\xf3\xb1\x88\x99" // U+F1219
+#define ICON_MDI_LANGUAGE_LUA "\xf3\xb0\xa2\xb1" // U+F08B1
+#define ICON_MDI_LANGUAGE_MARKDOWN "\xf3\xb0\x8d\x94" // U+F0354
+#define ICON_MDI_LANGUAGE_MARKDOWN_OUTLINE "\xf3\xb0\xbd\x9b" // U+F0F5B
+#define ICON_MDI_LANGUAGE_PHP "\xf3\xb0\x8c\x9f" // U+F031F
+#define ICON_MDI_LANGUAGE_PYTHON "\xf3\xb0\x8c\xa0" // U+F0320
+#define ICON_MDI_LANGUAGE_R "\xf3\xb0\x9f\x94" // U+F07D4
+#define ICON_MDI_LANGUAGE_RUBY "\xf3\xb0\xb4\xad" // U+F0D2D
+#define ICON_MDI_LANGUAGE_RUBY_ON_RAILS "\xf3\xb0\xab\x8f" // U+F0ACF
+#define ICON_MDI_LANGUAGE_RUST "\xf3\xb1\x98\x97" // U+F1617
+#define ICON_MDI_LANGUAGE_SWIFT "\xf3\xb0\x9b\xa5" // U+F06E5
+#define ICON_MDI_LANGUAGE_TYPESCRIPT "\xf3\xb0\x9b\xa6" // U+F06E6
+#define ICON_MDI_LANGUAGE_XAML "\xf3\xb0\x99\xb3" // U+F0673
+#define ICON_MDI_LAPTOP "\xf3\xb0\x8c\xa2" // U+F0322
+#define ICON_MDI_LAPTOP_ACCOUNT "\xf3\xb1\xa9\x8a" // U+F1A4A
+#define ICON_MDI_LAPTOP_OFF "\xf3\xb0\x9b\xa7" // U+F06E7
+#define ICON_MDI_LARAVEL "\xf3\xb0\xab\x90" // U+F0AD0
+#define ICON_MDI_LASER_POINTER "\xf3\xb1\x92\x84" // U+F1484
+#define ICON_MDI_LASSO "\xf3\xb0\xbc\x83" // U+F0F03
+#define ICON_MDI_LASTPASS "\xf3\xb0\x91\x86" // U+F0446
+#define ICON_MDI_LATITUDE "\xf3\xb0\xbd\x97" // U+F0F57
+#define ICON_MDI_LAUNCH "\xf3\xb0\x8c\xa7" // U+F0327
+#define ICON_MDI_LAVA_LAMP "\xf3\xb0\x9f\x95" // U+F07D5
+#define ICON_MDI_LAYERS "\xf3\xb0\x8c\xa8" // U+F0328
+#define ICON_MDI_LAYERS_EDIT "\xf3\xb1\xa2\x92" // U+F1892
+#define ICON_MDI_LAYERS_MINUS "\xf3\xb0\xb9\x8c" // U+F0E4C
+#define ICON_MDI_LAYERS_OFF "\xf3\xb0\x8c\xa9" // U+F0329
+#define ICON_MDI_LAYERS_OFF_OUTLINE "\xf3\xb0\xa7\xbd" // U+F09FD
+#define ICON_MDI_LAYERS_OUTLINE "\xf3\xb0\xa7\xbe" // U+F09FE
+#define ICON_MDI_LAYERS_PLUS "\xf3\xb0\xb9\x8d" // U+F0E4D
+#define ICON_MDI_LAYERS_REMOVE "\xf3\xb0\xb9\x8e" // U+F0E4E
+#define ICON_MDI_LAYERS_SEARCH "\xf3\xb1\x88\x86" // U+F1206
+#define ICON_MDI_LAYERS_SEARCH_OUTLINE "\xf3\xb1\x88\x87" // U+F1207
+#define ICON_MDI_LAYERS_TRIPLE "\xf3\xb0\xbd\x98" // U+F0F58
+#define ICON_MDI_LAYERS_TRIPLE_OUTLINE "\xf3\xb0\xbd\x99" // U+F0F59
+#define ICON_MDI_LEAD_PENCIL "\xf3\xb0\x99\x8f" // U+F064F
+#define ICON_MDI_LEAF "\xf3\xb0\x8c\xaa" // U+F032A
+#define ICON_MDI_LEAF_CIRCLE "\xf3\xb1\xa4\x85" // U+F1905
+#define ICON_MDI_LEAF_CIRCLE_OUTLINE "\xf3\xb1\xa4\x86" // U+F1906
+#define ICON_MDI_LEAF_MAPLE "\xf3\xb0\xb2\x93" // U+F0C93
+#define ICON_MDI_LEAF_MAPLE_OFF "\xf3\xb1\x8b\x9a" // U+F12DA
+#define ICON_MDI_LEAF_OFF "\xf3\xb1\x8b\x99" // U+F12D9
+#define ICON_MDI_LEAK "\xf3\xb0\xb7\x97" // U+F0DD7
+#define ICON_MDI_LEAK_OFF "\xf3\xb0\xb7\x98" // U+F0DD8
+#define ICON_MDI_LECTERN "\xf3\xb1\xab\xb0" // U+F1AF0
+#define ICON_MDI_LED_OFF "\xf3\xb0\x8c\xab" // U+F032B
+#define ICON_MDI_LED_ON "\xf3\xb0\x8c\xac" // U+F032C
+#define ICON_MDI_LED_OUTLINE "\xf3\xb0\x8c\xad" // U+F032D
+#define ICON_MDI_LED_STRIP "\xf3\xb0\x9f\x96" // U+F07D6
+#define ICON_MDI_LED_STRIP_VARIANT "\xf3\xb1\x81\x91" // U+F1051
+#define ICON_MDI_LED_STRIP_VARIANT_OFF "\xf3\xb1\xa9\x8b" // U+F1A4B
+#define ICON_MDI_LED_VARIANT_OFF "\xf3\xb0\x8c\xae" // U+F032E
+#define ICON_MDI_LED_VARIANT_ON "\xf3\xb0\x8c\xaf" // U+F032F
+#define ICON_MDI_LED_VARIANT_OUTLINE "\xf3\xb0\x8c\xb0" // U+F0330
+#define ICON_MDI_LEEK "\xf3\xb1\x85\xbd" // U+F117D
+#define ICON_MDI_LESS_THAN "\xf3\xb0\xa5\xbc" // U+F097C
+#define ICON_MDI_LESS_THAN_OR_EQUAL "\xf3\xb0\xa5\xbd" // U+F097D
+#define ICON_MDI_LIBRARY "\xf3\xb0\x8c\xb1" // U+F0331
+#define ICON_MDI_LIBRARY_OUTLINE "\xf3\xb1\xa8\xa2" // U+F1A22
+#define ICON_MDI_LIBRARY_SHELVES "\xf3\xb0\xae\xa9" // U+F0BA9
+#define ICON_MDI_LICENSE "\xf3\xb0\xbf\x83" // U+F0FC3
+#define ICON_MDI_LIFEBUOY "\xf3\xb0\xa1\xbe" // U+F087E
+#define ICON_MDI_LIGHT_FLOOD_DOWN "\xf3\xb1\xa6\x87" // U+F1987
+#define ICON_MDI_LIGHT_FLOOD_UP "\xf3\xb1\xa6\x88" // U+F1988
+#define ICON_MDI_LIGHT_RECESSED "\xf3\xb1\x9e\x9b" // U+F179B
+#define ICON_MDI_LIGHT_SWITCH "\xf3\xb0\xa5\xbe" // U+F097E
+#define ICON_MDI_LIGHT_SWITCH_OFF "\xf3\xb1\xa8\xa4" // U+F1A24
+#define ICON_MDI_LIGHTBULB "\xf3\xb0\x8c\xb5" // U+F0335
+#define ICON_MDI_LIGHTBULB_ALERT "\xf3\xb1\xa7\xa1" // U+F19E1
+#define ICON_MDI_LIGHTBULB_ALERT_OUTLINE "\xf3\xb1\xa7\xa2" // U+F19E2
+#define ICON_MDI_LIGHTBULB_AUTO "\xf3\xb1\xa0\x80" // U+F1800
+#define ICON_MDI_LIGHTBULB_AUTO_OUTLINE "\xf3\xb1\xa0\x81" // U+F1801
+#define ICON_MDI_LIGHTBULB_CFL "\xf3\xb1\x88\x88" // U+F1208
+#define ICON_MDI_LIGHTBULB_CFL_OFF "\xf3\xb1\x88\x89" // U+F1209
+#define ICON_MDI_LIGHTBULB_CFL_SPIRAL "\xf3\xb1\x89\xb5" // U+F1275
+#define ICON_MDI_LIGHTBULB_CFL_SPIRAL_OFF "\xf3\xb1\x8b\x83" // U+F12C3
+#define ICON_MDI_LIGHTBULB_FLUORESCENT_TUBE "\xf3\xb1\xa0\x84" // U+F1804
+#define ICON_MDI_LIGHTBULB_FLUORESCENT_TUBE_OUTLINE "\xf3\xb1\xa0\x85" // U+F1805
+#define ICON_MDI_LIGHTBULB_GROUP "\xf3\xb1\x89\x93" // U+F1253
+#define ICON_MDI_LIGHTBULB_GROUP_OFF "\xf3\xb1\x8b\x8d" // U+F12CD
+#define ICON_MDI_LIGHTBULB_GROUP_OFF_OUTLINE "\xf3\xb1\x8b\x8e" // U+F12CE
+#define ICON_MDI_LIGHTBULB_GROUP_OUTLINE "\xf3\xb1\x89\x94" // U+F1254
+#define ICON_MDI_LIGHTBULB_MULTIPLE "\xf3\xb1\x89\x95" // U+F1255
+#define ICON_MDI_LIGHTBULB_MULTIPLE_OFF "\xf3\xb1\x8b\x8f" // U+F12CF
+#define ICON_MDI_LIGHTBULB_MULTIPLE_OFF_OUTLINE "\xf3\xb1\x8b\x90" // U+F12D0
+#define ICON_MDI_LIGHTBULB_MULTIPLE_OUTLINE "\xf3\xb1\x89\x96" // U+F1256
+#define ICON_MDI_LIGHTBULB_NIGHT "\xf3\xb1\xa9\x8c" // U+F1A4C
+#define ICON_MDI_LIGHTBULB_NIGHT_OUTLINE "\xf3\xb1\xa9\x8d" // U+F1A4D
+#define ICON_MDI_LIGHTBULB_OFF "\xf3\xb0\xb9\x8f" // U+F0E4F
+#define ICON_MDI_LIGHTBULB_OFF_OUTLINE "\xf3\xb0\xb9\x90" // U+F0E50
+#define ICON_MDI_LIGHTBULB_ON "\xf3\xb0\x9b\xa8" // U+F06E8
+#define ICON_MDI_LIGHTBULB_ON_10 "\xf3\xb1\xa9\x8e" // U+F1A4E
+#define ICON_MDI_LIGHTBULB_ON_20 "\xf3\xb1\xa9\x8f" // U+F1A4F
+#define ICON_MDI_LIGHTBULB_ON_30 "\xf3\xb1\xa9\x90" // U+F1A50
+#define ICON_MDI_LIGHTBULB_ON_40 "\xf3\xb1\xa9\x91" // U+F1A51
+#define ICON_MDI_LIGHTBULB_ON_50 "\xf3\xb1\xa9\x92" // U+F1A52
+#define ICON_MDI_LIGHTBULB_ON_60 "\xf3\xb1\xa9\x93" // U+F1A53
+#define ICON_MDI_LIGHTBULB_ON_70 "\xf3\xb1\xa9\x94" // U+F1A54
+#define ICON_MDI_LIGHTBULB_ON_80 "\xf3\xb1\xa9\x95" // U+F1A55
+#define ICON_MDI_LIGHTBULB_ON_90 "\xf3\xb1\xa9\x96" // U+F1A56
+#define ICON_MDI_LIGHTBULB_ON_OUTLINE "\xf3\xb0\x9b\xa9" // U+F06E9
+#define ICON_MDI_LIGHTBULB_OUTLINE "\xf3\xb0\x8c\xb6" // U+F0336
+#define ICON_MDI_LIGHTBULB_QUESTION "\xf3\xb1\xa7\xa3" // U+F19E3
+#define ICON_MDI_LIGHTBULB_QUESTION_OUTLINE "\xf3\xb1\xa7\xa4" // U+F19E4
+#define ICON_MDI_LIGHTBULB_SPOT "\xf3\xb1\x9f\xb4" // U+F17F4
+#define ICON_MDI_LIGHTBULB_SPOT_OFF "\xf3\xb1\x9f\xb5" // U+F17F5
+#define ICON_MDI_LIGHTBULB_VARIANT "\xf3\xb1\xa0\x82" // U+F1802
+#define ICON_MDI_LIGHTBULB_VARIANT_OUTLINE "\xf3\xb1\xa0\x83" // U+F1803
+#define ICON_MDI_LIGHTHOUSE "\xf3\xb0\xa7\xbf" // U+F09FF
+#define ICON_MDI_LIGHTHOUSE_ON "\xf3\xb0\xa8\x80" // U+F0A00
+#define ICON_MDI_LIGHTNING_BOLT "\xf3\xb1\x90\x8b" // U+F140B
+#define ICON_MDI_LIGHTNING_BOLT_CIRCLE "\xf3\xb0\xa0\xa0" // U+F0820
+#define ICON_MDI_LIGHTNING_BOLT_OUTLINE "\xf3\xb1\x90\x8c" // U+F140C
+#define ICON_MDI_LINE_SCAN "\xf3\xb0\x98\xa4" // U+F0624
+#define ICON_MDI_LINGERIE "\xf3\xb1\x91\xb6" // U+F1476
+#define ICON_MDI_LINK "\xf3\xb0\x8c\xb7" // U+F0337
+#define ICON_MDI_LINK_BOX "\xf3\xb0\xb4\x9a" // U+F0D1A
+#define ICON_MDI_LINK_BOX_OUTLINE "\xf3\xb0\xb4\x9b" // U+F0D1B
+#define ICON_MDI_LINK_BOX_VARIANT "\xf3\xb0\xb4\x9c" // U+F0D1C
+#define ICON_MDI_LINK_BOX_VARIANT_OUTLINE "\xf3\xb0\xb4\x9d" // U+F0D1D
+#define ICON_MDI_LINK_CIRCLE "\xf3\xb1\xb2\xac" // U+F1CAC
+#define ICON_MDI_LINK_CIRCLE_OUTLINE "\xf3\xb1\xb2\xad" // U+F1CAD
+#define ICON_MDI_LINK_EDIT "\xf3\xb1\xb2\xae" // U+F1CAE
+#define ICON_MDI_LINK_LOCK "\xf3\xb1\x82\xba" // U+F10BA
+#define ICON_MDI_LINK_OFF "\xf3\xb0\x8c\xb8" // U+F0338
+#define ICON_MDI_LINK_PLUS "\xf3\xb0\xb2\x94" // U+F0C94
+#define ICON_MDI_LINK_VARIANT "\xf3\xb0\x8c\xb9" // U+F0339
+#define ICON_MDI_LINK_VARIANT_MINUS "\xf3\xb1\x83\xbf" // U+F10FF
+#define ICON_MDI_LINK_VARIANT_OFF "\xf3\xb0\x8c\xba" // U+F033A
+#define ICON_MDI_LINK_VARIANT_PLUS "\xf3\xb1\x84\x80" // U+F1100
+#define ICON_MDI_LINK_VARIANT_REMOVE "\xf3\xb1\x84\x81" // U+F1101
+#define ICON_MDI_LINKEDIN "\xf3\xb0\x8c\xbb" // U+F033B
+#define ICON_MDI_LINUX "\xf3\xb0\x8c\xbd" // U+F033D
+#define ICON_MDI_LINUX_MINT "\xf3\xb0\xa3\xad" // U+F08ED
+#define ICON_MDI_LIPSTICK "\xf3\xb1\x8e\xb5" // U+F13B5
+#define ICON_MDI_LIQUID_SPOT "\xf3\xb1\xa0\xa6" // U+F1826
+#define ICON_MDI_LIQUOR "\xf3\xb1\xa4\x9e" // U+F191E
+#define ICON_MDI_LIST_BOX "\xf3\xb1\xad\xbb" // U+F1B7B
+#define ICON_MDI_LIST_BOX_OUTLINE "\xf3\xb1\xad\xbc" // U+F1B7C
+#define ICON_MDI_LIST_STATUS "\xf3\xb1\x96\xab" // U+F15AB
+#define ICON_MDI_LITECOIN "\xf3\xb0\xa9\xa1" // U+F0A61
+#define ICON_MDI_LOADING "\xf3\xb0\x9d\xb2" // U+F0772
+#define ICON_MDI_LOCATION_ENTER "\xf3\xb0\xbf\x84" // U+F0FC4
+#define ICON_MDI_LOCATION_EXIT "\xf3\xb0\xbf\x85" // U+F0FC5
+#define ICON_MDI_LOCK "\xf3\xb0\x8c\xbe" // U+F033E
+#define ICON_MDI_LOCK_ALERT "\xf3\xb0\xa3\xae" // U+F08EE
+#define ICON_MDI_LOCK_ALERT_OUTLINE "\xf3\xb1\x97\x91" // U+F15D1
+#define ICON_MDI_LOCK_CHECK "\xf3\xb1\x8e\x9a" // U+F139A
+#define ICON_MDI_LOCK_CHECK_OUTLINE "\xf3\xb1\x9a\xa8" // U+F16A8
+#define ICON_MDI_LOCK_CLOCK "\xf3\xb0\xa5\xbf" // U+F097F
+#define ICON_MDI_LOCK_MINUS "\xf3\xb1\x9a\xa9" // U+F16A9
+#define ICON_MDI_LOCK_MINUS_OUTLINE "\xf3\xb1\x9a\xaa" // U+F16AA
+#define ICON_MDI_LOCK_OFF "\xf3\xb1\x99\xb1" // U+F1671
+#define ICON_MDI_LOCK_OFF_OUTLINE "\xf3\xb1\x99\xb2" // U+F1672
+#define ICON_MDI_LOCK_OPEN "\xf3\xb0\x8c\xbf" // U+F033F
+#define ICON_MDI_LOCK_OPEN_ALERT "\xf3\xb1\x8e\x9b" // U+F139B
+#define ICON_MDI_LOCK_OPEN_ALERT_OUTLINE "\xf3\xb1\x97\x92" // U+F15D2
+#define ICON_MDI_LOCK_OPEN_CHECK "\xf3\xb1\x8e\x9c" // U+F139C
+#define ICON_MDI_LOCK_OPEN_CHECK_OUTLINE "\xf3\xb1\x9a\xab" // U+F16AB
+#define ICON_MDI_LOCK_OPEN_MINUS "\xf3\xb1\x9a\xac" // U+F16AC
+#define ICON_MDI_LOCK_OPEN_MINUS_OUTLINE "\xf3\xb1\x9a\xad" // U+F16AD
+#define ICON_MDI_LOCK_OPEN_OUTLINE "\xf3\xb0\x8d\x80" // U+F0340
+#define ICON_MDI_LOCK_OPEN_PLUS "\xf3\xb1\x9a\xae" // U+F16AE
+#define ICON_MDI_LOCK_OPEN_PLUS_OUTLINE "\xf3\xb1\x9a\xaf" // U+F16AF
+#define ICON_MDI_LOCK_OPEN_REMOVE "\xf3\xb1\x9a\xb0" // U+F16B0
+#define ICON_MDI_LOCK_OPEN_REMOVE_OUTLINE "\xf3\xb1\x9a\xb1" // U+F16B1
+#define ICON_MDI_LOCK_OPEN_VARIANT "\xf3\xb0\xbf\x86" // U+F0FC6
+#define ICON_MDI_LOCK_OPEN_VARIANT_OUTLINE "\xf3\xb0\xbf\x87" // U+F0FC7
+#define ICON_MDI_LOCK_OUTLINE "\xf3\xb0\x8d\x81" // U+F0341
+#define ICON_MDI_LOCK_PATTERN "\xf3\xb0\x9b\xaa" // U+F06EA
+#define ICON_MDI_LOCK_PERCENT "\xf3\xb1\xb0\x92" // U+F1C12
+#define ICON_MDI_LOCK_PERCENT_OPEN "\xf3\xb1\xb0\x93" // U+F1C13
+#define ICON_MDI_LOCK_PERCENT_OPEN_OUTLINE "\xf3\xb1\xb0\x94" // U+F1C14
+#define ICON_MDI_LOCK_PERCENT_OPEN_VARIANT "\xf3\xb1\xb0\x95" // U+F1C15
+#define ICON_MDI_LOCK_PERCENT_OPEN_VARIANT_OUTLINE "\xf3\xb1\xb0\x96" // U+F1C16
+#define ICON_MDI_LOCK_PERCENT_OUTLINE "\xf3\xb1\xb0\x97" // U+F1C17
+#define ICON_MDI_LOCK_PLUS "\xf3\xb0\x97\xbb" // U+F05FB
+#define ICON_MDI_LOCK_PLUS_OUTLINE "\xf3\xb1\x9a\xb2" // U+F16B2
+#define ICON_MDI_LOCK_QUESTION "\xf3\xb0\xa3\xaf" // U+F08EF
+#define ICON_MDI_LOCK_REMOVE "\xf3\xb1\x9a\xb3" // U+F16B3
+#define ICON_MDI_LOCK_REMOVE_OUTLINE "\xf3\xb1\x9a\xb4" // U+F16B4
+#define ICON_MDI_LOCK_RESET "\xf3\xb0\x9d\xb3" // U+F0773
+#define ICON_MDI_LOCK_SMART "\xf3\xb0\xa2\xb2" // U+F08B2
+#define ICON_MDI_LOCKER "\xf3\xb0\x9f\x97" // U+F07D7
+#define ICON_MDI_LOCKER_MULTIPLE "\xf3\xb0\x9f\x98" // U+F07D8
+#define ICON_MDI_LOGIN "\xf3\xb0\x8d\x82" // U+F0342
+#define ICON_MDI_LOGIN_VARIANT "\xf3\xb0\x97\xbc" // U+F05FC
+#define ICON_MDI_LOGOUT "\xf3\xb0\x8d\x83" // U+F0343
+#define ICON_MDI_LOGOUT_VARIANT "\xf3\xb0\x97\xbd" // U+F05FD
+#define ICON_MDI_LONGITUDE "\xf3\xb0\xbd\x9a" // U+F0F5A
+#define ICON_MDI_LOOKS "\xf3\xb0\x8d\x84" // U+F0344
+#define ICON_MDI_LOTION "\xf3\xb1\x96\x82" // U+F1582
+#define ICON_MDI_LOTION_OUTLINE "\xf3\xb1\x96\x83" // U+F1583
+#define ICON_MDI_LOTION_PLUS "\xf3\xb1\x96\x84" // U+F1584
+#define ICON_MDI_LOTION_PLUS_OUTLINE "\xf3\xb1\x96\x85" // U+F1585
+#define ICON_MDI_LOUPE "\xf3\xb0\x8d\x85" // U+F0345
+#define ICON_MDI_LUMX "\xf3\xb0\x8d\x86" // U+F0346
+#define ICON_MDI_LUNGS "\xf3\xb1\x82\x84" // U+F1084
+#define ICON_MDI_MACE "\xf3\xb1\xa1\x83" // U+F1843
+#define ICON_MDI_MAGAZINE_PISTOL "\xf3\xb0\x8c\xa4" // U+F0324
+#define ICON_MDI_MAGAZINE_RIFLE "\xf3\xb0\x8c\xa3" // U+F0323
+#define ICON_MDI_MAGIC_STAFF "\xf3\xb1\xa1\x84" // U+F1844
+#define ICON_MDI_MAGNET "\xf3\xb0\x8d\x87" // U+F0347
+#define ICON_MDI_MAGNET_ON "\xf3\xb0\x8d\x88" // U+F0348
+#define ICON_MDI_MAGNIFY "\xf3\xb0\x8d\x89" // U+F0349
+#define ICON_MDI_MAGNIFY_CLOSE "\xf3\xb0\xa6\x80" // U+F0980
+#define ICON_MDI_MAGNIFY_EXPAND "\xf3\xb1\xa1\xb4" // U+F1874
+#define ICON_MDI_MAGNIFY_MINUS "\xf3\xb0\x8d\x8a" // U+F034A
+#define ICON_MDI_MAGNIFY_MINUS_CURSOR "\xf3\xb0\xa9\xa2" // U+F0A62
+#define ICON_MDI_MAGNIFY_MINUS_OUTLINE "\xf3\xb0\x9b\xac" // U+F06EC
+#define ICON_MDI_MAGNIFY_PLUS "\xf3\xb0\x8d\x8b" // U+F034B
+#define ICON_MDI_MAGNIFY_PLUS_CURSOR "\xf3\xb0\xa9\xa3" // U+F0A63
+#define ICON_MDI_MAGNIFY_PLUS_OUTLINE "\xf3\xb0\x9b\xad" // U+F06ED
+#define ICON_MDI_MAGNIFY_REMOVE_CURSOR "\xf3\xb1\x88\x8c" // U+F120C
+#define ICON_MDI_MAGNIFY_REMOVE_OUTLINE "\xf3\xb1\x88\x8d" // U+F120D
+#define ICON_MDI_MAGNIFY_SCAN "\xf3\xb1\x89\xb6" // U+F1276
+#define ICON_MDI_MAIL "\xf3\xb0\xba\xbb" // U+F0EBB
+#define ICON_MDI_MAILBOX "\xf3\xb0\x9b\xae" // U+F06EE
+#define ICON_MDI_MAILBOX_OPEN "\xf3\xb0\xb6\x88" // U+F0D88
+#define ICON_MDI_MAILBOX_OPEN_OUTLINE "\xf3\xb0\xb6\x89" // U+F0D89
+#define ICON_MDI_MAILBOX_OPEN_UP "\xf3\xb0\xb6\x8a" // U+F0D8A
+#define ICON_MDI_MAILBOX_OPEN_UP_OUTLINE "\xf3\xb0\xb6\x8b" // U+F0D8B
+#define ICON_MDI_MAILBOX_OUTLINE "\xf3\xb0\xb6\x8c" // U+F0D8C
+#define ICON_MDI_MAILBOX_UP "\xf3\xb0\xb6\x8d" // U+F0D8D
+#define ICON_MDI_MAILBOX_UP_OUTLINE "\xf3\xb0\xb6\x8e" // U+F0D8E
+#define ICON_MDI_MANJARO "\xf3\xb1\x98\x8a" // U+F160A
+#define ICON_MDI_MAP "\xf3\xb0\x8d\x8d" // U+F034D
+#define ICON_MDI_MAP_CHECK "\xf3\xb0\xba\xbc" // U+F0EBC
+#define ICON_MDI_MAP_CHECK_OUTLINE "\xf3\xb0\xba\xbd" // U+F0EBD
+#define ICON_MDI_MAP_CLOCK "\xf3\xb0\xb4\x9e" // U+F0D1E
+#define ICON_MDI_MAP_CLOCK_OUTLINE "\xf3\xb0\xb4\x9f" // U+F0D1F
+#define ICON_MDI_MAP_LEGEND "\xf3\xb0\xa8\x81" // U+F0A01
+#define ICON_MDI_MAP_MARKER "\xf3\xb0\x8d\x8e" // U+F034E
+#define ICON_MDI_MAP_MARKER_ACCOUNT "\xf3\xb1\xa3\xa3" // U+F18E3
+#define ICON_MDI_MAP_MARKER_ACCOUNT_OUTLINE "\xf3\xb1\xa3\xa4" // U+F18E4
+#define ICON_MDI_MAP_MARKER_ALERT "\xf3\xb0\xbc\x85" // U+F0F05
+#define ICON_MDI_MAP_MARKER_ALERT_OUTLINE "\xf3\xb0\xbc\x86" // U+F0F06
+#define ICON_MDI_MAP_MARKER_CHECK "\xf3\xb0\xb2\x95" // U+F0C95
+#define ICON_MDI_MAP_MARKER_CHECK_OUTLINE "\xf3\xb1\x8b\xbb" // U+F12FB
+#define ICON_MDI_MAP_MARKER_CIRCLE "\xf3\xb0\x8d\x8f" // U+F034F
+#define ICON_MDI_MAP_MARKER_DISTANCE "\xf3\xb0\xa3\xb0" // U+F08F0
+#define ICON_MDI_MAP_MARKER_DOWN "\xf3\xb1\x84\x82" // U+F1102
+#define ICON_MDI_MAP_MARKER_LEFT "\xf3\xb1\x8b\x9b" // U+F12DB
+#define ICON_MDI_MAP_MARKER_LEFT_OUTLINE "\xf3\xb1\x8b\x9d" // U+F12DD
+#define ICON_MDI_MAP_MARKER_MINUS "\xf3\xb0\x99\x90" // U+F0650
+#define ICON_MDI_MAP_MARKER_MINUS_OUTLINE "\xf3\xb1\x8b\xb9" // U+F12F9
+#define ICON_MDI_MAP_MARKER_MULTIPLE "\xf3\xb0\x8d\x90" // U+F0350
+#define ICON_MDI_MAP_MARKER_MULTIPLE_OUTLINE "\xf3\xb1\x89\xb7" // U+F1277
+#define ICON_MDI_MAP_MARKER_OFF "\xf3\xb0\x8d\x91" // U+F0351
+#define ICON_MDI_MAP_MARKER_OFF_OUTLINE "\xf3\xb1\x8b\xbd" // U+F12FD
+#define ICON_MDI_MAP_MARKER_OUTLINE "\xf3\xb0\x9f\x99" // U+F07D9
+#define ICON_MDI_MAP_MARKER_PATH "\xf3\xb0\xb4\xa0" // U+F0D20
+#define ICON_MDI_MAP_MARKER_PLUS "\xf3\xb0\x99\x91" // U+F0651
+#define ICON_MDI_MAP_MARKER_PLUS_OUTLINE "\xf3\xb1\x8b\xb8" // U+F12F8
+#define ICON_MDI_MAP_MARKER_QUESTION "\xf3\xb0\xbc\x87" // U+F0F07
+#define ICON_MDI_MAP_MARKER_QUESTION_OUTLINE "\xf3\xb0\xbc\x88" // U+F0F08
+#define ICON_MDI_MAP_MARKER_RADIUS "\xf3\xb0\x8d\x92" // U+F0352
+#define ICON_MDI_MAP_MARKER_RADIUS_OUTLINE "\xf3\xb1\x8b\xbc" // U+F12FC
+#define ICON_MDI_MAP_MARKER_REMOVE "\xf3\xb0\xbc\x89" // U+F0F09
+#define ICON_MDI_MAP_MARKER_REMOVE_OUTLINE "\xf3\xb1\x8b\xba" // U+F12FA
+#define ICON_MDI_MAP_MARKER_REMOVE_VARIANT "\xf3\xb0\xbc\x8a" // U+F0F0A
+#define ICON_MDI_MAP_MARKER_RIGHT "\xf3\xb1\x8b\x9c" // U+F12DC
+#define ICON_MDI_MAP_MARKER_RIGHT_OUTLINE "\xf3\xb1\x8b\x9e" // U+F12DE
+#define ICON_MDI_MAP_MARKER_STAR "\xf3\xb1\x98\x88" // U+F1608
+#define ICON_MDI_MAP_MARKER_STAR_OUTLINE "\xf3\xb1\x98\x89" // U+F1609
+#define ICON_MDI_MAP_MARKER_UP "\xf3\xb1\x84\x83" // U+F1103
+#define ICON_MDI_MAP_MINUS "\xf3\xb0\xa6\x81" // U+F0981
+#define ICON_MDI_MAP_OUTLINE "\xf3\xb0\xa6\x82" // U+F0982
+#define ICON_MDI_MAP_PLUS "\xf3\xb0\xa6\x83" // U+F0983
+#define ICON_MDI_MAP_SEARCH "\xf3\xb0\xa6\x84" // U+F0984
+#define ICON_MDI_MAP_SEARCH_OUTLINE "\xf3\xb0\xa6\x85" // U+F0985
+#define ICON_MDI_MAPBOX "\xf3\xb0\xae\xaa" // U+F0BAA
+#define ICON_MDI_MARGIN "\xf3\xb0\x8d\x93" // U+F0353
+#define ICON_MDI_MARKER "\xf3\xb0\x99\x92" // U+F0652
+#define ICON_MDI_MARKER_CANCEL "\xf3\xb0\xb7\x99" // U+F0DD9
+#define ICON_MDI_MARKER_CHECK "\xf3\xb0\x8d\x95" // U+F0355
+#define ICON_MDI_MASTODON "\xf3\xb0\xab\x91" // U+F0AD1
+#define ICON_MDI_MATERIAL_DESIGN "\xf3\xb0\xa6\x86" // U+F0986
+#define ICON_MDI_MATERIAL_UI "\xf3\xb0\x8d\x97" // U+F0357
+#define ICON_MDI_MATH_COMPASS "\xf3\xb0\x8d\x98" // U+F0358
+#define ICON_MDI_MATH_COS "\xf3\xb0\xb2\x96" // U+F0C96
+#define ICON_MDI_MATH_INTEGRAL "\xf3\xb0\xbf\x88" // U+F0FC8
+#define ICON_MDI_MATH_INTEGRAL_BOX "\xf3\xb0\xbf\x89" // U+F0FC9
+#define ICON_MDI_MATH_LOG "\xf3\xb1\x82\x85" // U+F1085
+#define ICON_MDI_MATH_NORM "\xf3\xb0\xbf\x8a" // U+F0FCA
+#define ICON_MDI_MATH_NORM_BOX "\xf3\xb0\xbf\x8b" // U+F0FCB
+#define ICON_MDI_MATH_SIN "\xf3\xb0\xb2\x97" // U+F0C97
+#define ICON_MDI_MATH_TAN "\xf3\xb0\xb2\x98" // U+F0C98
+#define ICON_MDI_MATRIX "\xf3\xb0\x98\xa8" // U+F0628
+#define ICON_MDI_MEDAL "\xf3\xb0\xa6\x87" // U+F0987
+#define ICON_MDI_MEDAL_OUTLINE "\xf3\xb1\x8c\xa6" // U+F1326
+#define ICON_MDI_MEDICAL_BAG "\xf3\xb0\x9b\xaf" // U+F06EF
+#define ICON_MDI_MEDICAL_COTTON_SWAB "\xf3\xb1\xaa\xb8" // U+F1AB8
+#define ICON_MDI_MEDICATION "\xf3\xb1\xac\x94" // U+F1B14
+#define ICON_MDI_MEDICATION_OUTLINE "\xf3\xb1\xac\x95" // U+F1B15
+#define ICON_MDI_MEDITATION "\xf3\xb1\x85\xbb" // U+F117B
+#define ICON_MDI_MEMORY "\xf3\xb0\x8d\x9b" // U+F035B
+#define ICON_MDI_MEMORY_ARROW_DOWN "\xf3\xb1\xb2\xa6" // U+F1CA6
+#define ICON_MDI_MENORAH "\xf3\xb1\x9f\x94" // U+F17D4
+#define ICON_MDI_MENORAH_FIRE "\xf3\xb1\x9f\x95" // U+F17D5
+#define ICON_MDI_MENU "\xf3\xb0\x8d\x9c" // U+F035C
+#define ICON_MDI_MENU_CLOSE "\xf3\xb1\xb2\x90" // U+F1C90
+#define ICON_MDI_MENU_DOWN "\xf3\xb0\x8d\x9d" // U+F035D
+#define ICON_MDI_MENU_DOWN_OUTLINE "\xf3\xb0\x9a\xb6" // U+F06B6
+#define ICON_MDI_MENU_LEFT "\xf3\xb0\x8d\x9e" // U+F035E
+#define ICON_MDI_MENU_LEFT_OUTLINE "\xf3\xb0\xa8\x82" // U+F0A02
+#define ICON_MDI_MENU_OPEN "\xf3\xb0\xae\xab" // U+F0BAB
+#define ICON_MDI_MENU_RIGHT "\xf3\xb0\x8d\x9f" // U+F035F
+#define ICON_MDI_MENU_RIGHT_OUTLINE "\xf3\xb0\xa8\x83" // U+F0A03
+#define ICON_MDI_MENU_SWAP "\xf3\xb0\xa9\xa4" // U+F0A64
+#define ICON_MDI_MENU_SWAP_OUTLINE "\xf3\xb0\xa9\xa5" // U+F0A65
+#define ICON_MDI_MENU_UP "\xf3\xb0\x8d\xa0" // U+F0360
+#define ICON_MDI_MENU_UP_OUTLINE "\xf3\xb0\x9a\xb7" // U+F06B7
+#define ICON_MDI_MERGE "\xf3\xb0\xbd\x9c" // U+F0F5C
+#define ICON_MDI_MESSAGE "\xf3\xb0\x8d\xa1" // U+F0361
+#define ICON_MDI_MESSAGE_ALERT "\xf3\xb0\x8d\xa2" // U+F0362
+#define ICON_MDI_MESSAGE_ALERT_OUTLINE "\xf3\xb0\xa8\x84" // U+F0A04
+#define ICON_MDI_MESSAGE_ARROW_LEFT "\xf3\xb1\x8b\xb2" // U+F12F2
+#define ICON_MDI_MESSAGE_ARROW_LEFT_OUTLINE "\xf3\xb1\x8b\xb3" // U+F12F3
+#define ICON_MDI_MESSAGE_ARROW_RIGHT "\xf3\xb1\x8b\xb4" // U+F12F4
+#define ICON_MDI_MESSAGE_ARROW_RIGHT_OUTLINE "\xf3\xb1\x8b\xb5" // U+F12F5
+#define ICON_MDI_MESSAGE_BADGE "\xf3\xb1\xa5\x81" // U+F1941
+#define ICON_MDI_MESSAGE_BADGE_OUTLINE "\xf3\xb1\xa5\x82" // U+F1942
+#define ICON_MDI_MESSAGE_BOOKMARK "\xf3\xb1\x96\xac" // U+F15AC
+#define ICON_MDI_MESSAGE_BOOKMARK_OUTLINE "\xf3\xb1\x96\xad" // U+F15AD
+#define ICON_MDI_MESSAGE_BULLETED "\xf3\xb0\x9a\xa2" // U+F06A2
+#define ICON_MDI_MESSAGE_BULLETED_OFF "\xf3\xb0\x9a\xa3" // U+F06A3
+#define ICON_MDI_MESSAGE_CHECK "\xf3\xb1\xae\x8a" // U+F1B8A
+#define ICON_MDI_MESSAGE_CHECK_OUTLINE "\xf3\xb1\xae\x8b" // U+F1B8B
+#define ICON_MDI_MESSAGE_COG "\xf3\xb0\x9b\xb1" // U+F06F1
+#define ICON_MDI_MESSAGE_COG_OUTLINE "\xf3\xb1\x85\xb2" // U+F1172
+#define ICON_MDI_MESSAGE_DRAW "\xf3\xb0\x8d\xa3" // U+F0363
+#define ICON_MDI_MESSAGE_FAST "\xf3\xb1\xa7\x8c" // U+F19CC
+#define ICON_MDI_MESSAGE_FAST_OUTLINE "\xf3\xb1\xa7\x8d" // U+F19CD
+#define ICON_MDI_MESSAGE_FLASH "\xf3\xb1\x96\xa9" // U+F15A9
+#define ICON_MDI_MESSAGE_FLASH_OUTLINE "\xf3\xb1\x96\xaa" // U+F15AA
+#define ICON_MDI_MESSAGE_IMAGE "\xf3\xb0\x8d\xa4" // U+F0364
+#define ICON_MDI_MESSAGE_IMAGE_OUTLINE "\xf3\xb1\x85\xac" // U+F116C
+#define ICON_MDI_MESSAGE_LOCK "\xf3\xb0\xbf\x8c" // U+F0FCC
+#define ICON_MDI_MESSAGE_LOCK_OUTLINE "\xf3\xb1\x85\xad" // U+F116D
+#define ICON_MDI_MESSAGE_MINUS "\xf3\xb1\x85\xae" // U+F116E
+#define ICON_MDI_MESSAGE_MINUS_OUTLINE "\xf3\xb1\x85\xaf" // U+F116F
+#define ICON_MDI_MESSAGE_OFF "\xf3\xb1\x99\x8d" // U+F164D
+#define ICON_MDI_MESSAGE_OFF_OUTLINE "\xf3\xb1\x99\x8e" // U+F164E
+#define ICON_MDI_MESSAGE_OUTLINE "\xf3\xb0\x8d\xa5" // U+F0365
+#define ICON_MDI_MESSAGE_PLUS "\xf3\xb0\x99\x93" // U+F0653
+#define ICON_MDI_MESSAGE_PLUS_OUTLINE "\xf3\xb1\x82\xbb" // U+F10BB
+#define ICON_MDI_MESSAGE_PROCESSING "\xf3\xb0\x8d\xa6" // U+F0366
+#define ICON_MDI_MESSAGE_PROCESSING_OUTLINE "\xf3\xb1\x85\xb0" // U+F1170
+#define ICON_MDI_MESSAGE_QUESTION "\xf3\xb1\x9c\xba" // U+F173A
+#define ICON_MDI_MESSAGE_QUESTION_OUTLINE "\xf3\xb1\x9c\xbb" // U+F173B
+#define ICON_MDI_MESSAGE_REPLY "\xf3\xb0\x8d\xa7" // U+F0367
+#define ICON_MDI_MESSAGE_REPLY_OUTLINE "\xf3\xb1\x9c\xbd" // U+F173D
+#define ICON_MDI_MESSAGE_REPLY_TEXT "\xf3\xb0\x8d\xa8" // U+F0368
+#define ICON_MDI_MESSAGE_REPLY_TEXT_OUTLINE "\xf3\xb1\x9c\xbe" // U+F173E
+#define ICON_MDI_MESSAGE_SETTINGS "\xf3\xb0\x9b\xb0" // U+F06F0
+#define ICON_MDI_MESSAGE_SETTINGS_OUTLINE "\xf3\xb1\x85\xb1" // U+F1171
+#define ICON_MDI_MESSAGE_STAR "\xf3\xb0\x9a\x9a" // U+F069A
+#define ICON_MDI_MESSAGE_STAR_OUTLINE "\xf3\xb1\x89\x90" // U+F1250
+#define ICON_MDI_MESSAGE_TEXT "\xf3\xb0\x8d\xa9" // U+F0369
+#define ICON_MDI_MESSAGE_TEXT_CLOCK "\xf3\xb1\x85\xb3" // U+F1173
+#define ICON_MDI_MESSAGE_TEXT_CLOCK_OUTLINE "\xf3\xb1\x85\xb4" // U+F1174
+#define ICON_MDI_MESSAGE_TEXT_FAST "\xf3\xb1\xa7\x8e" // U+F19CE
+#define ICON_MDI_MESSAGE_TEXT_FAST_OUTLINE "\xf3\xb1\xa7\x8f" // U+F19CF
+#define ICON_MDI_MESSAGE_TEXT_LOCK "\xf3\xb0\xbf\x8d" // U+F0FCD
+#define ICON_MDI_MESSAGE_TEXT_LOCK_OUTLINE "\xf3\xb1\x85\xb5" // U+F1175
+#define ICON_MDI_MESSAGE_TEXT_OUTLINE "\xf3\xb0\x8d\xaa" // U+F036A
+#define ICON_MDI_MESSAGE_VIDEO "\xf3\xb0\x8d\xab" // U+F036B
+#define ICON_MDI_METEOR "\xf3\xb0\x98\xa9" // U+F0629
+#define ICON_MDI_METER_ELECTRIC "\xf3\xb1\xa9\x97" // U+F1A57
+#define ICON_MDI_METER_ELECTRIC_OUTLINE "\xf3\xb1\xa9\x98" // U+F1A58
+#define ICON_MDI_METER_GAS "\xf3\xb1\xa9\x99" // U+F1A59
+#define ICON_MDI_METER_GAS_OUTLINE "\xf3\xb1\xa9\x9a" // U+F1A5A
+#define ICON_MDI_METRONOME "\xf3\xb0\x9f\x9a" // U+F07DA
+#define ICON_MDI_METRONOME_TICK "\xf3\xb0\x9f\x9b" // U+F07DB
+#define ICON_MDI_MICRO_SD "\xf3\xb0\x9f\x9c" // U+F07DC
+#define ICON_MDI_MICROPHONE "\xf3\xb0\x8d\xac" // U+F036C
+#define ICON_MDI_MICROPHONE_MESSAGE "\xf3\xb0\x94\x8a" // U+F050A
+#define ICON_MDI_MICROPHONE_MESSAGE_OFF "\xf3\xb0\x94\x8b" // U+F050B
+#define ICON_MDI_MICROPHONE_MINUS "\xf3\xb0\xa2\xb3" // U+F08B3
+#define ICON_MDI_MICROPHONE_OFF "\xf3\xb0\x8d\xad" // U+F036D
+#define ICON_MDI_MICROPHONE_OUTLINE "\xf3\xb0\x8d\xae" // U+F036E
+#define ICON_MDI_MICROPHONE_PLUS "\xf3\xb0\xa2\xb4" // U+F08B4
+#define ICON_MDI_MICROPHONE_QUESTION "\xf3\xb1\xa6\x89" // U+F1989
+#define ICON_MDI_MICROPHONE_QUESTION_OUTLINE "\xf3\xb1\xa6\x8a" // U+F198A
+#define ICON_MDI_MICROPHONE_SETTINGS "\xf3\xb0\x8d\xaf" // U+F036F
+#define ICON_MDI_MICROPHONE_VARIANT "\xf3\xb0\x8d\xb0" // U+F0370
+#define ICON_MDI_MICROPHONE_VARIANT_OFF "\xf3\xb0\x8d\xb1" // U+F0371
+#define ICON_MDI_MICROSCOPE "\xf3\xb0\x99\x94" // U+F0654
+#define ICON_MDI_MICROSOFT "\xf3\xb0\x8d\xb2" // U+F0372
+#define ICON_MDI_MICROSOFT_ACCESS "\xf3\xb1\x8e\x8e" // U+F138E
+#define ICON_MDI_MICROSOFT_AZURE "\xf3\xb0\xa0\x85" // U+F0805
+#define ICON_MDI_MICROSOFT_AZURE_DEVOPS "\xf3\xb0\xbf\x95" // U+F0FD5
+#define ICON_MDI_MICROSOFT_BING "\xf3\xb0\x82\xa4" // U+F00A4
+#define ICON_MDI_MICROSOFT_DYNAMICS_365 "\xf3\xb0\xa6\x88" // U+F0988
+#define ICON_MDI_MICROSOFT_EDGE "\xf3\xb0\x87\xa9" // U+F01E9
+#define ICON_MDI_MICROSOFT_EXCEL "\xf3\xb1\x8e\x8f" // U+F138F
+#define ICON_MDI_MICROSOFT_INTERNET_EXPLORER "\xf3\xb0\x8c\x80" // U+F0300
+#define ICON_MDI_MICROSOFT_OFFICE "\xf3\xb0\x8f\x86" // U+F03C6
+#define ICON_MDI_MICROSOFT_ONEDRIVE "\xf3\xb0\x8f\x8a" // U+F03CA
+#define ICON_MDI_MICROSOFT_ONENOTE "\xf3\xb0\x9d\x87" // U+F0747
+#define ICON_MDI_MICROSOFT_OUTLOOK "\xf3\xb0\xb4\xa2" // U+F0D22
+#define ICON_MDI_MICROSOFT_POWERPOINT "\xf3\xb1\x8e\x90" // U+F1390
+#define ICON_MDI_MICROSOFT_SHAREPOINT "\xf3\xb1\x8e\x91" // U+F1391
+#define ICON_MDI_MICROSOFT_TEAMS "\xf3\xb0\x8a\xbb" // U+F02BB
+#define ICON_MDI_MICROSOFT_VISUAL_STUDIO "\xf3\xb0\x98\x90" // U+F0610
+#define ICON_MDI_MICROSOFT_VISUAL_STUDIO_CODE "\xf3\xb0\xa8\x9e" // U+F0A1E
+#define ICON_MDI_MICROSOFT_WINDOWS "\xf3\xb0\x96\xb3" // U+F05B3
+#define ICON_MDI_MICROSOFT_WINDOWS_CLASSIC "\xf3\xb0\xa8\xa1" // U+F0A21
+#define ICON_MDI_MICROSOFT_WORD "\xf3\xb1\x8e\x92" // U+F1392
+#define ICON_MDI_MICROSOFT_XBOX "\xf3\xb0\x96\xb9" // U+F05B9
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER "\xf3\xb0\x96\xba" // U+F05BA
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_ALERT "\xf3\xb0\x9d\x8b" // U+F074B
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_CHARGING "\xf3\xb0\xa8\xa2" // U+F0A22
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_EMPTY "\xf3\xb0\x9d\x8c" // U+F074C
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_FULL "\xf3\xb0\x9d\x8d" // U+F074D
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_LOW "\xf3\xb0\x9d\x8e" // U+F074E
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_MEDIUM "\xf3\xb0\x9d\x8f" // U+F074F
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_BATTERY_UNKNOWN "\xf3\xb0\x9d\x90" // U+F0750
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_MENU "\xf3\xb0\xb9\xaf" // U+F0E6F
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_OFF "\xf3\xb0\x96\xbb" // U+F05BB
+#define ICON_MDI_MICROSOFT_XBOX_CONTROLLER_VIEW "\xf3\xb0\xb9\xb0" // U+F0E70
+#define ICON_MDI_MICROWAVE "\xf3\xb0\xb2\x99" // U+F0C99
+#define ICON_MDI_MICROWAVE_OFF "\xf3\xb1\x90\xa3" // U+F1423
+#define ICON_MDI_MIDDLEWARE "\xf3\xb0\xbd\x9d" // U+F0F5D
+#define ICON_MDI_MIDDLEWARE_OUTLINE "\xf3\xb0\xbd\x9e" // U+F0F5E
+#define ICON_MDI_MIDI "\xf3\xb0\xa3\xb1" // U+F08F1
+#define ICON_MDI_MIDI_PORT "\xf3\xb0\xa3\xb2" // U+F08F2
+#define ICON_MDI_MINE "\xf3\xb0\xb7\x9a" // U+F0DDA
+#define ICON_MDI_MINECRAFT "\xf3\xb0\x8d\xb3" // U+F0373
+#define ICON_MDI_MINI_SD "\xf3\xb0\xa8\x85" // U+F0A05
+#define ICON_MDI_MINIDISC "\xf3\xb0\xa8\x86" // U+F0A06
+#define ICON_MDI_MINUS "\xf3\xb0\x8d\xb4" // U+F0374
+#define ICON_MDI_MINUS_BOX "\xf3\xb0\x8d\xb5" // U+F0375
+#define ICON_MDI_MINUS_BOX_MULTIPLE "\xf3\xb1\x85\x81" // U+F1141
+#define ICON_MDI_MINUS_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x85\x82" // U+F1142
+#define ICON_MDI_MINUS_BOX_OUTLINE "\xf3\xb0\x9b\xb2" // U+F06F2
+#define ICON_MDI_MINUS_CIRCLE "\xf3\xb0\x8d\xb6" // U+F0376
+#define ICON_MDI_MINUS_CIRCLE_MULTIPLE "\xf3\xb0\x8d\x9a" // U+F035A
+#define ICON_MDI_MINUS_CIRCLE_MULTIPLE_OUTLINE "\xf3\xb0\xab\x93" // U+F0AD3
+#define ICON_MDI_MINUS_CIRCLE_OFF "\xf3\xb1\x91\x99" // U+F1459
+#define ICON_MDI_MINUS_CIRCLE_OFF_OUTLINE "\xf3\xb1\x91\x9a" // U+F145A
+#define ICON_MDI_MINUS_CIRCLE_OUTLINE "\xf3\xb0\x8d\xb7" // U+F0377
+#define ICON_MDI_MINUS_NETWORK "\xf3\xb0\x8d\xb8" // U+F0378
+#define ICON_MDI_MINUS_NETWORK_OUTLINE "\xf3\xb0\xb2\x9a" // U+F0C9A
+#define ICON_MDI_MINUS_THICK "\xf3\xb1\x98\xb9" // U+F1639
+#define ICON_MDI_MIRROR "\xf3\xb1\x87\xbd" // U+F11FD
+#define ICON_MDI_MIRROR_RECTANGLE "\xf3\xb1\x9e\x9f" // U+F179F
+#define ICON_MDI_MIRROR_VARIANT "\xf3\xb1\x9e\xa0" // U+F17A0
+#define ICON_MDI_MIXED_MARTIAL_ARTS "\xf3\xb0\xb6\x8f" // U+F0D8F
+#define ICON_MDI_MIXED_REALITY "\xf3\xb0\xa1\xbf" // U+F087F
+#define ICON_MDI_MOLECULE "\xf3\xb0\xae\xac" // U+F0BAC
+#define ICON_MDI_MOLECULE_CO "\xf3\xb1\x8b\xbe" // U+F12FE
+#define ICON_MDI_MOLECULE_CO2 "\xf3\xb0\x9f\xa4" // U+F07E4
+#define ICON_MDI_MONITOR "\xf3\xb0\x8d\xb9" // U+F0379
+#define ICON_MDI_MONITOR_ACCOUNT "\xf3\xb1\xa9\x9b" // U+F1A5B
+#define ICON_MDI_MONITOR_ARROW_DOWN "\xf3\xb1\xa7\x90" // U+F19D0
+#define ICON_MDI_MONITOR_ARROW_DOWN_VARIANT "\xf3\xb1\xa7\x91" // U+F19D1
+#define ICON_MDI_MONITOR_CELLPHONE "\xf3\xb0\xa6\x89" // U+F0989
+#define ICON_MDI_MONITOR_CELLPHONE_STAR "\xf3\xb0\xa6\x8a" // U+F098A
+#define ICON_MDI_MONITOR_DASHBOARD "\xf3\xb0\xa8\x87" // U+F0A07
+#define ICON_MDI_MONITOR_EDIT "\xf3\xb1\x8b\x86" // U+F12C6
+#define ICON_MDI_MONITOR_EYE "\xf3\xb1\x8e\xb4" // U+F13B4
+#define ICON_MDI_MONITOR_LOCK "\xf3\xb0\xb7\x9b" // U+F0DDB
+#define ICON_MDI_MONITOR_MULTIPLE "\xf3\xb0\x8d\xba" // U+F037A
+#define ICON_MDI_MONITOR_OFF "\xf3\xb0\xb6\x90" // U+F0D90
+#define ICON_MDI_MONITOR_SCREENSHOT "\xf3\xb0\xb9\x91" // U+F0E51
+#define ICON_MDI_MONITOR_SHARE "\xf3\xb1\x92\x83" // U+F1483
+#define ICON_MDI_MONITOR_SHIMMER "\xf3\xb1\x84\x84" // U+F1104
+#define ICON_MDI_MONITOR_SMALL "\xf3\xb1\xa1\xb6" // U+F1876
+#define ICON_MDI_MONITOR_SPEAKER "\xf3\xb0\xbd\x9f" // U+F0F5F
+#define ICON_MDI_MONITOR_SPEAKER_OFF "\xf3\xb0\xbd\xa0" // U+F0F60
+#define ICON_MDI_MONITOR_STAR "\xf3\xb0\xb7\x9c" // U+F0DDC
+#define ICON_MDI_MONITOR_VERTICAL "\xf3\xb1\xb0\xb3" // U+F1C33
+#define ICON_MDI_MOON_FIRST_QUARTER "\xf3\xb0\xbd\xa1" // U+F0F61
+#define ICON_MDI_MOON_FULL "\xf3\xb0\xbd\xa2" // U+F0F62
+#define ICON_MDI_MOON_LAST_QUARTER "\xf3\xb0\xbd\xa3" // U+F0F63
+#define ICON_MDI_MOON_NEW "\xf3\xb0\xbd\xa4" // U+F0F64
+#define ICON_MDI_MOON_WANING_CRESCENT "\xf3\xb0\xbd\xa5" // U+F0F65
+#define ICON_MDI_MOON_WANING_GIBBOUS "\xf3\xb0\xbd\xa6" // U+F0F66
+#define ICON_MDI_MOON_WAXING_CRESCENT "\xf3\xb0\xbd\xa7" // U+F0F67
+#define ICON_MDI_MOON_WAXING_GIBBOUS "\xf3\xb0\xbd\xa8" // U+F0F68
+#define ICON_MDI_MOPED "\xf3\xb1\x82\x86" // U+F1086
+#define ICON_MDI_MOPED_ELECTRIC "\xf3\xb1\x96\xb7" // U+F15B7
+#define ICON_MDI_MOPED_ELECTRIC_OUTLINE "\xf3\xb1\x96\xb8" // U+F15B8
+#define ICON_MDI_MOPED_OUTLINE "\xf3\xb1\x96\xb9" // U+F15B9
+#define ICON_MDI_MORE "\xf3\xb0\x8d\xbb" // U+F037B
+#define ICON_MDI_MORTAR_PESTLE "\xf3\xb1\x9d\x88" // U+F1748
+#define ICON_MDI_MORTAR_PESTLE_PLUS "\xf3\xb0\x8f\xb1" // U+F03F1
+#define ICON_MDI_MOSQUE "\xf3\xb0\xb5\x85" // U+F0D45
+#define ICON_MDI_MOSQUE_OUTLINE "\xf3\xb1\xa0\xa7" // U+F1827
+#define ICON_MDI_MOTHER_HEART "\xf3\xb1\x8c\x94" // U+F1314
+#define ICON_MDI_MOTHER_NURSE "\xf3\xb0\xb4\xa1" // U+F0D21
+#define ICON_MDI_MOTION "\xf3\xb1\x96\xb2" // U+F15B2
+#define ICON_MDI_MOTION_OUTLINE "\xf3\xb1\x96\xb3" // U+F15B3
+#define ICON_MDI_MOTION_PAUSE "\xf3\xb1\x96\x90" // U+F1590
+#define ICON_MDI_MOTION_PAUSE_OUTLINE "\xf3\xb1\x96\x92" // U+F1592
+#define ICON_MDI_MOTION_PLAY "\xf3\xb1\x96\x8f" // U+F158F
+#define ICON_MDI_MOTION_PLAY_OUTLINE "\xf3\xb1\x96\x91" // U+F1591
+#define ICON_MDI_MOTION_SENSOR "\xf3\xb0\xb6\x91" // U+F0D91
+#define ICON_MDI_MOTION_SENSOR_OFF "\xf3\xb1\x90\xb5" // U+F1435
+#define ICON_MDI_MOTORBIKE "\xf3\xb0\x8d\xbc" // U+F037C
+#define ICON_MDI_MOTORBIKE_ELECTRIC "\xf3\xb1\x96\xba" // U+F15BA
+#define ICON_MDI_MOTORBIKE_OFF "\xf3\xb1\xac\x96" // U+F1B16
+#define ICON_MDI_MOUSE "\xf3\xb0\x8d\xbd" // U+F037D
+#define ICON_MDI_MOUSE_BLUETOOTH "\xf3\xb0\xa6\x8b" // U+F098B
+#define ICON_MDI_MOUSE_MOVE_DOWN "\xf3\xb1\x95\x90" // U+F1550
+#define ICON_MDI_MOUSE_MOVE_UP "\xf3\xb1\x95\x91" // U+F1551
+#define ICON_MDI_MOUSE_MOVE_VERTICAL "\xf3\xb1\x95\x92" // U+F1552
+#define ICON_MDI_MOUSE_OFF "\xf3\xb0\x8d\xbe" // U+F037E
+#define ICON_MDI_MOUSE_VARIANT "\xf3\xb0\x8d\xbf" // U+F037F
+#define ICON_MDI_MOUSE_VARIANT_OFF "\xf3\xb0\x8e\x80" // U+F0380
+#define ICON_MDI_MOVE_RESIZE "\xf3\xb0\x99\x95" // U+F0655
+#define ICON_MDI_MOVE_RESIZE_VARIANT "\xf3\xb0\x99\x96" // U+F0656
+#define ICON_MDI_MOVIE "\xf3\xb0\x8e\x81" // U+F0381
+#define ICON_MDI_MOVIE_CHECK "\xf3\xb1\x9b\xb3" // U+F16F3
+#define ICON_MDI_MOVIE_CHECK_OUTLINE "\xf3\xb1\x9b\xb4" // U+F16F4
+#define ICON_MDI_MOVIE_COG "\xf3\xb1\x9b\xb5" // U+F16F5
+#define ICON_MDI_MOVIE_COG_OUTLINE "\xf3\xb1\x9b\xb6" // U+F16F6
+#define ICON_MDI_MOVIE_EDIT "\xf3\xb1\x84\xa2" // U+F1122
+#define ICON_MDI_MOVIE_EDIT_OUTLINE "\xf3\xb1\x84\xa3" // U+F1123
+#define ICON_MDI_MOVIE_FILTER "\xf3\xb1\x84\xa4" // U+F1124
+#define ICON_MDI_MOVIE_FILTER_OUTLINE "\xf3\xb1\x84\xa5" // U+F1125
+#define ICON_MDI_MOVIE_MINUS "\xf3\xb1\x9b\xb7" // U+F16F7
+#define ICON_MDI_MOVIE_MINUS_OUTLINE "\xf3\xb1\x9b\xb8" // U+F16F8
+#define ICON_MDI_MOVIE_OFF "\xf3\xb1\x9b\xb9" // U+F16F9
+#define ICON_MDI_MOVIE_OFF_OUTLINE "\xf3\xb1\x9b\xba" // U+F16FA
+#define ICON_MDI_MOVIE_OPEN "\xf3\xb0\xbf\x8e" // U+F0FCE
+#define ICON_MDI_MOVIE_OPEN_CHECK "\xf3\xb1\x9b\xbb" // U+F16FB
+#define ICON_MDI_MOVIE_OPEN_CHECK_OUTLINE "\xf3\xb1\x9b\xbc" // U+F16FC
+#define ICON_MDI_MOVIE_OPEN_COG "\xf3\xb1\x9b\xbd" // U+F16FD
+#define ICON_MDI_MOVIE_OPEN_COG_OUTLINE "\xf3\xb1\x9b\xbe" // U+F16FE
+#define ICON_MDI_MOVIE_OPEN_EDIT "\xf3\xb1\x9b\xbf" // U+F16FF
+#define ICON_MDI_MOVIE_OPEN_EDIT_OUTLINE "\xf3\xb1\x9c\x80" // U+F1700
+#define ICON_MDI_MOVIE_OPEN_MINUS "\xf3\xb1\x9c\x81" // U+F1701
+#define ICON_MDI_MOVIE_OPEN_MINUS_OUTLINE "\xf3\xb1\x9c\x82" // U+F1702
+#define ICON_MDI_MOVIE_OPEN_OFF "\xf3\xb1\x9c\x83" // U+F1703
+#define ICON_MDI_MOVIE_OPEN_OFF_OUTLINE "\xf3\xb1\x9c\x84" // U+F1704
+#define ICON_MDI_MOVIE_OPEN_OUTLINE "\xf3\xb0\xbf\x8f" // U+F0FCF
+#define ICON_MDI_MOVIE_OPEN_PLAY "\xf3\xb1\x9c\x85" // U+F1705
+#define ICON_MDI_MOVIE_OPEN_PLAY_OUTLINE "\xf3\xb1\x9c\x86" // U+F1706
+#define ICON_MDI_MOVIE_OPEN_PLUS "\xf3\xb1\x9c\x87" // U+F1707
+#define ICON_MDI_MOVIE_OPEN_PLUS_OUTLINE "\xf3\xb1\x9c\x88" // U+F1708
+#define ICON_MDI_MOVIE_OPEN_REMOVE "\xf3\xb1\x9c\x89" // U+F1709
+#define ICON_MDI_MOVIE_OPEN_REMOVE_OUTLINE "\xf3\xb1\x9c\x8a" // U+F170A
+#define ICON_MDI_MOVIE_OPEN_SETTINGS "\xf3\xb1\x9c\x8b" // U+F170B
+#define ICON_MDI_MOVIE_OPEN_SETTINGS_OUTLINE "\xf3\xb1\x9c\x8c" // U+F170C
+#define ICON_MDI_MOVIE_OPEN_STAR "\xf3\xb1\x9c\x8d" // U+F170D
+#define ICON_MDI_MOVIE_OPEN_STAR_OUTLINE "\xf3\xb1\x9c\x8e" // U+F170E
+#define ICON_MDI_MOVIE_OUTLINE "\xf3\xb0\xb7\x9d" // U+F0DDD
+#define ICON_MDI_MOVIE_PLAY "\xf3\xb1\x9c\x8f" // U+F170F
+#define ICON_MDI_MOVIE_PLAY_OUTLINE "\xf3\xb1\x9c\x90" // U+F1710
+#define ICON_MDI_MOVIE_PLUS "\xf3\xb1\x9c\x91" // U+F1711
+#define ICON_MDI_MOVIE_PLUS_OUTLINE "\xf3\xb1\x9c\x92" // U+F1712
+#define ICON_MDI_MOVIE_REMOVE "\xf3\xb1\x9c\x93" // U+F1713
+#define ICON_MDI_MOVIE_REMOVE_OUTLINE "\xf3\xb1\x9c\x94" // U+F1714
+#define ICON_MDI_MOVIE_ROLL "\xf3\xb0\x9f\x9e" // U+F07DE
+#define ICON_MDI_MOVIE_SEARCH "\xf3\xb1\x87\x92" // U+F11D2
+#define ICON_MDI_MOVIE_SEARCH_OUTLINE "\xf3\xb1\x87\x93" // U+F11D3
+#define ICON_MDI_MOVIE_SETTINGS "\xf3\xb1\x9c\x95" // U+F1715
+#define ICON_MDI_MOVIE_SETTINGS_OUTLINE "\xf3\xb1\x9c\x96" // U+F1716
+#define ICON_MDI_MOVIE_STAR "\xf3\xb1\x9c\x97" // U+F1717
+#define ICON_MDI_MOVIE_STAR_OUTLINE "\xf3\xb1\x9c\x98" // U+F1718
+#define ICON_MDI_MOWER "\xf3\xb1\x99\xaf" // U+F166F
+#define ICON_MDI_MOWER_BAG "\xf3\xb1\x99\xb0" // U+F1670
+#define ICON_MDI_MOWER_BAG_ON "\xf3\xb1\xad\xa0" // U+F1B60
+#define ICON_MDI_MOWER_ON "\xf3\xb1\xad\x9f" // U+F1B5F
+#define ICON_MDI_MUFFIN "\xf3\xb0\xa6\x8c" // U+F098C
+#define ICON_MDI_MULTICAST "\xf3\xb1\xa2\x93" // U+F1893
+#define ICON_MDI_MULTIMEDIA "\xf3\xb1\xae\x97" // U+F1B97
+#define ICON_MDI_MULTIPLICATION "\xf3\xb0\x8e\x82" // U+F0382
+#define ICON_MDI_MULTIPLICATION_BOX "\xf3\xb0\x8e\x83" // U+F0383
+#define ICON_MDI_MUSHROOM "\xf3\xb0\x9f\x9f" // U+F07DF
+#define ICON_MDI_MUSHROOM_OFF "\xf3\xb1\x8f\xba" // U+F13FA
+#define ICON_MDI_MUSHROOM_OFF_OUTLINE "\xf3\xb1\x8f\xbb" // U+F13FB
+#define ICON_MDI_MUSHROOM_OUTLINE "\xf3\xb0\x9f\xa0" // U+F07E0
+#define ICON_MDI_MUSIC "\xf3\xb0\x9d\x9a" // U+F075A
+#define ICON_MDI_MUSIC_ACCIDENTAL_DOUBLE_FLAT "\xf3\xb0\xbd\xa9" // U+F0F69
+#define ICON_MDI_MUSIC_ACCIDENTAL_DOUBLE_SHARP "\xf3\xb0\xbd\xaa" // U+F0F6A
+#define ICON_MDI_MUSIC_ACCIDENTAL_FLAT "\xf3\xb0\xbd\xab" // U+F0F6B
+#define ICON_MDI_MUSIC_ACCIDENTAL_NATURAL "\xf3\xb0\xbd\xac" // U+F0F6C
+#define ICON_MDI_MUSIC_ACCIDENTAL_SHARP "\xf3\xb0\xbd\xad" // U+F0F6D
+#define ICON_MDI_MUSIC_BOX "\xf3\xb0\x8e\x84" // U+F0384
+#define ICON_MDI_MUSIC_BOX_MULTIPLE "\xf3\xb0\x8c\xb3" // U+F0333
+#define ICON_MDI_MUSIC_BOX_MULTIPLE_OUTLINE "\xf3\xb0\xbc\x84" // U+F0F04
+#define ICON_MDI_MUSIC_BOX_OUTLINE "\xf3\xb0\x8e\x85" // U+F0385
+#define ICON_MDI_MUSIC_CIRCLE "\xf3\xb0\x8e\x86" // U+F0386
+#define ICON_MDI_MUSIC_CIRCLE_OUTLINE "\xf3\xb0\xab\x94" // U+F0AD4
+#define ICON_MDI_MUSIC_CLEF_ALTO "\xf3\xb0\xbd\xae" // U+F0F6E
+#define ICON_MDI_MUSIC_CLEF_BASS "\xf3\xb0\xbd\xaf" // U+F0F6F
+#define ICON_MDI_MUSIC_CLEF_TREBLE "\xf3\xb0\xbd\xb0" // U+F0F70
+#define ICON_MDI_MUSIC_NOTE "\xf3\xb0\x8e\x87" // U+F0387
+#define ICON_MDI_MUSIC_NOTE_BLUETOOTH "\xf3\xb0\x97\xbe" // U+F05FE
+#define ICON_MDI_MUSIC_NOTE_BLUETOOTH_OFF "\xf3\xb0\x97\xbf" // U+F05FF
+#define ICON_MDI_MUSIC_NOTE_EIGHTH "\xf3\xb0\x8e\x88" // U+F0388
+#define ICON_MDI_MUSIC_NOTE_EIGHTH_DOTTED "\xf3\xb0\xbd\xb1" // U+F0F71
+#define ICON_MDI_MUSIC_NOTE_HALF "\xf3\xb0\x8e\x89" // U+F0389
+#define ICON_MDI_MUSIC_NOTE_HALF_DOTTED "\xf3\xb0\xbd\xb2" // U+F0F72
+#define ICON_MDI_MUSIC_NOTE_MINUS "\xf3\xb1\xae\x89" // U+F1B89
+#define ICON_MDI_MUSIC_NOTE_OFF "\xf3\xb0\x8e\x8a" // U+F038A
+#define ICON_MDI_MUSIC_NOTE_OFF_OUTLINE "\xf3\xb0\xbd\xb3" // U+F0F73
+#define ICON_MDI_MUSIC_NOTE_OUTLINE "\xf3\xb0\xbd\xb4" // U+F0F74
+#define ICON_MDI_MUSIC_NOTE_PLUS "\xf3\xb0\xb7\x9e" // U+F0DDE
+#define ICON_MDI_MUSIC_NOTE_QUARTER "\xf3\xb0\x8e\x8b" // U+F038B
+#define ICON_MDI_MUSIC_NOTE_QUARTER_DOTTED "\xf3\xb0\xbd\xb5" // U+F0F75
+#define ICON_MDI_MUSIC_NOTE_SIXTEENTH "\xf3\xb0\x8e\x8c" // U+F038C
+#define ICON_MDI_MUSIC_NOTE_SIXTEENTH_DOTTED "\xf3\xb0\xbd\xb6" // U+F0F76
+#define ICON_MDI_MUSIC_NOTE_WHOLE "\xf3\xb0\x8e\x8d" // U+F038D
+#define ICON_MDI_MUSIC_NOTE_WHOLE_DOTTED "\xf3\xb0\xbd\xb7" // U+F0F77
+#define ICON_MDI_MUSIC_OFF "\xf3\xb0\x9d\x9b" // U+F075B
+#define ICON_MDI_MUSIC_REST_EIGHTH "\xf3\xb0\xbd\xb8" // U+F0F78
+#define ICON_MDI_MUSIC_REST_HALF "\xf3\xb0\xbd\xb9" // U+F0F79
+#define ICON_MDI_MUSIC_REST_QUARTER "\xf3\xb0\xbd\xba" // U+F0F7A
+#define ICON_MDI_MUSIC_REST_SIXTEENTH "\xf3\xb0\xbd\xbb" // U+F0F7B
+#define ICON_MDI_MUSIC_REST_WHOLE "\xf3\xb0\xbd\xbc" // U+F0F7C
+#define ICON_MDI_MUSTACHE "\xf3\xb1\x97\x9e" // U+F15DE
+#define ICON_MDI_NAIL "\xf3\xb0\xb7\x9f" // U+F0DDF
+#define ICON_MDI_NAS "\xf3\xb0\xa3\xb3" // U+F08F3
+#define ICON_MDI_NATIVESCRIPT "\xf3\xb0\xa2\x80" // U+F0880
+#define ICON_MDI_NATURE "\xf3\xb0\x8e\x8e" // U+F038E
+#define ICON_MDI_NATURE_OUTLINE "\xf3\xb1\xb1\xb1" // U+F1C71
+#define ICON_MDI_NATURE_PEOPLE "\xf3\xb0\x8e\x8f" // U+F038F
+#define ICON_MDI_NATURE_PEOPLE_OUTLINE "\xf3\xb1\xb1\xb2" // U+F1C72
+#define ICON_MDI_NAVIGATION "\xf3\xb0\x8e\x90" // U+F0390
+#define ICON_MDI_NAVIGATION_OUTLINE "\xf3\xb1\x98\x87" // U+F1607
+#define ICON_MDI_NAVIGATION_VARIANT "\xf3\xb1\xa3\xb0" // U+F18F0
+#define ICON_MDI_NAVIGATION_VARIANT_OUTLINE "\xf3\xb1\xa3\xb1" // U+F18F1
+#define ICON_MDI_NEAR_ME "\xf3\xb0\x97\x8d" // U+F05CD
+#define ICON_MDI_NECKLACE "\xf3\xb0\xbc\x8b" // U+F0F0B
+#define ICON_MDI_NEEDLE "\xf3\xb0\x8e\x91" // U+F0391
+#define ICON_MDI_NEEDLE_OFF "\xf3\xb1\xa7\x92" // U+F19D2
+#define ICON_MDI_NETFLIX "\xf3\xb0\x9d\x86" // U+F0746
+#define ICON_MDI_NETWORK "\xf3\xb0\x9b\xb3" // U+F06F3
+#define ICON_MDI_NETWORK_OFF "\xf3\xb0\xb2\x9b" // U+F0C9B
+#define ICON_MDI_NETWORK_OFF_OUTLINE "\xf3\xb0\xb2\x9c" // U+F0C9C
+#define ICON_MDI_NETWORK_OUTLINE "\xf3\xb0\xb2\x9d" // U+F0C9D
+#define ICON_MDI_NETWORK_POS "\xf3\xb1\xab\x8b" // U+F1ACB
+#define ICON_MDI_NETWORK_STRENGTH_1 "\xf3\xb0\xa3\xb4" // U+F08F4
+#define ICON_MDI_NETWORK_STRENGTH_1_ALERT "\xf3\xb0\xa3\xb5" // U+F08F5
+#define ICON_MDI_NETWORK_STRENGTH_2 "\xf3\xb0\xa3\xb6" // U+F08F6
+#define ICON_MDI_NETWORK_STRENGTH_2_ALERT "\xf3\xb0\xa3\xb7" // U+F08F7
+#define ICON_MDI_NETWORK_STRENGTH_3 "\xf3\xb0\xa3\xb8" // U+F08F8
+#define ICON_MDI_NETWORK_STRENGTH_3_ALERT "\xf3\xb0\xa3\xb9" // U+F08F9
+#define ICON_MDI_NETWORK_STRENGTH_4 "\xf3\xb0\xa3\xba" // U+F08FA
+#define ICON_MDI_NETWORK_STRENGTH_4_ALERT "\xf3\xb0\xa3\xbb" // U+F08FB
+#define ICON_MDI_NETWORK_STRENGTH_4_COG "\xf3\xb1\xa4\x9a" // U+F191A
+#define ICON_MDI_NETWORK_STRENGTH_OFF "\xf3\xb0\xa3\xbc" // U+F08FC
+#define ICON_MDI_NETWORK_STRENGTH_OFF_OUTLINE "\xf3\xb0\xa3\xbd" // U+F08FD
+#define ICON_MDI_NETWORK_STRENGTH_OUTLINE "\xf3\xb0\xa3\xbe" // U+F08FE
+#define ICON_MDI_NEW_BOX "\xf3\xb0\x8e\x94" // U+F0394
+#define ICON_MDI_NEWSPAPER "\xf3\xb0\x8e\x95" // U+F0395
+#define ICON_MDI_NEWSPAPER_CHECK "\xf3\xb1\xa5\x83" // U+F1943
+#define ICON_MDI_NEWSPAPER_MINUS "\xf3\xb0\xbc\x8c" // U+F0F0C
+#define ICON_MDI_NEWSPAPER_PLUS "\xf3\xb0\xbc\x8d" // U+F0F0D
+#define ICON_MDI_NEWSPAPER_REMOVE "\xf3\xb1\xa5\x84" // U+F1944
+#define ICON_MDI_NEWSPAPER_VARIANT "\xf3\xb1\x80\x81" // U+F1001
+#define ICON_MDI_NEWSPAPER_VARIANT_MULTIPLE "\xf3\xb1\x80\x82" // U+F1002
+#define ICON_MDI_NEWSPAPER_VARIANT_MULTIPLE_OUTLINE "\xf3\xb1\x80\x83" // U+F1003
+#define ICON_MDI_NEWSPAPER_VARIANT_OUTLINE "\xf3\xb1\x80\x84" // U+F1004
+#define ICON_MDI_NFC "\xf3\xb0\x8e\x96" // U+F0396
+#define ICON_MDI_NFC_SEARCH_VARIANT "\xf3\xb0\xb9\x93" // U+F0E53
+#define ICON_MDI_NFC_TAP "\xf3\xb0\x8e\x97" // U+F0397
+#define ICON_MDI_NFC_VARIANT "\xf3\xb0\x8e\x98" // U+F0398
+#define ICON_MDI_NFC_VARIANT_OFF "\xf3\xb0\xb9\x94" // U+F0E54
+#define ICON_MDI_NINJA "\xf3\xb0\x9d\xb4" // U+F0774
+#define ICON_MDI_NINTENDO_GAME_BOY "\xf3\xb1\x8e\x93" // U+F1393
+#define ICON_MDI_NINTENDO_SWITCH "\xf3\xb0\x9f\xa1" // U+F07E1
+#define ICON_MDI_NINTENDO_WII "\xf3\xb0\x96\xab" // U+F05AB
+#define ICON_MDI_NINTENDO_WIIU "\xf3\xb0\x9c\xad" // U+F072D
+#define ICON_MDI_NIX "\xf3\xb1\x84\x85" // U+F1105
+#define ICON_MDI_NODEJS "\xf3\xb0\x8e\x99" // U+F0399
+#define ICON_MDI_NOODLES "\xf3\xb1\x85\xbe" // U+F117E
+#define ICON_MDI_NOT_EQUAL "\xf3\xb0\xa6\x8d" // U+F098D
+#define ICON_MDI_NOT_EQUAL_VARIANT "\xf3\xb0\xa6\x8e" // U+F098E
+#define ICON_MDI_NOTE "\xf3\xb0\x8e\x9a" // U+F039A
+#define ICON_MDI_NOTE_ALERT "\xf3\xb1\x9d\xbd" // U+F177D
+#define ICON_MDI_NOTE_ALERT_OUTLINE "\xf3\xb1\x9d\xbe" // U+F177E
+#define ICON_MDI_NOTE_CHECK "\xf3\xb1\x9d\xbf" // U+F177F
+#define ICON_MDI_NOTE_CHECK_OUTLINE "\xf3\xb1\x9e\x80" // U+F1780
+#define ICON_MDI_NOTE_EDIT "\xf3\xb1\x9e\x81" // U+F1781
+#define ICON_MDI_NOTE_EDIT_OUTLINE "\xf3\xb1\x9e\x82" // U+F1782
+#define ICON_MDI_NOTE_MINUS "\xf3\xb1\x99\x8f" // U+F164F
+#define ICON_MDI_NOTE_MINUS_OUTLINE "\xf3\xb1\x99\x90" // U+F1650
+#define ICON_MDI_NOTE_MULTIPLE "\xf3\xb0\x9a\xb8" // U+F06B8
+#define ICON_MDI_NOTE_MULTIPLE_OUTLINE "\xf3\xb0\x9a\xb9" // U+F06B9
+#define ICON_MDI_NOTE_OFF "\xf3\xb1\x9e\x83" // U+F1783
+#define ICON_MDI_NOTE_OFF_OUTLINE "\xf3\xb1\x9e\x84" // U+F1784
+#define ICON_MDI_NOTE_OUTLINE "\xf3\xb0\x8e\x9b" // U+F039B
+#define ICON_MDI_NOTE_PLUS "\xf3\xb0\x8e\x9c" // U+F039C
+#define ICON_MDI_NOTE_PLUS_OUTLINE "\xf3\xb0\x8e\x9d" // U+F039D
+#define ICON_MDI_NOTE_REMOVE "\xf3\xb1\x99\x91" // U+F1651
+#define ICON_MDI_NOTE_REMOVE_OUTLINE "\xf3\xb1\x99\x92" // U+F1652
+#define ICON_MDI_NOTE_SEARCH "\xf3\xb1\x99\x93" // U+F1653
+#define ICON_MDI_NOTE_SEARCH_OUTLINE "\xf3\xb1\x99\x94" // U+F1654
+#define ICON_MDI_NOTE_TEXT "\xf3\xb0\x8e\x9e" // U+F039E
+#define ICON_MDI_NOTE_TEXT_OUTLINE "\xf3\xb1\x87\x97" // U+F11D7
+#define ICON_MDI_NOTEBOOK "\xf3\xb0\xa0\xae" // U+F082E
+#define ICON_MDI_NOTEBOOK_CHECK "\xf3\xb1\x93\xb5" // U+F14F5
+#define ICON_MDI_NOTEBOOK_CHECK_OUTLINE "\xf3\xb1\x93\xb6" // U+F14F6
+#define ICON_MDI_NOTEBOOK_EDIT "\xf3\xb1\x93\xa7" // U+F14E7
+#define ICON_MDI_NOTEBOOK_EDIT_OUTLINE "\xf3\xb1\x93\xa9" // U+F14E9
+#define ICON_MDI_NOTEBOOK_HEART "\xf3\xb1\xa8\x8b" // U+F1A0B
+#define ICON_MDI_NOTEBOOK_HEART_OUTLINE "\xf3\xb1\xa8\x8c" // U+F1A0C
+#define ICON_MDI_NOTEBOOK_MINUS "\xf3\xb1\x98\x90" // U+F1610
+#define ICON_MDI_NOTEBOOK_MINUS_OUTLINE "\xf3\xb1\x98\x91" // U+F1611
+#define ICON_MDI_NOTEBOOK_MULTIPLE "\xf3\xb0\xb9\x95" // U+F0E55
+#define ICON_MDI_NOTEBOOK_OUTLINE "\xf3\xb0\xba\xbf" // U+F0EBF
+#define ICON_MDI_NOTEBOOK_PLUS "\xf3\xb1\x98\x92" // U+F1612
+#define ICON_MDI_NOTEBOOK_PLUS_OUTLINE "\xf3\xb1\x98\x93" // U+F1613
+#define ICON_MDI_NOTEBOOK_REMOVE "\xf3\xb1\x98\x94" // U+F1614
+#define ICON_MDI_NOTEBOOK_REMOVE_OUTLINE "\xf3\xb1\x98\x95" // U+F1615
+#define ICON_MDI_NOTIFICATION_CLEAR_ALL "\xf3\xb0\x8e\x9f" // U+F039F
+#define ICON_MDI_NPM "\xf3\xb0\x9b\xb7" // U+F06F7
+#define ICON_MDI_NUKE "\xf3\xb0\x9a\xa4" // U+F06A4
+#define ICON_MDI_NULL "\xf3\xb0\x9f\xa2" // U+F07E2
+#define ICON_MDI_NUMERIC "\xf3\xb0\x8e\xa0" // U+F03A0
+#define ICON_MDI_NUMERIC_0 "\xf3\xb0\xac\xb9" // U+F0B39
+#define ICON_MDI_NUMERIC_0_BOX "\xf3\xb0\x8e\xa1" // U+F03A1
+#define ICON_MDI_NUMERIC_0_BOX_MULTIPLE "\xf3\xb0\xbc\x8e" // U+F0F0E
+#define ICON_MDI_NUMERIC_0_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xa2" // U+F03A2
+#define ICON_MDI_NUMERIC_0_BOX_OUTLINE "\xf3\xb0\x8e\xa3" // U+F03A3
+#define ICON_MDI_NUMERIC_0_CIRCLE "\xf3\xb0\xb2\x9e" // U+F0C9E
+#define ICON_MDI_NUMERIC_0_CIRCLE_OUTLINE "\xf3\xb0\xb2\x9f" // U+F0C9F
+#define ICON_MDI_NUMERIC_1 "\xf3\xb0\xac\xba" // U+F0B3A
+#define ICON_MDI_NUMERIC_1_BOX "\xf3\xb0\x8e\xa4" // U+F03A4
+#define ICON_MDI_NUMERIC_1_BOX_MULTIPLE "\xf3\xb0\xbc\x8f" // U+F0F0F
+#define ICON_MDI_NUMERIC_1_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xa5" // U+F03A5
+#define ICON_MDI_NUMERIC_1_BOX_OUTLINE "\xf3\xb0\x8e\xa6" // U+F03A6
+#define ICON_MDI_NUMERIC_1_CIRCLE "\xf3\xb0\xb2\xa0" // U+F0CA0
+#define ICON_MDI_NUMERIC_1_CIRCLE_OUTLINE "\xf3\xb0\xb2\xa1" // U+F0CA1
+#define ICON_MDI_NUMERIC_10 "\xf3\xb0\xbf\xa9" // U+F0FE9
+#define ICON_MDI_NUMERIC_10_BOX "\xf3\xb0\xbd\xbd" // U+F0F7D
+#define ICON_MDI_NUMERIC_10_BOX_MULTIPLE "\xf3\xb0\xbf\xaa" // U+F0FEA
+#define ICON_MDI_NUMERIC_10_BOX_MULTIPLE_OUTLINE "\xf3\xb0\xbf\xab" // U+F0FEB
+#define ICON_MDI_NUMERIC_10_BOX_OUTLINE "\xf3\xb0\xbd\xbe" // U+F0F7E
+#define ICON_MDI_NUMERIC_10_CIRCLE "\xf3\xb0\xbf\xac" // U+F0FEC
+#define ICON_MDI_NUMERIC_10_CIRCLE_OUTLINE "\xf3\xb0\xbf\xad" // U+F0FED
+#define ICON_MDI_NUMERIC_2 "\xf3\xb0\xac\xbb" // U+F0B3B
+#define ICON_MDI_NUMERIC_2_BOX "\xf3\xb0\x8e\xa7" // U+F03A7
+#define ICON_MDI_NUMERIC_2_BOX_MULTIPLE "\xf3\xb0\xbc\x90" // U+F0F10
+#define ICON_MDI_NUMERIC_2_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xa8" // U+F03A8
+#define ICON_MDI_NUMERIC_2_BOX_OUTLINE "\xf3\xb0\x8e\xa9" // U+F03A9
+#define ICON_MDI_NUMERIC_2_CIRCLE "\xf3\xb0\xb2\xa2" // U+F0CA2
+#define ICON_MDI_NUMERIC_2_CIRCLE_OUTLINE "\xf3\xb0\xb2\xa3" // U+F0CA3
+#define ICON_MDI_NUMERIC_3 "\xf3\xb0\xac\xbc" // U+F0B3C
+#define ICON_MDI_NUMERIC_3_BOX "\xf3\xb0\x8e\xaa" // U+F03AA
+#define ICON_MDI_NUMERIC_3_BOX_MULTIPLE "\xf3\xb0\xbc\x91" // U+F0F11
+#define ICON_MDI_NUMERIC_3_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xab" // U+F03AB
+#define ICON_MDI_NUMERIC_3_BOX_OUTLINE "\xf3\xb0\x8e\xac" // U+F03AC
+#define ICON_MDI_NUMERIC_3_CIRCLE "\xf3\xb0\xb2\xa4" // U+F0CA4
+#define ICON_MDI_NUMERIC_3_CIRCLE_OUTLINE "\xf3\xb0\xb2\xa5" // U+F0CA5
+#define ICON_MDI_NUMERIC_4 "\xf3\xb0\xac\xbd" // U+F0B3D
+#define ICON_MDI_NUMERIC_4_BOX "\xf3\xb0\x8e\xad" // U+F03AD
+#define ICON_MDI_NUMERIC_4_BOX_MULTIPLE "\xf3\xb0\xbc\x92" // U+F0F12
+#define ICON_MDI_NUMERIC_4_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xb2" // U+F03B2
+#define ICON_MDI_NUMERIC_4_BOX_OUTLINE "\xf3\xb0\x8e\xae" // U+F03AE
+#define ICON_MDI_NUMERIC_4_CIRCLE "\xf3\xb0\xb2\xa6" // U+F0CA6
+#define ICON_MDI_NUMERIC_4_CIRCLE_OUTLINE "\xf3\xb0\xb2\xa7" // U+F0CA7
+#define ICON_MDI_NUMERIC_5 "\xf3\xb0\xac\xbe" // U+F0B3E
+#define ICON_MDI_NUMERIC_5_BOX "\xf3\xb0\x8e\xb1" // U+F03B1
+#define ICON_MDI_NUMERIC_5_BOX_MULTIPLE "\xf3\xb0\xbc\x93" // U+F0F13
+#define ICON_MDI_NUMERIC_5_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xaf" // U+F03AF
+#define ICON_MDI_NUMERIC_5_BOX_OUTLINE "\xf3\xb0\x8e\xb0" // U+F03B0
+#define ICON_MDI_NUMERIC_5_CIRCLE "\xf3\xb0\xb2\xa8" // U+F0CA8
+#define ICON_MDI_NUMERIC_5_CIRCLE_OUTLINE "\xf3\xb0\xb2\xa9" // U+F0CA9
+#define ICON_MDI_NUMERIC_6 "\xf3\xb0\xac\xbf" // U+F0B3F
+#define ICON_MDI_NUMERIC_6_BOX "\xf3\xb0\x8e\xb3" // U+F03B3
+#define ICON_MDI_NUMERIC_6_BOX_MULTIPLE "\xf3\xb0\xbc\x94" // U+F0F14
+#define ICON_MDI_NUMERIC_6_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xb4" // U+F03B4
+#define ICON_MDI_NUMERIC_6_BOX_OUTLINE "\xf3\xb0\x8e\xb5" // U+F03B5
+#define ICON_MDI_NUMERIC_6_CIRCLE "\xf3\xb0\xb2\xaa" // U+F0CAA
+#define ICON_MDI_NUMERIC_6_CIRCLE_OUTLINE "\xf3\xb0\xb2\xab" // U+F0CAB
+#define ICON_MDI_NUMERIC_7 "\xf3\xb0\xad\x80" // U+F0B40
+#define ICON_MDI_NUMERIC_7_BOX "\xf3\xb0\x8e\xb6" // U+F03B6
+#define ICON_MDI_NUMERIC_7_BOX_MULTIPLE "\xf3\xb0\xbc\x95" // U+F0F15
+#define ICON_MDI_NUMERIC_7_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xb7" // U+F03B7
+#define ICON_MDI_NUMERIC_7_BOX_OUTLINE "\xf3\xb0\x8e\xb8" // U+F03B8
+#define ICON_MDI_NUMERIC_7_CIRCLE "\xf3\xb0\xb2\xac" // U+F0CAC
+#define ICON_MDI_NUMERIC_7_CIRCLE_OUTLINE "\xf3\xb0\xb2\xad" // U+F0CAD
+#define ICON_MDI_NUMERIC_8 "\xf3\xb0\xad\x81" // U+F0B41
+#define ICON_MDI_NUMERIC_8_BOX "\xf3\xb0\x8e\xb9" // U+F03B9
+#define ICON_MDI_NUMERIC_8_BOX_MULTIPLE "\xf3\xb0\xbc\x96" // U+F0F16
+#define ICON_MDI_NUMERIC_8_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xba" // U+F03BA
+#define ICON_MDI_NUMERIC_8_BOX_OUTLINE "\xf3\xb0\x8e\xbb" // U+F03BB
+#define ICON_MDI_NUMERIC_8_CIRCLE "\xf3\xb0\xb2\xae" // U+F0CAE
+#define ICON_MDI_NUMERIC_8_CIRCLE_OUTLINE "\xf3\xb0\xb2\xaf" // U+F0CAF
+#define ICON_MDI_NUMERIC_9 "\xf3\xb0\xad\x82" // U+F0B42
+#define ICON_MDI_NUMERIC_9_BOX "\xf3\xb0\x8e\xbc" // U+F03BC
+#define ICON_MDI_NUMERIC_9_BOX_MULTIPLE "\xf3\xb0\xbc\x97" // U+F0F17
+#define ICON_MDI_NUMERIC_9_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8e\xbd" // U+F03BD
+#define ICON_MDI_NUMERIC_9_BOX_OUTLINE "\xf3\xb0\x8e\xbe" // U+F03BE
+#define ICON_MDI_NUMERIC_9_CIRCLE "\xf3\xb0\xb2\xb0" // U+F0CB0
+#define ICON_MDI_NUMERIC_9_CIRCLE_OUTLINE "\xf3\xb0\xb2\xb1" // U+F0CB1
+#define ICON_MDI_NUMERIC_9_PLUS "\xf3\xb0\xbf\xae" // U+F0FEE
+#define ICON_MDI_NUMERIC_9_PLUS_BOX "\xf3\xb0\x8e\xbf" // U+F03BF
+#define ICON_MDI_NUMERIC_9_PLUS_BOX_MULTIPLE "\xf3\xb0\xbc\x98" // U+F0F18
+#define ICON_MDI_NUMERIC_9_PLUS_BOX_MULTIPLE_OUTLINE "\xf3\xb0\x8f\x80" // U+F03C0
+#define ICON_MDI_NUMERIC_9_PLUS_BOX_OUTLINE "\xf3\xb0\x8f\x81" // U+F03C1
+#define ICON_MDI_NUMERIC_9_PLUS_CIRCLE "\xf3\xb0\xb2\xb2" // U+F0CB2
+#define ICON_MDI_NUMERIC_9_PLUS_CIRCLE_OUTLINE "\xf3\xb0\xb2\xb3" // U+F0CB3
+#define ICON_MDI_NUMERIC_NEGATIVE_1 "\xf3\xb1\x81\x92" // U+F1052
+#define ICON_MDI_NUMERIC_OFF "\xf3\xb1\xa7\x93" // U+F19D3
+#define ICON_MDI_NUMERIC_POSITIVE_1 "\xf3\xb1\x97\x8b" // U+F15CB
+#define ICON_MDI_NUT "\xf3\xb0\x9b\xb8" // U+F06F8
+#define ICON_MDI_NUTRITION "\xf3\xb0\x8f\x82" // U+F03C2
+#define ICON_MDI_NUXT "\xf3\xb1\x84\x86" // U+F1106
+#define ICON_MDI_OAR "\xf3\xb0\x99\xbc" // U+F067C
+#define ICON_MDI_OCARINA "\xf3\xb0\xb7\xa0" // U+F0DE0
+#define ICON_MDI_OCI "\xf3\xb1\x8b\xa9" // U+F12E9
+#define ICON_MDI_OCR "\xf3\xb1\x84\xba" // U+F113A
+#define ICON_MDI_OCTAGON "\xf3\xb0\x8f\x83" // U+F03C3
+#define ICON_MDI_OCTAGON_OUTLINE "\xf3\xb0\x8f\x84" // U+F03C4
+#define ICON_MDI_OCTAGRAM "\xf3\xb0\x9b\xb9" // U+F06F9
+#define ICON_MDI_OCTAGRAM_EDIT "\xf3\xb1\xb0\xb4" // U+F1C34
+#define ICON_MDI_OCTAGRAM_EDIT_OUTLINE "\xf3\xb1\xb0\xb5" // U+F1C35
+#define ICON_MDI_OCTAGRAM_MINUS "\xf3\xb1\xb0\xb6" // U+F1C36
+#define ICON_MDI_OCTAGRAM_MINUS_OUTLINE "\xf3\xb1\xb0\xb7" // U+F1C37
+#define ICON_MDI_OCTAGRAM_OUTLINE "\xf3\xb0\x9d\xb5" // U+F0775
+#define ICON_MDI_OCTAGRAM_PLUS "\xf3\xb1\xb0\xb8" // U+F1C38
+#define ICON_MDI_OCTAGRAM_PLUS_OUTLINE "\xf3\xb1\xb0\xb9" // U+F1C39
+#define ICON_MDI_OCTAHEDRON "\xf3\xb1\xa5\x90" // U+F1950
+#define ICON_MDI_OCTAHEDRON_OFF "\xf3\xb1\xa5\x91" // U+F1951
+#define ICON_MDI_ODNOKLASSNIKI "\xf3\xb0\x8f\x85" // U+F03C5
+#define ICON_MDI_OFFER "\xf3\xb1\x88\x9b" // U+F121B
+#define ICON_MDI_OFFICE_BUILDING "\xf3\xb0\xa6\x91" // U+F0991
+#define ICON_MDI_OFFICE_BUILDING_COG "\xf3\xb1\xa5\x89" // U+F1949
+#define ICON_MDI_OFFICE_BUILDING_COG_OUTLINE "\xf3\xb1\xa5\x8a" // U+F194A
+#define ICON_MDI_OFFICE_BUILDING_MARKER "\xf3\xb1\x94\xa0" // U+F1520
+#define ICON_MDI_OFFICE_BUILDING_MARKER_OUTLINE "\xf3\xb1\x94\xa1" // U+F1521
+#define ICON_MDI_OFFICE_BUILDING_MINUS "\xf3\xb1\xae\xaa" // U+F1BAA
+#define ICON_MDI_OFFICE_BUILDING_MINUS_OUTLINE "\xf3\xb1\xae\xab" // U+F1BAB
+#define ICON_MDI_OFFICE_BUILDING_OUTLINE "\xf3\xb1\x94\x9f" // U+F151F
+#define ICON_MDI_OFFICE_BUILDING_PLUS "\xf3\xb1\xae\xa8" // U+F1BA8
+#define ICON_MDI_OFFICE_BUILDING_PLUS_OUTLINE "\xf3\xb1\xae\xa9" // U+F1BA9
+#define ICON_MDI_OFFICE_BUILDING_REMOVE "\xf3\xb1\xae\xac" // U+F1BAC
+#define ICON_MDI_OFFICE_BUILDING_REMOVE_OUTLINE "\xf3\xb1\xae\xad" // U+F1BAD
+#define ICON_MDI_OIL "\xf3\xb0\x8f\x87" // U+F03C7
+#define ICON_MDI_OIL_LAMP "\xf3\xb0\xbc\x99" // U+F0F19
+#define ICON_MDI_OIL_LEVEL "\xf3\xb1\x81\x93" // U+F1053
+#define ICON_MDI_OIL_TEMPERATURE "\xf3\xb0\xbf\xb8" // U+F0FF8
+#define ICON_MDI_OM "\xf3\xb0\xa5\xb3" // U+F0973
+#define ICON_MDI_OMEGA "\xf3\xb0\x8f\x89" // U+F03C9
+#define ICON_MDI_ONE_UP "\xf3\xb0\xae\xad" // U+F0BAD
+#define ICON_MDI_ONEPASSWORD "\xf3\xb0\xa2\x81" // U+F0881
+#define ICON_MDI_OPACITY "\xf3\xb0\x97\x8c" // U+F05CC
+#define ICON_MDI_OPEN_IN_APP "\xf3\xb0\x8f\x8b" // U+F03CB
+#define ICON_MDI_OPEN_IN_NEW "\xf3\xb0\x8f\x8c" // U+F03CC
+#define ICON_MDI_OPEN_SOURCE_INITIATIVE "\xf3\xb0\xae\xae" // U+F0BAE
+#define ICON_MDI_OPENID "\xf3\xb0\x8f\x8d" // U+F03CD
+#define ICON_MDI_OPERA "\xf3\xb0\x8f\x8e" // U+F03CE
+#define ICON_MDI_ORBIT "\xf3\xb0\x80\x98" // U+F0018
+#define ICON_MDI_ORBIT_VARIANT "\xf3\xb1\x97\x9b" // U+F15DB
+#define ICON_MDI_ORDER_ALPHABETICAL_ASCENDING "\xf3\xb0\x88\x8d" // U+F020D
+#define ICON_MDI_ORDER_ALPHABETICAL_DESCENDING "\xf3\xb0\xb4\x87" // U+F0D07
+#define ICON_MDI_ORDER_BOOL_ASCENDING "\xf3\xb0\x8a\xbe" // U+F02BE
+#define ICON_MDI_ORDER_BOOL_ASCENDING_VARIANT "\xf3\xb0\xa6\x8f" // U+F098F
+#define ICON_MDI_ORDER_BOOL_DESCENDING "\xf3\xb1\x8e\x84" // U+F1384
+#define ICON_MDI_ORDER_BOOL_DESCENDING_VARIANT "\xf3\xb0\xa6\x90" // U+F0990
+#define ICON_MDI_ORDER_NUMERIC_ASCENDING "\xf3\xb0\x95\x85" // U+F0545
+#define ICON_MDI_ORDER_NUMERIC_DESCENDING "\xf3\xb0\x95\x86" // U+F0546
+#define ICON_MDI_ORIGIN "\xf3\xb0\xad\x83" // U+F0B43
+#define ICON_MDI_ORNAMENT "\xf3\xb0\x8f\x8f" // U+F03CF
+#define ICON_MDI_ORNAMENT_VARIANT "\xf3\xb0\x8f\x90" // U+F03D0
+#define ICON_MDI_OUTDOOR_LAMP "\xf3\xb1\x81\x94" // U+F1054
+#define ICON_MDI_OVERSCAN "\xf3\xb1\x80\x85" // U+F1005
+#define ICON_MDI_OWL "\xf3\xb0\x8f\x92" // U+F03D2
+#define ICON_MDI_PAC_MAN "\xf3\xb0\xae\xaf" // U+F0BAF
+#define ICON_MDI_PACKAGE "\xf3\xb0\x8f\x93" // U+F03D3
+#define ICON_MDI_PACKAGE_CHECK "\xf3\xb1\xad\x91" // U+F1B51
+#define ICON_MDI_PACKAGE_DOWN "\xf3\xb0\x8f\x94" // U+F03D4
+#define ICON_MDI_PACKAGE_UP "\xf3\xb0\x8f\x95" // U+F03D5
+#define ICON_MDI_PACKAGE_VARIANT "\xf3\xb0\x8f\x96" // U+F03D6
+#define ICON_MDI_PACKAGE_VARIANT_CLOSED "\xf3\xb0\x8f\x97" // U+F03D7
+#define ICON_MDI_PACKAGE_VARIANT_CLOSED_CHECK "\xf3\xb1\xad\x92" // U+F1B52
+#define ICON_MDI_PACKAGE_VARIANT_CLOSED_MINUS "\xf3\xb1\xa7\x94" // U+F19D4
+#define ICON_MDI_PACKAGE_VARIANT_CLOSED_PLUS "\xf3\xb1\xa7\x95" // U+F19D5
+#define ICON_MDI_PACKAGE_VARIANT_CLOSED_REMOVE "\xf3\xb1\xa7\x96" // U+F19D6
+#define ICON_MDI_PACKAGE_VARIANT_MINUS "\xf3\xb1\xa7\x97" // U+F19D7
+#define ICON_MDI_PACKAGE_VARIANT_PLUS "\xf3\xb1\xa7\x98" // U+F19D8
+#define ICON_MDI_PACKAGE_VARIANT_REMOVE "\xf3\xb1\xa7\x99" // U+F19D9
+#define ICON_MDI_PAGE_FIRST "\xf3\xb0\x98\x80" // U+F0600
+#define ICON_MDI_PAGE_LAST "\xf3\xb0\x98\x81" // U+F0601
+#define ICON_MDI_PAGE_LAYOUT_BODY "\xf3\xb0\x9b\xba" // U+F06FA
+#define ICON_MDI_PAGE_LAYOUT_FOOTER "\xf3\xb0\x9b\xbb" // U+F06FB
+#define ICON_MDI_PAGE_LAYOUT_HEADER "\xf3\xb0\x9b\xbc" // U+F06FC
+#define ICON_MDI_PAGE_LAYOUT_HEADER_FOOTER "\xf3\xb0\xbd\xbf" // U+F0F7F
+#define ICON_MDI_PAGE_LAYOUT_SIDEBAR_LEFT "\xf3\xb0\x9b\xbd" // U+F06FD
+#define ICON_MDI_PAGE_LAYOUT_SIDEBAR_RIGHT "\xf3\xb0\x9b\xbe" // U+F06FE
+#define ICON_MDI_PAGE_NEXT "\xf3\xb0\xae\xb0" // U+F0BB0
+#define ICON_MDI_PAGE_NEXT_OUTLINE "\xf3\xb0\xae\xb1" // U+F0BB1
+#define ICON_MDI_PAGE_PREVIOUS "\xf3\xb0\xae\xb2" // U+F0BB2
+#define ICON_MDI_PAGE_PREVIOUS_OUTLINE "\xf3\xb0\xae\xb3" // U+F0BB3
+#define ICON_MDI_PAIL "\xf3\xb1\x90\x97" // U+F1417
+#define ICON_MDI_PAIL_MINUS "\xf3\xb1\x90\xb7" // U+F1437
+#define ICON_MDI_PAIL_MINUS_OUTLINE "\xf3\xb1\x90\xbc" // U+F143C
+#define ICON_MDI_PAIL_OFF "\xf3\xb1\x90\xb9" // U+F1439
+#define ICON_MDI_PAIL_OFF_OUTLINE "\xf3\xb1\x90\xbe" // U+F143E
+#define ICON_MDI_PAIL_OUTLINE "\xf3\xb1\x90\xba" // U+F143A
+#define ICON_MDI_PAIL_PLUS "\xf3\xb1\x90\xb6" // U+F1436
+#define ICON_MDI_PAIL_PLUS_OUTLINE "\xf3\xb1\x90\xbb" // U+F143B
+#define ICON_MDI_PAIL_REMOVE "\xf3\xb1\x90\xb8" // U+F1438
+#define ICON_MDI_PAIL_REMOVE_OUTLINE "\xf3\xb1\x90\xbd" // U+F143D
+#define ICON_MDI_PALETTE "\xf3\xb0\x8f\x98" // U+F03D8
+#define ICON_MDI_PALETTE_ADVANCED "\xf3\xb0\x8f\x99" // U+F03D9
+#define ICON_MDI_PALETTE_OUTLINE "\xf3\xb0\xb8\x8c" // U+F0E0C
+#define ICON_MDI_PALETTE_SWATCH "\xf3\xb0\xa2\xb5" // U+F08B5
+#define ICON_MDI_PALETTE_SWATCH_OUTLINE "\xf3\xb1\x8d\x9c" // U+F135C
+#define ICON_MDI_PALETTE_SWATCH_VARIANT "\xf3\xb1\xa5\x9a" // U+F195A
+#define ICON_MDI_PALM_TREE "\xf3\xb1\x81\x95" // U+F1055
+#define ICON_MDI_PAN "\xf3\xb0\xae\xb4" // U+F0BB4
+#define ICON_MDI_PAN_BOTTOM_LEFT "\xf3\xb0\xae\xb5" // U+F0BB5
+#define ICON_MDI_PAN_BOTTOM_RIGHT "\xf3\xb0\xae\xb6" // U+F0BB6
+#define ICON_MDI_PAN_DOWN "\xf3\xb0\xae\xb7" // U+F0BB7
+#define ICON_MDI_PAN_HORIZONTAL "\xf3\xb0\xae\xb8" // U+F0BB8
+#define ICON_MDI_PAN_LEFT "\xf3\xb0\xae\xb9" // U+F0BB9
+#define ICON_MDI_PAN_RIGHT "\xf3\xb0\xae\xba" // U+F0BBA
+#define ICON_MDI_PAN_TOP_LEFT "\xf3\xb0\xae\xbb" // U+F0BBB
+#define ICON_MDI_PAN_TOP_RIGHT "\xf3\xb0\xae\xbc" // U+F0BBC
+#define ICON_MDI_PAN_UP "\xf3\xb0\xae\xbd" // U+F0BBD
+#define ICON_MDI_PAN_VERTICAL "\xf3\xb0\xae\xbe" // U+F0BBE
+#define ICON_MDI_PANDA "\xf3\xb0\x8f\x9a" // U+F03DA
+#define ICON_MDI_PANDORA "\xf3\xb0\x8f\x9b" // U+F03DB
+#define ICON_MDI_PANORAMA "\xf3\xb0\x8f\x9c" // U+F03DC
+#define ICON_MDI_PANORAMA_FISHEYE "\xf3\xb0\x8f\x9d" // U+F03DD
+#define ICON_MDI_PANORAMA_HORIZONTAL "\xf3\xb1\xa4\xa8" // U+F1928
+#define ICON_MDI_PANORAMA_HORIZONTAL_OUTLINE "\xf3\xb0\x8f\x9e" // U+F03DE
+#define ICON_MDI_PANORAMA_OUTLINE "\xf3\xb1\xa6\x8c" // U+F198C
+#define ICON_MDI_PANORAMA_SPHERE "\xf3\xb1\xa6\x8d" // U+F198D
+#define ICON_MDI_PANORAMA_SPHERE_OUTLINE "\xf3\xb1\xa6\x8e" // U+F198E
+#define ICON_MDI_PANORAMA_VARIANT "\xf3\xb1\xa6\x8f" // U+F198F
+#define ICON_MDI_PANORAMA_VARIANT_OUTLINE "\xf3\xb1\xa6\x90" // U+F1990
+#define ICON_MDI_PANORAMA_VERTICAL "\xf3\xb1\xa4\xa9" // U+F1929
+#define ICON_MDI_PANORAMA_VERTICAL_OUTLINE "\xf3\xb0\x8f\x9f" // U+F03DF
+#define ICON_MDI_PANORAMA_WIDE_ANGLE "\xf3\xb1\xa5\x9f" // U+F195F
+#define ICON_MDI_PANORAMA_WIDE_ANGLE_OUTLINE "\xf3\xb0\x8f\xa0" // U+F03E0
+#define ICON_MDI_PAPER_CUT_VERTICAL "\xf3\xb0\x8f\xa1" // U+F03E1
+#define ICON_MDI_PAPER_ROLL "\xf3\xb1\x85\x97" // U+F1157
+#define ICON_MDI_PAPER_ROLL_OUTLINE "\xf3\xb1\x85\x98" // U+F1158
+#define ICON_MDI_PAPERCLIP "\xf3\xb0\x8f\xa2" // U+F03E2
+#define ICON_MDI_PAPERCLIP_CHECK "\xf3\xb1\xab\x86" // U+F1AC6
+#define ICON_MDI_PAPERCLIP_LOCK "\xf3\xb1\xa7\x9a" // U+F19DA
+#define ICON_MDI_PAPERCLIP_MINUS "\xf3\xb1\xab\x87" // U+F1AC7
+#define ICON_MDI_PAPERCLIP_OFF "\xf3\xb1\xab\x88" // U+F1AC8
+#define ICON_MDI_PAPERCLIP_PLUS "\xf3\xb1\xab\x89" // U+F1AC9
+#define ICON_MDI_PAPERCLIP_REMOVE "\xf3\xb1\xab\x8a" // U+F1ACA
+#define ICON_MDI_PARACHUTE "\xf3\xb0\xb2\xb4" // U+F0CB4
+#define ICON_MDI_PARACHUTE_OUTLINE "\xf3\xb0\xb2\xb5" // U+F0CB5
+#define ICON_MDI_PARAGLIDING "\xf3\xb1\x9d\x85" // U+F1745
+#define ICON_MDI_PARKING "\xf3\xb0\x8f\xa3" // U+F03E3
+#define ICON_MDI_PARTY_POPPER "\xf3\xb1\x81\x96" // U+F1056
+#define ICON_MDI_PASSPORT "\xf3\xb0\x9f\xa3" // U+F07E3
+#define ICON_MDI_PASSPORT_ALERT "\xf3\xb1\xb2\xb8" // U+F1CB8
+#define ICON_MDI_PASSPORT_BIOMETRIC "\xf3\xb0\xb7\xa1" // U+F0DE1
+#define ICON_MDI_PASSPORT_CANCEL "\xf3\xb1\xb2\xb9" // U+F1CB9
+#define ICON_MDI_PASSPORT_CHECK "\xf3\xb1\xb2\xba" // U+F1CBA
+#define ICON_MDI_PASSPORT_MINUS "\xf3\xb1\xb2\xbb" // U+F1CBB
+#define ICON_MDI_PASSPORT_PLUS "\xf3\xb1\xb2\xbc" // U+F1CBC
+#define ICON_MDI_PASSPORT_REMOVE "\xf3\xb1\xb2\xbd" // U+F1CBD
+#define ICON_MDI_PASTA "\xf3\xb1\x85\xa0" // U+F1160
+#define ICON_MDI_PATIO_HEATER "\xf3\xb0\xbe\x80" // U+F0F80
+#define ICON_MDI_PATREON "\xf3\xb0\xa2\x82" // U+F0882
+#define ICON_MDI_PAUSE "\xf3\xb0\x8f\xa4" // U+F03E4
+#define ICON_MDI_PAUSE_BOX "\xf3\xb0\x82\xbc" // U+F00BC
+#define ICON_MDI_PAUSE_BOX_OUTLINE "\xf3\xb1\xad\xba" // U+F1B7A
+#define ICON_MDI_PAUSE_CIRCLE "\xf3\xb0\x8f\xa5" // U+F03E5
+#define ICON_MDI_PAUSE_CIRCLE_OUTLINE "\xf3\xb0\x8f\xa6" // U+F03E6
+#define ICON_MDI_PAUSE_OCTAGON "\xf3\xb0\x8f\xa7" // U+F03E7
+#define ICON_MDI_PAUSE_OCTAGON_OUTLINE "\xf3\xb0\x8f\xa8" // U+F03E8
+#define ICON_MDI_PAW "\xf3\xb0\x8f\xa9" // U+F03E9
+#define ICON_MDI_PAW_OFF "\xf3\xb0\x99\x97" // U+F0657
+#define ICON_MDI_PAW_OFF_OUTLINE "\xf3\xb1\x99\xb6" // U+F1676
+#define ICON_MDI_PAW_OUTLINE "\xf3\xb1\x99\xb5" // U+F1675
+#define ICON_MDI_PEACE "\xf3\xb0\xa2\x84" // U+F0884
+#define ICON_MDI_PEANUT "\xf3\xb0\xbf\xbc" // U+F0FFC
+#define ICON_MDI_PEANUT_OFF "\xf3\xb0\xbf\xbd" // U+F0FFD
+#define ICON_MDI_PEANUT_OFF_OUTLINE "\xf3\xb0\xbf\xbf" // U+F0FFF
+#define ICON_MDI_PEANUT_OUTLINE "\xf3\xb0\xbf\xbe" // U+F0FFE
+#define ICON_MDI_PEN "\xf3\xb0\x8f\xaa" // U+F03EA
+#define ICON_MDI_PEN_LOCK "\xf3\xb0\xb7\xa2" // U+F0DE2
+#define ICON_MDI_PEN_MINUS "\xf3\xb0\xb7\xa3" // U+F0DE3
+#define ICON_MDI_PEN_OFF "\xf3\xb0\xb7\xa4" // U+F0DE4
+#define ICON_MDI_PEN_PLUS "\xf3\xb0\xb7\xa5" // U+F0DE5
+#define ICON_MDI_PEN_REMOVE "\xf3\xb0\xb7\xa6" // U+F0DE6
+#define ICON_MDI_PENCIL "\xf3\xb0\x8f\xab" // U+F03EB
+#define ICON_MDI_PENCIL_BOX "\xf3\xb0\x8f\xac" // U+F03EC
+#define ICON_MDI_PENCIL_BOX_MULTIPLE "\xf3\xb1\x85\x84" // U+F1144
+#define ICON_MDI_PENCIL_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x85\x85" // U+F1145
+#define ICON_MDI_PENCIL_BOX_OUTLINE "\xf3\xb0\x8f\xad" // U+F03ED
+#define ICON_MDI_PENCIL_CIRCLE "\xf3\xb0\x9b\xbf" // U+F06FF
+#define ICON_MDI_PENCIL_CIRCLE_OUTLINE "\xf3\xb0\x9d\xb6" // U+F0776
+#define ICON_MDI_PENCIL_LOCK "\xf3\xb0\x8f\xae" // U+F03EE
+#define ICON_MDI_PENCIL_LOCK_OUTLINE "\xf3\xb0\xb7\xa7" // U+F0DE7
+#define ICON_MDI_PENCIL_MINUS "\xf3\xb0\xb7\xa8" // U+F0DE8
+#define ICON_MDI_PENCIL_MINUS_OUTLINE "\xf3\xb0\xb7\xa9" // U+F0DE9
+#define ICON_MDI_PENCIL_OFF "\xf3\xb0\x8f\xaf" // U+F03EF
+#define ICON_MDI_PENCIL_OFF_OUTLINE "\xf3\xb0\xb7\xaa" // U+F0DEA
+#define ICON_MDI_PENCIL_OUTLINE "\xf3\xb0\xb2\xb6" // U+F0CB6
+#define ICON_MDI_PENCIL_PLUS "\xf3\xb0\xb7\xab" // U+F0DEB
+#define ICON_MDI_PENCIL_PLUS_OUTLINE "\xf3\xb0\xb7\xac" // U+F0DEC
+#define ICON_MDI_PENCIL_REMOVE "\xf3\xb0\xb7\xad" // U+F0DED
+#define ICON_MDI_PENCIL_REMOVE_OUTLINE "\xf3\xb0\xb7\xae" // U+F0DEE
+#define ICON_MDI_PENCIL_RULER "\xf3\xb1\x8d\x93" // U+F1353
+#define ICON_MDI_PENCIL_RULER_OUTLINE "\xf3\xb1\xb0\x91" // U+F1C11
+#define ICON_MDI_PENGUIN "\xf3\xb0\xbb\x80" // U+F0EC0
+#define ICON_MDI_PENTAGON "\xf3\xb0\x9c\x81" // U+F0701
+#define ICON_MDI_PENTAGON_OUTLINE "\xf3\xb0\x9c\x80" // U+F0700
+#define ICON_MDI_PENTAGRAM "\xf3\xb1\x99\xa7" // U+F1667
+#define ICON_MDI_PERCENT "\xf3\xb0\x8f\xb0" // U+F03F0
+#define ICON_MDI_PERCENT_BOX "\xf3\xb1\xa8\x82" // U+F1A02
+#define ICON_MDI_PERCENT_BOX_OUTLINE "\xf3\xb1\xa8\x83" // U+F1A03
+#define ICON_MDI_PERCENT_CIRCLE "\xf3\xb1\xa8\x84" // U+F1A04
+#define ICON_MDI_PERCENT_CIRCLE_OUTLINE "\xf3\xb1\xa8\x85" // U+F1A05
+#define ICON_MDI_PERCENT_OUTLINE "\xf3\xb1\x89\xb8" // U+F1278
+#define ICON_MDI_PERIODIC_TABLE "\xf3\xb0\xa2\xb6" // U+F08B6
+#define ICON_MDI_PERSPECTIVE_LESS "\xf3\xb0\xb4\xa3" // U+F0D23
+#define ICON_MDI_PERSPECTIVE_MORE "\xf3\xb0\xb4\xa4" // U+F0D24
+#define ICON_MDI_PH "\xf3\xb1\x9f\x85" // U+F17C5
+#define ICON_MDI_PHONE "\xf3\xb0\x8f\xb2" // U+F03F2
+#define ICON_MDI_PHONE_ALERT "\xf3\xb0\xbc\x9a" // U+F0F1A
+#define ICON_MDI_PHONE_ALERT_OUTLINE "\xf3\xb1\x86\x8e" // U+F118E
+#define ICON_MDI_PHONE_BLUETOOTH "\xf3\xb0\x8f\xb3" // U+F03F3
+#define ICON_MDI_PHONE_BLUETOOTH_OUTLINE "\xf3\xb1\x86\x8f" // U+F118F
+#define ICON_MDI_PHONE_CANCEL "\xf3\xb1\x82\xbc" // U+F10BC
+#define ICON_MDI_PHONE_CANCEL_OUTLINE "\xf3\xb1\x86\x90" // U+F1190
+#define ICON_MDI_PHONE_CHECK "\xf3\xb1\x86\xa9" // U+F11A9
+#define ICON_MDI_PHONE_CHECK_OUTLINE "\xf3\xb1\x86\xaa" // U+F11AA
+#define ICON_MDI_PHONE_CLASSIC "\xf3\xb0\x98\x82" // U+F0602
+#define ICON_MDI_PHONE_CLASSIC_OFF "\xf3\xb1\x89\xb9" // U+F1279
+#define ICON_MDI_PHONE_CLOCK "\xf3\xb1\xa7\x9b" // U+F19DB
+#define ICON_MDI_PHONE_DIAL "\xf3\xb1\x95\x99" // U+F1559
+#define ICON_MDI_PHONE_DIAL_OUTLINE "\xf3\xb1\x95\x9a" // U+F155A
+#define ICON_MDI_PHONE_FORWARD "\xf3\xb0\x8f\xb4" // U+F03F4
+#define ICON_MDI_PHONE_FORWARD_OUTLINE "\xf3\xb1\x86\x91" // U+F1191
+#define ICON_MDI_PHONE_HANGUP "\xf3\xb0\x8f\xb5" // U+F03F5
+#define ICON_MDI_PHONE_HANGUP_OUTLINE "\xf3\xb1\x86\x92" // U+F1192
+#define ICON_MDI_PHONE_IN_TALK "\xf3\xb0\x8f\xb6" // U+F03F6
+#define ICON_MDI_PHONE_IN_TALK_OUTLINE "\xf3\xb1\x86\x82" // U+F1182
+#define ICON_MDI_PHONE_INCOMING "\xf3\xb0\x8f\xb7" // U+F03F7
+#define ICON_MDI_PHONE_INCOMING_OUTGOING "\xf3\xb1\xac\xbf" // U+F1B3F
+#define ICON_MDI_PHONE_INCOMING_OUTGOING_OUTLINE "\xf3\xb1\xad\x80" // U+F1B40
+#define ICON_MDI_PHONE_INCOMING_OUTLINE "\xf3\xb1\x86\x93" // U+F1193
+#define ICON_MDI_PHONE_LOCK "\xf3\xb0\x8f\xb8" // U+F03F8
+#define ICON_MDI_PHONE_LOCK_OUTLINE "\xf3\xb1\x86\x94" // U+F1194
+#define ICON_MDI_PHONE_LOG "\xf3\xb0\x8f\xb9" // U+F03F9
+#define ICON_MDI_PHONE_LOG_OUTLINE "\xf3\xb1\x86\x95" // U+F1195
+#define ICON_MDI_PHONE_MESSAGE "\xf3\xb1\x86\x96" // U+F1196
+#define ICON_MDI_PHONE_MESSAGE_OUTLINE "\xf3\xb1\x86\x97" // U+F1197
+#define ICON_MDI_PHONE_MINUS "\xf3\xb0\x99\x98" // U+F0658
+#define ICON_MDI_PHONE_MINUS_OUTLINE "\xf3\xb1\x86\x98" // U+F1198
+#define ICON_MDI_PHONE_MISSED "\xf3\xb0\x8f\xba" // U+F03FA
+#define ICON_MDI_PHONE_MISSED_OUTLINE "\xf3\xb1\x86\xa5" // U+F11A5
+#define ICON_MDI_PHONE_OFF "\xf3\xb0\xb7\xaf" // U+F0DEF
+#define ICON_MDI_PHONE_OFF_OUTLINE "\xf3\xb1\x86\xa6" // U+F11A6
+#define ICON_MDI_PHONE_OUTGOING "\xf3\xb0\x8f\xbb" // U+F03FB
+#define ICON_MDI_PHONE_OUTGOING_OUTLINE "\xf3\xb1\x86\x99" // U+F1199
+#define ICON_MDI_PHONE_OUTLINE "\xf3\xb0\xb7\xb0" // U+F0DF0
+#define ICON_MDI_PHONE_PAUSED "\xf3\xb0\x8f\xbc" // U+F03FC
+#define ICON_MDI_PHONE_PAUSED_OUTLINE "\xf3\xb1\x86\x9a" // U+F119A
+#define ICON_MDI_PHONE_PLUS "\xf3\xb0\x99\x99" // U+F0659
+#define ICON_MDI_PHONE_PLUS_OUTLINE "\xf3\xb1\x86\x9b" // U+F119B
+#define ICON_MDI_PHONE_REFRESH "\xf3\xb1\xa6\x93" // U+F1993
+#define ICON_MDI_PHONE_REFRESH_OUTLINE "\xf3\xb1\xa6\x94" // U+F1994
+#define ICON_MDI_PHONE_REMOVE "\xf3\xb1\x94\xaf" // U+F152F
+#define ICON_MDI_PHONE_REMOVE_OUTLINE "\xf3\xb1\x94\xb0" // U+F1530
+#define ICON_MDI_PHONE_RETURN "\xf3\xb0\xa0\xaf" // U+F082F
+#define ICON_MDI_PHONE_RETURN_OUTLINE "\xf3\xb1\x86\x9c" // U+F119C
+#define ICON_MDI_PHONE_RING "\xf3\xb1\x86\xab" // U+F11AB
+#define ICON_MDI_PHONE_RING_OUTLINE "\xf3\xb1\x86\xac" // U+F11AC
+#define ICON_MDI_PHONE_ROTATE_LANDSCAPE "\xf3\xb0\xa2\x85" // U+F0885
+#define ICON_MDI_PHONE_ROTATE_PORTRAIT "\xf3\xb0\xa2\x86" // U+F0886
+#define ICON_MDI_PHONE_SETTINGS "\xf3\xb0\x8f\xbd" // U+F03FD
+#define ICON_MDI_PHONE_SETTINGS_OUTLINE "\xf3\xb1\x86\x9d" // U+F119D
+#define ICON_MDI_PHONE_SYNC "\xf3\xb1\xa6\x95" // U+F1995
+#define ICON_MDI_PHONE_SYNC_OUTLINE "\xf3\xb1\xa6\x96" // U+F1996
+#define ICON_MDI_PHONE_VOIP "\xf3\xb0\x8f\xbe" // U+F03FE
+#define ICON_MDI_PI "\xf3\xb0\x8f\xbf" // U+F03FF
+#define ICON_MDI_PI_BOX "\xf3\xb0\x90\x80" // U+F0400
+#define ICON_MDI_PI_HOLE "\xf3\xb0\xb7\xb1" // U+F0DF1
+#define ICON_MDI_PIANO "\xf3\xb0\x99\xbd" // U+F067D
+#define ICON_MDI_PIANO_OFF "\xf3\xb0\x9a\x98" // U+F0698
+#define ICON_MDI_PICKAXE "\xf3\xb0\xa2\xb7" // U+F08B7
+#define ICON_MDI_PICTURE_IN_PICTURE_BOTTOM_RIGHT "\xf3\xb0\xb9\x97" // U+F0E57
+#define ICON_MDI_PICTURE_IN_PICTURE_BOTTOM_RIGHT_OUTLINE "\xf3\xb0\xb9\x98" // U+F0E58
+#define ICON_MDI_PICTURE_IN_PICTURE_TOP_RIGHT "\xf3\xb0\xb9\x99" // U+F0E59
+#define ICON_MDI_PICTURE_IN_PICTURE_TOP_RIGHT_OUTLINE "\xf3\xb0\xb9\x9a" // U+F0E5A
+#define ICON_MDI_PIER "\xf3\xb0\xa2\x87" // U+F0887
+#define ICON_MDI_PIER_CRANE "\xf3\xb0\xa2\x88" // U+F0888
+#define ICON_MDI_PIG "\xf3\xb0\x90\x81" // U+F0401
+#define ICON_MDI_PIG_VARIANT "\xf3\xb1\x80\x86" // U+F1006
+#define ICON_MDI_PIG_VARIANT_OUTLINE "\xf3\xb1\x99\xb8" // U+F1678
+#define ICON_MDI_PIGGY_BANK "\xf3\xb1\x80\x87" // U+F1007
+#define ICON_MDI_PIGGY_BANK_OUTLINE "\xf3\xb1\x99\xb9" // U+F1679
+#define ICON_MDI_PILL "\xf3\xb0\x90\x82" // U+F0402
+#define ICON_MDI_PILL_MULTIPLE "\xf3\xb1\xad\x8c" // U+F1B4C
+#define ICON_MDI_PILL_OFF "\xf3\xb1\xa9\x9c" // U+F1A5C
+#define ICON_MDI_PILLAR "\xf3\xb0\x9c\x82" // U+F0702
+#define ICON_MDI_PIN "\xf3\xb0\x90\x83" // U+F0403
+#define ICON_MDI_PIN_OFF "\xf3\xb0\x90\x84" // U+F0404
+#define ICON_MDI_PIN_OFF_OUTLINE "\xf3\xb0\xa4\xb0" // U+F0930
+#define ICON_MDI_PIN_OUTLINE "\xf3\xb0\xa4\xb1" // U+F0931
+#define ICON_MDI_PINE_TREE "\xf3\xb0\x90\x85" // U+F0405
+#define ICON_MDI_PINE_TREE_BOX "\xf3\xb0\x90\x86" // U+F0406
+#define ICON_MDI_PINE_TREE_FIRE "\xf3\xb1\x90\x9a" // U+F141A
+#define ICON_MDI_PINE_TREE_VARIANT "\xf3\xb1\xb1\xb3" // U+F1C73
+#define ICON_MDI_PINE_TREE_VARIANT_OUTLINE "\xf3\xb1\xb1\xb4" // U+F1C74
+#define ICON_MDI_PINTEREST "\xf3\xb0\x90\x87" // U+F0407
+#define ICON_MDI_PINWHEEL "\xf3\xb0\xab\x95" // U+F0AD5
+#define ICON_MDI_PINWHEEL_OUTLINE "\xf3\xb0\xab\x96" // U+F0AD6
+#define ICON_MDI_PIPE "\xf3\xb0\x9f\xa5" // U+F07E5
+#define ICON_MDI_PIPE_DISCONNECTED "\xf3\xb0\x9f\xa6" // U+F07E6
+#define ICON_MDI_PIPE_LEAK "\xf3\xb0\xa2\x89" // U+F0889
+#define ICON_MDI_PIPE_VALVE "\xf3\xb1\xa1\x8d" // U+F184D
+#define ICON_MDI_PIPE_WRENCH "\xf3\xb1\x8d\x94" // U+F1354
+#define ICON_MDI_PIRATE "\xf3\xb0\xa8\x88" // U+F0A08
+#define ICON_MDI_PISTOL "\xf3\xb0\x9c\x83" // U+F0703
+#define ICON_MDI_PISTON "\xf3\xb0\xa2\x8a" // U+F088A
+#define ICON_MDI_PITCHFORK "\xf3\xb1\x95\x93" // U+F1553
+#define ICON_MDI_PIZZA "\xf3\xb0\x90\x89" // U+F0409
+#define ICON_MDI_PLANE_CAR "\xf3\xb1\xab\xbf" // U+F1AFF
+#define ICON_MDI_PLANE_TRAIN "\xf3\xb1\xac\x80" // U+F1B00
+#define ICON_MDI_PLAY "\xf3\xb0\x90\x8a" // U+F040A
+#define ICON_MDI_PLAY_BOX "\xf3\xb1\x89\xba" // U+F127A
+#define ICON_MDI_PLAY_BOX_EDIT_OUTLINE "\xf3\xb1\xb0\xba" // U+F1C3A
+#define ICON_MDI_PLAY_BOX_LOCK "\xf3\xb1\xa8\x96" // U+F1A16
+#define ICON_MDI_PLAY_BOX_LOCK_OPEN "\xf3\xb1\xa8\x97" // U+F1A17
+#define ICON_MDI_PLAY_BOX_LOCK_OPEN_OUTLINE "\xf3\xb1\xa8\x98" // U+F1A18
+#define ICON_MDI_PLAY_BOX_LOCK_OUTLINE "\xf3\xb1\xa8\x99" // U+F1A19
+#define ICON_MDI_PLAY_BOX_MULTIPLE "\xf3\xb0\xb4\x99" // U+F0D19
+#define ICON_MDI_PLAY_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x8f\xa6" // U+F13E6
+#define ICON_MDI_PLAY_BOX_OUTLINE "\xf3\xb0\x90\x8b" // U+F040B
+#define ICON_MDI_PLAY_CIRCLE "\xf3\xb0\x90\x8c" // U+F040C
+#define ICON_MDI_PLAY_CIRCLE_OUTLINE "\xf3\xb0\x90\x8d" // U+F040D
+#define ICON_MDI_PLAY_NETWORK "\xf3\xb0\xa2\x8b" // U+F088B
+#define ICON_MDI_PLAY_NETWORK_OUTLINE "\xf3\xb0\xb2\xb7" // U+F0CB7
+#define ICON_MDI_PLAY_OUTLINE "\xf3\xb0\xbc\x9b" // U+F0F1B
+#define ICON_MDI_PLAY_PAUSE "\xf3\xb0\x90\x8e" // U+F040E
+#define ICON_MDI_PLAY_PROTECTED_CONTENT "\xf3\xb0\x90\x8f" // U+F040F
+#define ICON_MDI_PLAY_SPEED "\xf3\xb0\xa3\xbf" // U+F08FF
+#define ICON_MDI_PLAYLIST_CHECK "\xf3\xb0\x97\x87" // U+F05C7
+#define ICON_MDI_PLAYLIST_EDIT "\xf3\xb0\xa4\x80" // U+F0900
+#define ICON_MDI_PLAYLIST_MINUS "\xf3\xb0\x90\x90" // U+F0410
+#define ICON_MDI_PLAYLIST_MUSIC "\xf3\xb0\xb2\xb8" // U+F0CB8
+#define ICON_MDI_PLAYLIST_MUSIC_OUTLINE "\xf3\xb0\xb2\xb9" // U+F0CB9
+#define ICON_MDI_PLAYLIST_PLAY "\xf3\xb0\x90\x91" // U+F0411
+#define ICON_MDI_PLAYLIST_PLUS "\xf3\xb0\x90\x92" // U+F0412
+#define ICON_MDI_PLAYLIST_REMOVE "\xf3\xb0\x90\x93" // U+F0413
+#define ICON_MDI_PLAYLIST_STAR "\xf3\xb0\xb7\xb2" // U+F0DF2
+#define ICON_MDI_PLEX "\xf3\xb0\x9a\xba" // U+F06BA
+#define ICON_MDI_PLIERS "\xf3\xb1\xa6\xa4" // U+F19A4
+#define ICON_MDI_PLUS "\xf3\xb0\x90\x95" // U+F0415
+#define ICON_MDI_PLUS_BOX "\xf3\xb0\x90\x96" // U+F0416
+#define ICON_MDI_PLUS_BOX_MULTIPLE "\xf3\xb0\x8c\xb4" // U+F0334
+#define ICON_MDI_PLUS_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x85\x83" // U+F1143
+#define ICON_MDI_PLUS_BOX_OUTLINE "\xf3\xb0\x9c\x84" // U+F0704
+#define ICON_MDI_PLUS_CIRCLE "\xf3\xb0\x90\x97" // U+F0417
+#define ICON_MDI_PLUS_CIRCLE_MULTIPLE "\xf3\xb0\x8d\x8c" // U+F034C
+#define ICON_MDI_PLUS_CIRCLE_MULTIPLE_OUTLINE "\xf3\xb0\x90\x98" // U+F0418
+#define ICON_MDI_PLUS_CIRCLE_OUTLINE "\xf3\xb0\x90\x99" // U+F0419
+#define ICON_MDI_PLUS_LOCK "\xf3\xb1\xa9\x9d" // U+F1A5D
+#define ICON_MDI_PLUS_LOCK_OPEN "\xf3\xb1\xa9\x9e" // U+F1A5E
+#define ICON_MDI_PLUS_MINUS "\xf3\xb0\xa6\x92" // U+F0992
+#define ICON_MDI_PLUS_MINUS_BOX "\xf3\xb0\xa6\x93" // U+F0993
+#define ICON_MDI_PLUS_MINUS_VARIANT "\xf3\xb1\x93\x89" // U+F14C9
+#define ICON_MDI_PLUS_NETWORK "\xf3\xb0\x90\x9a" // U+F041A
+#define ICON_MDI_PLUS_NETWORK_OUTLINE "\xf3\xb0\xb2\xba" // U+F0CBA
+#define ICON_MDI_PLUS_OUTLINE "\xf3\xb0\x9c\x85" // U+F0705
+#define ICON_MDI_PLUS_THICK "\xf3\xb1\x87\xac" // U+F11EC
+#define ICON_MDI_POCKET "\xf3\xb1\xb2\xbe" // U+F1CBE
+#define ICON_MDI_PODCAST "\xf3\xb0\xa6\x94" // U+F0994
+#define ICON_MDI_PODIUM "\xf3\xb0\xb4\xa5" // U+F0D25
+#define ICON_MDI_PODIUM_BRONZE "\xf3\xb0\xb4\xa6" // U+F0D26
+#define ICON_MDI_PODIUM_GOLD "\xf3\xb0\xb4\xa7" // U+F0D27
+#define ICON_MDI_PODIUM_SILVER "\xf3\xb0\xb4\xa8" // U+F0D28
+#define ICON_MDI_POINT_OF_SALE "\xf3\xb0\xb6\x92" // U+F0D92
+#define ICON_MDI_POKEBALL "\xf3\xb0\x90\x9d" // U+F041D
+#define ICON_MDI_POKEMON_GO "\xf3\xb0\xa8\x89" // U+F0A09
+#define ICON_MDI_POKER_CHIP "\xf3\xb0\xa0\xb0" // U+F0830
+#define ICON_MDI_POLAROID "\xf3\xb0\x90\x9e" // U+F041E
+#define ICON_MDI_POLICE_BADGE "\xf3\xb1\x85\xa7" // U+F1167
+#define ICON_MDI_POLICE_BADGE_OUTLINE "\xf3\xb1\x85\xa8" // U+F1168
+#define ICON_MDI_POLICE_STATION "\xf3\xb1\xa0\xb9" // U+F1839
+#define ICON_MDI_POLL "\xf3\xb0\x90\x9f" // U+F041F
+#define ICON_MDI_POLO "\xf3\xb1\x93\x83" // U+F14C3
+#define ICON_MDI_POLYMER "\xf3\xb0\x90\xa1" // U+F0421
+#define ICON_MDI_POOL "\xf3\xb0\x98\x86" // U+F0606
+#define ICON_MDI_POOL_THERMOMETER "\xf3\xb1\xa9\x9f" // U+F1A5F
+#define ICON_MDI_POPCORN "\xf3\xb0\x90\xa2" // U+F0422
+#define ICON_MDI_POST "\xf3\xb1\x80\x88" // U+F1008
+#define ICON_MDI_POST_LAMP "\xf3\xb1\xa9\xa0" // U+F1A60
+#define ICON_MDI_POST_OUTLINE "\xf3\xb1\x80\x89" // U+F1009
+#define ICON_MDI_POSTAGE_STAMP "\xf3\xb0\xb2\xbb" // U+F0CBB
+#define ICON_MDI_POT "\xf3\xb0\x8b\xa5" // U+F02E5
+#define ICON_MDI_POT_MIX "\xf3\xb0\x99\x9b" // U+F065B
+#define ICON_MDI_POT_MIX_OUTLINE "\xf3\xb0\x99\xb7" // U+F0677
+#define ICON_MDI_POT_OUTLINE "\xf3\xb0\x8b\xbf" // U+F02FF
+#define ICON_MDI_POT_STEAM "\xf3\xb0\x99\x9a" // U+F065A
+#define ICON_MDI_POT_STEAM_OUTLINE "\xf3\xb0\x8c\xa6" // U+F0326
+#define ICON_MDI_POUND "\xf3\xb0\x90\xa3" // U+F0423
+#define ICON_MDI_POUND_BOX "\xf3\xb0\x90\xa4" // U+F0424
+#define ICON_MDI_POUND_BOX_OUTLINE "\xf3\xb1\x85\xbf" // U+F117F
+#define ICON_MDI_POWER "\xf3\xb0\x90\xa5" // U+F0425
+#define ICON_MDI_POWER_CYCLE "\xf3\xb0\xa4\x81" // U+F0901
+#define ICON_MDI_POWER_OFF "\xf3\xb0\xa4\x82" // U+F0902
+#define ICON_MDI_POWER_ON "\xf3\xb0\xa4\x83" // U+F0903
+#define ICON_MDI_POWER_PLUG "\xf3\xb0\x9a\xa5" // U+F06A5
+#define ICON_MDI_POWER_PLUG_BATTERY "\xf3\xb1\xb0\xbb" // U+F1C3B
+#define ICON_MDI_POWER_PLUG_BATTERY_OUTLINE "\xf3\xb1\xb0\xbc" // U+F1C3C
+#define ICON_MDI_POWER_PLUG_OFF "\xf3\xb0\x9a\xa6" // U+F06A6
+#define ICON_MDI_POWER_PLUG_OFF_OUTLINE "\xf3\xb1\x90\xa4" // U+F1424
+#define ICON_MDI_POWER_PLUG_OUTLINE "\xf3\xb1\x90\xa5" // U+F1425
+#define ICON_MDI_POWER_SETTINGS "\xf3\xb0\x90\xa6" // U+F0426
+#define ICON_MDI_POWER_SLEEP "\xf3\xb0\xa4\x84" // U+F0904
+#define ICON_MDI_POWER_SOCKET "\xf3\xb0\x90\xa7" // U+F0427
+#define ICON_MDI_POWER_SOCKET_AU "\xf3\xb0\xa4\x85" // U+F0905
+#define ICON_MDI_POWER_SOCKET_CH "\xf3\xb0\xbe\xb3" // U+F0FB3
+#define ICON_MDI_POWER_SOCKET_DE "\xf3\xb1\x84\x87" // U+F1107
+#define ICON_MDI_POWER_SOCKET_EU "\xf3\xb0\x9f\xa7" // U+F07E7
+#define ICON_MDI_POWER_SOCKET_FR "\xf3\xb1\x84\x88" // U+F1108
+#define ICON_MDI_POWER_SOCKET_IT "\xf3\xb1\x93\xbf" // U+F14FF
+#define ICON_MDI_POWER_SOCKET_JP "\xf3\xb1\x84\x89" // U+F1109
+#define ICON_MDI_POWER_SOCKET_UK "\xf3\xb0\x9f\xa8" // U+F07E8
+#define ICON_MDI_POWER_SOCKET_US "\xf3\xb0\x9f\xa9" // U+F07E9
+#define ICON_MDI_POWER_STANDBY "\xf3\xb0\xa4\x86" // U+F0906
+#define ICON_MDI_POWERSHELL "\xf3\xb0\xa8\x8a" // U+F0A0A
+#define ICON_MDI_PRESCRIPTION "\xf3\xb0\x9c\x86" // U+F0706
+#define ICON_MDI_PRESENTATION "\xf3\xb0\x90\xa8" // U+F0428
+#define ICON_MDI_PRESENTATION_PLAY "\xf3\xb0\x90\xa9" // U+F0429
+#define ICON_MDI_PRETZEL "\xf3\xb1\x95\xa2" // U+F1562
+#define ICON_MDI_PRINTER "\xf3\xb0\x90\xaa" // U+F042A
+#define ICON_MDI_PRINTER_3D "\xf3\xb0\x90\xab" // U+F042B
+#define ICON_MDI_PRINTER_3D_NOZZLE "\xf3\xb0\xb9\x9b" // U+F0E5B
+#define ICON_MDI_PRINTER_3D_NOZZLE_ALERT "\xf3\xb1\x87\x80" // U+F11C0
+#define ICON_MDI_PRINTER_3D_NOZZLE_ALERT_OUTLINE "\xf3\xb1\x87\x81" // U+F11C1
+#define ICON_MDI_PRINTER_3D_NOZZLE_HEAT "\xf3\xb1\xa2\xb8" // U+F18B8
+#define ICON_MDI_PRINTER_3D_NOZZLE_HEAT_OUTLINE "\xf3\xb1\xa2\xb9" // U+F18B9
+#define ICON_MDI_PRINTER_3D_NOZZLE_OFF "\xf3\xb1\xac\x99" // U+F1B19
+#define ICON_MDI_PRINTER_3D_NOZZLE_OFF_OUTLINE "\xf3\xb1\xac\x9a" // U+F1B1A
+#define ICON_MDI_PRINTER_3D_NOZZLE_OUTLINE "\xf3\xb0\xb9\x9c" // U+F0E5C
+#define ICON_MDI_PRINTER_3D_OFF "\xf3\xb1\xac\x8e" // U+F1B0E
+#define ICON_MDI_PRINTER_ALERT "\xf3\xb0\x90\xac" // U+F042C
+#define ICON_MDI_PRINTER_CHECK "\xf3\xb1\x85\x86" // U+F1146
+#define ICON_MDI_PRINTER_EYE "\xf3\xb1\x91\x98" // U+F1458
+#define ICON_MDI_PRINTER_OFF "\xf3\xb0\xb9\x9d" // U+F0E5D
+#define ICON_MDI_PRINTER_OFF_OUTLINE "\xf3\xb1\x9e\x85" // U+F1785
+#define ICON_MDI_PRINTER_OUTLINE "\xf3\xb1\x9e\x86" // U+F1786
+#define ICON_MDI_PRINTER_POS "\xf3\xb1\x81\x97" // U+F1057
+#define ICON_MDI_PRINTER_POS_ALERT "\xf3\xb1\xae\xbc" // U+F1BBC
+#define ICON_MDI_PRINTER_POS_ALERT_OUTLINE "\xf3\xb1\xae\xbd" // U+F1BBD
+#define ICON_MDI_PRINTER_POS_CANCEL "\xf3\xb1\xae\xbe" // U+F1BBE
+#define ICON_MDI_PRINTER_POS_CANCEL_OUTLINE "\xf3\xb1\xae\xbf" // U+F1BBF
+#define ICON_MDI_PRINTER_POS_CHECK "\xf3\xb1\xaf\x80" // U+F1BC0
+#define ICON_MDI_PRINTER_POS_CHECK_OUTLINE "\xf3\xb1\xaf\x81" // U+F1BC1
+#define ICON_MDI_PRINTER_POS_COG "\xf3\xb1\xaf\x82" // U+F1BC2
+#define ICON_MDI_PRINTER_POS_COG_OUTLINE "\xf3\xb1\xaf\x83" // U+F1BC3
+#define ICON_MDI_PRINTER_POS_EDIT "\xf3\xb1\xaf\x84" // U+F1BC4
+#define ICON_MDI_PRINTER_POS_EDIT_OUTLINE "\xf3\xb1\xaf\x85" // U+F1BC5
+#define ICON_MDI_PRINTER_POS_MINUS "\xf3\xb1\xaf\x86" // U+F1BC6
+#define ICON_MDI_PRINTER_POS_MINUS_OUTLINE "\xf3\xb1\xaf\x87" // U+F1BC7
+#define ICON_MDI_PRINTER_POS_NETWORK "\xf3\xb1\xaf\x88" // U+F1BC8
+#define ICON_MDI_PRINTER_POS_NETWORK_OUTLINE "\xf3\xb1\xaf\x89" // U+F1BC9
+#define ICON_MDI_PRINTER_POS_OFF "\xf3\xb1\xaf\x8a" // U+F1BCA
+#define ICON_MDI_PRINTER_POS_OFF_OUTLINE "\xf3\xb1\xaf\x8b" // U+F1BCB
+#define ICON_MDI_PRINTER_POS_OUTLINE "\xf3\xb1\xaf\x8c" // U+F1BCC
+#define ICON_MDI_PRINTER_POS_PAUSE "\xf3\xb1\xaf\x8d" // U+F1BCD
+#define ICON_MDI_PRINTER_POS_PAUSE_OUTLINE "\xf3\xb1\xaf\x8e" // U+F1BCE
+#define ICON_MDI_PRINTER_POS_PLAY "\xf3\xb1\xaf\x8f" // U+F1BCF
+#define ICON_MDI_PRINTER_POS_PLAY_OUTLINE "\xf3\xb1\xaf\x90" // U+F1BD0
+#define ICON_MDI_PRINTER_POS_PLUS "\xf3\xb1\xaf\x91" // U+F1BD1
+#define ICON_MDI_PRINTER_POS_PLUS_OUTLINE "\xf3\xb1\xaf\x92" // U+F1BD2
+#define ICON_MDI_PRINTER_POS_REFRESH "\xf3\xb1\xaf\x93" // U+F1BD3
+#define ICON_MDI_PRINTER_POS_REFRESH_OUTLINE "\xf3\xb1\xaf\x94" // U+F1BD4
+#define ICON_MDI_PRINTER_POS_REMOVE "\xf3\xb1\xaf\x95" // U+F1BD5
+#define ICON_MDI_PRINTER_POS_REMOVE_OUTLINE "\xf3\xb1\xaf\x96" // U+F1BD6
+#define ICON_MDI_PRINTER_POS_STAR "\xf3\xb1\xaf\x97" // U+F1BD7
+#define ICON_MDI_PRINTER_POS_STAR_OUTLINE "\xf3\xb1\xaf\x98" // U+F1BD8
+#define ICON_MDI_PRINTER_POS_STOP "\xf3\xb1\xaf\x99" // U+F1BD9
+#define ICON_MDI_PRINTER_POS_STOP_OUTLINE "\xf3\xb1\xaf\x9a" // U+F1BDA
+#define ICON_MDI_PRINTER_POS_SYNC "\xf3\xb1\xaf\x9b" // U+F1BDB
+#define ICON_MDI_PRINTER_POS_SYNC_OUTLINE "\xf3\xb1\xaf\x9c" // U+F1BDC
+#define ICON_MDI_PRINTER_POS_WRENCH "\xf3\xb1\xaf\x9d" // U+F1BDD
+#define ICON_MDI_PRINTER_POS_WRENCH_OUTLINE "\xf3\xb1\xaf\x9e" // U+F1BDE
+#define ICON_MDI_PRINTER_SEARCH "\xf3\xb1\x91\x97" // U+F1457
+#define ICON_MDI_PRINTER_SETTINGS "\xf3\xb0\x9c\x87" // U+F0707
+#define ICON_MDI_PRINTER_WIRELESS "\xf3\xb0\xa8\x8b" // U+F0A0B
+#define ICON_MDI_PRIORITY_HIGH "\xf3\xb0\x98\x83" // U+F0603
+#define ICON_MDI_PRIORITY_LOW "\xf3\xb0\x98\x84" // U+F0604
+#define ICON_MDI_PROFESSIONAL_HEXAGON "\xf3\xb0\x90\xad" // U+F042D
+#define ICON_MDI_PROGRESS_ALERT "\xf3\xb0\xb2\xbc" // U+F0CBC
+#define ICON_MDI_PROGRESS_CHECK "\xf3\xb0\xa6\x95" // U+F0995
+#define ICON_MDI_PROGRESS_CLOCK "\xf3\xb0\xa6\x96" // U+F0996
+#define ICON_MDI_PROGRESS_CLOSE "\xf3\xb1\x84\x8a" // U+F110A
+#define ICON_MDI_PROGRESS_DOWNLOAD "\xf3\xb0\xa6\x97" // U+F0997
+#define ICON_MDI_PROGRESS_HELPER "\xf3\xb1\xae\xa2" // U+F1BA2
+#define ICON_MDI_PROGRESS_PENCIL "\xf3\xb1\x9e\x87" // U+F1787
+#define ICON_MDI_PROGRESS_QUESTION "\xf3\xb1\x94\xa2" // U+F1522
+#define ICON_MDI_PROGRESS_STAR "\xf3\xb1\x9e\x88" // U+F1788
+#define ICON_MDI_PROGRESS_STAR_FOUR_POINTS "\xf3\xb1\xb0\xbd" // U+F1C3D
+#define ICON_MDI_PROGRESS_UPLOAD "\xf3\xb0\xa6\x98" // U+F0998
+#define ICON_MDI_PROGRESS_WRENCH "\xf3\xb0\xb2\xbd" // U+F0CBD
+#define ICON_MDI_PROJECTOR "\xf3\xb0\x90\xae" // U+F042E
+#define ICON_MDI_PROJECTOR_OFF "\xf3\xb1\xa8\xa3" // U+F1A23
+#define ICON_MDI_PROJECTOR_SCREEN "\xf3\xb0\x90\xaf" // U+F042F
+#define ICON_MDI_PROJECTOR_SCREEN_OFF "\xf3\xb1\xa0\x8d" // U+F180D
+#define ICON_MDI_PROJECTOR_SCREEN_OFF_OUTLINE "\xf3\xb1\xa0\x8e" // U+F180E
+#define ICON_MDI_PROJECTOR_SCREEN_OUTLINE "\xf3\xb1\x9c\xa4" // U+F1724
+#define ICON_MDI_PROJECTOR_SCREEN_VARIANT "\xf3\xb1\xa0\x8f" // U+F180F
+#define ICON_MDI_PROJECTOR_SCREEN_VARIANT_OFF "\xf3\xb1\xa0\x90" // U+F1810
+#define ICON_MDI_PROJECTOR_SCREEN_VARIANT_OFF_OUTLINE "\xf3\xb1\xa0\x91" // U+F1811
+#define ICON_MDI_PROJECTOR_SCREEN_VARIANT_OUTLINE "\xf3\xb1\xa0\x92" // U+F1812
+#define ICON_MDI_PROPANE_TANK "\xf3\xb1\x8d\x97" // U+F1357
+#define ICON_MDI_PROPANE_TANK_OUTLINE "\xf3\xb1\x8d\x98" // U+F1358
+#define ICON_MDI_PROTOCOL "\xf3\xb0\xbf\x98" // U+F0FD8
+#define ICON_MDI_PUBLISH "\xf3\xb0\x9a\xa7" // U+F06A7
+#define ICON_MDI_PUBLISH_OFF "\xf3\xb1\xa5\x85" // U+F1945
+#define ICON_MDI_PULSE "\xf3\xb0\x90\xb0" // U+F0430
+#define ICON_MDI_PUMP "\xf3\xb1\x90\x82" // U+F1402
+#define ICON_MDI_PUMP_OFF "\xf3\xb1\xac\xa2" // U+F1B22
+#define ICON_MDI_PUMPKIN "\xf3\xb0\xae\xbf" // U+F0BBF
+#define ICON_MDI_PURSE "\xf3\xb0\xbc\x9c" // U+F0F1C
+#define ICON_MDI_PURSE_OUTLINE "\xf3\xb0\xbc\x9d" // U+F0F1D
+#define ICON_MDI_PUZZLE "\xf3\xb0\x90\xb1" // U+F0431
+#define ICON_MDI_PUZZLE_CHECK "\xf3\xb1\x90\xa6" // U+F1426
+#define ICON_MDI_PUZZLE_CHECK_OUTLINE "\xf3\xb1\x90\xa7" // U+F1427
+#define ICON_MDI_PUZZLE_EDIT "\xf3\xb1\x93\x93" // U+F14D3
+#define ICON_MDI_PUZZLE_EDIT_OUTLINE "\xf3\xb1\x93\x99" // U+F14D9
+#define ICON_MDI_PUZZLE_HEART "\xf3\xb1\x93\x94" // U+F14D4
+#define ICON_MDI_PUZZLE_HEART_OUTLINE "\xf3\xb1\x93\x9a" // U+F14DA
+#define ICON_MDI_PUZZLE_MINUS "\xf3\xb1\x93\x91" // U+F14D1
+#define ICON_MDI_PUZZLE_MINUS_OUTLINE "\xf3\xb1\x93\x97" // U+F14D7
+#define ICON_MDI_PUZZLE_OUTLINE "\xf3\xb0\xa9\xa6" // U+F0A66
+#define ICON_MDI_PUZZLE_PLUS "\xf3\xb1\x93\x90" // U+F14D0
+#define ICON_MDI_PUZZLE_PLUS_OUTLINE "\xf3\xb1\x93\x96" // U+F14D6
+#define ICON_MDI_PUZZLE_REMOVE "\xf3\xb1\x93\x92" // U+F14D2
+#define ICON_MDI_PUZZLE_REMOVE_OUTLINE "\xf3\xb1\x93\x98" // U+F14D8
+#define ICON_MDI_PUZZLE_STAR "\xf3\xb1\x93\x95" // U+F14D5
+#define ICON_MDI_PUZZLE_STAR_OUTLINE "\xf3\xb1\x93\x9b" // U+F14DB
+#define ICON_MDI_PYRAMID "\xf3\xb1\xa5\x92" // U+F1952
+#define ICON_MDI_PYRAMID_OFF "\xf3\xb1\xa5\x93" // U+F1953
+#define ICON_MDI_QI "\xf3\xb0\xa6\x99" // U+F0999
+#define ICON_MDI_QQCHAT "\xf3\xb0\x98\x85" // U+F0605
+#define ICON_MDI_QRCODE "\xf3\xb0\x90\xb2" // U+F0432
+#define ICON_MDI_QRCODE_EDIT "\xf3\xb0\xa2\xb8" // U+F08B8
+#define ICON_MDI_QRCODE_MINUS "\xf3\xb1\x86\x8c" // U+F118C
+#define ICON_MDI_QRCODE_PLUS "\xf3\xb1\x86\x8b" // U+F118B
+#define ICON_MDI_QRCODE_REMOVE "\xf3\xb1\x86\x8d" // U+F118D
+#define ICON_MDI_QRCODE_SCAN "\xf3\xb0\x90\xb3" // U+F0433
+#define ICON_MDI_QUADCOPTER "\xf3\xb0\x90\xb4" // U+F0434
+#define ICON_MDI_QUALITY_HIGH "\xf3\xb0\x90\xb5" // U+F0435
+#define ICON_MDI_QUALITY_LOW "\xf3\xb0\xa8\x8c" // U+F0A0C
+#define ICON_MDI_QUALITY_MEDIUM "\xf3\xb0\xa8\x8d" // U+F0A0D
+#define ICON_MDI_QUEUE_FIRST_IN_LAST_OUT "\xf3\xb1\xb2\xaf" // U+F1CAF
+#define ICON_MDI_QUORA "\xf3\xb0\xb4\xa9" // U+F0D29
+#define ICON_MDI_RABBIT "\xf3\xb0\xa4\x87" // U+F0907
+#define ICON_MDI_RABBIT_VARIANT "\xf3\xb1\xa9\xa1" // U+F1A61
+#define ICON_MDI_RABBIT_VARIANT_OUTLINE "\xf3\xb1\xa9\xa2" // U+F1A62
+#define ICON_MDI_RACING_HELMET "\xf3\xb0\xb6\x93" // U+F0D93
+#define ICON_MDI_RACQUETBALL "\xf3\xb0\xb6\x94" // U+F0D94
+#define ICON_MDI_RADAR "\xf3\xb0\x90\xb7" // U+F0437
+#define ICON_MDI_RADIATOR "\xf3\xb0\x90\xb8" // U+F0438
+#define ICON_MDI_RADIATOR_DISABLED "\xf3\xb0\xab\x97" // U+F0AD7
+#define ICON_MDI_RADIATOR_OFF "\xf3\xb0\xab\x98" // U+F0AD8
+#define ICON_MDI_RADIO "\xf3\xb0\x90\xb9" // U+F0439
+#define ICON_MDI_RADIO_AM "\xf3\xb0\xb2\xbe" // U+F0CBE
+#define ICON_MDI_RADIO_FM "\xf3\xb0\xb2\xbf" // U+F0CBF
+#define ICON_MDI_RADIO_HANDHELD "\xf3\xb0\x90\xba" // U+F043A
+#define ICON_MDI_RADIO_OFF "\xf3\xb1\x88\x9c" // U+F121C
+#define ICON_MDI_RADIO_TOWER "\xf3\xb0\x90\xbb" // U+F043B
+#define ICON_MDI_RADIOACTIVE "\xf3\xb0\x90\xbc" // U+F043C
+#define ICON_MDI_RADIOACTIVE_CIRCLE "\xf3\xb1\xa1\x9d" // U+F185D
+#define ICON_MDI_RADIOACTIVE_CIRCLE_OUTLINE "\xf3\xb1\xa1\x9e" // U+F185E
+#define ICON_MDI_RADIOACTIVE_OFF "\xf3\xb0\xbb\x81" // U+F0EC1
+#define ICON_MDI_RADIOBOX_BLANK "\xf3\xb0\x90\xbd" // U+F043D
+#define ICON_MDI_RADIOBOX_INDETERMINATE_VARIANT "\xf3\xb1\xb1\x9e" // U+F1C5E
+#define ICON_MDI_RADIOBOX_MARKED "\xf3\xb0\x90\xbe" // U+F043E
+#define ICON_MDI_RADIOLOGY_BOX "\xf3\xb1\x93\x85" // U+F14C5
+#define ICON_MDI_RADIOLOGY_BOX_OUTLINE "\xf3\xb1\x93\x86" // U+F14C6
+#define ICON_MDI_RADIUS "\xf3\xb0\xb3\x80" // U+F0CC0
+#define ICON_MDI_RADIUS_OUTLINE "\xf3\xb0\xb3\x81" // U+F0CC1
+#define ICON_MDI_RAILROAD_LIGHT "\xf3\xb0\xbc\x9e" // U+F0F1E
+#define ICON_MDI_RAKE "\xf3\xb1\x95\x84" // U+F1544
+#define ICON_MDI_RASPBERRY_PI "\xf3\xb0\x90\xbf" // U+F043F
+#define ICON_MDI_RAW "\xf3\xb1\xa8\x8f" // U+F1A0F
+#define ICON_MDI_RAW_OFF "\xf3\xb1\xa8\x90" // U+F1A10
+#define ICON_MDI_RAY_END "\xf3\xb0\x91\x80" // U+F0440
+#define ICON_MDI_RAY_END_ARROW "\xf3\xb0\x91\x81" // U+F0441
+#define ICON_MDI_RAY_START "\xf3\xb0\x91\x82" // U+F0442
+#define ICON_MDI_RAY_START_ARROW "\xf3\xb0\x91\x83" // U+F0443
+#define ICON_MDI_RAY_START_END "\xf3\xb0\x91\x84" // U+F0444
+#define ICON_MDI_RAY_START_VERTEX_END "\xf3\xb1\x97\x98" // U+F15D8
+#define ICON_MDI_RAY_VERTEX "\xf3\xb0\x91\x85" // U+F0445
+#define ICON_MDI_RAZOR_DOUBLE_EDGE "\xf3\xb1\xa6\x97" // U+F1997
+#define ICON_MDI_RAZOR_SINGLE_EDGE "\xf3\xb1\xa6\x98" // U+F1998
+#define ICON_MDI_REACT "\xf3\xb0\x9c\x88" // U+F0708
+#define ICON_MDI_READ "\xf3\xb0\x91\x87" // U+F0447
+#define ICON_MDI_RECEIPT "\xf3\xb0\xa0\xa4" // U+F0824
+#define ICON_MDI_RECEIPT_CLOCK "\xf3\xb1\xb0\xbe" // U+F1C3E
+#define ICON_MDI_RECEIPT_CLOCK_OUTLINE "\xf3\xb1\xb0\xbf" // U+F1C3F
+#define ICON_MDI_RECEIPT_OUTLINE "\xf3\xb0\x93\xb7" // U+F04F7
+#define ICON_MDI_RECEIPT_SEND "\xf3\xb1\xb1\x80" // U+F1C40
+#define ICON_MDI_RECEIPT_SEND_OUTLINE "\xf3\xb1\xb1\x81" // U+F1C41
+#define ICON_MDI_RECEIPT_TEXT "\xf3\xb0\x91\x89" // U+F0449
+#define ICON_MDI_RECEIPT_TEXT_ARROW_LEFT "\xf3\xb1\xb1\x82" // U+F1C42
+#define ICON_MDI_RECEIPT_TEXT_ARROW_LEFT_OUTLINE "\xf3\xb1\xb1\x83" // U+F1C43
+#define ICON_MDI_RECEIPT_TEXT_ARROW_RIGHT "\xf3\xb1\xb1\x84" // U+F1C44
+#define ICON_MDI_RECEIPT_TEXT_ARROW_RIGHT_OUTLINE "\xf3\xb1\xb1\x85" // U+F1C45
+#define ICON_MDI_RECEIPT_TEXT_CHECK "\xf3\xb1\xa9\xa3" // U+F1A63
+#define ICON_MDI_RECEIPT_TEXT_CHECK_OUTLINE "\xf3\xb1\xa9\xa4" // U+F1A64
+#define ICON_MDI_RECEIPT_TEXT_CLOCK "\xf3\xb1\xb1\x86" // U+F1C46
+#define ICON_MDI_RECEIPT_TEXT_CLOCK_OUTLINE "\xf3\xb1\xb1\x87" // U+F1C47
+#define ICON_MDI_RECEIPT_TEXT_EDIT "\xf3\xb1\xb1\x88" // U+F1C48
+#define ICON_MDI_RECEIPT_TEXT_EDIT_OUTLINE "\xf3\xb1\xb1\x89" // U+F1C49
+#define ICON_MDI_RECEIPT_TEXT_MINUS "\xf3\xb1\xa9\xa5" // U+F1A65
+#define ICON_MDI_RECEIPT_TEXT_MINUS_OUTLINE "\xf3\xb1\xa9\xa6" // U+F1A66
+#define ICON_MDI_RECEIPT_TEXT_OUTLINE "\xf3\xb1\xa7\x9c" // U+F19DC
+#define ICON_MDI_RECEIPT_TEXT_PLUS "\xf3\xb1\xa9\xa7" // U+F1A67
+#define ICON_MDI_RECEIPT_TEXT_PLUS_OUTLINE "\xf3\xb1\xa9\xa8" // U+F1A68
+#define ICON_MDI_RECEIPT_TEXT_REMOVE "\xf3\xb1\xa9\xa9" // U+F1A69
+#define ICON_MDI_RECEIPT_TEXT_REMOVE_OUTLINE "\xf3\xb1\xa9\xaa" // U+F1A6A
+#define ICON_MDI_RECEIPT_TEXT_SEND "\xf3\xb1\xb1\x8a" // U+F1C4A
+#define ICON_MDI_RECEIPT_TEXT_SEND_OUTLINE "\xf3\xb1\xb1\x8b" // U+F1C4B
+#define ICON_MDI_RECORD "\xf3\xb0\x91\x8a" // U+F044A
+#define ICON_MDI_RECORD_CIRCLE "\xf3\xb0\xbb\x82" // U+F0EC2
+#define ICON_MDI_RECORD_CIRCLE_OUTLINE "\xf3\xb0\xbb\x83" // U+F0EC3
+#define ICON_MDI_RECORD_PLAYER "\xf3\xb0\xa6\x9a" // U+F099A
+#define ICON_MDI_RECORD_REC "\xf3\xb0\x91\x8b" // U+F044B
+#define ICON_MDI_RECTANGLE "\xf3\xb0\xb9\x9e" // U+F0E5E
+#define ICON_MDI_RECTANGLE_OUTLINE "\xf3\xb0\xb9\x9f" // U+F0E5F
+#define ICON_MDI_RECYCLE "\xf3\xb0\x91\x8c" // U+F044C
+#define ICON_MDI_RECYCLE_VARIANT "\xf3\xb1\x8e\x9d" // U+F139D
+#define ICON_MDI_REDDIT "\xf3\xb0\x91\x8d" // U+F044D
+#define ICON_MDI_REDHAT "\xf3\xb1\x84\x9b" // U+F111B
+#define ICON_MDI_REDO "\xf3\xb0\x91\x8e" // U+F044E
+#define ICON_MDI_REDO_VARIANT "\xf3\xb0\x91\x8f" // U+F044F
+#define ICON_MDI_REFLECT_HORIZONTAL "\xf3\xb0\xa8\x8e" // U+F0A0E
+#define ICON_MDI_REFLECT_VERTICAL "\xf3\xb0\xa8\x8f" // U+F0A0F
+#define ICON_MDI_REFRESH "\xf3\xb0\x91\x90" // U+F0450
+#define ICON_MDI_REFRESH_AUTO "\xf3\xb1\xa3\xb2" // U+F18F2
+#define ICON_MDI_REFRESH_CIRCLE "\xf3\xb1\x8d\xb7" // U+F1377
+#define ICON_MDI_REGEX "\xf3\xb0\x91\x91" // U+F0451
+#define ICON_MDI_REGISTERED_TRADEMARK "\xf3\xb0\xa9\xa7" // U+F0A67
+#define ICON_MDI_REITERATE "\xf3\xb1\x96\x88" // U+F1588
+#define ICON_MDI_RELATION_MANY_TO_MANY "\xf3\xb1\x92\x96" // U+F1496
+#define ICON_MDI_RELATION_MANY_TO_ONE "\xf3\xb1\x92\x97" // U+F1497
+#define ICON_MDI_RELATION_MANY_TO_ONE_OR_MANY "\xf3\xb1\x92\x98" // U+F1498
+#define ICON_MDI_RELATION_MANY_TO_ONLY_ONE "\xf3\xb1\x92\x99" // U+F1499
+#define ICON_MDI_RELATION_MANY_TO_ZERO_OR_MANY "\xf3\xb1\x92\x9a" // U+F149A
+#define ICON_MDI_RELATION_MANY_TO_ZERO_OR_ONE "\xf3\xb1\x92\x9b" // U+F149B
+#define ICON_MDI_RELATION_ONE_OR_MANY_TO_MANY "\xf3\xb1\x92\x9c" // U+F149C
+#define ICON_MDI_RELATION_ONE_OR_MANY_TO_ONE "\xf3\xb1\x92\x9d" // U+F149D
+#define ICON_MDI_RELATION_ONE_OR_MANY_TO_ONE_OR_MANY "\xf3\xb1\x92\x9e" // U+F149E
+#define ICON_MDI_RELATION_ONE_OR_MANY_TO_ONLY_ONE "\xf3\xb1\x92\x9f" // U+F149F
+#define ICON_MDI_RELATION_ONE_OR_MANY_TO_ZERO_OR_MANY "\xf3\xb1\x92\xa0" // U+F14A0
+#define ICON_MDI_RELATION_ONE_OR_MANY_TO_ZERO_OR_ONE "\xf3\xb1\x92\xa1" // U+F14A1
+#define ICON_MDI_RELATION_ONE_TO_MANY "\xf3\xb1\x92\xa2" // U+F14A2
+#define ICON_MDI_RELATION_ONE_TO_ONE "\xf3\xb1\x92\xa3" // U+F14A3
+#define ICON_MDI_RELATION_ONE_TO_ONE_OR_MANY "\xf3\xb1\x92\xa4" // U+F14A4
+#define ICON_MDI_RELATION_ONE_TO_ONLY_ONE "\xf3\xb1\x92\xa5" // U+F14A5
+#define ICON_MDI_RELATION_ONE_TO_ZERO_OR_MANY "\xf3\xb1\x92\xa6" // U+F14A6
+#define ICON_MDI_RELATION_ONE_TO_ZERO_OR_ONE "\xf3\xb1\x92\xa7" // U+F14A7
+#define ICON_MDI_RELATION_ONLY_ONE_TO_MANY "\xf3\xb1\x92\xa8" // U+F14A8
+#define ICON_MDI_RELATION_ONLY_ONE_TO_ONE "\xf3\xb1\x92\xa9" // U+F14A9
+#define ICON_MDI_RELATION_ONLY_ONE_TO_ONE_OR_MANY "\xf3\xb1\x92\xaa" // U+F14AA
+#define ICON_MDI_RELATION_ONLY_ONE_TO_ONLY_ONE "\xf3\xb1\x92\xab" // U+F14AB
+#define ICON_MDI_RELATION_ONLY_ONE_TO_ZERO_OR_MANY "\xf3\xb1\x92\xac" // U+F14AC
+#define ICON_MDI_RELATION_ONLY_ONE_TO_ZERO_OR_ONE "\xf3\xb1\x92\xad" // U+F14AD
+#define ICON_MDI_RELATION_ZERO_OR_MANY_TO_MANY "\xf3\xb1\x92\xae" // U+F14AE
+#define ICON_MDI_RELATION_ZERO_OR_MANY_TO_ONE "\xf3\xb1\x92\xaf" // U+F14AF
+#define ICON_MDI_RELATION_ZERO_OR_MANY_TO_ONE_OR_MANY "\xf3\xb1\x92\xb0" // U+F14B0
+#define ICON_MDI_RELATION_ZERO_OR_MANY_TO_ONLY_ONE "\xf3\xb1\x92\xb1" // U+F14B1
+#define ICON_MDI_RELATION_ZERO_OR_MANY_TO_ZERO_OR_MANY "\xf3\xb1\x92\xb2" // U+F14B2
+#define ICON_MDI_RELATION_ZERO_OR_MANY_TO_ZERO_OR_ONE "\xf3\xb1\x92\xb3" // U+F14B3
+#define ICON_MDI_RELATION_ZERO_OR_ONE_TO_MANY "\xf3\xb1\x92\xb4" // U+F14B4
+#define ICON_MDI_RELATION_ZERO_OR_ONE_TO_ONE "\xf3\xb1\x92\xb5" // U+F14B5
+#define ICON_MDI_RELATION_ZERO_OR_ONE_TO_ONE_OR_MANY "\xf3\xb1\x92\xb6" // U+F14B6
+#define ICON_MDI_RELATION_ZERO_OR_ONE_TO_ONLY_ONE "\xf3\xb1\x92\xb7" // U+F14B7
+#define ICON_MDI_RELATION_ZERO_OR_ONE_TO_ZERO_OR_MANY "\xf3\xb1\x92\xb8" // U+F14B8
+#define ICON_MDI_RELATION_ZERO_OR_ONE_TO_ZERO_OR_ONE "\xf3\xb1\x92\xb9" // U+F14B9
+#define ICON_MDI_RELATIVE_SCALE "\xf3\xb0\x91\x92" // U+F0452
+#define ICON_MDI_RELOAD "\xf3\xb0\x91\x93" // U+F0453
+#define ICON_MDI_RELOAD_ALERT "\xf3\xb1\x84\x8b" // U+F110B
+#define ICON_MDI_REMINDER "\xf3\xb0\xa2\x8c" // U+F088C
+#define ICON_MDI_REMOTE "\xf3\xb0\x91\x94" // U+F0454
+#define ICON_MDI_REMOTE_DESKTOP "\xf3\xb0\xa2\xb9" // U+F08B9
+#define ICON_MDI_REMOTE_OFF "\xf3\xb0\xbb\x84" // U+F0EC4
+#define ICON_MDI_REMOTE_TV "\xf3\xb0\xbb\x85" // U+F0EC5
+#define ICON_MDI_REMOTE_TV_OFF "\xf3\xb0\xbb\x86" // U+F0EC6
+#define ICON_MDI_RENAME "\xf3\xb1\xb0\x98" // U+F1C18
+#define ICON_MDI_RENAME_BOX "\xf3\xb0\x91\x95" // U+F0455
+#define ICON_MDI_RENAME_BOX_OUTLINE "\xf3\xb1\xb0\x99" // U+F1C19
+#define ICON_MDI_RENAME_OUTLINE "\xf3\xb1\xb0\x9a" // U+F1C1A
+#define ICON_MDI_REORDER_HORIZONTAL "\xf3\xb0\x9a\x88" // U+F0688
+#define ICON_MDI_REORDER_VERTICAL "\xf3\xb0\x9a\x89" // U+F0689
+#define ICON_MDI_REPEAT "\xf3\xb0\x91\x96" // U+F0456
+#define ICON_MDI_REPEAT_OFF "\xf3\xb0\x91\x97" // U+F0457
+#define ICON_MDI_REPEAT_ONCE "\xf3\xb0\x91\x98" // U+F0458
+#define ICON_MDI_REPEAT_VARIANT "\xf3\xb0\x95\x87" // U+F0547
+#define ICON_MDI_REPLAY "\xf3\xb0\x91\x99" // U+F0459
+#define ICON_MDI_REPLY "\xf3\xb0\x91\x9a" // U+F045A
+#define ICON_MDI_REPLY_ALL "\xf3\xb0\x91\x9b" // U+F045B
+#define ICON_MDI_REPLY_ALL_OUTLINE "\xf3\xb0\xbc\x9f" // U+F0F1F
+#define ICON_MDI_REPLY_CIRCLE "\xf3\xb1\x86\xae" // U+F11AE
+#define ICON_MDI_REPLY_OUTLINE "\xf3\xb0\xbc\xa0" // U+F0F20
+#define ICON_MDI_REPRODUCTION "\xf3\xb0\x91\x9c" // U+F045C
+#define ICON_MDI_RESISTOR "\xf3\xb0\xad\x84" // U+F0B44
+#define ICON_MDI_RESISTOR_NODES "\xf3\xb0\xad\x85" // U+F0B45
+#define ICON_MDI_RESIZE "\xf3\xb0\xa9\xa8" // U+F0A68
+#define ICON_MDI_RESIZE_BOTTOM_RIGHT "\xf3\xb0\x91\x9d" // U+F045D
+#define ICON_MDI_RESPONSIVE "\xf3\xb0\x91\x9e" // U+F045E
+#define ICON_MDI_RESTART "\xf3\xb0\x9c\x89" // U+F0709
+#define ICON_MDI_RESTART_ALERT "\xf3\xb1\x84\x8c" // U+F110C
+#define ICON_MDI_RESTART_OFF "\xf3\xb0\xb6\x95" // U+F0D95
+#define ICON_MDI_RESTORE "\xf3\xb0\xa6\x9b" // U+F099B
+#define ICON_MDI_RESTORE_ALERT "\xf3\xb1\x84\x8d" // U+F110D
+#define ICON_MDI_REWIND "\xf3\xb0\x91\x9f" // U+F045F
+#define ICON_MDI_REWIND_10 "\xf3\xb0\xb4\xaa" // U+F0D2A
+#define ICON_MDI_REWIND_15 "\xf3\xb1\xa5\x86" // U+F1946
+#define ICON_MDI_REWIND_30 "\xf3\xb0\xb6\x96" // U+F0D96
+#define ICON_MDI_REWIND_45 "\xf3\xb1\xac\x93" // U+F1B13
+#define ICON_MDI_REWIND_5 "\xf3\xb1\x87\xb9" // U+F11F9
+#define ICON_MDI_REWIND_60 "\xf3\xb1\x98\x8c" // U+F160C
+#define ICON_MDI_REWIND_OUTLINE "\xf3\xb0\x9c\x8a" // U+F070A
+#define ICON_MDI_RHOMBUS "\xf3\xb0\x9c\x8b" // U+F070B
+#define ICON_MDI_RHOMBUS_MEDIUM "\xf3\xb0\xa8\x90" // U+F0A10
+#define ICON_MDI_RHOMBUS_MEDIUM_OUTLINE "\xf3\xb1\x93\x9c" // U+F14DC
+#define ICON_MDI_RHOMBUS_OUTLINE "\xf3\xb0\x9c\x8c" // U+F070C
+#define ICON_MDI_RHOMBUS_SPLIT "\xf3\xb0\xa8\x91" // U+F0A11
+#define ICON_MDI_RHOMBUS_SPLIT_OUTLINE "\xf3\xb1\x93\x9d" // U+F14DD
+#define ICON_MDI_RIBBON "\xf3\xb0\x91\xa0" // U+F0460
+#define ICON_MDI_RICE "\xf3\xb0\x9f\xaa" // U+F07EA
+#define ICON_MDI_RICKSHAW "\xf3\xb1\x96\xbb" // U+F15BB
+#define ICON_MDI_RICKSHAW_ELECTRIC "\xf3\xb1\x96\xbc" // U+F15BC
+#define ICON_MDI_RING "\xf3\xb0\x9f\xab" // U+F07EB
+#define ICON_MDI_RIVET "\xf3\xb0\xb9\xa0" // U+F0E60
+#define ICON_MDI_ROAD "\xf3\xb0\x91\xa1" // U+F0461
+#define ICON_MDI_ROAD_VARIANT "\xf3\xb0\x91\xa2" // U+F0462
+#define ICON_MDI_ROBBER "\xf3\xb1\x81\x98" // U+F1058
+#define ICON_MDI_ROBOT "\xf3\xb0\x9a\xa9" // U+F06A9
+#define ICON_MDI_ROBOT_ANGRY "\xf3\xb1\x9a\x9d" // U+F169D
+#define ICON_MDI_ROBOT_ANGRY_OUTLINE "\xf3\xb1\x9a\x9e" // U+F169E
+#define ICON_MDI_ROBOT_CONFUSED "\xf3\xb1\x9a\x9f" // U+F169F
+#define ICON_MDI_ROBOT_CONFUSED_OUTLINE "\xf3\xb1\x9a\xa0" // U+F16A0
+#define ICON_MDI_ROBOT_DEAD "\xf3\xb1\x9a\xa1" // U+F16A1
+#define ICON_MDI_ROBOT_DEAD_OUTLINE "\xf3\xb1\x9a\xa2" // U+F16A2
+#define ICON_MDI_ROBOT_EXCITED "\xf3\xb1\x9a\xa3" // U+F16A3
+#define ICON_MDI_ROBOT_EXCITED_OUTLINE "\xf3\xb1\x9a\xa4" // U+F16A4
+#define ICON_MDI_ROBOT_HAPPY "\xf3\xb1\x9c\x99" // U+F1719
+#define ICON_MDI_ROBOT_HAPPY_OUTLINE "\xf3\xb1\x9c\x9a" // U+F171A
+#define ICON_MDI_ROBOT_INDUSTRIAL "\xf3\xb0\xad\x86" // U+F0B46
+#define ICON_MDI_ROBOT_INDUSTRIAL_OUTLINE "\xf3\xb1\xa8\x9a" // U+F1A1A
+#define ICON_MDI_ROBOT_LOVE "\xf3\xb1\x9a\xa5" // U+F16A5
+#define ICON_MDI_ROBOT_LOVE_OUTLINE "\xf3\xb1\x9a\xa6" // U+F16A6
+#define ICON_MDI_ROBOT_MOWER "\xf3\xb1\x87\xb7" // U+F11F7
+#define ICON_MDI_ROBOT_MOWER_OUTLINE "\xf3\xb1\x87\xb3" // U+F11F3
+#define ICON_MDI_ROBOT_OFF "\xf3\xb1\x9a\xa7" // U+F16A7
+#define ICON_MDI_ROBOT_OFF_OUTLINE "\xf3\xb1\x99\xbb" // U+F167B
+#define ICON_MDI_ROBOT_OUTLINE "\xf3\xb1\x99\xba" // U+F167A
+#define ICON_MDI_ROBOT_VACUUM "\xf3\xb0\x9c\x8d" // U+F070D
+#define ICON_MDI_ROBOT_VACUUM_ALERT "\xf3\xb1\xad\x9d" // U+F1B5D
+#define ICON_MDI_ROBOT_VACUUM_OFF "\xf3\xb1\xb0\x81" // U+F1C01
+#define ICON_MDI_ROBOT_VACUUM_VARIANT "\xf3\xb0\xa4\x88" // U+F0908
+#define ICON_MDI_ROBOT_VACUUM_VARIANT_ALERT "\xf3\xb1\xad\x9e" // U+F1B5E
+#define ICON_MDI_ROBOT_VACUUM_VARIANT_OFF "\xf3\xb1\xb0\x82" // U+F1C02
+#define ICON_MDI_ROCKET "\xf3\xb0\x91\xa3" // U+F0463
+#define ICON_MDI_ROCKET_LAUNCH "\xf3\xb1\x93\x9e" // U+F14DE
+#define ICON_MDI_ROCKET_LAUNCH_OUTLINE "\xf3\xb1\x93\x9f" // U+F14DF
+#define ICON_MDI_ROCKET_OUTLINE "\xf3\xb1\x8e\xaf" // U+F13AF
+#define ICON_MDI_RODENT "\xf3\xb1\x8c\xa7" // U+F1327
+#define ICON_MDI_ROLLER_SHADE "\xf3\xb1\xa9\xab" // U+F1A6B
+#define ICON_MDI_ROLLER_SHADE_CLOSED "\xf3\xb1\xa9\xac" // U+F1A6C
+#define ICON_MDI_ROLLER_SKATE "\xf3\xb0\xb4\xab" // U+F0D2B
+#define ICON_MDI_ROLLER_SKATE_OFF "\xf3\xb0\x85\x85" // U+F0145
+#define ICON_MDI_ROLLERBLADE "\xf3\xb0\xb4\xac" // U+F0D2C
+#define ICON_MDI_ROLLERBLADE_OFF "\xf3\xb0\x80\xae" // U+F002E
+#define ICON_MDI_ROLLUPJS "\xf3\xb0\xaf\x80" // U+F0BC0
+#define ICON_MDI_ROLODEX "\xf3\xb1\xaa\xb9" // U+F1AB9
+#define ICON_MDI_ROLODEX_OUTLINE "\xf3\xb1\xaa\xba" // U+F1ABA
+#define ICON_MDI_ROMAN_NUMERAL_1 "\xf3\xb1\x82\x88" // U+F1088
+#define ICON_MDI_ROMAN_NUMERAL_10 "\xf3\xb1\x82\x91" // U+F1091
+#define ICON_MDI_ROMAN_NUMERAL_2 "\xf3\xb1\x82\x89" // U+F1089
+#define ICON_MDI_ROMAN_NUMERAL_3 "\xf3\xb1\x82\x8a" // U+F108A
+#define ICON_MDI_ROMAN_NUMERAL_4 "\xf3\xb1\x82\x8b" // U+F108B
+#define ICON_MDI_ROMAN_NUMERAL_5 "\xf3\xb1\x82\x8c" // U+F108C
+#define ICON_MDI_ROMAN_NUMERAL_6 "\xf3\xb1\x82\x8d" // U+F108D
+#define ICON_MDI_ROMAN_NUMERAL_7 "\xf3\xb1\x82\x8e" // U+F108E
+#define ICON_MDI_ROMAN_NUMERAL_8 "\xf3\xb1\x82\x8f" // U+F108F
+#define ICON_MDI_ROMAN_NUMERAL_9 "\xf3\xb1\x82\x90" // U+F1090
+#define ICON_MDI_ROOM_SERVICE "\xf3\xb0\xa2\x8d" // U+F088D
+#define ICON_MDI_ROOM_SERVICE_OUTLINE "\xf3\xb0\xb6\x97" // U+F0D97
+#define ICON_MDI_ROTATE_360 "\xf3\xb1\xa6\x99" // U+F1999
+#define ICON_MDI_ROTATE_3D "\xf3\xb0\xbb\x87" // U+F0EC7
+#define ICON_MDI_ROTATE_3D_VARIANT "\xf3\xb0\x91\xa4" // U+F0464
+#define ICON_MDI_ROTATE_LEFT "\xf3\xb0\x91\xa5" // U+F0465
+#define ICON_MDI_ROTATE_LEFT_VARIANT "\xf3\xb0\x91\xa6" // U+F0466
+#define ICON_MDI_ROTATE_ORBIT "\xf3\xb0\xb6\x98" // U+F0D98
+#define ICON_MDI_ROTATE_RIGHT "\xf3\xb0\x91\xa7" // U+F0467
+#define ICON_MDI_ROTATE_RIGHT_VARIANT "\xf3\xb0\x91\xa8" // U+F0468
+#define ICON_MDI_ROUNDED_CORNER "\xf3\xb0\x98\x87" // U+F0607
+#define ICON_MDI_ROUTER "\xf3\xb1\x87\xa2" // U+F11E2
+#define ICON_MDI_ROUTER_NETWORK "\xf3\xb1\x82\x87" // U+F1087
+#define ICON_MDI_ROUTER_NETWORK_WIRELESS "\xf3\xb1\xb2\x97" // U+F1C97
+#define ICON_MDI_ROUTER_WIRELESS "\xf3\xb0\x91\xa9" // U+F0469
+#define ICON_MDI_ROUTER_WIRELESS_OFF "\xf3\xb1\x96\xa3" // U+F15A3
+#define ICON_MDI_ROUTER_WIRELESS_SETTINGS "\xf3\xb0\xa9\xa9" // U+F0A69
+#define ICON_MDI_ROUTES "\xf3\xb0\x91\xaa" // U+F046A
+#define ICON_MDI_ROUTES_CLOCK "\xf3\xb1\x81\x99" // U+F1059
+#define ICON_MDI_ROWING "\xf3\xb0\x98\x88" // U+F0608
+#define ICON_MDI_RSS "\xf3\xb0\x91\xab" // U+F046B
+#define ICON_MDI_RSS_BOX "\xf3\xb0\x91\xac" // U+F046C
+#define ICON_MDI_RSS_OFF "\xf3\xb0\xbc\xa1" // U+F0F21
+#define ICON_MDI_RUG "\xf3\xb1\x91\xb5" // U+F1475
+#define ICON_MDI_RUGBY "\xf3\xb0\xb6\x99" // U+F0D99
+#define ICON_MDI_RULER "\xf3\xb0\x91\xad" // U+F046D
+#define ICON_MDI_RULER_SQUARE "\xf3\xb0\xb3\x82" // U+F0CC2
+#define ICON_MDI_RULER_SQUARE_COMPASS "\xf3\xb0\xba\xbe" // U+F0EBE
+#define ICON_MDI_RUN "\xf3\xb0\x9c\x8e" // U+F070E
+#define ICON_MDI_RUN_FAST "\xf3\xb0\x91\xae" // U+F046E
+#define ICON_MDI_RV_TRUCK "\xf3\xb1\x87\x94" // U+F11D4
+#define ICON_MDI_SACK "\xf3\xb0\xb4\xae" // U+F0D2E
+#define ICON_MDI_SACK_OUTLINE "\xf3\xb1\xb1\x8c" // U+F1C4C
+#define ICON_MDI_SACK_PERCENT "\xf3\xb0\xb4\xaf" // U+F0D2F
+#define ICON_MDI_SAFE "\xf3\xb0\xa9\xaa" // U+F0A6A
+#define ICON_MDI_SAFE_SQUARE "\xf3\xb1\x89\xbc" // U+F127C
+#define ICON_MDI_SAFE_SQUARE_OUTLINE "\xf3\xb1\x89\xbd" // U+F127D
+#define ICON_MDI_SAFETY_GOGGLES "\xf3\xb0\xb4\xb0" // U+F0D30
+#define ICON_MDI_SAIL_BOAT "\xf3\xb0\xbb\x88" // U+F0EC8
+#define ICON_MDI_SAIL_BOAT_SINK "\xf3\xb1\xab\xaf" // U+F1AEF
+#define ICON_MDI_SALE "\xf3\xb0\x91\xaf" // U+F046F
+#define ICON_MDI_SALE_OUTLINE "\xf3\xb1\xa8\x86" // U+F1A06
+#define ICON_MDI_SALESFORCE "\xf3\xb0\xa2\x8e" // U+F088E
+#define ICON_MDI_SASS "\xf3\xb0\x9f\xac" // U+F07EC
+#define ICON_MDI_SATELLITE "\xf3\xb0\x91\xb0" // U+F0470
+#define ICON_MDI_SATELLITE_UPLINK "\xf3\xb0\xa4\x89" // U+F0909
+#define ICON_MDI_SATELLITE_VARIANT "\xf3\xb0\x91\xb1" // U+F0471
+#define ICON_MDI_SAUSAGE "\xf3\xb0\xa2\xba" // U+F08BA
+#define ICON_MDI_SAUSAGE_OFF "\xf3\xb1\x9e\x89" // U+F1789
+#define ICON_MDI_SAW_BLADE "\xf3\xb0\xb9\xa1" // U+F0E61
+#define ICON_MDI_SAWTOOTH_WAVE "\xf3\xb1\x91\xba" // U+F147A
+#define ICON_MDI_SAXOPHONE "\xf3\xb0\x98\x89" // U+F0609
+#define ICON_MDI_SCALE "\xf3\xb0\x91\xb2" // U+F0472
+#define ICON_MDI_SCALE_BALANCE "\xf3\xb0\x97\x91" // U+F05D1
+#define ICON_MDI_SCALE_BATHROOM "\xf3\xb0\x91\xb3" // U+F0473
+#define ICON_MDI_SCALE_OFF "\xf3\xb1\x81\x9a" // U+F105A
+#define ICON_MDI_SCALE_UNBALANCED "\xf3\xb1\xa6\xb8" // U+F19B8
+#define ICON_MDI_SCAN_HELPER "\xf3\xb1\x8f\x98" // U+F13D8
+#define ICON_MDI_SCANNER "\xf3\xb0\x9a\xab" // U+F06AB
+#define ICON_MDI_SCANNER_OFF "\xf3\xb0\xa4\x8a" // U+F090A
+#define ICON_MDI_SCATTER_PLOT "\xf3\xb0\xbb\x89" // U+F0EC9
+#define ICON_MDI_SCATTER_PLOT_OUTLINE "\xf3\xb0\xbb\x8a" // U+F0ECA
+#define ICON_MDI_SCENT "\xf3\xb1\xa5\x98" // U+F1958
+#define ICON_MDI_SCENT_OFF "\xf3\xb1\xa5\x99" // U+F1959
+#define ICON_MDI_SCHOOL "\xf3\xb0\x91\xb4" // U+F0474
+#define ICON_MDI_SCHOOL_OUTLINE "\xf3\xb1\x86\x80" // U+F1180
+#define ICON_MDI_SCISSORS_CUTTING "\xf3\xb0\xa9\xab" // U+F0A6B
+#define ICON_MDI_SCOOTER "\xf3\xb1\x96\xbd" // U+F15BD
+#define ICON_MDI_SCOOTER_ELECTRIC "\xf3\xb1\x96\xbe" // U+F15BE
+#define ICON_MDI_SCOREBOARD "\xf3\xb1\x89\xbe" // U+F127E
+#define ICON_MDI_SCOREBOARD_OUTLINE "\xf3\xb1\x89\xbf" // U+F127F
+#define ICON_MDI_SCREEN_ROTATION "\xf3\xb0\x91\xb5" // U+F0475
+#define ICON_MDI_SCREEN_ROTATION_LOCK "\xf3\xb0\x91\xb8" // U+F0478
+#define ICON_MDI_SCREW_FLAT_TOP "\xf3\xb0\xb7\xb3" // U+F0DF3
+#define ICON_MDI_SCREW_LAG "\xf3\xb0\xb7\xb4" // U+F0DF4
+#define ICON_MDI_SCREW_MACHINE_FLAT_TOP "\xf3\xb0\xb7\xb5" // U+F0DF5
+#define ICON_MDI_SCREW_MACHINE_ROUND_TOP "\xf3\xb0\xb7\xb6" // U+F0DF6
+#define ICON_MDI_SCREW_ROUND_TOP "\xf3\xb0\xb7\xb7" // U+F0DF7
+#define ICON_MDI_SCREWDRIVER "\xf3\xb0\x91\xb6" // U+F0476
+#define ICON_MDI_SCRIPT "\xf3\xb0\xaf\x81" // U+F0BC1
+#define ICON_MDI_SCRIPT_OUTLINE "\xf3\xb0\x91\xb7" // U+F0477
+#define ICON_MDI_SCRIPT_TEXT "\xf3\xb0\xaf\x82" // U+F0BC2
+#define ICON_MDI_SCRIPT_TEXT_KEY "\xf3\xb1\x9c\xa5" // U+F1725
+#define ICON_MDI_SCRIPT_TEXT_KEY_OUTLINE "\xf3\xb1\x9c\xa6" // U+F1726
+#define ICON_MDI_SCRIPT_TEXT_OUTLINE "\xf3\xb0\xaf\x83" // U+F0BC3
+#define ICON_MDI_SCRIPT_TEXT_PLAY "\xf3\xb1\x9c\xa7" // U+F1727
+#define ICON_MDI_SCRIPT_TEXT_PLAY_OUTLINE "\xf3\xb1\x9c\xa8" // U+F1728
+#define ICON_MDI_SD "\xf3\xb0\x91\xb9" // U+F0479
+#define ICON_MDI_SEAL "\xf3\xb0\x91\xba" // U+F047A
+#define ICON_MDI_SEAL_VARIANT "\xf3\xb0\xbf\x99" // U+F0FD9
+#define ICON_MDI_SEARCH_WEB "\xf3\xb0\x9c\x8f" // U+F070F
+#define ICON_MDI_SEAT "\xf3\xb0\xb3\x83" // U+F0CC3
+#define ICON_MDI_SEAT_FLAT "\xf3\xb0\x91\xbb" // U+F047B
+#define ICON_MDI_SEAT_FLAT_ANGLED "\xf3\xb0\x91\xbc" // U+F047C
+#define ICON_MDI_SEAT_INDIVIDUAL_SUITE "\xf3\xb0\x91\xbd" // U+F047D
+#define ICON_MDI_SEAT_LEGROOM_EXTRA "\xf3\xb0\x91\xbe" // U+F047E
+#define ICON_MDI_SEAT_LEGROOM_NORMAL "\xf3\xb0\x91\xbf" // U+F047F
+#define ICON_MDI_SEAT_LEGROOM_REDUCED "\xf3\xb0\x92\x80" // U+F0480
+#define ICON_MDI_SEAT_OUTLINE "\xf3\xb0\xb3\x84" // U+F0CC4
+#define ICON_MDI_SEAT_PASSENGER "\xf3\xb1\x89\x89" // U+F1249
+#define ICON_MDI_SEAT_RECLINE_EXTRA "\xf3\xb0\x92\x81" // U+F0481
+#define ICON_MDI_SEAT_RECLINE_NORMAL "\xf3\xb0\x92\x82" // U+F0482
+#define ICON_MDI_SEATBELT "\xf3\xb0\xb3\x85" // U+F0CC5
+#define ICON_MDI_SECURITY "\xf3\xb0\x92\x83" // U+F0483
+#define ICON_MDI_SECURITY_NETWORK "\xf3\xb0\x92\x84" // U+F0484
+#define ICON_MDI_SEED "\xf3\xb0\xb9\xa2" // U+F0E62
+#define ICON_MDI_SEED_OFF "\xf3\xb1\x8f\xbd" // U+F13FD
+#define ICON_MDI_SEED_OFF_OUTLINE "\xf3\xb1\x8f\xbe" // U+F13FE
+#define ICON_MDI_SEED_OUTLINE "\xf3\xb0\xb9\xa3" // U+F0E63
+#define ICON_MDI_SEED_PLUS "\xf3\xb1\xa9\xad" // U+F1A6D
+#define ICON_MDI_SEED_PLUS_OUTLINE "\xf3\xb1\xa9\xae" // U+F1A6E
+#define ICON_MDI_SEESAW "\xf3\xb1\x96\xa4" // U+F15A4
+#define ICON_MDI_SEGMENT "\xf3\xb0\xbb\x8b" // U+F0ECB
+#define ICON_MDI_SELECT "\xf3\xb0\x92\x85" // U+F0485
+#define ICON_MDI_SELECT_ALL "\xf3\xb0\x92\x86" // U+F0486
+#define ICON_MDI_SELECT_ARROW_DOWN "\xf3\xb1\xad\x99" // U+F1B59
+#define ICON_MDI_SELECT_ARROW_UP "\xf3\xb1\xad\x98" // U+F1B58
+#define ICON_MDI_SELECT_COLOR "\xf3\xb0\xb4\xb1" // U+F0D31
+#define ICON_MDI_SELECT_COMPARE "\xf3\xb0\xab\x99" // U+F0AD9
+#define ICON_MDI_SELECT_DRAG "\xf3\xb0\xa9\xac" // U+F0A6C
+#define ICON_MDI_SELECT_GROUP "\xf3\xb0\xbe\x82" // U+F0F82
+#define ICON_MDI_SELECT_INVERSE "\xf3\xb0\x92\x87" // U+F0487
+#define ICON_MDI_SELECT_MARKER "\xf3\xb1\x8a\x80" // U+F1280
+#define ICON_MDI_SELECT_MULTIPLE "\xf3\xb1\x8a\x81" // U+F1281
+#define ICON_MDI_SELECT_MULTIPLE_MARKER "\xf3\xb1\x8a\x82" // U+F1282
+#define ICON_MDI_SELECT_OFF "\xf3\xb0\x92\x88" // U+F0488
+#define ICON_MDI_SELECT_PLACE "\xf3\xb0\xbf\x9a" // U+F0FDA
+#define ICON_MDI_SELECT_REMOVE "\xf3\xb1\x9f\x81" // U+F17C1
+#define ICON_MDI_SELECT_SEARCH "\xf3\xb1\x88\x84" // U+F1204
+#define ICON_MDI_SELECTION "\xf3\xb0\x92\x89" // U+F0489
+#define ICON_MDI_SELECTION_DRAG "\xf3\xb0\xa9\xad" // U+F0A6D
+#define ICON_MDI_SELECTION_ELLIPSE "\xf3\xb0\xb4\xb2" // U+F0D32
+#define ICON_MDI_SELECTION_ELLIPSE_ARROW_INSIDE "\xf3\xb0\xbc\xa2" // U+F0F22
+#define ICON_MDI_SELECTION_ELLIPSE_REMOVE "\xf3\xb1\x9f\x82" // U+F17C2
+#define ICON_MDI_SELECTION_MARKER "\xf3\xb1\x8a\x83" // U+F1283
+#define ICON_MDI_SELECTION_MULTIPLE "\xf3\xb1\x8a\x85" // U+F1285
+#define ICON_MDI_SELECTION_MULTIPLE_MARKER "\xf3\xb1\x8a\x84" // U+F1284
+#define ICON_MDI_SELECTION_OFF "\xf3\xb0\x9d\xb7" // U+F0777
+#define ICON_MDI_SELECTION_REMOVE "\xf3\xb1\x9f\x83" // U+F17C3
+#define ICON_MDI_SELECTION_SEARCH "\xf3\xb1\x88\x85" // U+F1205
+#define ICON_MDI_SEMANTIC_WEB "\xf3\xb1\x8c\x96" // U+F1316
+#define ICON_MDI_SEND "\xf3\xb0\x92\x8a" // U+F048A
+#define ICON_MDI_SEND_CHECK "\xf3\xb1\x85\xa1" // U+F1161
+#define ICON_MDI_SEND_CHECK_OUTLINE "\xf3\xb1\x85\xa2" // U+F1162
+#define ICON_MDI_SEND_CIRCLE "\xf3\xb0\xb7\xb8" // U+F0DF8
+#define ICON_MDI_SEND_CIRCLE_OUTLINE "\xf3\xb0\xb7\xb9" // U+F0DF9
+#define ICON_MDI_SEND_CLOCK "\xf3\xb1\x85\xa3" // U+F1163
+#define ICON_MDI_SEND_CLOCK_OUTLINE "\xf3\xb1\x85\xa4" // U+F1164
+#define ICON_MDI_SEND_LOCK "\xf3\xb0\x9f\xad" // U+F07ED
+#define ICON_MDI_SEND_LOCK_OUTLINE "\xf3\xb1\x85\xa6" // U+F1166
+#define ICON_MDI_SEND_OUTLINE "\xf3\xb1\x85\xa5" // U+F1165
+#define ICON_MDI_SEND_VARIANT "\xf3\xb1\xb1\x8d" // U+F1C4D
+#define ICON_MDI_SEND_VARIANT_CLOCK "\xf3\xb1\xb1\xbe" // U+F1C7E
+#define ICON_MDI_SEND_VARIANT_CLOCK_OUTLINE "\xf3\xb1\xb1\xbf" // U+F1C7F
+#define ICON_MDI_SEND_VARIANT_OUTLINE "\xf3\xb1\xb1\x8e" // U+F1C4E
+#define ICON_MDI_SERIAL_PORT "\xf3\xb0\x99\x9c" // U+F065C
+#define ICON_MDI_SERVER "\xf3\xb0\x92\x8b" // U+F048B
+#define ICON_MDI_SERVER_MINUS "\xf3\xb0\x92\x8c" // U+F048C
+#define ICON_MDI_SERVER_MINUS_OUTLINE "\xf3\xb1\xb2\x98" // U+F1C98
+#define ICON_MDI_SERVER_NETWORK "\xf3\xb0\x92\x8d" // U+F048D
+#define ICON_MDI_SERVER_NETWORK_OFF "\xf3\xb0\x92\x8e" // U+F048E
+#define ICON_MDI_SERVER_NETWORK_OUTLINE "\xf3\xb1\xb2\x99" // U+F1C99
+#define ICON_MDI_SERVER_OFF "\xf3\xb0\x92\x8f" // U+F048F
+#define ICON_MDI_SERVER_OUTLINE "\xf3\xb1\xb2\x9a" // U+F1C9A
+#define ICON_MDI_SERVER_PLUS "\xf3\xb0\x92\x90" // U+F0490
+#define ICON_MDI_SERVER_PLUS_OUTLINE "\xf3\xb1\xb2\x9b" // U+F1C9B
+#define ICON_MDI_SERVER_REMOVE "\xf3\xb0\x92\x91" // U+F0491
+#define ICON_MDI_SERVER_SECURITY "\xf3\xb0\x92\x92" // U+F0492
+#define ICON_MDI_SET_ALL "\xf3\xb0\x9d\xb8" // U+F0778
+#define ICON_MDI_SET_CENTER "\xf3\xb0\x9d\xb9" // U+F0779
+#define ICON_MDI_SET_CENTER_RIGHT "\xf3\xb0\x9d\xba" // U+F077A
+#define ICON_MDI_SET_LEFT "\xf3\xb0\x9d\xbb" // U+F077B
+#define ICON_MDI_SET_LEFT_CENTER "\xf3\xb0\x9d\xbc" // U+F077C
+#define ICON_MDI_SET_LEFT_RIGHT "\xf3\xb0\x9d\xbd" // U+F077D
+#define ICON_MDI_SET_MERGE "\xf3\xb1\x93\xa0" // U+F14E0
+#define ICON_MDI_SET_NONE "\xf3\xb0\x9d\xbe" // U+F077E
+#define ICON_MDI_SET_RIGHT "\xf3\xb0\x9d\xbf" // U+F077F
+#define ICON_MDI_SET_SPLIT "\xf3\xb1\x93\xa1" // U+F14E1
+#define ICON_MDI_SET_SQUARE "\xf3\xb1\x91\x9d" // U+F145D
+#define ICON_MDI_SET_TOP_BOX "\xf3\xb0\xa6\x9f" // U+F099F
+#define ICON_MDI_SETTINGS_HELPER "\xf3\xb0\xa9\xae" // U+F0A6E
+#define ICON_MDI_SHAKER "\xf3\xb1\x84\x8e" // U+F110E
+#define ICON_MDI_SHAKER_OUTLINE "\xf3\xb1\x84\x8f" // U+F110F
+#define ICON_MDI_SHAPE "\xf3\xb0\xa0\xb1" // U+F0831
+#define ICON_MDI_SHAPE_CIRCLE_PLUS "\xf3\xb0\x99\x9d" // U+F065D
+#define ICON_MDI_SHAPE_OUTLINE "\xf3\xb0\xa0\xb2" // U+F0832
+#define ICON_MDI_SHAPE_OVAL_PLUS "\xf3\xb1\x87\xba" // U+F11FA
+#define ICON_MDI_SHAPE_PLUS "\xf3\xb0\x92\x95" // U+F0495
+#define ICON_MDI_SHAPE_PLUS_OUTLINE "\xf3\xb1\xb1\x8f" // U+F1C4F
+#define ICON_MDI_SHAPE_POLYGON_PLUS "\xf3\xb0\x99\x9e" // U+F065E
+#define ICON_MDI_SHAPE_RECTANGLE_PLUS "\xf3\xb0\x99\x9f" // U+F065F
+#define ICON_MDI_SHAPE_SQUARE_PLUS "\xf3\xb0\x99\xa0" // U+F0660
+#define ICON_MDI_SHAPE_SQUARE_ROUNDED_PLUS "\xf3\xb1\x93\xba" // U+F14FA
+#define ICON_MDI_SHARE "\xf3\xb0\x92\x96" // U+F0496
+#define ICON_MDI_SHARE_ALL "\xf3\xb1\x87\xb4" // U+F11F4
+#define ICON_MDI_SHARE_ALL_OUTLINE "\xf3\xb1\x87\xb5" // U+F11F5
+#define ICON_MDI_SHARE_CIRCLE "\xf3\xb1\x86\xad" // U+F11AD
+#define ICON_MDI_SHARE_OFF "\xf3\xb0\xbc\xa3" // U+F0F23
+#define ICON_MDI_SHARE_OFF_OUTLINE "\xf3\xb0\xbc\xa4" // U+F0F24
+#define ICON_MDI_SHARE_OUTLINE "\xf3\xb0\xa4\xb2" // U+F0932
+#define ICON_MDI_SHARE_VARIANT "\xf3\xb0\x92\x97" // U+F0497
+#define ICON_MDI_SHARE_VARIANT_OUTLINE "\xf3\xb1\x94\x94" // U+F1514
+#define ICON_MDI_SHARK "\xf3\xb1\xa2\xba" // U+F18BA
+#define ICON_MDI_SHARK_FIN "\xf3\xb1\x99\xb3" // U+F1673
+#define ICON_MDI_SHARK_FIN_OUTLINE "\xf3\xb1\x99\xb4" // U+F1674
+#define ICON_MDI_SHARK_OFF "\xf3\xb1\xa2\xbb" // U+F18BB
+#define ICON_MDI_SHEEP "\xf3\xb0\xb3\x86" // U+F0CC6
+#define ICON_MDI_SHIELD "\xf3\xb0\x92\x98" // U+F0498
+#define ICON_MDI_SHIELD_ACCOUNT "\xf3\xb0\xa2\x8f" // U+F088F
+#define ICON_MDI_SHIELD_ACCOUNT_OUTLINE "\xf3\xb0\xa8\x92" // U+F0A12
+#define ICON_MDI_SHIELD_ACCOUNT_VARIANT "\xf3\xb1\x96\xa7" // U+F15A7
+#define ICON_MDI_SHIELD_ACCOUNT_VARIANT_OUTLINE "\xf3\xb1\x96\xa8" // U+F15A8
+#define ICON_MDI_SHIELD_AIRPLANE "\xf3\xb0\x9a\xbb" // U+F06BB
+#define ICON_MDI_SHIELD_AIRPLANE_OUTLINE "\xf3\xb0\xb3\x87" // U+F0CC7
+#define ICON_MDI_SHIELD_ALERT "\xf3\xb0\xbb\x8c" // U+F0ECC
+#define ICON_MDI_SHIELD_ALERT_OUTLINE "\xf3\xb0\xbb\x8d" // U+F0ECD
+#define ICON_MDI_SHIELD_BUG "\xf3\xb1\x8f\x9a" // U+F13DA
+#define ICON_MDI_SHIELD_BUG_OUTLINE "\xf3\xb1\x8f\x9b" // U+F13DB
+#define ICON_MDI_SHIELD_CAR "\xf3\xb0\xbe\x83" // U+F0F83
+#define ICON_MDI_SHIELD_CHECK "\xf3\xb0\x95\xa5" // U+F0565
+#define ICON_MDI_SHIELD_CHECK_OUTLINE "\xf3\xb0\xb3\x88" // U+F0CC8
+#define ICON_MDI_SHIELD_CROSS "\xf3\xb0\xb3\x89" // U+F0CC9
+#define ICON_MDI_SHIELD_CROSS_OUTLINE "\xf3\xb0\xb3\x8a" // U+F0CCA
+#define ICON_MDI_SHIELD_CROWN "\xf3\xb1\xa2\xbc" // U+F18BC
+#define ICON_MDI_SHIELD_CROWN_OUTLINE "\xf3\xb1\xa2\xbd" // U+F18BD
+#define ICON_MDI_SHIELD_EDIT "\xf3\xb1\x86\xa0" // U+F11A0
+#define ICON_MDI_SHIELD_EDIT_OUTLINE "\xf3\xb1\x86\xa1" // U+F11A1
+#define ICON_MDI_SHIELD_HALF "\xf3\xb1\x8d\xa0" // U+F1360
+#define ICON_MDI_SHIELD_HALF_FULL "\xf3\xb0\x9e\x80" // U+F0780
+#define ICON_MDI_SHIELD_HOME "\xf3\xb0\x9a\x8a" // U+F068A
+#define ICON_MDI_SHIELD_HOME_OUTLINE "\xf3\xb0\xb3\x8b" // U+F0CCB
+#define ICON_MDI_SHIELD_KEY "\xf3\xb0\xaf\x84" // U+F0BC4
+#define ICON_MDI_SHIELD_KEY_OUTLINE "\xf3\xb0\xaf\x85" // U+F0BC5
+#define ICON_MDI_SHIELD_LINK_VARIANT "\xf3\xb0\xb4\xb3" // U+F0D33
+#define ICON_MDI_SHIELD_LINK_VARIANT_OUTLINE "\xf3\xb0\xb4\xb4" // U+F0D34
+#define ICON_MDI_SHIELD_LOCK "\xf3\xb0\xa6\x9d" // U+F099D
+#define ICON_MDI_SHIELD_LOCK_OPEN "\xf3\xb1\xa6\x9a" // U+F199A
+#define ICON_MDI_SHIELD_LOCK_OPEN_OUTLINE "\xf3\xb1\xa6\x9b" // U+F199B
+#define ICON_MDI_SHIELD_LOCK_OUTLINE "\xf3\xb0\xb3\x8c" // U+F0CCC
+#define ICON_MDI_SHIELD_MOON "\xf3\xb1\xa0\xa8" // U+F1828
+#define ICON_MDI_SHIELD_MOON_OUTLINE "\xf3\xb1\xa0\xa9" // U+F1829
+#define ICON_MDI_SHIELD_OFF "\xf3\xb0\xa6\x9e" // U+F099E
+#define ICON_MDI_SHIELD_OFF_OUTLINE "\xf3\xb0\xa6\x9c" // U+F099C
+#define ICON_MDI_SHIELD_OUTLINE "\xf3\xb0\x92\x99" // U+F0499
+#define ICON_MDI_SHIELD_PLUS "\xf3\xb0\xab\x9a" // U+F0ADA
+#define ICON_MDI_SHIELD_PLUS_OUTLINE "\xf3\xb0\xab\x9b" // U+F0ADB
+#define ICON_MDI_SHIELD_REFRESH "\xf3\xb0\x82\xaa" // U+F00AA
+#define ICON_MDI_SHIELD_REFRESH_OUTLINE "\xf3\xb0\x87\xa0" // U+F01E0
+#define ICON_MDI_SHIELD_REMOVE "\xf3\xb0\xab\x9c" // U+F0ADC
+#define ICON_MDI_SHIELD_REMOVE_OUTLINE "\xf3\xb0\xab\x9d" // U+F0ADD
+#define ICON_MDI_SHIELD_SEARCH "\xf3\xb0\xb6\x9a" // U+F0D9A
+#define ICON_MDI_SHIELD_STAR "\xf3\xb1\x84\xbb" // U+F113B
+#define ICON_MDI_SHIELD_STAR_OUTLINE "\xf3\xb1\x84\xbc" // U+F113C
+#define ICON_MDI_SHIELD_SUN "\xf3\xb1\x81\x9d" // U+F105D
+#define ICON_MDI_SHIELD_SUN_OUTLINE "\xf3\xb1\x81\x9e" // U+F105E
+#define ICON_MDI_SHIELD_SWORD "\xf3\xb1\xa2\xbe" // U+F18BE
+#define ICON_MDI_SHIELD_SWORD_OUTLINE "\xf3\xb1\xa2\xbf" // U+F18BF
+#define ICON_MDI_SHIELD_SYNC "\xf3\xb1\x86\xa2" // U+F11A2
+#define ICON_MDI_SHIELD_SYNC_OUTLINE "\xf3\xb1\x86\xa3" // U+F11A3
+#define ICON_MDI_SHIMMER "\xf3\xb1\x95\x85" // U+F1545
+#define ICON_MDI_SHIP_WHEEL "\xf3\xb0\xa0\xb3" // U+F0833
+#define ICON_MDI_SHIPPING_PALLET "\xf3\xb1\xa1\x8e" // U+F184E
+#define ICON_MDI_SHOE_BALLET "\xf3\xb1\x97\x8a" // U+F15CA
+#define ICON_MDI_SHOE_CLEAT "\xf3\xb1\x97\x87" // U+F15C7
+#define ICON_MDI_SHOE_FORMAL "\xf3\xb0\xad\x87" // U+F0B47
+#define ICON_MDI_SHOE_HEEL "\xf3\xb0\xad\x88" // U+F0B48
+#define ICON_MDI_SHOE_PRINT "\xf3\xb0\xb7\xba" // U+F0DFA
+#define ICON_MDI_SHOE_SNEAKER "\xf3\xb1\x97\x88" // U+F15C8
+#define ICON_MDI_SHOPPING "\xf3\xb0\x92\x9a" // U+F049A
+#define ICON_MDI_SHOPPING_MUSIC "\xf3\xb0\x92\x9b" // U+F049B
+#define ICON_MDI_SHOPPING_OUTLINE "\xf3\xb1\x87\x95" // U+F11D5
+#define ICON_MDI_SHOPPING_SEARCH "\xf3\xb0\xbe\x84" // U+F0F84
+#define ICON_MDI_SHOPPING_SEARCH_OUTLINE "\xf3\xb1\xa9\xaf" // U+F1A6F
+#define ICON_MDI_SHORE "\xf3\xb1\x93\xb9" // U+F14F9
+#define ICON_MDI_SHOVEL "\xf3\xb0\x9c\x90" // U+F0710
+#define ICON_MDI_SHOVEL_OFF "\xf3\xb0\x9c\x91" // U+F0711
+#define ICON_MDI_SHOWER "\xf3\xb0\xa6\xa0" // U+F09A0
+#define ICON_MDI_SHOWER_HEAD "\xf3\xb0\xa6\xa1" // U+F09A1
+#define ICON_MDI_SHREDDER "\xf3\xb0\x92\x9c" // U+F049C
+#define ICON_MDI_SHUFFLE "\xf3\xb0\x92\x9d" // U+F049D
+#define ICON_MDI_SHUFFLE_DISABLED "\xf3\xb0\x92\x9e" // U+F049E
+#define ICON_MDI_SHUFFLE_VARIANT "\xf3\xb0\x92\x9f" // U+F049F
+#define ICON_MDI_SHURIKEN "\xf3\xb1\x8d\xbf" // U+F137F
+#define ICON_MDI_SICKLE "\xf3\xb1\xa3\x80" // U+F18C0
+#define ICON_MDI_SIGMA "\xf3\xb0\x92\xa0" // U+F04A0
+#define ICON_MDI_SIGMA_LOWER "\xf3\xb0\x98\xab" // U+F062B
+#define ICON_MDI_SIGN_CAUTION "\xf3\xb0\x92\xa1" // U+F04A1
+#define ICON_MDI_SIGN_DIRECTION "\xf3\xb0\x9e\x81" // U+F0781
+#define ICON_MDI_SIGN_DIRECTION_MINUS "\xf3\xb1\x80\x80" // U+F1000
+#define ICON_MDI_SIGN_DIRECTION_PLUS "\xf3\xb0\xbf\x9c" // U+F0FDC
+#define ICON_MDI_SIGN_DIRECTION_REMOVE "\xf3\xb0\xbf\x9d" // U+F0FDD
+#define ICON_MDI_SIGN_LANGUAGE "\xf3\xb1\xad\x8d" // U+F1B4D
+#define ICON_MDI_SIGN_LANGUAGE_OUTLINE "\xf3\xb1\xad\x8e" // U+F1B4E
+#define ICON_MDI_SIGN_POLE "\xf3\xb1\x93\xb8" // U+F14F8
+#define ICON_MDI_SIGN_REAL_ESTATE "\xf3\xb1\x84\x98" // U+F1118
+#define ICON_MDI_SIGN_TEXT "\xf3\xb0\x9e\x82" // U+F0782
+#define ICON_MDI_SIGN_YIELD "\xf3\xb1\xae\xaf" // U+F1BAF
+#define ICON_MDI_SIGNAL "\xf3\xb0\x92\xa2" // U+F04A2
+#define ICON_MDI_SIGNAL_2G "\xf3\xb0\x9c\x92" // U+F0712
+#define ICON_MDI_SIGNAL_3G "\xf3\xb0\x9c\x93" // U+F0713
+#define ICON_MDI_SIGNAL_4G "\xf3\xb0\x9c\x94" // U+F0714
+#define ICON_MDI_SIGNAL_5G "\xf3\xb0\xa9\xaf" // U+F0A6F
+#define ICON_MDI_SIGNAL_CELLULAR_1 "\xf3\xb0\xa2\xbc" // U+F08BC
+#define ICON_MDI_SIGNAL_CELLULAR_2 "\xf3\xb0\xa2\xbd" // U+F08BD
+#define ICON_MDI_SIGNAL_CELLULAR_3 "\xf3\xb0\xa2\xbe" // U+F08BE
+#define ICON_MDI_SIGNAL_CELLULAR_OUTLINE "\xf3\xb0\xa2\xbf" // U+F08BF
+#define ICON_MDI_SIGNAL_DISTANCE_VARIANT "\xf3\xb0\xb9\xa4" // U+F0E64
+#define ICON_MDI_SIGNAL_HSPA "\xf3\xb0\x9c\x95" // U+F0715
+#define ICON_MDI_SIGNAL_HSPA_PLUS "\xf3\xb0\x9c\x96" // U+F0716
+#define ICON_MDI_SIGNAL_OFF "\xf3\xb0\x9e\x83" // U+F0783
+#define ICON_MDI_SIGNAL_VARIANT "\xf3\xb0\x98\x8a" // U+F060A
+#define ICON_MDI_SIGNATURE "\xf3\xb0\xb7\xbb" // U+F0DFB
+#define ICON_MDI_SIGNATURE_FREEHAND "\xf3\xb0\xb7\xbc" // U+F0DFC
+#define ICON_MDI_SIGNATURE_IMAGE "\xf3\xb0\xb7\xbd" // U+F0DFD
+#define ICON_MDI_SIGNATURE_TEXT "\xf3\xb0\xb7\xbe" // U+F0DFE
+#define ICON_MDI_SILO "\xf3\xb1\xae\x9f" // U+F1B9F
+#define ICON_MDI_SILO_OUTLINE "\xf3\xb0\xad\x89" // U+F0B49
+#define ICON_MDI_SILVERWARE "\xf3\xb0\x92\xa3" // U+F04A3
+#define ICON_MDI_SILVERWARE_CLEAN "\xf3\xb0\xbf\x9e" // U+F0FDE
+#define ICON_MDI_SILVERWARE_FORK "\xf3\xb0\x92\xa4" // U+F04A4
+#define ICON_MDI_SILVERWARE_FORK_KNIFE "\xf3\xb0\xa9\xb0" // U+F0A70
+#define ICON_MDI_SILVERWARE_SPOON "\xf3\xb0\x92\xa5" // U+F04A5
+#define ICON_MDI_SILVERWARE_VARIANT "\xf3\xb0\x92\xa6" // U+F04A6
+#define ICON_MDI_SIM "\xf3\xb0\x92\xa7" // U+F04A7
+#define ICON_MDI_SIM_ALERT "\xf3\xb0\x92\xa8" // U+F04A8
+#define ICON_MDI_SIM_ALERT_OUTLINE "\xf3\xb1\x97\x93" // U+F15D3
+#define ICON_MDI_SIM_OFF "\xf3\xb0\x92\xa9" // U+F04A9
+#define ICON_MDI_SIM_OFF_OUTLINE "\xf3\xb1\x97\x94" // U+F15D4
+#define ICON_MDI_SIM_OUTLINE "\xf3\xb1\x97\x95" // U+F15D5
+#define ICON_MDI_SIMPLE_ICONS "\xf3\xb1\x8c\x9d" // U+F131D
+#define ICON_MDI_SINA_WEIBO "\xf3\xb0\xab\x9f" // U+F0ADF
+#define ICON_MDI_SINE_WAVE "\xf3\xb0\xa5\x9b" // U+F095B
+#define ICON_MDI_SITEMAP "\xf3\xb0\x92\xaa" // U+F04AA
+#define ICON_MDI_SITEMAP_OUTLINE "\xf3\xb1\xa6\x9c" // U+F199C
+#define ICON_MDI_SIZE_L "\xf3\xb1\x8e\xa6" // U+F13A6
+#define ICON_MDI_SIZE_M "\xf3\xb1\x8e\xa5" // U+F13A5
+#define ICON_MDI_SIZE_S "\xf3\xb1\x8e\xa4" // U+F13A4
+#define ICON_MDI_SIZE_XL "\xf3\xb1\x8e\xa7" // U+F13A7
+#define ICON_MDI_SIZE_XS "\xf3\xb1\x8e\xa3" // U+F13A3
+#define ICON_MDI_SIZE_XXL "\xf3\xb1\x8e\xa8" // U+F13A8
+#define ICON_MDI_SIZE_XXS "\xf3\xb1\x8e\xa2" // U+F13A2
+#define ICON_MDI_SIZE_XXXL "\xf3\xb1\x8e\xa9" // U+F13A9
+#define ICON_MDI_SKATE "\xf3\xb0\xb4\xb5" // U+F0D35
+#define ICON_MDI_SKATE_OFF "\xf3\xb0\x9a\x99" // U+F0699
+#define ICON_MDI_SKATEBOARD "\xf3\xb1\x93\x82" // U+F14C2
+#define ICON_MDI_SKATEBOARDING "\xf3\xb0\x94\x81" // U+F0501
+#define ICON_MDI_SKEW_LESS "\xf3\xb0\xb4\xb6" // U+F0D36
+#define ICON_MDI_SKEW_MORE "\xf3\xb0\xb4\xb7" // U+F0D37
+#define ICON_MDI_SKI "\xf3\xb1\x8c\x84" // U+F1304
+#define ICON_MDI_SKI_CROSS_COUNTRY "\xf3\xb1\x8c\x85" // U+F1305
+#define ICON_MDI_SKI_WATER "\xf3\xb1\x8c\x86" // U+F1306
+#define ICON_MDI_SKIP_BACKWARD "\xf3\xb0\x92\xab" // U+F04AB
+#define ICON_MDI_SKIP_BACKWARD_OUTLINE "\xf3\xb0\xbc\xa5" // U+F0F25
+#define ICON_MDI_SKIP_FORWARD "\xf3\xb0\x92\xac" // U+F04AC
+#define ICON_MDI_SKIP_FORWARD_OUTLINE "\xf3\xb0\xbc\xa6" // U+F0F26
+#define ICON_MDI_SKIP_NEXT "\xf3\xb0\x92\xad" // U+F04AD
+#define ICON_MDI_SKIP_NEXT_CIRCLE "\xf3\xb0\x99\xa1" // U+F0661
+#define ICON_MDI_SKIP_NEXT_CIRCLE_OUTLINE "\xf3\xb0\x99\xa2" // U+F0662
+#define ICON_MDI_SKIP_NEXT_OUTLINE "\xf3\xb0\xbc\xa7" // U+F0F27
+#define ICON_MDI_SKIP_PREVIOUS "\xf3\xb0\x92\xae" // U+F04AE
+#define ICON_MDI_SKIP_PREVIOUS_CIRCLE "\xf3\xb0\x99\xa3" // U+F0663
+#define ICON_MDI_SKIP_PREVIOUS_CIRCLE_OUTLINE "\xf3\xb0\x99\xa4" // U+F0664
+#define ICON_MDI_SKIP_PREVIOUS_OUTLINE "\xf3\xb0\xbc\xa8" // U+F0F28
+#define ICON_MDI_SKULL "\xf3\xb0\x9a\x8c" // U+F068C
+#define ICON_MDI_SKULL_CROSSBONES "\xf3\xb0\xaf\x86" // U+F0BC6
+#define ICON_MDI_SKULL_CROSSBONES_OUTLINE "\xf3\xb0\xaf\x87" // U+F0BC7
+#define ICON_MDI_SKULL_OUTLINE "\xf3\xb0\xaf\x88" // U+F0BC8
+#define ICON_MDI_SKULL_SCAN "\xf3\xb1\x93\x87" // U+F14C7
+#define ICON_MDI_SKULL_SCAN_OUTLINE "\xf3\xb1\x93\x88" // U+F14C8
+#define ICON_MDI_SKYPE "\xf3\xb0\x92\xaf" // U+F04AF
+#define ICON_MDI_SKYPE_BUSINESS "\xf3\xb0\x92\xb0" // U+F04B0
+#define ICON_MDI_SLACK "\xf3\xb0\x92\xb1" // U+F04B1
+#define ICON_MDI_SLASH_FORWARD "\xf3\xb0\xbf\x9f" // U+F0FDF
+#define ICON_MDI_SLASH_FORWARD_BOX "\xf3\xb0\xbf\xa0" // U+F0FE0
+#define ICON_MDI_SLEDDING "\xf3\xb0\x90\x9b" // U+F041B
+#define ICON_MDI_SLEEP "\xf3\xb0\x92\xb2" // U+F04B2
+#define ICON_MDI_SLEEP_OFF "\xf3\xb0\x92\xb3" // U+F04B3
+#define ICON_MDI_SLIDE "\xf3\xb1\x96\xa5" // U+F15A5
+#define ICON_MDI_SLOPE_DOWNHILL "\xf3\xb0\xb7\xbf" // U+F0DFF
+#define ICON_MDI_SLOPE_UPHILL "\xf3\xb0\xb8\x80" // U+F0E00
+#define ICON_MDI_SLOT_MACHINE "\xf3\xb1\x84\x94" // U+F1114
+#define ICON_MDI_SLOT_MACHINE_OUTLINE "\xf3\xb1\x84\x95" // U+F1115
+#define ICON_MDI_SMART_CARD "\xf3\xb1\x82\xbd" // U+F10BD
+#define ICON_MDI_SMART_CARD_OFF "\xf3\xb1\xa3\xb7" // U+F18F7
+#define ICON_MDI_SMART_CARD_OFF_OUTLINE "\xf3\xb1\xa3\xb8" // U+F18F8
+#define ICON_MDI_SMART_CARD_OUTLINE "\xf3\xb1\x82\xbe" // U+F10BE
+#define ICON_MDI_SMART_CARD_READER "\xf3\xb1\x82\xbf" // U+F10BF
+#define ICON_MDI_SMART_CARD_READER_OUTLINE "\xf3\xb1\x83\x80" // U+F10C0
+#define ICON_MDI_SMOG "\xf3\xb0\xa9\xb1" // U+F0A71
+#define ICON_MDI_SMOKE "\xf3\xb1\x9e\x99" // U+F1799
+#define ICON_MDI_SMOKE_DETECTOR "\xf3\xb0\x8e\x92" // U+F0392
+#define ICON_MDI_SMOKE_DETECTOR_ALERT "\xf3\xb1\xa4\xae" // U+F192E
+#define ICON_MDI_SMOKE_DETECTOR_ALERT_OUTLINE "\xf3\xb1\xa4\xaf" // U+F192F
+#define ICON_MDI_SMOKE_DETECTOR_OFF "\xf3\xb1\xa0\x89" // U+F1809
+#define ICON_MDI_SMOKE_DETECTOR_OFF_OUTLINE "\xf3\xb1\xa0\x8a" // U+F180A
+#define ICON_MDI_SMOKE_DETECTOR_OUTLINE "\xf3\xb1\xa0\x88" // U+F1808
+#define ICON_MDI_SMOKE_DETECTOR_VARIANT "\xf3\xb1\xa0\x8b" // U+F180B
+#define ICON_MDI_SMOKE_DETECTOR_VARIANT_ALERT "\xf3\xb1\xa4\xb0" // U+F1930
+#define ICON_MDI_SMOKE_DETECTOR_VARIANT_OFF "\xf3\xb1\xa0\x8c" // U+F180C
+#define ICON_MDI_SMOKING "\xf3\xb0\x92\xb4" // U+F04B4
+#define ICON_MDI_SMOKING_OFF "\xf3\xb0\x92\xb5" // U+F04B5
+#define ICON_MDI_SMOKING_PIPE "\xf3\xb1\x90\x8d" // U+F140D
+#define ICON_MDI_SMOKING_PIPE_OFF "\xf3\xb1\x90\xa8" // U+F1428
+#define ICON_MDI_SNAIL "\xf3\xb1\x99\xb7" // U+F1677
+#define ICON_MDI_SNAKE "\xf3\xb1\x94\x8e" // U+F150E
+#define ICON_MDI_SNAPCHAT "\xf3\xb0\x92\xb6" // U+F04B6
+#define ICON_MDI_SNOWBOARD "\xf3\xb1\x8c\x87" // U+F1307
+#define ICON_MDI_SNOWFLAKE "\xf3\xb0\x9c\x97" // U+F0717
+#define ICON_MDI_SNOWFLAKE_ALERT "\xf3\xb0\xbc\xa9" // U+F0F29
+#define ICON_MDI_SNOWFLAKE_CHECK "\xf3\xb1\xa9\xb0" // U+F1A70
+#define ICON_MDI_SNOWFLAKE_MELT "\xf3\xb1\x8b\x8b" // U+F12CB
+#define ICON_MDI_SNOWFLAKE_OFF "\xf3\xb1\x93\xa3" // U+F14E3
+#define ICON_MDI_SNOWFLAKE_THERMOMETER "\xf3\xb1\xa9\xb1" // U+F1A71
+#define ICON_MDI_SNOWFLAKE_VARIANT "\xf3\xb0\xbc\xaa" // U+F0F2A
+#define ICON_MDI_SNOWMAN "\xf3\xb0\x92\xb7" // U+F04B7
+#define ICON_MDI_SNOWMOBILE "\xf3\xb0\x9b\x9d" // U+F06DD
+#define ICON_MDI_SNOWSHOEING "\xf3\xb1\xa9\xb2" // U+F1A72
+#define ICON_MDI_SOCCER "\xf3\xb0\x92\xb8" // U+F04B8
+#define ICON_MDI_SOCCER_FIELD "\xf3\xb0\xa0\xb4" // U+F0834
+#define ICON_MDI_SOCIAL_DISTANCE_2_METERS "\xf3\xb1\x95\xb9" // U+F1579
+#define ICON_MDI_SOCIAL_DISTANCE_6_FEET "\xf3\xb1\x95\xba" // U+F157A
+#define ICON_MDI_SOFA "\xf3\xb0\x92\xb9" // U+F04B9
+#define ICON_MDI_SOFA_OUTLINE "\xf3\xb1\x95\xad" // U+F156D
+#define ICON_MDI_SOFA_SINGLE "\xf3\xb1\x95\xae" // U+F156E
+#define ICON_MDI_SOFA_SINGLE_OUTLINE "\xf3\xb1\x95\xaf" // U+F156F
+#define ICON_MDI_SOLAR_PANEL "\xf3\xb0\xb6\x9b" // U+F0D9B
+#define ICON_MDI_SOLAR_PANEL_LARGE "\xf3\xb0\xb6\x9c" // U+F0D9C
+#define ICON_MDI_SOLAR_POWER "\xf3\xb0\xa9\xb2" // U+F0A72
+#define ICON_MDI_SOLAR_POWER_VARIANT "\xf3\xb1\xa9\xb3" // U+F1A73
+#define ICON_MDI_SOLAR_POWER_VARIANT_OUTLINE "\xf3\xb1\xa9\xb4" // U+F1A74
+#define ICON_MDI_SOLDERING_IRON "\xf3\xb1\x82\x92" // U+F1092
+#define ICON_MDI_SOLID "\xf3\xb0\x9a\x8d" // U+F068D
+#define ICON_MDI_SONY_PLAYSTATION "\xf3\xb0\x90\x94" // U+F0414
+#define ICON_MDI_SORT "\xf3\xb0\x92\xba" // U+F04BA
+#define ICON_MDI_SORT_ALPHABETICAL_ASCENDING "\xf3\xb0\x96\xbd" // U+F05BD
+#define ICON_MDI_SORT_ALPHABETICAL_ASCENDING_VARIANT "\xf3\xb1\x85\x88" // U+F1148
+#define ICON_MDI_SORT_ALPHABETICAL_DESCENDING "\xf3\xb0\x96\xbf" // U+F05BF
+#define ICON_MDI_SORT_ALPHABETICAL_DESCENDING_VARIANT "\xf3\xb1\x85\x89" // U+F1149
+#define ICON_MDI_SORT_ALPHABETICAL_VARIANT "\xf3\xb0\x92\xbb" // U+F04BB
+#define ICON_MDI_SORT_ASCENDING "\xf3\xb0\x92\xbc" // U+F04BC
+#define ICON_MDI_SORT_BOOL_ASCENDING "\xf3\xb1\x8e\x85" // U+F1385
+#define ICON_MDI_SORT_BOOL_ASCENDING_VARIANT "\xf3\xb1\x8e\x86" // U+F1386
+#define ICON_MDI_SORT_BOOL_DESCENDING "\xf3\xb1\x8e\x87" // U+F1387
+#define ICON_MDI_SORT_BOOL_DESCENDING_VARIANT "\xf3\xb1\x8e\x88" // U+F1388
+#define ICON_MDI_SORT_CALENDAR_ASCENDING "\xf3\xb1\x95\x87" // U+F1547
+#define ICON_MDI_SORT_CALENDAR_DESCENDING "\xf3\xb1\x95\x88" // U+F1548
+#define ICON_MDI_SORT_CLOCK_ASCENDING "\xf3\xb1\x95\x89" // U+F1549
+#define ICON_MDI_SORT_CLOCK_ASCENDING_OUTLINE "\xf3\xb1\x95\x8a" // U+F154A
+#define ICON_MDI_SORT_CLOCK_DESCENDING "\xf3\xb1\x95\x8b" // U+F154B
+#define ICON_MDI_SORT_CLOCK_DESCENDING_OUTLINE "\xf3\xb1\x95\x8c" // U+F154C
+#define ICON_MDI_SORT_DESCENDING "\xf3\xb0\x92\xbd" // U+F04BD
+#define ICON_MDI_SORT_NUMERIC_ASCENDING "\xf3\xb1\x8e\x89" // U+F1389
+#define ICON_MDI_SORT_NUMERIC_ASCENDING_VARIANT "\xf3\xb0\xa4\x8d" // U+F090D
+#define ICON_MDI_SORT_NUMERIC_DESCENDING "\xf3\xb1\x8e\x8a" // U+F138A
+#define ICON_MDI_SORT_NUMERIC_DESCENDING_VARIANT "\xf3\xb0\xab\x92" // U+F0AD2
+#define ICON_MDI_SORT_NUMERIC_VARIANT "\xf3\xb0\x92\xbe" // U+F04BE
+#define ICON_MDI_SORT_REVERSE_VARIANT "\xf3\xb0\x8c\xbc" // U+F033C
+#define ICON_MDI_SORT_VARIANT "\xf3\xb0\x92\xbf" // U+F04BF
+#define ICON_MDI_SORT_VARIANT_LOCK "\xf3\xb0\xb3\x8d" // U+F0CCD
+#define ICON_MDI_SORT_VARIANT_LOCK_OPEN "\xf3\xb0\xb3\x8e" // U+F0CCE
+#define ICON_MDI_SORT_VARIANT_OFF "\xf3\xb1\xaa\xbb" // U+F1ABB
+#define ICON_MDI_SORT_VARIANT_REMOVE "\xf3\xb1\x85\x87" // U+F1147
+#define ICON_MDI_SOUNDBAR "\xf3\xb1\x9f\x9b" // U+F17DB
+#define ICON_MDI_SOUNDCLOUD "\xf3\xb0\x93\x80" // U+F04C0
+#define ICON_MDI_SOURCE_BRANCH "\xf3\xb0\x98\xac" // U+F062C
+#define ICON_MDI_SOURCE_BRANCH_CHECK "\xf3\xb1\x93\x8f" // U+F14CF
+#define ICON_MDI_SOURCE_BRANCH_MINUS "\xf3\xb1\x93\x8b" // U+F14CB
+#define ICON_MDI_SOURCE_BRANCH_PLUS "\xf3\xb1\x93\x8a" // U+F14CA
+#define ICON_MDI_SOURCE_BRANCH_REFRESH "\xf3\xb1\x93\x8d" // U+F14CD
+#define ICON_MDI_SOURCE_BRANCH_REMOVE "\xf3\xb1\x93\x8c" // U+F14CC
+#define ICON_MDI_SOURCE_BRANCH_SYNC "\xf3\xb1\x93\x8e" // U+F14CE
+#define ICON_MDI_SOURCE_COMMIT "\xf3\xb0\x9c\x98" // U+F0718
+#define ICON_MDI_SOURCE_COMMIT_END "\xf3\xb0\x9c\x99" // U+F0719
+#define ICON_MDI_SOURCE_COMMIT_END_LOCAL "\xf3\xb0\x9c\x9a" // U+F071A
+#define ICON_MDI_SOURCE_COMMIT_LOCAL "\xf3\xb0\x9c\x9b" // U+F071B
+#define ICON_MDI_SOURCE_COMMIT_NEXT_LOCAL "\xf3\xb0\x9c\x9c" // U+F071C
+#define ICON_MDI_SOURCE_COMMIT_START "\xf3\xb0\x9c\x9d" // U+F071D
+#define ICON_MDI_SOURCE_COMMIT_START_NEXT_LOCAL "\xf3\xb0\x9c\x9e" // U+F071E
+#define ICON_MDI_SOURCE_FORK "\xf3\xb0\x93\x81" // U+F04C1
+#define ICON_MDI_SOURCE_MERGE "\xf3\xb0\x98\xad" // U+F062D
+#define ICON_MDI_SOURCE_PULL "\xf3\xb0\x93\x82" // U+F04C2
+#define ICON_MDI_SOURCE_REPOSITORY "\xf3\xb0\xb3\x8f" // U+F0CCF
+#define ICON_MDI_SOURCE_REPOSITORY_MULTIPLE "\xf3\xb0\xb3\x90" // U+F0CD0
+#define ICON_MDI_SOY_SAUCE "\xf3\xb0\x9f\xae" // U+F07EE
+#define ICON_MDI_SOY_SAUCE_OFF "\xf3\xb1\x8f\xbc" // U+F13FC
+#define ICON_MDI_SPA "\xf3\xb0\xb3\x91" // U+F0CD1
+#define ICON_MDI_SPA_OUTLINE "\xf3\xb0\xb3\x92" // U+F0CD2
+#define ICON_MDI_SPACE_INVADERS "\xf3\xb0\xaf\x89" // U+F0BC9
+#define ICON_MDI_SPACE_STATION "\xf3\xb1\x8e\x83" // U+F1383
+#define ICON_MDI_SPADE "\xf3\xb0\xb9\xa5" // U+F0E65
+#define ICON_MDI_SPEAKER "\xf3\xb0\x93\x83" // U+F04C3
+#define ICON_MDI_SPEAKER_BLUETOOTH "\xf3\xb0\xa6\xa2" // U+F09A2
+#define ICON_MDI_SPEAKER_MESSAGE "\xf3\xb1\xac\x91" // U+F1B11
+#define ICON_MDI_SPEAKER_MULTIPLE "\xf3\xb0\xb4\xb8" // U+F0D38
+#define ICON_MDI_SPEAKER_OFF "\xf3\xb0\x93\x84" // U+F04C4
+#define ICON_MDI_SPEAKER_PAUSE "\xf3\xb1\xad\xb3" // U+F1B73
+#define ICON_MDI_SPEAKER_PLAY "\xf3\xb1\xad\xb2" // U+F1B72
+#define ICON_MDI_SPEAKER_STOP "\xf3\xb1\xad\xb4" // U+F1B74
+#define ICON_MDI_SPEAKER_WIRELESS "\xf3\xb0\x9c\x9f" // U+F071F
+#define ICON_MDI_SPEAR "\xf3\xb1\xa1\x85" // U+F1845
+#define ICON_MDI_SPEEDOMETER "\xf3\xb0\x93\x85" // U+F04C5
+#define ICON_MDI_SPEEDOMETER_MEDIUM "\xf3\xb0\xbe\x85" // U+F0F85
+#define ICON_MDI_SPEEDOMETER_SLOW "\xf3\xb0\xbe\x86" // U+F0F86
+#define ICON_MDI_SPELLCHECK "\xf3\xb0\x93\x86" // U+F04C6
+#define ICON_MDI_SPHERE "\xf3\xb1\xa5\x94" // U+F1954
+#define ICON_MDI_SPHERE_OFF "\xf3\xb1\xa5\x95" // U+F1955
+#define ICON_MDI_SPIDER "\xf3\xb1\x87\xaa" // U+F11EA
+#define ICON_MDI_SPIDER_OUTLINE "\xf3\xb1\xb1\xb5" // U+F1C75
+#define ICON_MDI_SPIDER_THREAD "\xf3\xb1\x87\xab" // U+F11EB
+#define ICON_MDI_SPIDER_WEB "\xf3\xb0\xaf\x8a" // U+F0BCA
+#define ICON_MDI_SPIRIT_LEVEL "\xf3\xb1\x93\xb1" // U+F14F1
+#define ICON_MDI_SPOON_SUGAR "\xf3\xb1\x90\xa9" // U+F1429
+#define ICON_MDI_SPOTIFY "\xf3\xb0\x93\x87" // U+F04C7
+#define ICON_MDI_SPOTLIGHT "\xf3\xb0\x93\x88" // U+F04C8
+#define ICON_MDI_SPOTLIGHT_BEAM "\xf3\xb0\x93\x89" // U+F04C9
+#define ICON_MDI_SPRAY "\xf3\xb0\x99\xa5" // U+F0665
+#define ICON_MDI_SPRAY_BOTTLE "\xf3\xb0\xab\xa0" // U+F0AE0
+#define ICON_MDI_SPRINKLER "\xf3\xb1\x81\x9f" // U+F105F
+#define ICON_MDI_SPRINKLER_FIRE "\xf3\xb1\xa6\x9d" // U+F199D
+#define ICON_MDI_SPRINKLER_VARIANT "\xf3\xb1\x81\xa0" // U+F1060
+#define ICON_MDI_SPROUT "\xf3\xb0\xb9\xa6" // U+F0E66
+#define ICON_MDI_SPROUT_OUTLINE "\xf3\xb0\xb9\xa7" // U+F0E67
+#define ICON_MDI_SQUARE "\xf3\xb0\x9d\xa4" // U+F0764
+#define ICON_MDI_SQUARE_CIRCLE "\xf3\xb1\x94\x80" // U+F1500
+#define ICON_MDI_SQUARE_CIRCLE_OUTLINE "\xf3\xb1\xb1\x90" // U+F1C50
+#define ICON_MDI_SQUARE_EDIT_OUTLINE "\xf3\xb0\xa4\x8c" // U+F090C
+#define ICON_MDI_SQUARE_MEDIUM "\xf3\xb0\xa8\x93" // U+F0A13
+#define ICON_MDI_SQUARE_MEDIUM_OUTLINE "\xf3\xb0\xa8\x94" // U+F0A14
+#define ICON_MDI_SQUARE_OFF "\xf3\xb1\x8b\xae" // U+F12EE
+#define ICON_MDI_SQUARE_OFF_OUTLINE "\xf3\xb1\x8b\xaf" // U+F12EF
+#define ICON_MDI_SQUARE_OPACITY "\xf3\xb1\xa1\x94" // U+F1854
+#define ICON_MDI_SQUARE_OUTLINE "\xf3\xb0\x9d\xa3" // U+F0763
+#define ICON_MDI_SQUARE_ROOT "\xf3\xb0\x9e\x84" // U+F0784
+#define ICON_MDI_SQUARE_ROOT_BOX "\xf3\xb0\xa6\xa3" // U+F09A3
+#define ICON_MDI_SQUARE_ROUNDED "\xf3\xb1\x93\xbb" // U+F14FB
+#define ICON_MDI_SQUARE_ROUNDED_BADGE "\xf3\xb1\xa8\x87" // U+F1A07
+#define ICON_MDI_SQUARE_ROUNDED_BADGE_OUTLINE "\xf3\xb1\xa8\x88" // U+F1A08
+#define ICON_MDI_SQUARE_ROUNDED_OUTLINE "\xf3\xb1\x93\xbc" // U+F14FC
+#define ICON_MDI_SQUARE_SMALL "\xf3\xb0\xa8\x95" // U+F0A15
+#define ICON_MDI_SQUARE_WAVE "\xf3\xb1\x91\xbb" // U+F147B
+#define ICON_MDI_SQUEEGEE "\xf3\xb0\xab\xa1" // U+F0AE1
+#define ICON_MDI_SSH "\xf3\xb0\xa3\x80" // U+F08C0
+#define ICON_MDI_STACK_EXCHANGE "\xf3\xb0\x98\x8b" // U+F060B
+#define ICON_MDI_STACK_OVERFLOW "\xf3\xb0\x93\x8c" // U+F04CC
+#define ICON_MDI_STACKPATH "\xf3\xb0\x8d\x99" // U+F0359
+#define ICON_MDI_STADIUM "\xf3\xb0\xbf\xb9" // U+F0FF9
+#define ICON_MDI_STADIUM_OUTLINE "\xf3\xb1\xac\x83" // U+F1B03
+#define ICON_MDI_STADIUM_VARIANT "\xf3\xb0\x9c\xa0" // U+F0720
+#define ICON_MDI_STAIRS "\xf3\xb0\x93\x8d" // U+F04CD
+#define ICON_MDI_STAIRS_BOX "\xf3\xb1\x8e\x9e" // U+F139E
+#define ICON_MDI_STAIRS_DOWN "\xf3\xb1\x8a\xbe" // U+F12BE
+#define ICON_MDI_STAIRS_UP "\xf3\xb1\x8a\xbd" // U+F12BD
+#define ICON_MDI_STAMPER "\xf3\xb0\xb4\xb9" // U+F0D39
+#define ICON_MDI_STANDARD_DEFINITION "\xf3\xb0\x9f\xaf" // U+F07EF
+#define ICON_MDI_STAR "\xf3\xb0\x93\x8e" // U+F04CE
+#define ICON_MDI_STAR_BOX "\xf3\xb0\xa9\xb3" // U+F0A73
+#define ICON_MDI_STAR_BOX_MULTIPLE "\xf3\xb1\x8a\x86" // U+F1286
+#define ICON_MDI_STAR_BOX_MULTIPLE_OUTLINE "\xf3\xb1\x8a\x87" // U+F1287
+#define ICON_MDI_STAR_BOX_OUTLINE "\xf3\xb0\xa9\xb4" // U+F0A74
+#define ICON_MDI_STAR_CHECK "\xf3\xb1\x95\xa6" // U+F1566
+#define ICON_MDI_STAR_CHECK_OUTLINE "\xf3\xb1\x95\xaa" // U+F156A
+#define ICON_MDI_STAR_CIRCLE "\xf3\xb0\x93\x8f" // U+F04CF
+#define ICON_MDI_STAR_CIRCLE_OUTLINE "\xf3\xb0\xa6\xa4" // U+F09A4
+#define ICON_MDI_STAR_COG "\xf3\xb1\x99\xa8" // U+F1668
+#define ICON_MDI_STAR_COG_OUTLINE "\xf3\xb1\x99\xa9" // U+F1669
+#define ICON_MDI_STAR_CRESCENT "\xf3\xb0\xa5\xb9" // U+F0979
+#define ICON_MDI_STAR_DAVID "\xf3\xb0\xa5\xba" // U+F097A
+#define ICON_MDI_STAR_FACE "\xf3\xb0\xa6\xa5" // U+F09A5
+#define ICON_MDI_STAR_FOUR_POINTS "\xf3\xb0\xab\xa2" // U+F0AE2
+#define ICON_MDI_STAR_FOUR_POINTS_BOX "\xf3\xb1\xb1\x91" // U+F1C51
+#define ICON_MDI_STAR_FOUR_POINTS_BOX_OUTLINE "\xf3\xb1\xb1\x92" // U+F1C52
+#define ICON_MDI_STAR_FOUR_POINTS_CIRCLE "\xf3\xb1\xb1\x93" // U+F1C53
+#define ICON_MDI_STAR_FOUR_POINTS_CIRCLE_OUTLINE "\xf3\xb1\xb1\x94" // U+F1C54
+#define ICON_MDI_STAR_FOUR_POINTS_OUTLINE "\xf3\xb0\xab\xa3" // U+F0AE3
+#define ICON_MDI_STAR_FOUR_POINTS_SMALL "\xf3\xb1\xb1\x95" // U+F1C55
+#define ICON_MDI_STAR_HALF "\xf3\xb0\x89\x86" // U+F0246
+#define ICON_MDI_STAR_HALF_FULL "\xf3\xb0\x93\x90" // U+F04D0
+#define ICON_MDI_STAR_MINUS "\xf3\xb1\x95\xa4" // U+F1564
+#define ICON_MDI_STAR_MINUS_OUTLINE "\xf3\xb1\x95\xa8" // U+F1568
+#define ICON_MDI_STAR_OFF "\xf3\xb0\x93\x91" // U+F04D1
+#define ICON_MDI_STAR_OFF_OUTLINE "\xf3\xb1\x95\x9b" // U+F155B
+#define ICON_MDI_STAR_OUTLINE "\xf3\xb0\x93\x92" // U+F04D2
+#define ICON_MDI_STAR_PLUS "\xf3\xb1\x95\xa3" // U+F1563
+#define ICON_MDI_STAR_PLUS_OUTLINE "\xf3\xb1\x95\xa7" // U+F1567
+#define ICON_MDI_STAR_REMOVE "\xf3\xb1\x95\xa5" // U+F1565
+#define ICON_MDI_STAR_REMOVE_OUTLINE "\xf3\xb1\x95\xa9" // U+F1569
+#define ICON_MDI_STAR_SETTINGS "\xf3\xb1\x99\xaa" // U+F166A
+#define ICON_MDI_STAR_SETTINGS_OUTLINE "\xf3\xb1\x99\xab" // U+F166B
+#define ICON_MDI_STAR_SHOOTING "\xf3\xb1\x9d\x81" // U+F1741
+#define ICON_MDI_STAR_SHOOTING_OUTLINE "\xf3\xb1\x9d\x82" // U+F1742
+#define ICON_MDI_STAR_THREE_POINTS "\xf3\xb0\xab\xa4" // U+F0AE4
+#define ICON_MDI_STAR_THREE_POINTS_OUTLINE "\xf3\xb0\xab\xa5" // U+F0AE5
+#define ICON_MDI_STATE_MACHINE "\xf3\xb1\x87\xaf" // U+F11EF
+#define ICON_MDI_STEAM "\xf3\xb0\x93\x93" // U+F04D3
+#define ICON_MDI_STEERING "\xf3\xb0\x93\x94" // U+F04D4
+#define ICON_MDI_STEERING_OFF "\xf3\xb0\xa4\x8e" // U+F090E
+#define ICON_MDI_STEP_BACKWARD "\xf3\xb0\x93\x95" // U+F04D5
+#define ICON_MDI_STEP_BACKWARD_2 "\xf3\xb0\x93\x96" // U+F04D6
+#define ICON_MDI_STEP_FORWARD "\xf3\xb0\x93\x97" // U+F04D7
+#define ICON_MDI_STEP_FORWARD_2 "\xf3\xb0\x93\x98" // U+F04D8
+#define ICON_MDI_STETHOSCOPE "\xf3\xb0\x93\x99" // U+F04D9
+#define ICON_MDI_STICKER "\xf3\xb1\x8d\xa4" // U+F1364
+#define ICON_MDI_STICKER_ALERT "\xf3\xb1\x8d\xa5" // U+F1365
+#define ICON_MDI_STICKER_ALERT_OUTLINE "\xf3\xb1\x8d\xa6" // U+F1366
+#define ICON_MDI_STICKER_CHECK "\xf3\xb1\x8d\xa7" // U+F1367
+#define ICON_MDI_STICKER_CHECK_OUTLINE "\xf3\xb1\x8d\xa8" // U+F1368
+#define ICON_MDI_STICKER_CIRCLE_OUTLINE "\xf3\xb0\x97\x90" // U+F05D0
+#define ICON_MDI_STICKER_EMOJI "\xf3\xb0\x9e\x85" // U+F0785
+#define ICON_MDI_STICKER_MINUS "\xf3\xb1\x8d\xa9" // U+F1369
+#define ICON_MDI_STICKER_MINUS_OUTLINE "\xf3\xb1\x8d\xaa" // U+F136A
+#define ICON_MDI_STICKER_OUTLINE "\xf3\xb1\x8d\xab" // U+F136B
+#define ICON_MDI_STICKER_PLUS "\xf3\xb1\x8d\xac" // U+F136C
+#define ICON_MDI_STICKER_PLUS_OUTLINE "\xf3\xb1\x8d\xad" // U+F136D
+#define ICON_MDI_STICKER_REMOVE "\xf3\xb1\x8d\xae" // U+F136E
+#define ICON_MDI_STICKER_REMOVE_OUTLINE "\xf3\xb1\x8d\xaf" // U+F136F
+#define ICON_MDI_STICKER_TEXT "\xf3\xb1\x9e\x8e" // U+F178E
+#define ICON_MDI_STICKER_TEXT_OUTLINE "\xf3\xb1\x9e\x8f" // U+F178F
+#define ICON_MDI_STOCKING "\xf3\xb0\x93\x9a" // U+F04DA
+#define ICON_MDI_STOMACH "\xf3\xb1\x82\x93" // U+F1093
+#define ICON_MDI_STOOL "\xf3\xb1\xa5\x9d" // U+F195D
+#define ICON_MDI_STOOL_OUTLINE "\xf3\xb1\xa5\x9e" // U+F195E
+#define ICON_MDI_STOP "\xf3\xb0\x93\x9b" // U+F04DB
+#define ICON_MDI_STOP_CIRCLE "\xf3\xb0\x99\xa6" // U+F0666
+#define ICON_MDI_STOP_CIRCLE_OUTLINE "\xf3\xb0\x99\xa7" // U+F0667
+#define ICON_MDI_STORAGE_TANK "\xf3\xb1\xa9\xb5" // U+F1A75
+#define ICON_MDI_STORAGE_TANK_OUTLINE "\xf3\xb1\xa9\xb6" // U+F1A76
+#define ICON_MDI_STORE "\xf3\xb0\x93\x9c" // U+F04DC
+#define ICON_MDI_STORE_24_HOUR "\xf3\xb0\x93\x9d" // U+F04DD
+#define ICON_MDI_STORE_ALERT "\xf3\xb1\xa3\x81" // U+F18C1
+#define ICON_MDI_STORE_ALERT_OUTLINE "\xf3\xb1\xa3\x82" // U+F18C2
+#define ICON_MDI_STORE_CHECK "\xf3\xb1\xa3\x83" // U+F18C3
+#define ICON_MDI_STORE_CHECK_OUTLINE "\xf3\xb1\xa3\x84" // U+F18C4
+#define ICON_MDI_STORE_CLOCK "\xf3\xb1\xa3\x85" // U+F18C5
+#define ICON_MDI_STORE_CLOCK_OUTLINE "\xf3\xb1\xa3\x86" // U+F18C6
+#define ICON_MDI_STORE_COG "\xf3\xb1\xa3\x87" // U+F18C7
+#define ICON_MDI_STORE_COG_OUTLINE "\xf3\xb1\xa3\x88" // U+F18C8
+#define ICON_MDI_STORE_EDIT "\xf3\xb1\xa3\x89" // U+F18C9
+#define ICON_MDI_STORE_EDIT_OUTLINE "\xf3\xb1\xa3\x8a" // U+F18CA
+#define ICON_MDI_STORE_MARKER "\xf3\xb1\xa3\x8b" // U+F18CB
+#define ICON_MDI_STORE_MARKER_OUTLINE "\xf3\xb1\xa3\x8c" // U+F18CC
+#define ICON_MDI_STORE_MINUS "\xf3\xb1\x99\x9e" // U+F165E
+#define ICON_MDI_STORE_MINUS_OUTLINE "\xf3\xb1\xa3\x8d" // U+F18CD
+#define ICON_MDI_STORE_OFF "\xf3\xb1\xa3\x8e" // U+F18CE
+#define ICON_MDI_STORE_OFF_OUTLINE "\xf3\xb1\xa3\x8f" // U+F18CF
+#define ICON_MDI_STORE_OUTLINE "\xf3\xb1\x8d\xa1" // U+F1361
+#define ICON_MDI_STORE_PLUS "\xf3\xb1\x99\x9f" // U+F165F
+#define ICON_MDI_STORE_PLUS_OUTLINE "\xf3\xb1\xa3\x90" // U+F18D0
+#define ICON_MDI_STORE_REMOVE "\xf3\xb1\x99\xa0" // U+F1660
+#define ICON_MDI_STORE_REMOVE_OUTLINE "\xf3\xb1\xa3\x91" // U+F18D1
+#define ICON_MDI_STORE_SEARCH "\xf3\xb1\xa3\x92" // U+F18D2
+#define ICON_MDI_STORE_SEARCH_OUTLINE "\xf3\xb1\xa3\x93" // U+F18D3
+#define ICON_MDI_STORE_SETTINGS "\xf3\xb1\xa3\x94" // U+F18D4
+#define ICON_MDI_STORE_SETTINGS_OUTLINE "\xf3\xb1\xa3\x95" // U+F18D5
+#define ICON_MDI_STOREFRONT "\xf3\xb0\x9f\x87" // U+F07C7
+#define ICON_MDI_STOREFRONT_CHECK "\xf3\xb1\xad\xbd" // U+F1B7D
+#define ICON_MDI_STOREFRONT_CHECK_OUTLINE "\xf3\xb1\xad\xbe" // U+F1B7E
+#define ICON_MDI_STOREFRONT_EDIT "\xf3\xb1\xad\xbf" // U+F1B7F
+#define ICON_MDI_STOREFRONT_EDIT_OUTLINE "\xf3\xb1\xae\x80" // U+F1B80
+#define ICON_MDI_STOREFRONT_MINUS "\xf3\xb1\xae\x83" // U+F1B83
+#define ICON_MDI_STOREFRONT_MINUS_OUTLINE "\xf3\xb1\xae\x84" // U+F1B84
+#define ICON_MDI_STOREFRONT_OUTLINE "\xf3\xb1\x83\x81" // U+F10C1
+#define ICON_MDI_STOREFRONT_PLUS "\xf3\xb1\xae\x81" // U+F1B81
+#define ICON_MDI_STOREFRONT_PLUS_OUTLINE "\xf3\xb1\xae\x82" // U+F1B82
+#define ICON_MDI_STOREFRONT_REMOVE "\xf3\xb1\xae\x85" // U+F1B85
+#define ICON_MDI_STOREFRONT_REMOVE_OUTLINE "\xf3\xb1\xae\x86" // U+F1B86
+#define ICON_MDI_STOVE "\xf3\xb0\x93\x9e" // U+F04DE
+#define ICON_MDI_STRATEGY "\xf3\xb1\x87\x96" // U+F11D6
+#define ICON_MDI_STRETCH_TO_PAGE "\xf3\xb0\xbc\xab" // U+F0F2B
+#define ICON_MDI_STRETCH_TO_PAGE_OUTLINE "\xf3\xb0\xbc\xac" // U+F0F2C
+#define ICON_MDI_STRING_LIGHTS "\xf3\xb1\x8a\xba" // U+F12BA
+#define ICON_MDI_STRING_LIGHTS_OFF "\xf3\xb1\x8a\xbb" // U+F12BB
+#define ICON_MDI_SUBDIRECTORY_ARROW_LEFT "\xf3\xb0\x98\x8c" // U+F060C
+#define ICON_MDI_SUBDIRECTORY_ARROW_RIGHT "\xf3\xb0\x98\x8d" // U+F060D
+#define ICON_MDI_SUBMARINE "\xf3\xb1\x95\xac" // U+F156C
+#define ICON_MDI_SUBTITLES "\xf3\xb0\xa8\x96" // U+F0A16
+#define ICON_MDI_SUBTITLES_OUTLINE "\xf3\xb0\xa8\x97" // U+F0A17
+#define ICON_MDI_SUBWAY "\xf3\xb0\x9a\xac" // U+F06AC
+#define ICON_MDI_SUBWAY_ALERT_VARIANT "\xf3\xb0\xb6\x9d" // U+F0D9D
+#define ICON_MDI_SUBWAY_VARIANT "\xf3\xb0\x93\x9f" // U+F04DF
+#define ICON_MDI_SUMMIT "\xf3\xb0\x9e\x86" // U+F0786
+#define ICON_MDI_SUN_ANGLE "\xf3\xb1\xac\xa7" // U+F1B27
+#define ICON_MDI_SUN_ANGLE_OUTLINE "\xf3\xb1\xac\xa8" // U+F1B28
+#define ICON_MDI_SUN_CLOCK "\xf3\xb1\xa9\xb7" // U+F1A77
+#define ICON_MDI_SUN_CLOCK_OUTLINE "\xf3\xb1\xa9\xb8" // U+F1A78
+#define ICON_MDI_SUN_COMPASS "\xf3\xb1\xa6\xa5" // U+F19A5
+#define ICON_MDI_SUN_SNOWFLAKE "\xf3\xb1\x9e\x96" // U+F1796
+#define ICON_MDI_SUN_SNOWFLAKE_VARIANT "\xf3\xb1\xa9\xb9" // U+F1A79
+#define ICON_MDI_SUN_THERMOMETER "\xf3\xb1\xa3\x96" // U+F18D6
+#define ICON_MDI_SUN_THERMOMETER_OUTLINE "\xf3\xb1\xa3\x97" // U+F18D7
+#define ICON_MDI_SUN_WIRELESS "\xf3\xb1\x9f\xbe" // U+F17FE
+#define ICON_MDI_SUN_WIRELESS_OUTLINE "\xf3\xb1\x9f\xbf" // U+F17FF
+#define ICON_MDI_SUNGLASSES "\xf3\xb0\x93\xa0" // U+F04E0
+#define ICON_MDI_SURFING "\xf3\xb1\x9d\x86" // U+F1746
+#define ICON_MDI_SURROUND_SOUND "\xf3\xb0\x97\x85" // U+F05C5
+#define ICON_MDI_SURROUND_SOUND_2_0 "\xf3\xb0\x9f\xb0" // U+F07F0
+#define ICON_MDI_SURROUND_SOUND_2_1 "\xf3\xb1\x9c\xa9" // U+F1729
+#define ICON_MDI_SURROUND_SOUND_3_1 "\xf3\xb0\x9f\xb1" // U+F07F1
+#define ICON_MDI_SURROUND_SOUND_5_1 "\xf3\xb0\x9f\xb2" // U+F07F2
+#define ICON_MDI_SURROUND_SOUND_5_1_2 "\xf3\xb1\x9c\xaa" // U+F172A
+#define ICON_MDI_SURROUND_SOUND_7_1 "\xf3\xb0\x9f\xb3" // U+F07F3
+#define ICON_MDI_SVG "\xf3\xb0\x9c\xa1" // U+F0721
+#define ICON_MDI_SWAP_HORIZONTAL "\xf3\xb0\x93\xa1" // U+F04E1
+#define ICON_MDI_SWAP_HORIZONTAL_BOLD "\xf3\xb0\xaf\x8d" // U+F0BCD
+#define ICON_MDI_SWAP_HORIZONTAL_CIRCLE "\xf3\xb0\xbf\xa1" // U+F0FE1
+#define ICON_MDI_SWAP_HORIZONTAL_CIRCLE_OUTLINE "\xf3\xb0\xbf\xa2" // U+F0FE2
+#define ICON_MDI_SWAP_HORIZONTAL_VARIANT "\xf3\xb0\xa3\x81" // U+F08C1
+#define ICON_MDI_SWAP_VERTICAL "\xf3\xb0\x93\xa2" // U+F04E2
+#define ICON_MDI_SWAP_VERTICAL_BOLD "\xf3\xb0\xaf\x8e" // U+F0BCE
+#define ICON_MDI_SWAP_VERTICAL_CIRCLE "\xf3\xb0\xbf\xa3" // U+F0FE3
+#define ICON_MDI_SWAP_VERTICAL_CIRCLE_OUTLINE "\xf3\xb0\xbf\xa4" // U+F0FE4
+#define ICON_MDI_SWAP_VERTICAL_VARIANT "\xf3\xb0\xa3\x82" // U+F08C2
+#define ICON_MDI_SWIM "\xf3\xb0\x93\xa3" // U+F04E3
+#define ICON_MDI_SWITCH "\xf3\xb0\x93\xa4" // U+F04E4
+#define ICON_MDI_SWORD "\xf3\xb0\x93\xa5" // U+F04E5
+#define ICON_MDI_SWORD_CROSS "\xf3\xb0\x9e\x87" // U+F0787
+#define ICON_MDI_SYLLABARY_HANGUL "\xf3\xb1\x8c\xb3" // U+F1333
+#define ICON_MDI_SYLLABARY_HIRAGANA "\xf3\xb1\x8c\xb4" // U+F1334
+#define ICON_MDI_SYLLABARY_KATAKANA "\xf3\xb1\x8c\xb5" // U+F1335
+#define ICON_MDI_SYLLABARY_KATAKANA_HALFWIDTH "\xf3\xb1\x8c\xb6" // U+F1336
+#define ICON_MDI_SYMBOL "\xf3\xb1\x94\x81" // U+F1501
+#define ICON_MDI_SYMFONY "\xf3\xb0\xab\xa6" // U+F0AE6
+#define ICON_MDI_SYNAGOGUE "\xf3\xb1\xac\x84" // U+F1B04
+#define ICON_MDI_SYNAGOGUE_OUTLINE "\xf3\xb1\xac\x85" // U+F1B05
+#define ICON_MDI_SYNC "\xf3\xb0\x93\xa6" // U+F04E6
+#define ICON_MDI_SYNC_ALERT "\xf3\xb0\x93\xa7" // U+F04E7
+#define ICON_MDI_SYNC_CIRCLE "\xf3\xb1\x8d\xb8" // U+F1378
+#define ICON_MDI_SYNC_OFF "\xf3\xb0\x93\xa8" // U+F04E8
+#define ICON_MDI_TAB "\xf3\xb0\x93\xa9" // U+F04E9
+#define ICON_MDI_TAB_MINUS "\xf3\xb0\xad\x8b" // U+F0B4B
+#define ICON_MDI_TAB_PLUS "\xf3\xb0\x9d\x9c" // U+F075C
+#define ICON_MDI_TAB_REMOVE "\xf3\xb0\xad\x8c" // U+F0B4C
+#define ICON_MDI_TAB_SEARCH "\xf3\xb1\xa6\x9e" // U+F199E
+#define ICON_MDI_TAB_UNSELECTED "\xf3\xb0\x93\xaa" // U+F04EA
+#define ICON_MDI_TABLE "\xf3\xb0\x93\xab" // U+F04EB
+#define ICON_MDI_TABLE_ACCOUNT "\xf3\xb1\x8e\xb9" // U+F13B9
+#define ICON_MDI_TABLE_ALERT "\xf3\xb1\x8e\xba" // U+F13BA
+#define ICON_MDI_TABLE_ARROW_DOWN "\xf3\xb1\x8e\xbb" // U+F13BB
+#define ICON_MDI_TABLE_ARROW_LEFT "\xf3\xb1\x8e\xbc" // U+F13BC
+#define ICON_MDI_TABLE_ARROW_RIGHT "\xf3\xb1\x8e\xbd" // U+F13BD
+#define ICON_MDI_TABLE_ARROW_UP "\xf3\xb1\x8e\xbe" // U+F13BE
+#define ICON_MDI_TABLE_BORDER "\xf3\xb0\xa8\x98" // U+F0A18
+#define ICON_MDI_TABLE_CANCEL "\xf3\xb1\x8e\xbf" // U+F13BF
+#define ICON_MDI_TABLE_CHAIR "\xf3\xb1\x81\xa1" // U+F1061
+#define ICON_MDI_TABLE_CHECK "\xf3\xb1\x8f\x80" // U+F13C0
+#define ICON_MDI_TABLE_CLOCK "\xf3\xb1\x8f\x81" // U+F13C1
+#define ICON_MDI_TABLE_COG "\xf3\xb1\x8f\x82" // U+F13C2
+#define ICON_MDI_TABLE_COLUMN "\xf3\xb0\xa0\xb5" // U+F0835
+#define ICON_MDI_TABLE_COLUMN_PLUS_AFTER "\xf3\xb0\x93\xac" // U+F04EC
+#define ICON_MDI_TABLE_COLUMN_PLUS_BEFORE "\xf3\xb0\x93\xad" // U+F04ED
+#define ICON_MDI_TABLE_COLUMN_REMOVE "\xf3\xb0\x93\xae" // U+F04EE
+#define ICON_MDI_TABLE_COLUMN_WIDTH "\xf3\xb0\x93\xaf" // U+F04EF
+#define ICON_MDI_TABLE_EDIT "\xf3\xb0\x93\xb0" // U+F04F0
+#define ICON_MDI_TABLE_EYE "\xf3\xb1\x82\x94" // U+F1094
+#define ICON_MDI_TABLE_EYE_OFF "\xf3\xb1\x8f\x83" // U+F13C3
+#define ICON_MDI_TABLE_FILTER "\xf3\xb1\xae\x8c" // U+F1B8C
+#define ICON_MDI_TABLE_FURNITURE "\xf3\xb0\x96\xbc" // U+F05BC
+#define ICON_MDI_TABLE_HEADERS_EYE "\xf3\xb1\x88\x9d" // U+F121D
+#define ICON_MDI_TABLE_HEADERS_EYE_OFF "\xf3\xb1\x88\x9e" // U+F121E
+#define ICON_MDI_TABLE_HEART "\xf3\xb1\x8f\x84" // U+F13C4
+#define ICON_MDI_TABLE_KEY "\xf3\xb1\x8f\x85" // U+F13C5
+#define ICON_MDI_TABLE_LARGE "\xf3\xb0\x93\xb1" // U+F04F1
+#define ICON_MDI_TABLE_LARGE_PLUS "\xf3\xb0\xbe\x87" // U+F0F87
+#define ICON_MDI_TABLE_LARGE_REMOVE "\xf3\xb0\xbe\x88" // U+F0F88
+#define ICON_MDI_TABLE_LOCK "\xf3\xb1\x8f\x86" // U+F13C6
+#define ICON_MDI_TABLE_MERGE_CELLS "\xf3\xb0\xa6\xa6" // U+F09A6
+#define ICON_MDI_TABLE_MINUS "\xf3\xb1\x8f\x87" // U+F13C7
+#define ICON_MDI_TABLE_MULTIPLE "\xf3\xb1\x8f\x88" // U+F13C8
+#define ICON_MDI_TABLE_NETWORK "\xf3\xb1\x8f\x89" // U+F13C9
+#define ICON_MDI_TABLE_OF_CONTENTS "\xf3\xb0\xa0\xb6" // U+F0836
+#define ICON_MDI_TABLE_OFF "\xf3\xb1\x8f\x8a" // U+F13CA
+#define ICON_MDI_TABLE_PICNIC "\xf3\xb1\x9d\x83" // U+F1743
+#define ICON_MDI_TABLE_PIVOT "\xf3\xb1\xa0\xbc" // U+F183C
+#define ICON_MDI_TABLE_PLUS "\xf3\xb0\xa9\xb5" // U+F0A75
+#define ICON_MDI_TABLE_QUESTION "\xf3\xb1\xac\xa1" // U+F1B21
+#define ICON_MDI_TABLE_REFRESH "\xf3\xb1\x8e\xa0" // U+F13A0
+#define ICON_MDI_TABLE_REMOVE "\xf3\xb0\xa9\xb6" // U+F0A76
+#define ICON_MDI_TABLE_ROW "\xf3\xb0\xa0\xb7" // U+F0837
+#define ICON_MDI_TABLE_ROW_HEIGHT "\xf3\xb0\x93\xb2" // U+F04F2
+#define ICON_MDI_TABLE_ROW_PLUS_AFTER "\xf3\xb0\x93\xb3" // U+F04F3
+#define ICON_MDI_TABLE_ROW_PLUS_BEFORE "\xf3\xb0\x93\xb4" // U+F04F4
+#define ICON_MDI_TABLE_ROW_REMOVE "\xf3\xb0\x93\xb5" // U+F04F5
+#define ICON_MDI_TABLE_SEARCH "\xf3\xb0\xa4\x8f" // U+F090F
+#define ICON_MDI_TABLE_SETTINGS "\xf3\xb0\xa0\xb8" // U+F0838
+#define ICON_MDI_TABLE_SPLIT_CELL "\xf3\xb1\x90\xaa" // U+F142A
+#define ICON_MDI_TABLE_STAR "\xf3\xb1\x8f\x8b" // U+F13CB
+#define ICON_MDI_TABLE_SYNC "\xf3\xb1\x8e\xa1" // U+F13A1
+#define ICON_MDI_TABLE_TENNIS "\xf3\xb0\xb9\xa8" // U+F0E68
+#define ICON_MDI_TABLET "\xf3\xb0\x93\xb6" // U+F04F6
+#define ICON_MDI_TABLET_CELLPHONE "\xf3\xb0\xa6\xa7" // U+F09A7
+#define ICON_MDI_TABLET_DASHBOARD "\xf3\xb0\xbb\x8e" // U+F0ECE
+#define ICON_MDI_TACO "\xf3\xb0\x9d\xa2" // U+F0762
+#define ICON_MDI_TAG "\xf3\xb0\x93\xb9" // U+F04F9
+#define ICON_MDI_TAG_ARROW_DOWN "\xf3\xb1\x9c\xab" // U+F172B
+#define ICON_MDI_TAG_ARROW_DOWN_OUTLINE "\xf3\xb1\x9c\xac" // U+F172C
+#define ICON_MDI_TAG_ARROW_LEFT "\xf3\xb1\x9c\xad" // U+F172D
+#define ICON_MDI_TAG_ARROW_LEFT_OUTLINE "\xf3\xb1\x9c\xae" // U+F172E
+#define ICON_MDI_TAG_ARROW_RIGHT "\xf3\xb1\x9c\xaf" // U+F172F
+#define ICON_MDI_TAG_ARROW_RIGHT_OUTLINE "\xf3\xb1\x9c\xb0" // U+F1730
+#define ICON_MDI_TAG_ARROW_UP "\xf3\xb1\x9c\xb1" // U+F1731
+#define ICON_MDI_TAG_ARROW_UP_OUTLINE "\xf3\xb1\x9c\xb2" // U+F1732
+#define ICON_MDI_TAG_CHECK "\xf3\xb1\xa9\xba" // U+F1A7A
+#define ICON_MDI_TAG_CHECK_OUTLINE "\xf3\xb1\xa9\xbb" // U+F1A7B
+#define ICON_MDI_TAG_EDIT "\xf3\xb1\xb2\x9c" // U+F1C9C
+#define ICON_MDI_TAG_EDIT_OUTLINE "\xf3\xb1\xb2\x9d" // U+F1C9D
+#define ICON_MDI_TAG_FACES "\xf3\xb0\x93\xba" // U+F04FA
+#define ICON_MDI_TAG_HEART "\xf3\xb0\x9a\x8b" // U+F068B
+#define ICON_MDI_TAG_HEART_OUTLINE "\xf3\xb0\xaf\x8f" // U+F0BCF
+#define ICON_MDI_TAG_HIDDEN "\xf3\xb1\xb1\xb6" // U+F1C76
+#define ICON_MDI_TAG_MINUS "\xf3\xb0\xa4\x90" // U+F0910
+#define ICON_MDI_TAG_MINUS_OUTLINE "\xf3\xb1\x88\x9f" // U+F121F
+#define ICON_MDI_TAG_MULTIPLE "\xf3\xb0\x93\xbb" // U+F04FB
+#define ICON_MDI_TAG_MULTIPLE_OUTLINE "\xf3\xb1\x8b\xb7" // U+F12F7
+#define ICON_MDI_TAG_OFF "\xf3\xb1\x88\xa0" // U+F1220
+#define ICON_MDI_TAG_OFF_OUTLINE "\xf3\xb1\x88\xa1" // U+F1221
+#define ICON_MDI_TAG_OUTLINE "\xf3\xb0\x93\xbc" // U+F04FC
+#define ICON_MDI_TAG_PLUS "\xf3\xb0\x9c\xa2" // U+F0722
+#define ICON_MDI_TAG_PLUS_OUTLINE "\xf3\xb1\x88\xa2" // U+F1222
+#define ICON_MDI_TAG_REMOVE "\xf3\xb0\x9c\xa3" // U+F0723
+#define ICON_MDI_TAG_REMOVE_OUTLINE "\xf3\xb1\x88\xa3" // U+F1223
+#define ICON_MDI_TAG_SEARCH "\xf3\xb1\xa4\x87" // U+F1907
+#define ICON_MDI_TAG_SEARCH_OUTLINE "\xf3\xb1\xa4\x88" // U+F1908
+#define ICON_MDI_TAG_TEXT "\xf3\xb1\x88\xa4" // U+F1224
+#define ICON_MDI_TAG_TEXT_OUTLINE "\xf3\xb0\x93\xbd" // U+F04FD
+#define ICON_MDI_TAILWIND "\xf3\xb1\x8f\xbf" // U+F13FF
+#define ICON_MDI_TALLY_MARK_1 "\xf3\xb1\xaa\xbc" // U+F1ABC
+#define ICON_MDI_TALLY_MARK_2 "\xf3\xb1\xaa\xbd" // U+F1ABD
+#define ICON_MDI_TALLY_MARK_3 "\xf3\xb1\xaa\xbe" // U+F1ABE
+#define ICON_MDI_TALLY_MARK_4 "\xf3\xb1\xaa\xbf" // U+F1ABF
+#define ICON_MDI_TALLY_MARK_5 "\xf3\xb1\xab\x80" // U+F1AC0
+#define ICON_MDI_TANGRAM "\xf3\xb0\x93\xb8" // U+F04F8
+#define ICON_MDI_TANK "\xf3\xb0\xb4\xba" // U+F0D3A
+#define ICON_MDI_TANKER_TRUCK "\xf3\xb0\xbf\xa5" // U+F0FE5
+#define ICON_MDI_TAPE_DRIVE "\xf3\xb1\x9b\x9f" // U+F16DF
+#define ICON_MDI_TAPE_MEASURE "\xf3\xb0\xad\x8d" // U+F0B4D
+#define ICON_MDI_TARGET "\xf3\xb0\x93\xbe" // U+F04FE
+#define ICON_MDI_TARGET_ACCOUNT "\xf3\xb0\xaf\x90" // U+F0BD0
+#define ICON_MDI_TARGET_VARIANT "\xf3\xb0\xa9\xb7" // U+F0A77
+#define ICON_MDI_TAXI "\xf3\xb0\x93\xbf" // U+F04FF
+#define ICON_MDI_TEA "\xf3\xb0\xb6\x9e" // U+F0D9E
+#define ICON_MDI_TEA_OUTLINE "\xf3\xb0\xb6\x9f" // U+F0D9F
+#define ICON_MDI_TEAMVIEWER "\xf3\xb0\x94\x80" // U+F0500
+#define ICON_MDI_TEDDY_BEAR "\xf3\xb1\xa3\xbb" // U+F18FB
+#define ICON_MDI_TELESCOPE "\xf3\xb0\xad\x8e" // U+F0B4E
+#define ICON_MDI_TELEVISION "\xf3\xb0\x94\x82" // U+F0502
+#define ICON_MDI_TELEVISION_AMBIENT_LIGHT "\xf3\xb1\x8d\x96" // U+F1356
+#define ICON_MDI_TELEVISION_BOX "\xf3\xb0\xa0\xb9" // U+F0839
+#define ICON_MDI_TELEVISION_CLASSIC "\xf3\xb0\x9f\xb4" // U+F07F4
+#define ICON_MDI_TELEVISION_CLASSIC_OFF "\xf3\xb0\xa0\xba" // U+F083A
+#define ICON_MDI_TELEVISION_GUIDE "\xf3\xb0\x94\x83" // U+F0503
+#define ICON_MDI_TELEVISION_OFF "\xf3\xb0\xa0\xbb" // U+F083B
+#define ICON_MDI_TELEVISION_PAUSE "\xf3\xb0\xbe\x89" // U+F0F89
+#define ICON_MDI_TELEVISION_PLAY "\xf3\xb0\xbb\x8f" // U+F0ECF
+#define ICON_MDI_TELEVISION_SHIMMER "\xf3\xb1\x84\x90" // U+F1110
+#define ICON_MDI_TELEVISION_SPEAKER "\xf3\xb1\xac\x9b" // U+F1B1B
+#define ICON_MDI_TELEVISION_SPEAKER_OFF "\xf3\xb1\xac\x9c" // U+F1B1C
+#define ICON_MDI_TELEVISION_STOP "\xf3\xb0\xbe\x8a" // U+F0F8A
+#define ICON_MDI_TEMPERATURE_CELSIUS "\xf3\xb0\x94\x84" // U+F0504
+#define ICON_MDI_TEMPERATURE_FAHRENHEIT "\xf3\xb0\x94\x85" // U+F0505
+#define ICON_MDI_TEMPERATURE_KELVIN "\xf3\xb0\x94\x86" // U+F0506
+#define ICON_MDI_TEMPLE_BUDDHIST "\xf3\xb1\xac\x86" // U+F1B06
+#define ICON_MDI_TEMPLE_BUDDHIST_OUTLINE "\xf3\xb1\xac\x87" // U+F1B07
+#define ICON_MDI_TEMPLE_HINDU "\xf3\xb1\xac\x88" // U+F1B08
+#define ICON_MDI_TEMPLE_HINDU_OUTLINE "\xf3\xb1\xac\x89" // U+F1B09
+#define ICON_MDI_TENNIS "\xf3\xb0\xb6\xa0" // U+F0DA0
+#define ICON_MDI_TENNIS_BALL "\xf3\xb0\x94\x87" // U+F0507
+#define ICON_MDI_TENNIS_BALL_OUTLINE "\xf3\xb1\xb1\x9f" // U+F1C5F
+#define ICON_MDI_TENT "\xf3\xb0\x94\x88" // U+F0508
+#define ICON_MDI_TERRAFORM "\xf3\xb1\x81\xa2" // U+F1062
+#define ICON_MDI_TERRAIN "\xf3\xb0\x94\x89" // U+F0509
+#define ICON_MDI_TEST_TUBE "\xf3\xb0\x99\xa8" // U+F0668
+#define ICON_MDI_TEST_TUBE_EMPTY "\xf3\xb0\xa4\x91" // U+F0911
+#define ICON_MDI_TEST_TUBE_OFF "\xf3\xb0\xa4\x92" // U+F0912
+#define ICON_MDI_TEXT "\xf3\xb0\xa6\xa8" // U+F09A8
+#define ICON_MDI_TEXT_ACCOUNT "\xf3\xb1\x95\xb0" // U+F1570
+#define ICON_MDI_TEXT_BOX "\xf3\xb0\x88\x9a" // U+F021A
+#define ICON_MDI_TEXT_BOX_CHECK "\xf3\xb0\xba\xa6" // U+F0EA6
+#define ICON_MDI_TEXT_BOX_CHECK_OUTLINE "\xf3\xb0\xba\xa7" // U+F0EA7
+#define ICON_MDI_TEXT_BOX_EDIT "\xf3\xb1\xa9\xbc" // U+F1A7C
+#define ICON_MDI_TEXT_BOX_EDIT_OUTLINE "\xf3\xb1\xa9\xbd" // U+F1A7D
+#define ICON_MDI_TEXT_BOX_MINUS "\xf3\xb0\xba\xa8" // U+F0EA8
+#define ICON_MDI_TEXT_BOX_MINUS_OUTLINE "\xf3\xb0\xba\xa9" // U+F0EA9
+#define ICON_MDI_TEXT_BOX_MULTIPLE "\xf3\xb0\xaa\xb7" // U+F0AB7
+#define ICON_MDI_TEXT_BOX_MULTIPLE_OUTLINE "\xf3\xb0\xaa\xb8" // U+F0AB8
+#define ICON_MDI_TEXT_BOX_OUTLINE "\xf3\xb0\xa7\xad" // U+F09ED
+#define ICON_MDI_TEXT_BOX_PLUS "\xf3\xb0\xba\xaa" // U+F0EAA
+#define ICON_MDI_TEXT_BOX_PLUS_OUTLINE "\xf3\xb0\xba\xab" // U+F0EAB
+#define ICON_MDI_TEXT_BOX_REMOVE "\xf3\xb0\xba\xac" // U+F0EAC
+#define ICON_MDI_TEXT_BOX_REMOVE_OUTLINE "\xf3\xb0\xba\xad" // U+F0EAD
+#define ICON_MDI_TEXT_BOX_SEARCH "\xf3\xb0\xba\xae" // U+F0EAE
+#define ICON_MDI_TEXT_BOX_SEARCH_OUTLINE "\xf3\xb0\xba\xaf" // U+F0EAF
+#define ICON_MDI_TEXT_LONG "\xf3\xb0\xa6\xaa" // U+F09AA
+#define ICON_MDI_TEXT_RECOGNITION "\xf3\xb1\x84\xbd" // U+F113D
+#define ICON_MDI_TEXT_SEARCH "\xf3\xb1\x8e\xb8" // U+F13B8
+#define ICON_MDI_TEXT_SEARCH_VARIANT "\xf3\xb1\xa9\xbe" // U+F1A7E
+#define ICON_MDI_TEXT_SHADOW "\xf3\xb0\x99\xa9" // U+F0669
+#define ICON_MDI_TEXT_SHORT "\xf3\xb0\xa6\xa9" // U+F09A9
+#define ICON_MDI_TEXTURE "\xf3\xb0\x94\x8c" // U+F050C
+#define ICON_MDI_TEXTURE_BOX "\xf3\xb0\xbf\xa6" // U+F0FE6
+#define ICON_MDI_THEATER "\xf3\xb0\x94\x8d" // U+F050D
+#define ICON_MDI_THEME_LIGHT_DARK "\xf3\xb0\x94\x8e" // U+F050E
+#define ICON_MDI_THERMOMETER "\xf3\xb0\x94\x8f" // U+F050F
+#define ICON_MDI_THERMOMETER_ALERT "\xf3\xb0\xb8\x81" // U+F0E01
+#define ICON_MDI_THERMOMETER_AUTO "\xf3\xb1\xac\x8f" // U+F1B0F
+#define ICON_MDI_THERMOMETER_BLUETOOTH "\xf3\xb1\xa2\x95" // U+F1895
+#define ICON_MDI_THERMOMETER_CHECK "\xf3\xb1\xa9\xbf" // U+F1A7F
+#define ICON_MDI_THERMOMETER_CHEVRON_DOWN "\xf3\xb0\xb8\x82" // U+F0E02
+#define ICON_MDI_THERMOMETER_CHEVRON_UP "\xf3\xb0\xb8\x83" // U+F0E03
+#define ICON_MDI_THERMOMETER_HIGH "\xf3\xb1\x83\x82" // U+F10C2
+#define ICON_MDI_THERMOMETER_LINES "\xf3\xb0\x94\x90" // U+F0510
+#define ICON_MDI_THERMOMETER_LOW "\xf3\xb1\x83\x83" // U+F10C3
+#define ICON_MDI_THERMOMETER_MINUS "\xf3\xb0\xb8\x84" // U+F0E04
+#define ICON_MDI_THERMOMETER_OFF "\xf3\xb1\x94\xb1" // U+F1531
+#define ICON_MDI_THERMOMETER_PLUS "\xf3\xb0\xb8\x85" // U+F0E05
+#define ICON_MDI_THERMOMETER_PROBE "\xf3\xb1\xac\xab" // U+F1B2B
+#define ICON_MDI_THERMOMETER_PROBE_OFF "\xf3\xb1\xac\xac" // U+F1B2C
+#define ICON_MDI_THERMOMETER_WATER "\xf3\xb1\xaa\x80" // U+F1A80
+#define ICON_MDI_THERMOSTAT "\xf3\xb0\x8e\x93" // U+F0393
+#define ICON_MDI_THERMOSTAT_AUTO "\xf3\xb1\xac\x97" // U+F1B17
+#define ICON_MDI_THERMOSTAT_BOX "\xf3\xb0\xa2\x91" // U+F0891
+#define ICON_MDI_THERMOSTAT_BOX_AUTO "\xf3\xb1\xac\x98" // U+F1B18
+#define ICON_MDI_THERMOSTAT_COG "\xf3\xb1\xb2\x80" // U+F1C80
+#define ICON_MDI_THOUGHT_BUBBLE "\xf3\xb0\x9f\xb6" // U+F07F6
+#define ICON_MDI_THOUGHT_BUBBLE_OUTLINE "\xf3\xb0\x9f\xb7" // U+F07F7
+#define ICON_MDI_THUMB_DOWN "\xf3\xb0\x94\x91" // U+F0511
+#define ICON_MDI_THUMB_DOWN_OUTLINE "\xf3\xb0\x94\x92" // U+F0512
+#define ICON_MDI_THUMB_UP "\xf3\xb0\x94\x93" // U+F0513
+#define ICON_MDI_THUMB_UP_OUTLINE "\xf3\xb0\x94\x94" // U+F0514
+#define ICON_MDI_THUMBS_UP_DOWN "\xf3\xb0\x94\x95" // U+F0515
+#define ICON_MDI_THUMBS_UP_DOWN_OUTLINE "\xf3\xb1\xa4\x94" // U+F1914
+#define ICON_MDI_TICKET "\xf3\xb0\x94\x96" // U+F0516
+#define ICON_MDI_TICKET_ACCOUNT "\xf3\xb0\x94\x97" // U+F0517
+#define ICON_MDI_TICKET_CONFIRMATION "\xf3\xb0\x94\x98" // U+F0518
+#define ICON_MDI_TICKET_CONFIRMATION_OUTLINE "\xf3\xb1\x8e\xaa" // U+F13AA
+#define ICON_MDI_TICKET_OUTLINE "\xf3\xb0\xa4\x93" // U+F0913
+#define ICON_MDI_TICKET_PERCENT "\xf3\xb0\x9c\xa4" // U+F0724
+#define ICON_MDI_TICKET_PERCENT_OUTLINE "\xf3\xb1\x90\xab" // U+F142B
+#define ICON_MDI_TIE "\xf3\xb0\x94\x99" // U+F0519
+#define ICON_MDI_TILDE "\xf3\xb0\x9c\xa5" // U+F0725
+#define ICON_MDI_TILDE_OFF "\xf3\xb1\xa3\xb3" // U+F18F3
+#define ICON_MDI_TIMELAPSE "\xf3\xb0\x94\x9a" // U+F051A
+#define ICON_MDI_TIMELINE "\xf3\xb0\xaf\x91" // U+F0BD1
+#define ICON_MDI_TIMELINE_ALERT "\xf3\xb0\xbe\x95" // U+F0F95
+#define ICON_MDI_TIMELINE_ALERT_OUTLINE "\xf3\xb0\xbe\x98" // U+F0F98
+#define ICON_MDI_TIMELINE_CHECK "\xf3\xb1\x94\xb2" // U+F1532
+#define ICON_MDI_TIMELINE_CHECK_OUTLINE "\xf3\xb1\x94\xb3" // U+F1533
+#define ICON_MDI_TIMELINE_CLOCK "\xf3\xb1\x87\xbb" // U+F11FB
+#define ICON_MDI_TIMELINE_CLOCK_OUTLINE "\xf3\xb1\x87\xbc" // U+F11FC
+#define ICON_MDI_TIMELINE_MINUS "\xf3\xb1\x94\xb4" // U+F1534
+#define ICON_MDI_TIMELINE_MINUS_OUTLINE "\xf3\xb1\x94\xb5" // U+F1535
+#define ICON_MDI_TIMELINE_OUTLINE "\xf3\xb0\xaf\x92" // U+F0BD2
+#define ICON_MDI_TIMELINE_PLUS "\xf3\xb0\xbe\x96" // U+F0F96
+#define ICON_MDI_TIMELINE_PLUS_OUTLINE "\xf3\xb0\xbe\x97" // U+F0F97
+#define ICON_MDI_TIMELINE_QUESTION "\xf3\xb0\xbe\x99" // U+F0F99
+#define ICON_MDI_TIMELINE_QUESTION_OUTLINE "\xf3\xb0\xbe\x9a" // U+F0F9A
+#define ICON_MDI_TIMELINE_REMOVE "\xf3\xb1\x94\xb6" // U+F1536
+#define ICON_MDI_TIMELINE_REMOVE_OUTLINE "\xf3\xb1\x94\xb7" // U+F1537
+#define ICON_MDI_TIMELINE_TEXT "\xf3\xb0\xaf\x93" // U+F0BD3
+#define ICON_MDI_TIMELINE_TEXT_OUTLINE "\xf3\xb0\xaf\x94" // U+F0BD4
+#define ICON_MDI_TIMER "\xf3\xb1\x8e\xab" // U+F13AB
+#define ICON_MDI_TIMER_10 "\xf3\xb0\x94\x9c" // U+F051C
+#define ICON_MDI_TIMER_3 "\xf3\xb0\x94\x9d" // U+F051D
+#define ICON_MDI_TIMER_ALERT "\xf3\xb1\xab\x8c" // U+F1ACC
+#define ICON_MDI_TIMER_ALERT_OUTLINE "\xf3\xb1\xab\x8d" // U+F1ACD
+#define ICON_MDI_TIMER_CANCEL "\xf3\xb1\xab\x8e" // U+F1ACE
+#define ICON_MDI_TIMER_CANCEL_OUTLINE "\xf3\xb1\xab\x8f" // U+F1ACF
+#define ICON_MDI_TIMER_CHECK "\xf3\xb1\xab\x90" // U+F1AD0
+#define ICON_MDI_TIMER_CHECK_OUTLINE "\xf3\xb1\xab\x91" // U+F1AD1
+#define ICON_MDI_TIMER_COG "\xf3\xb1\xa4\xa5" // U+F1925
+#define ICON_MDI_TIMER_COG_OUTLINE "\xf3\xb1\xa4\xa6" // U+F1926
+#define ICON_MDI_TIMER_EDIT "\xf3\xb1\xab\x92" // U+F1AD2
+#define ICON_MDI_TIMER_EDIT_OUTLINE "\xf3\xb1\xab\x93" // U+F1AD3
+#define ICON_MDI_TIMER_LOCK "\xf3\xb1\xab\x94" // U+F1AD4
+#define ICON_MDI_TIMER_LOCK_OPEN "\xf3\xb1\xab\x95" // U+F1AD5
+#define ICON_MDI_TIMER_LOCK_OPEN_OUTLINE "\xf3\xb1\xab\x96" // U+F1AD6
+#define ICON_MDI_TIMER_LOCK_OUTLINE "\xf3\xb1\xab\x97" // U+F1AD7
+#define ICON_MDI_TIMER_MARKER "\xf3\xb1\xab\x98" // U+F1AD8
+#define ICON_MDI_TIMER_MARKER_OUTLINE "\xf3\xb1\xab\x99" // U+F1AD9
+#define ICON_MDI_TIMER_MINUS "\xf3\xb1\xab\x9a" // U+F1ADA
+#define ICON_MDI_TIMER_MINUS_OUTLINE "\xf3\xb1\xab\x9b" // U+F1ADB
+#define ICON_MDI_TIMER_MUSIC "\xf3\xb1\xab\x9c" // U+F1ADC
+#define ICON_MDI_TIMER_MUSIC_OUTLINE "\xf3\xb1\xab\x9d" // U+F1ADD
+#define ICON_MDI_TIMER_OFF "\xf3\xb1\x8e\xac" // U+F13AC
+#define ICON_MDI_TIMER_OFF_OUTLINE "\xf3\xb0\x94\x9e" // U+F051E
+#define ICON_MDI_TIMER_OUTLINE "\xf3\xb0\x94\x9b" // U+F051B
+#define ICON_MDI_TIMER_PAUSE "\xf3\xb1\xab\x9e" // U+F1ADE
+#define ICON_MDI_TIMER_PAUSE_OUTLINE "\xf3\xb1\xab\x9f" // U+F1ADF
+#define ICON_MDI_TIMER_PLAY "\xf3\xb1\xab\xa0" // U+F1AE0
+#define ICON_MDI_TIMER_PLAY_OUTLINE "\xf3\xb1\xab\xa1" // U+F1AE1
+#define ICON_MDI_TIMER_PLUS "\xf3\xb1\xab\xa2" // U+F1AE2
+#define ICON_MDI_TIMER_PLUS_OUTLINE "\xf3\xb1\xab\xa3" // U+F1AE3
+#define ICON_MDI_TIMER_REFRESH "\xf3\xb1\xab\xa4" // U+F1AE4
+#define ICON_MDI_TIMER_REFRESH_OUTLINE "\xf3\xb1\xab\xa5" // U+F1AE5
+#define ICON_MDI_TIMER_REMOVE "\xf3\xb1\xab\xa6" // U+F1AE6
+#define ICON_MDI_TIMER_REMOVE_OUTLINE "\xf3\xb1\xab\xa7" // U+F1AE7
+#define ICON_MDI_TIMER_SAND "\xf3\xb0\x94\x9f" // U+F051F
+#define ICON_MDI_TIMER_SAND_COMPLETE "\xf3\xb1\xa6\x9f" // U+F199F
+#define ICON_MDI_TIMER_SAND_EMPTY "\xf3\xb0\x9a\xad" // U+F06AD
+#define ICON_MDI_TIMER_SAND_FULL "\xf3\xb0\x9e\x8c" // U+F078C
+#define ICON_MDI_TIMER_SAND_PAUSED "\xf3\xb1\xa6\xa0" // U+F19A0
+#define ICON_MDI_TIMER_SETTINGS "\xf3\xb1\xa4\xa3" // U+F1923
+#define ICON_MDI_TIMER_SETTINGS_OUTLINE "\xf3\xb1\xa4\xa4" // U+F1924
+#define ICON_MDI_TIMER_STAR "\xf3\xb1\xab\xa8" // U+F1AE8
+#define ICON_MDI_TIMER_STAR_OUTLINE "\xf3\xb1\xab\xa9" // U+F1AE9
+#define ICON_MDI_TIMER_STOP "\xf3\xb1\xab\xaa" // U+F1AEA
+#define ICON_MDI_TIMER_STOP_OUTLINE "\xf3\xb1\xab\xab" // U+F1AEB
+#define ICON_MDI_TIMER_SYNC "\xf3\xb1\xab\xac" // U+F1AEC
+#define ICON_MDI_TIMER_SYNC_OUTLINE "\xf3\xb1\xab\xad" // U+F1AED
+#define ICON_MDI_TIMETABLE "\xf3\xb0\x94\xa0" // U+F0520
+#define ICON_MDI_TIRE "\xf3\xb1\xa2\x96" // U+F1896
+#define ICON_MDI_TOASTER "\xf3\xb1\x81\xa3" // U+F1063
+#define ICON_MDI_TOASTER_OFF "\xf3\xb1\x86\xb7" // U+F11B7
+#define ICON_MDI_TOASTER_OVEN "\xf3\xb0\xb3\x93" // U+F0CD3
+#define ICON_MDI_TOGGLE_SWITCH "\xf3\xb0\x94\xa1" // U+F0521
+#define ICON_MDI_TOGGLE_SWITCH_OFF "\xf3\xb0\x94\xa2" // U+F0522
+#define ICON_MDI_TOGGLE_SWITCH_OFF_OUTLINE "\xf3\xb0\xa8\x99" // U+F0A19
+#define ICON_MDI_TOGGLE_SWITCH_OUTLINE "\xf3\xb0\xa8\x9a" // U+F0A1A
+#define ICON_MDI_TOGGLE_SWITCH_VARIANT "\xf3\xb1\xa8\xa5" // U+F1A25
+#define ICON_MDI_TOGGLE_SWITCH_VARIANT_OFF "\xf3\xb1\xa8\xa6" // U+F1A26
+#define ICON_MDI_TOILET "\xf3\xb0\xa6\xab" // U+F09AB
+#define ICON_MDI_TOOLBOX "\xf3\xb0\xa6\xac" // U+F09AC
+#define ICON_MDI_TOOLBOX_OUTLINE "\xf3\xb0\xa6\xad" // U+F09AD
+#define ICON_MDI_TOOLS "\xf3\xb1\x81\xa4" // U+F1064
+#define ICON_MDI_TOOLTIP "\xf3\xb0\x94\xa3" // U+F0523
+#define ICON_MDI_TOOLTIP_ACCOUNT "\xf3\xb0\x80\x8c" // U+F000C
+#define ICON_MDI_TOOLTIP_CELLPHONE "\xf3\xb1\xa0\xbb" // U+F183B
+#define ICON_MDI_TOOLTIP_CHECK "\xf3\xb1\x95\x9c" // U+F155C
+#define ICON_MDI_TOOLTIP_CHECK_OUTLINE "\xf3\xb1\x95\x9d" // U+F155D
+#define ICON_MDI_TOOLTIP_EDIT "\xf3\xb0\x94\xa4" // U+F0524
+#define ICON_MDI_TOOLTIP_EDIT_OUTLINE "\xf3\xb1\x8b\x85" // U+F12C5
+#define ICON_MDI_TOOLTIP_IMAGE "\xf3\xb0\x94\xa5" // U+F0525
+#define ICON_MDI_TOOLTIP_IMAGE_OUTLINE "\xf3\xb0\xaf\x95" // U+F0BD5
+#define ICON_MDI_TOOLTIP_MINUS "\xf3\xb1\x95\x9e" // U+F155E
+#define ICON_MDI_TOOLTIP_MINUS_OUTLINE "\xf3\xb1\x95\x9f" // U+F155F
+#define ICON_MDI_TOOLTIP_OUTLINE "\xf3\xb0\x94\xa6" // U+F0526
+#define ICON_MDI_TOOLTIP_PLUS "\xf3\xb0\xaf\x96" // U+F0BD6
+#define ICON_MDI_TOOLTIP_PLUS_OUTLINE "\xf3\xb0\x94\xa7" // U+F0527
+#define ICON_MDI_TOOLTIP_QUESTION "\xf3\xb1\xae\xba" // U+F1BBA
+#define ICON_MDI_TOOLTIP_QUESTION_OUTLINE "\xf3\xb1\xae\xbb" // U+F1BBB
+#define ICON_MDI_TOOLTIP_REMOVE "\xf3\xb1\x95\xa0" // U+F1560
+#define ICON_MDI_TOOLTIP_REMOVE_OUTLINE "\xf3\xb1\x95\xa1" // U+F1561
+#define ICON_MDI_TOOLTIP_TEXT "\xf3\xb0\x94\xa8" // U+F0528
+#define ICON_MDI_TOOLTIP_TEXT_OUTLINE "\xf3\xb0\xaf\x97" // U+F0BD7
+#define ICON_MDI_TOOTH "\xf3\xb0\xa3\x83" // U+F08C3
+#define ICON_MDI_TOOTH_OUTLINE "\xf3\xb0\x94\xa9" // U+F0529
+#define ICON_MDI_TOOTHBRUSH "\xf3\xb1\x84\xa9" // U+F1129
+#define ICON_MDI_TOOTHBRUSH_ELECTRIC "\xf3\xb1\x84\xac" // U+F112C
+#define ICON_MDI_TOOTHBRUSH_PASTE "\xf3\xb1\x84\xaa" // U+F112A
+#define ICON_MDI_TORCH "\xf3\xb1\x98\x86" // U+F1606
+#define ICON_MDI_TORTOISE "\xf3\xb0\xb4\xbb" // U+F0D3B
+#define ICON_MDI_TOSLINK "\xf3\xb1\x8a\xb8" // U+F12B8
+#define ICON_MDI_TOUCH_TEXT_OUTLINE "\xf3\xb1\xb1\xa0" // U+F1C60
+#define ICON_MDI_TOURNAMENT "\xf3\xb0\xa6\xae" // U+F09AE
+#define ICON_MDI_TOW_TRUCK "\xf3\xb0\xa0\xbc" // U+F083C
+#define ICON_MDI_TOWER_BEACH "\xf3\xb0\x9a\x81" // U+F0681
+#define ICON_MDI_TOWER_FIRE "\xf3\xb0\x9a\x82" // U+F0682
+#define ICON_MDI_TOWN_HALL "\xf3\xb1\xa1\xb5" // U+F1875
+#define ICON_MDI_TOY_BRICK "\xf3\xb1\x8a\x88" // U+F1288
+#define ICON_MDI_TOY_BRICK_MARKER "\xf3\xb1\x8a\x89" // U+F1289
+#define ICON_MDI_TOY_BRICK_MARKER_OUTLINE "\xf3\xb1\x8a\x8a" // U+F128A
+#define ICON_MDI_TOY_BRICK_MINUS "\xf3\xb1\x8a\x8b" // U+F128B
+#define ICON_MDI_TOY_BRICK_MINUS_OUTLINE "\xf3\xb1\x8a\x8c" // U+F128C
+#define ICON_MDI_TOY_BRICK_OUTLINE "\xf3\xb1\x8a\x8d" // U+F128D
+#define ICON_MDI_TOY_BRICK_PLUS "\xf3\xb1\x8a\x8e" // U+F128E
+#define ICON_MDI_TOY_BRICK_PLUS_OUTLINE "\xf3\xb1\x8a\x8f" // U+F128F
+#define ICON_MDI_TOY_BRICK_REMOVE "\xf3\xb1\x8a\x90" // U+F1290
+#define ICON_MDI_TOY_BRICK_REMOVE_OUTLINE "\xf3\xb1\x8a\x91" // U+F1291
+#define ICON_MDI_TOY_BRICK_SEARCH "\xf3\xb1\x8a\x92" // U+F1292
+#define ICON_MDI_TOY_BRICK_SEARCH_OUTLINE "\xf3\xb1\x8a\x93" // U+F1293
+#define ICON_MDI_TRACK_LIGHT "\xf3\xb0\xa4\x94" // U+F0914
+#define ICON_MDI_TRACK_LIGHT_OFF "\xf3\xb1\xac\x81" // U+F1B01
+#define ICON_MDI_TRACKPAD "\xf3\xb0\x9f\xb8" // U+F07F8
+#define ICON_MDI_TRACKPAD_LOCK "\xf3\xb0\xa4\xb3" // U+F0933
+#define ICON_MDI_TRACTOR "\xf3\xb0\xa2\x92" // U+F0892
+#define ICON_MDI_TRACTOR_VARIANT "\xf3\xb1\x93\x84" // U+F14C4
+#define ICON_MDI_TRADEMARK "\xf3\xb0\xa9\xb8" // U+F0A78
+#define ICON_MDI_TRAFFIC_CONE "\xf3\xb1\x8d\xbc" // U+F137C
+#define ICON_MDI_TRAFFIC_LIGHT "\xf3\xb0\x94\xab" // U+F052B
+#define ICON_MDI_TRAFFIC_LIGHT_OUTLINE "\xf3\xb1\xa0\xaa" // U+F182A
+#define ICON_MDI_TRAIN "\xf3\xb0\x94\xac" // U+F052C
+#define ICON_MDI_TRAIN_BUS "\xf3\xb1\xb3\x87" // U+F1CC7
+#define ICON_MDI_TRAIN_CAR "\xf3\xb0\xaf\x98" // U+F0BD8
+#define ICON_MDI_TRAIN_CAR_AUTORACK "\xf3\xb1\xac\xad" // U+F1B2D
+#define ICON_MDI_TRAIN_CAR_BOX "\xf3\xb1\xac\xae" // U+F1B2E
+#define ICON_MDI_TRAIN_CAR_BOX_FULL "\xf3\xb1\xac\xaf" // U+F1B2F
+#define ICON_MDI_TRAIN_CAR_BOX_OPEN "\xf3\xb1\xac\xb0" // U+F1B30
+#define ICON_MDI_TRAIN_CAR_CABOOSE "\xf3\xb1\xac\xb1" // U+F1B31
+#define ICON_MDI_TRAIN_CAR_CENTERBEAM "\xf3\xb1\xac\xb2" // U+F1B32
+#define ICON_MDI_TRAIN_CAR_CENTERBEAM_FULL "\xf3\xb1\xac\xb3" // U+F1B33
+#define ICON_MDI_TRAIN_CAR_CONTAINER "\xf3\xb1\xac\xb4" // U+F1B34
+#define ICON_MDI_TRAIN_CAR_FLATBED "\xf3\xb1\xac\xb5" // U+F1B35
+#define ICON_MDI_TRAIN_CAR_FLATBED_CAR "\xf3\xb1\xac\xb6" // U+F1B36
+#define ICON_MDI_TRAIN_CAR_FLATBED_TANK "\xf3\xb1\xac\xb7" // U+F1B37
+#define ICON_MDI_TRAIN_CAR_GONDOLA "\xf3\xb1\xac\xb8" // U+F1B38
+#define ICON_MDI_TRAIN_CAR_GONDOLA_FULL "\xf3\xb1\xac\xb9" // U+F1B39
+#define ICON_MDI_TRAIN_CAR_HOPPER "\xf3\xb1\xac\xba" // U+F1B3A
+#define ICON_MDI_TRAIN_CAR_HOPPER_COVERED "\xf3\xb1\xac\xbb" // U+F1B3B
+#define ICON_MDI_TRAIN_CAR_HOPPER_FULL "\xf3\xb1\xac\xbc" // U+F1B3C
+#define ICON_MDI_TRAIN_CAR_INTERMODAL "\xf3\xb1\xac\xbd" // U+F1B3D
+#define ICON_MDI_TRAIN_CAR_PASSENGER "\xf3\xb1\x9c\xb3" // U+F1733
+#define ICON_MDI_TRAIN_CAR_PASSENGER_DOOR "\xf3\xb1\x9c\xb4" // U+F1734
+#define ICON_MDI_TRAIN_CAR_PASSENGER_DOOR_OPEN "\xf3\xb1\x9c\xb5" // U+F1735
+#define ICON_MDI_TRAIN_CAR_PASSENGER_VARIANT "\xf3\xb1\x9c\xb6" // U+F1736
+#define ICON_MDI_TRAIN_CAR_TANK "\xf3\xb1\xac\xbe" // U+F1B3E
+#define ICON_MDI_TRAIN_VARIANT "\xf3\xb0\xa3\x84" // U+F08C4
+#define ICON_MDI_TRAM "\xf3\xb0\x94\xad" // U+F052D
+#define ICON_MDI_TRAM_SIDE "\xf3\xb0\xbf\xa7" // U+F0FE7
+#define ICON_MDI_TRANSCRIBE "\xf3\xb0\x94\xae" // U+F052E
+#define ICON_MDI_TRANSCRIBE_CLOSE "\xf3\xb0\x94\xaf" // U+F052F
+#define ICON_MDI_TRANSFER "\xf3\xb1\x81\xa5" // U+F1065
+#define ICON_MDI_TRANSFER_DOWN "\xf3\xb0\xb6\xa1" // U+F0DA1
+#define ICON_MDI_TRANSFER_LEFT "\xf3\xb0\xb6\xa2" // U+F0DA2
+#define ICON_MDI_TRANSFER_RIGHT "\xf3\xb0\x94\xb0" // U+F0530
+#define ICON_MDI_TRANSFER_UP "\xf3\xb0\xb6\xa3" // U+F0DA3
+#define ICON_MDI_TRANSIT_CONNECTION "\xf3\xb0\xb4\xbc" // U+F0D3C
+#define ICON_MDI_TRANSIT_CONNECTION_HORIZONTAL "\xf3\xb1\x95\x86" // U+F1546
+#define ICON_MDI_TRANSIT_CONNECTION_VARIANT "\xf3\xb0\xb4\xbd" // U+F0D3D
+#define ICON_MDI_TRANSIT_DETOUR "\xf3\xb0\xbe\x8b" // U+F0F8B
+#define ICON_MDI_TRANSIT_SKIP "\xf3\xb1\x94\x95" // U+F1515
+#define ICON_MDI_TRANSIT_TRANSFER "\xf3\xb0\x9a\xae" // U+F06AE
+#define ICON_MDI_TRANSITION "\xf3\xb0\xa4\x95" // U+F0915
+#define ICON_MDI_TRANSITION_MASKED "\xf3\xb0\xa4\x96" // U+F0916
+#define ICON_MDI_TRANSLATE "\xf3\xb0\x97\x8a" // U+F05CA
+#define ICON_MDI_TRANSLATE_OFF "\xf3\xb0\xb8\x86" // U+F0E06
+#define ICON_MDI_TRANSLATE_VARIANT "\xf3\xb1\xae\x99" // U+F1B99
+#define ICON_MDI_TRANSMISSION_TOWER "\xf3\xb0\xb4\xbe" // U+F0D3E
+#define ICON_MDI_TRANSMISSION_TOWER_EXPORT "\xf3\xb1\xa4\xac" // U+F192C
+#define ICON_MDI_TRANSMISSION_TOWER_IMPORT "\xf3\xb1\xa4\xad" // U+F192D
+#define ICON_MDI_TRANSMISSION_TOWER_OFF "\xf3\xb1\xa7\x9d" // U+F19DD
+#define ICON_MDI_TRASH_CAN "\xf3\xb0\xa9\xb9" // U+F0A79
+#define ICON_MDI_TRASH_CAN_OUTLINE "\xf3\xb0\xa9\xba" // U+F0A7A
+#define ICON_MDI_TRAY "\xf3\xb1\x8a\x94" // U+F1294
+#define ICON_MDI_TRAY_ALERT "\xf3\xb1\x8a\x95" // U+F1295
+#define ICON_MDI_TRAY_ARROW_DOWN "\xf3\xb0\x84\xa0" // U+F0120
+#define ICON_MDI_TRAY_ARROW_UP "\xf3\xb0\x84\x9d" // U+F011D
+#define ICON_MDI_TRAY_FULL "\xf3\xb1\x8a\x96" // U+F1296
+#define ICON_MDI_TRAY_MINUS "\xf3\xb1\x8a\x97" // U+F1297
+#define ICON_MDI_TRAY_PLUS "\xf3\xb1\x8a\x98" // U+F1298
+#define ICON_MDI_TRAY_REMOVE "\xf3\xb1\x8a\x99" // U+F1299
+#define ICON_MDI_TREASURE_CHEST "\xf3\xb0\x9c\xa6" // U+F0726
+#define ICON_MDI_TREASURE_CHEST_OUTLINE "\xf3\xb1\xb1\xb7" // U+F1C77
+#define ICON_MDI_TREE "\xf3\xb0\x94\xb1" // U+F0531
+#define ICON_MDI_TREE_OUTLINE "\xf3\xb0\xb9\xa9" // U+F0E69
+#define ICON_MDI_TRELLO "\xf3\xb0\x94\xb2" // U+F0532
+#define ICON_MDI_TRENDING_DOWN "\xf3\xb0\x94\xb3" // U+F0533
+#define ICON_MDI_TRENDING_NEUTRAL "\xf3\xb0\x94\xb4" // U+F0534
+#define ICON_MDI_TRENDING_UP "\xf3\xb0\x94\xb5" // U+F0535
+#define ICON_MDI_TRIANGLE "\xf3\xb0\x94\xb6" // U+F0536
+#define ICON_MDI_TRIANGLE_DOWN "\xf3\xb1\xb1\x96" // U+F1C56
+#define ICON_MDI_TRIANGLE_DOWN_OUTLINE "\xf3\xb1\xb1\x97" // U+F1C57
+#define ICON_MDI_TRIANGLE_OUTLINE "\xf3\xb0\x94\xb7" // U+F0537
+#define ICON_MDI_TRIANGLE_SMALL_DOWN "\xf3\xb1\xa8\x89" // U+F1A09
+#define ICON_MDI_TRIANGLE_SMALL_UP "\xf3\xb1\xa8\x8a" // U+F1A0A
+#define ICON_MDI_TRIANGLE_WAVE "\xf3\xb1\x91\xbc" // U+F147C
+#define ICON_MDI_TRIFORCE "\xf3\xb0\xaf\x99" // U+F0BD9
+#define ICON_MDI_TROPHY "\xf3\xb0\x94\xb8" // U+F0538
+#define ICON_MDI_TROPHY_AWARD "\xf3\xb0\x94\xb9" // U+F0539
+#define ICON_MDI_TROPHY_BROKEN "\xf3\xb0\xb6\xa4" // U+F0DA4
+#define ICON_MDI_TROPHY_OUTLINE "\xf3\xb0\x94\xba" // U+F053A
+#define ICON_MDI_TROPHY_VARIANT "\xf3\xb0\x94\xbb" // U+F053B
+#define ICON_MDI_TROPHY_VARIANT_OUTLINE "\xf3\xb0\x94\xbc" // U+F053C
+#define ICON_MDI_TRUCK "\xf3\xb0\x94\xbd" // U+F053D
+#define ICON_MDI_TRUCK_ALERT "\xf3\xb1\xa7\x9e" // U+F19DE
+#define ICON_MDI_TRUCK_ALERT_OUTLINE "\xf3\xb1\xa7\x9f" // U+F19DF
+#define ICON_MDI_TRUCK_CARGO_CONTAINER "\xf3\xb1\xa3\x98" // U+F18D8
+#define ICON_MDI_TRUCK_CHECK "\xf3\xb0\xb3\x94" // U+F0CD4
+#define ICON_MDI_TRUCK_CHECK_OUTLINE "\xf3\xb1\x8a\x9a" // U+F129A
+#define ICON_MDI_TRUCK_DELIVERY "\xf3\xb0\x94\xbe" // U+F053E
+#define ICON_MDI_TRUCK_DELIVERY_OUTLINE "\xf3\xb1\x8a\x9b" // U+F129B
+#define ICON_MDI_TRUCK_FAST "\xf3\xb0\x9e\x88" // U+F0788
+#define ICON_MDI_TRUCK_FAST_OUTLINE "\xf3\xb1\x8a\x9c" // U+F129C
+#define ICON_MDI_TRUCK_FLATBED "\xf3\xb1\xa2\x91" // U+F1891
+#define ICON_MDI_TRUCK_MINUS "\xf3\xb1\xa6\xae" // U+F19AE
+#define ICON_MDI_TRUCK_MINUS_OUTLINE "\xf3\xb1\xa6\xbd" // U+F19BD
+#define ICON_MDI_TRUCK_OFF_ROAD "\xf3\xb1\xb2\x9e" // U+F1C9E
+#define ICON_MDI_TRUCK_OFF_ROAD_OFF "\xf3\xb1\xb2\x9f" // U+F1C9F
+#define ICON_MDI_TRUCK_OUTLINE "\xf3\xb1\x8a\x9d" // U+F129D
+#define ICON_MDI_TRUCK_PLUS "\xf3\xb1\xa6\xad" // U+F19AD
+#define ICON_MDI_TRUCK_PLUS_OUTLINE "\xf3\xb1\xa6\xbc" // U+F19BC
+#define ICON_MDI_TRUCK_REMOVE "\xf3\xb1\xa6\xaf" // U+F19AF
+#define ICON_MDI_TRUCK_REMOVE_OUTLINE "\xf3\xb1\xa6\xbe" // U+F19BE
+#define ICON_MDI_TRUCK_SNOWFLAKE "\xf3\xb1\xa6\xa6" // U+F19A6
+#define ICON_MDI_TRUCK_TRAILER "\xf3\xb0\x9c\xa7" // U+F0727
+#define ICON_MDI_TRUMPET "\xf3\xb1\x82\x96" // U+F1096
+#define ICON_MDI_TSHIRT_CREW "\xf3\xb0\xa9\xbb" // U+F0A7B
+#define ICON_MDI_TSHIRT_CREW_OUTLINE "\xf3\xb0\x94\xbf" // U+F053F
+#define ICON_MDI_TSHIRT_V "\xf3\xb0\xa9\xbc" // U+F0A7C
+#define ICON_MDI_TSHIRT_V_OUTLINE "\xf3\xb0\x95\x80" // U+F0540
+#define ICON_MDI_TSUNAMI "\xf3\xb1\xaa\x81" // U+F1A81
+#define ICON_MDI_TUMBLE_DRYER "\xf3\xb0\xa4\x97" // U+F0917
+#define ICON_MDI_TUMBLE_DRYER_ALERT "\xf3\xb1\x86\xba" // U+F11BA
+#define ICON_MDI_TUMBLE_DRYER_OFF "\xf3\xb1\x86\xbb" // U+F11BB
+#define ICON_MDI_TUNE "\xf3\xb0\x98\xae" // U+F062E
+#define ICON_MDI_TUNE_VARIANT "\xf3\xb1\x95\x82" // U+F1542
+#define ICON_MDI_TUNE_VERTICAL "\xf3\xb0\x99\xaa" // U+F066A
+#define ICON_MDI_TUNE_VERTICAL_VARIANT "\xf3\xb1\x95\x83" // U+F1543
+#define ICON_MDI_TUNNEL "\xf3\xb1\xa0\xbd" // U+F183D
+#define ICON_MDI_TUNNEL_OUTLINE "\xf3\xb1\xa0\xbe" // U+F183E
+#define ICON_MDI_TURBINE "\xf3\xb1\xaa\x82" // U+F1A82
+#define ICON_MDI_TURKEY "\xf3\xb1\x9c\x9b" // U+F171B
+#define ICON_MDI_TURNSTILE "\xf3\xb0\xb3\x95" // U+F0CD5
+#define ICON_MDI_TURNSTILE_OUTLINE "\xf3\xb0\xb3\x96" // U+F0CD6
+#define ICON_MDI_TURTLE "\xf3\xb0\xb3\x97" // U+F0CD7
+#define ICON_MDI_TWITCH "\xf3\xb0\x95\x83" // U+F0543
+#define ICON_MDI_TWITTER "\xf3\xb0\x95\x84" // U+F0544
+#define ICON_MDI_TWO_FACTOR_AUTHENTICATION "\xf3\xb0\xa6\xaf" // U+F09AF
+#define ICON_MDI_TYPEWRITER "\xf3\xb0\xbc\xad" // U+F0F2D
+#define ICON_MDI_UBISOFT "\xf3\xb0\xaf\x9a" // U+F0BDA
+#define ICON_MDI_UBUNTU "\xf3\xb0\x95\x88" // U+F0548
+#define ICON_MDI_UFO "\xf3\xb1\x83\x84" // U+F10C4
+#define ICON_MDI_UFO_OUTLINE "\xf3\xb1\x83\x85" // U+F10C5
+#define ICON_MDI_ULTRA_HIGH_DEFINITION "\xf3\xb0\x9f\xb9" // U+F07F9
+#define ICON_MDI_UMBRACO "\xf3\xb0\x95\x89" // U+F0549
+#define ICON_MDI_UMBRELLA "\xf3\xb0\x95\x8a" // U+F054A
+#define ICON_MDI_UMBRELLA_BEACH "\xf3\xb1\xa2\x8a" // U+F188A
+#define ICON_MDI_UMBRELLA_BEACH_OUTLINE "\xf3\xb1\xa2\x8b" // U+F188B
+#define ICON_MDI_UMBRELLA_CLOSED "\xf3\xb0\xa6\xb0" // U+F09B0
+#define ICON_MDI_UMBRELLA_CLOSED_OUTLINE "\xf3\xb1\x8f\xa2" // U+F13E2
+#define ICON_MDI_UMBRELLA_CLOSED_VARIANT "\xf3\xb1\x8f\xa1" // U+F13E1
+#define ICON_MDI_UMBRELLA_OUTLINE "\xf3\xb0\x95\x8b" // U+F054B
+#define ICON_MDI_UNDO "\xf3\xb0\x95\x8c" // U+F054C
+#define ICON_MDI_UNDO_VARIANT "\xf3\xb0\x95\x8d" // U+F054D
+#define ICON_MDI_UNFOLD_LESS_HORIZONTAL "\xf3\xb0\x95\x8e" // U+F054E
+#define ICON_MDI_UNFOLD_LESS_VERTICAL "\xf3\xb0\x9d\xa0" // U+F0760
+#define ICON_MDI_UNFOLD_MORE_HORIZONTAL "\xf3\xb0\x95\x8f" // U+F054F
+#define ICON_MDI_UNFOLD_MORE_VERTICAL "\xf3\xb0\x9d\xa1" // U+F0761
+#define ICON_MDI_UNGROUP "\xf3\xb0\x95\x90" // U+F0550
+#define ICON_MDI_UNICODE "\xf3\xb0\xbb\x90" // U+F0ED0
+#define ICON_MDI_UNICORN "\xf3\xb1\x97\x82" // U+F15C2
+#define ICON_MDI_UNICORN_VARIANT "\xf3\xb1\x97\x83" // U+F15C3
+#define ICON_MDI_UNICYCLE "\xf3\xb1\x97\xa5" // U+F15E5
+#define ICON_MDI_UNITY "\xf3\xb0\x9a\xaf" // U+F06AF
+#define ICON_MDI_UNREAL "\xf3\xb0\xa6\xb1" // U+F09B1
+#define ICON_MDI_UPDATE "\xf3\xb0\x9a\xb0" // U+F06B0
+#define ICON_MDI_UPLOAD "\xf3\xb0\x95\x92" // U+F0552
+#define ICON_MDI_UPLOAD_LOCK "\xf3\xb1\x8d\xb3" // U+F1373
+#define ICON_MDI_UPLOAD_LOCK_OUTLINE "\xf3\xb1\x8d\xb4" // U+F1374
+#define ICON_MDI_UPLOAD_MULTIPLE "\xf3\xb0\xa0\xbd" // U+F083D
+#define ICON_MDI_UPLOAD_NETWORK "\xf3\xb0\x9b\xb6" // U+F06F6
+#define ICON_MDI_UPLOAD_NETWORK_OUTLINE "\xf3\xb0\xb3\x98" // U+F0CD8
+#define ICON_MDI_UPLOAD_OFF "\xf3\xb1\x83\x86" // U+F10C6
+#define ICON_MDI_UPLOAD_OFF_OUTLINE "\xf3\xb1\x83\x87" // U+F10C7
+#define ICON_MDI_UPLOAD_OUTLINE "\xf3\xb0\xb8\x87" // U+F0E07
+#define ICON_MDI_USB "\xf3\xb0\x95\x93" // U+F0553
+#define ICON_MDI_USB_C_PORT "\xf3\xb1\xb2\xbf" // U+F1CBF
+#define ICON_MDI_USB_FLASH_DRIVE "\xf3\xb1\x8a\x9e" // U+F129E
+#define ICON_MDI_USB_FLASH_DRIVE_OUTLINE "\xf3\xb1\x8a\x9f" // U+F129F
+#define ICON_MDI_USB_PORT "\xf3\xb1\x87\xb0" // U+F11F0
+#define ICON_MDI_VACUUM "\xf3\xb1\xa6\xa1" // U+F19A1
+#define ICON_MDI_VACUUM_OUTLINE "\xf3\xb1\xa6\xa2" // U+F19A2
+#define ICON_MDI_VALVE "\xf3\xb1\x81\xa6" // U+F1066
+#define ICON_MDI_VALVE_CLOSED "\xf3\xb1\x81\xa7" // U+F1067
+#define ICON_MDI_VALVE_OPEN "\xf3\xb1\x81\xa8" // U+F1068
+#define ICON_MDI_VAN_PASSENGER "\xf3\xb0\x9f\xba" // U+F07FA
+#define ICON_MDI_VAN_UTILITY "\xf3\xb0\x9f\xbb" // U+F07FB
+#define ICON_MDI_VANISH "\xf3\xb0\x9f\xbc" // U+F07FC
+#define ICON_MDI_VANISH_QUARTER "\xf3\xb1\x95\x94" // U+F1554
+#define ICON_MDI_VANITY_LIGHT "\xf3\xb1\x87\xa1" // U+F11E1
+#define ICON_MDI_VARIABLE "\xf3\xb0\xab\xa7" // U+F0AE7
+#define ICON_MDI_VARIABLE_BOX "\xf3\xb1\x84\x91" // U+F1111
+#define ICON_MDI_VECTOR_ARRANGE_ABOVE "\xf3\xb0\x95\x94" // U+F0554
+#define ICON_MDI_VECTOR_ARRANGE_BELOW "\xf3\xb0\x95\x95" // U+F0555
+#define ICON_MDI_VECTOR_BEZIER "\xf3\xb0\xab\xa8" // U+F0AE8
+#define ICON_MDI_VECTOR_CIRCLE "\xf3\xb0\x95\x96" // U+F0556
+#define ICON_MDI_VECTOR_CIRCLE_VARIANT "\xf3\xb0\x95\x97" // U+F0557
+#define ICON_MDI_VECTOR_COMBINE "\xf3\xb0\x95\x98" // U+F0558
+#define ICON_MDI_VECTOR_CURVE "\xf3\xb0\x95\x99" // U+F0559
+#define ICON_MDI_VECTOR_DIFFERENCE "\xf3\xb0\x95\x9a" // U+F055A
+#define ICON_MDI_VECTOR_DIFFERENCE_AB "\xf3\xb0\x95\x9b" // U+F055B
+#define ICON_MDI_VECTOR_DIFFERENCE_BA "\xf3\xb0\x95\x9c" // U+F055C
+#define ICON_MDI_VECTOR_ELLIPSE "\xf3\xb0\xa2\x93" // U+F0893
+#define ICON_MDI_VECTOR_INTERSECTION "\xf3\xb0\x95\x9d" // U+F055D
+#define ICON_MDI_VECTOR_LINE "\xf3\xb0\x95\x9e" // U+F055E
+#define ICON_MDI_VECTOR_LINK "\xf3\xb0\xbf\xa8" // U+F0FE8
+#define ICON_MDI_VECTOR_POINT "\xf3\xb0\x87\x84" // U+F01C4
+#define ICON_MDI_VECTOR_POINT_EDIT "\xf3\xb0\xa7\xa8" // U+F09E8
+#define ICON_MDI_VECTOR_POINT_MINUS "\xf3\xb1\xad\xb8" // U+F1B78
+#define ICON_MDI_VECTOR_POINT_PLUS "\xf3\xb1\xad\xb9" // U+F1B79
+#define ICON_MDI_VECTOR_POINT_SELECT "\xf3\xb0\x95\x9f" // U+F055F
+#define ICON_MDI_VECTOR_POLYGON "\xf3\xb0\x95\xa0" // U+F0560
+#define ICON_MDI_VECTOR_POLYGON_VARIANT "\xf3\xb1\xa1\x96" // U+F1856
+#define ICON_MDI_VECTOR_POLYLINE "\xf3\xb0\x95\xa1" // U+F0561
+#define ICON_MDI_VECTOR_POLYLINE_EDIT "\xf3\xb1\x88\xa5" // U+F1225
+#define ICON_MDI_VECTOR_POLYLINE_MINUS "\xf3\xb1\x88\xa6" // U+F1226
+#define ICON_MDI_VECTOR_POLYLINE_PLUS "\xf3\xb1\x88\xa7" // U+F1227
+#define ICON_MDI_VECTOR_POLYLINE_REMOVE "\xf3\xb1\x88\xa8" // U+F1228
+#define ICON_MDI_VECTOR_RADIUS "\xf3\xb0\x9d\x8a" // U+F074A
+#define ICON_MDI_VECTOR_RECTANGLE "\xf3\xb0\x97\x86" // U+F05C6
+#define ICON_MDI_VECTOR_SELECTION "\xf3\xb0\x95\xa2" // U+F0562
+#define ICON_MDI_VECTOR_SQUARE "\xf3\xb0\x80\x81" // U+F0001
+#define ICON_MDI_VECTOR_SQUARE_CLOSE "\xf3\xb1\xa1\x97" // U+F1857
+#define ICON_MDI_VECTOR_SQUARE_EDIT "\xf3\xb1\xa3\x99" // U+F18D9
+#define ICON_MDI_VECTOR_SQUARE_MINUS "\xf3\xb1\xa3\x9a" // U+F18DA
+#define ICON_MDI_VECTOR_SQUARE_OPEN "\xf3\xb1\xa1\x98" // U+F1858
+#define ICON_MDI_VECTOR_SQUARE_PLUS "\xf3\xb1\xa3\x9b" // U+F18DB
+#define ICON_MDI_VECTOR_SQUARE_REMOVE "\xf3\xb1\xa3\x9c" // U+F18DC
+#define ICON_MDI_VECTOR_TRIANGLE "\xf3\xb0\x95\xa3" // U+F0563
+#define ICON_MDI_VECTOR_UNION "\xf3\xb0\x95\xa4" // U+F0564
+#define ICON_MDI_VHS "\xf3\xb0\xa8\x9b" // U+F0A1B
+#define ICON_MDI_VIBRATE "\xf3\xb0\x95\xa6" // U+F0566
+#define ICON_MDI_VIBRATE_OFF "\xf3\xb0\xb3\x99" // U+F0CD9
+#define ICON_MDI_VIDEO "\xf3\xb0\x95\xa7" // U+F0567
+#define ICON_MDI_VIDEO_2D "\xf3\xb1\xa8\x9c" // U+F1A1C
+#define ICON_MDI_VIDEO_3D "\xf3\xb0\x9f\xbd" // U+F07FD
+#define ICON_MDI_VIDEO_3D_OFF "\xf3\xb1\x8f\x99" // U+F13D9
+#define ICON_MDI_VIDEO_3D_VARIANT "\xf3\xb0\xbb\x91" // U+F0ED1
+#define ICON_MDI_VIDEO_4K_BOX "\xf3\xb0\xa0\xbe" // U+F083E
+#define ICON_MDI_VIDEO_ACCOUNT "\xf3\xb0\xa4\x99" // U+F0919
+#define ICON_MDI_VIDEO_BOX "\xf3\xb0\x83\xbd" // U+F00FD
+#define ICON_MDI_VIDEO_BOX_OFF "\xf3\xb0\x83\xbe" // U+F00FE
+#define ICON_MDI_VIDEO_CHECK "\xf3\xb1\x81\xa9" // U+F1069
+#define ICON_MDI_VIDEO_CHECK_OUTLINE "\xf3\xb1\x81\xaa" // U+F106A
+#define ICON_MDI_VIDEO_HIGH_DEFINITION "\xf3\xb1\x94\xae" // U+F152E
+#define ICON_MDI_VIDEO_IMAGE "\xf3\xb0\xa4\x9a" // U+F091A
+#define ICON_MDI_VIDEO_INPUT_ANTENNA "\xf3\xb0\xa0\xbf" // U+F083F
+#define ICON_MDI_VIDEO_INPUT_COMPONENT "\xf3\xb0\xa1\x80" // U+F0840
+#define ICON_MDI_VIDEO_INPUT_HDMI "\xf3\xb0\xa1\x81" // U+F0841
+#define ICON_MDI_VIDEO_INPUT_SCART "\xf3\xb0\xbe\x8c" // U+F0F8C
+#define ICON_MDI_VIDEO_INPUT_SVIDEO "\xf3\xb0\xa1\x82" // U+F0842
+#define ICON_MDI_VIDEO_MARKER "\xf3\xb1\xa6\xa9" // U+F19A9
+#define ICON_MDI_VIDEO_MARKER_OUTLINE "\xf3\xb1\xa6\xaa" // U+F19AA
+#define ICON_MDI_VIDEO_MINUS "\xf3\xb0\xa6\xb2" // U+F09B2
+#define ICON_MDI_VIDEO_MINUS_OUTLINE "\xf3\xb0\x8a\xba" // U+F02BA
+#define ICON_MDI_VIDEO_OFF "\xf3\xb0\x95\xa8" // U+F0568
+#define ICON_MDI_VIDEO_OFF_OUTLINE "\xf3\xb0\xaf\x9b" // U+F0BDB
+#define ICON_MDI_VIDEO_OUTLINE "\xf3\xb0\xaf\x9c" // U+F0BDC
+#define ICON_MDI_VIDEO_PLUS "\xf3\xb0\xa6\xb3" // U+F09B3
+#define ICON_MDI_VIDEO_PLUS_OUTLINE "\xf3\xb0\x87\x93" // U+F01D3
+#define ICON_MDI_VIDEO_STABILIZATION "\xf3\xb0\xa4\x9b" // U+F091B
+#define ICON_MDI_VIDEO_STANDARD_DEFINITION "\xf3\xb1\xb2\xa0" // U+F1CA0
+#define ICON_MDI_VIDEO_SWITCH "\xf3\xb0\x95\xa9" // U+F0569
+#define ICON_MDI_VIDEO_SWITCH_OUTLINE "\xf3\xb0\x9e\x90" // U+F0790
+#define ICON_MDI_VIDEO_VINTAGE "\xf3\xb0\xa8\x9c" // U+F0A1C
+#define ICON_MDI_VIDEO_WIRELESS "\xf3\xb0\xbb\x92" // U+F0ED2
+#define ICON_MDI_VIDEO_WIRELESS_OUTLINE "\xf3\xb0\xbb\x93" // U+F0ED3
+#define ICON_MDI_VIEW_AGENDA "\xf3\xb0\x95\xaa" // U+F056A
+#define ICON_MDI_VIEW_AGENDA_OUTLINE "\xf3\xb1\x87\x98" // U+F11D8
+#define ICON_MDI_VIEW_ARRAY "\xf3\xb0\x95\xab" // U+F056B
+#define ICON_MDI_VIEW_ARRAY_OUTLINE "\xf3\xb1\x92\x85" // U+F1485
+#define ICON_MDI_VIEW_CAROUSEL "\xf3\xb0\x95\xac" // U+F056C
+#define ICON_MDI_VIEW_CAROUSEL_OUTLINE "\xf3\xb1\x92\x86" // U+F1486
+#define ICON_MDI_VIEW_COLUMN "\xf3\xb0\x95\xad" // U+F056D
+#define ICON_MDI_VIEW_COLUMN_OUTLINE "\xf3\xb1\x92\x87" // U+F1487
+#define ICON_MDI_VIEW_COMFY "\xf3\xb0\xb9\xaa" // U+F0E6A
+#define ICON_MDI_VIEW_COMFY_OUTLINE "\xf3\xb1\x92\x88" // U+F1488
+#define ICON_MDI_VIEW_COMPACT "\xf3\xb0\xb9\xab" // U+F0E6B
+#define ICON_MDI_VIEW_COMPACT_OUTLINE "\xf3\xb0\xb9\xac" // U+F0E6C
+#define ICON_MDI_VIEW_DASHBOARD "\xf3\xb0\x95\xae" // U+F056E
+#define ICON_MDI_VIEW_DASHBOARD_EDIT "\xf3\xb1\xa5\x87" // U+F1947
+#define ICON_MDI_VIEW_DASHBOARD_EDIT_OUTLINE "\xf3\xb1\xa5\x88" // U+F1948
+#define ICON_MDI_VIEW_DASHBOARD_OUTLINE "\xf3\xb0\xa8\x9d" // U+F0A1D
+#define ICON_MDI_VIEW_DASHBOARD_VARIANT "\xf3\xb0\xa1\x83" // U+F0843
+#define ICON_MDI_VIEW_DASHBOARD_VARIANT_OUTLINE "\xf3\xb1\x92\x89" // U+F1489
+#define ICON_MDI_VIEW_DAY "\xf3\xb0\x95\xaf" // U+F056F
+#define ICON_MDI_VIEW_DAY_OUTLINE "\xf3\xb1\x92\x8a" // U+F148A
+#define ICON_MDI_VIEW_GALLERY "\xf3\xb1\xa2\x88" // U+F1888
+#define ICON_MDI_VIEW_GALLERY_OUTLINE "\xf3\xb1\xa2\x89" // U+F1889
+#define ICON_MDI_VIEW_GRID "\xf3\xb0\x95\xb0" // U+F0570
+#define ICON_MDI_VIEW_GRID_COMPACT "\xf3\xb1\xb1\xa1" // U+F1C61
+#define ICON_MDI_VIEW_GRID_OUTLINE "\xf3\xb1\x87\x99" // U+F11D9
+#define ICON_MDI_VIEW_GRID_PLUS "\xf3\xb0\xbe\x8d" // U+F0F8D
+#define ICON_MDI_VIEW_GRID_PLUS_OUTLINE "\xf3\xb1\x87\x9a" // U+F11DA
+#define ICON_MDI_VIEW_HEADLINE "\xf3\xb0\x95\xb1" // U+F0571
+#define ICON_MDI_VIEW_LIST "\xf3\xb0\x95\xb2" // U+F0572
+#define ICON_MDI_VIEW_LIST_OUTLINE "\xf3\xb1\x92\x8b" // U+F148B
+#define ICON_MDI_VIEW_MODULE "\xf3\xb0\x95\xb3" // U+F0573
+#define ICON_MDI_VIEW_MODULE_OUTLINE "\xf3\xb1\x92\x8c" // U+F148C
+#define ICON_MDI_VIEW_PARALLEL "\xf3\xb0\x9c\xa8" // U+F0728
+#define ICON_MDI_VIEW_PARALLEL_OUTLINE "\xf3\xb1\x92\x8d" // U+F148D
+#define ICON_MDI_VIEW_QUILT "\xf3\xb0\x95\xb4" // U+F0574
+#define ICON_MDI_VIEW_QUILT_OUTLINE "\xf3\xb1\x92\x8e" // U+F148E
+#define ICON_MDI_VIEW_SEQUENTIAL "\xf3\xb0\x9c\xa9" // U+F0729
+#define ICON_MDI_VIEW_SEQUENTIAL_OUTLINE "\xf3\xb1\x92\x8f" // U+F148F
+#define ICON_MDI_VIEW_SPLIT_HORIZONTAL "\xf3\xb0\xaf\x8b" // U+F0BCB
+#define ICON_MDI_VIEW_SPLIT_VERTICAL "\xf3\xb0\xaf\x8c" // U+F0BCC
+#define ICON_MDI_VIEW_STREAM "\xf3\xb0\x95\xb5" // U+F0575
+#define ICON_MDI_VIEW_STREAM_OUTLINE "\xf3\xb1\x92\x90" // U+F1490
+#define ICON_MDI_VIEW_WEEK "\xf3\xb0\x95\xb6" // U+F0576
+#define ICON_MDI_VIEW_WEEK_OUTLINE "\xf3\xb1\x92\x91" // U+F1491
+#define ICON_MDI_VIMEO "\xf3\xb0\x95\xb7" // U+F0577
+#define ICON_MDI_VIOLIN "\xf3\xb0\x98\x8f" // U+F060F
+#define ICON_MDI_VIRTUAL_REALITY "\xf3\xb0\xa2\x94" // U+F0894
+#define ICON_MDI_VIRUS "\xf3\xb1\x8e\xb6" // U+F13B6
+#define ICON_MDI_VIRUS_OFF "\xf3\xb1\xa3\xa1" // U+F18E1
+#define ICON_MDI_VIRUS_OFF_OUTLINE "\xf3\xb1\xa3\xa2" // U+F18E2
+#define ICON_MDI_VIRUS_OUTLINE "\xf3\xb1\x8e\xb7" // U+F13B7
+#define ICON_MDI_VLC "\xf3\xb0\x95\xbc" // U+F057C
+#define ICON_MDI_VOICEMAIL "\xf3\xb0\x95\xbd" // U+F057D
+#define ICON_MDI_VOLCANO "\xf3\xb1\xaa\x83" // U+F1A83
+#define ICON_MDI_VOLCANO_OUTLINE "\xf3\xb1\xaa\x84" // U+F1A84
+#define ICON_MDI_VOLLEYBALL "\xf3\xb0\xa6\xb4" // U+F09B4
+#define ICON_MDI_VOLUME_EQUAL "\xf3\xb1\xac\x90" // U+F1B10
+#define ICON_MDI_VOLUME_HIGH "\xf3\xb0\x95\xbe" // U+F057E
+#define ICON_MDI_VOLUME_LOW "\xf3\xb0\x95\xbf" // U+F057F
+#define ICON_MDI_VOLUME_MEDIUM "\xf3\xb0\x96\x80" // U+F0580
+#define ICON_MDI_VOLUME_MINUS "\xf3\xb0\x9d\x9e" // U+F075E
+#define ICON_MDI_VOLUME_MUTE "\xf3\xb0\x9d\x9f" // U+F075F
+#define ICON_MDI_VOLUME_OFF "\xf3\xb0\x96\x81" // U+F0581
+#define ICON_MDI_VOLUME_PLUS "\xf3\xb0\x9d\x9d" // U+F075D
+#define ICON_MDI_VOLUME_SOURCE "\xf3\xb1\x84\xa0" // U+F1120
+#define ICON_MDI_VOLUME_VARIANT_OFF "\xf3\xb0\xb8\x88" // U+F0E08
+#define ICON_MDI_VOLUME_VIBRATE "\xf3\xb1\x84\xa1" // U+F1121
+#define ICON_MDI_VOTE "\xf3\xb0\xa8\x9f" // U+F0A1F
+#define ICON_MDI_VOTE_OUTLINE "\xf3\xb0\xa8\xa0" // U+F0A20
+#define ICON_MDI_VPN "\xf3\xb0\x96\x82" // U+F0582
+#define ICON_MDI_VUEJS "\xf3\xb0\xa1\x84" // U+F0844
+#define ICON_MDI_VUETIFY "\xf3\xb0\xb9\xad" // U+F0E6D
+#define ICON_MDI_WALK "\xf3\xb0\x96\x83" // U+F0583
+#define ICON_MDI_WALL "\xf3\xb0\x9f\xbe" // U+F07FE
+#define ICON_MDI_WALL_FIRE "\xf3\xb1\xa8\x91" // U+F1A11
+#define ICON_MDI_WALL_SCONCE "\xf3\xb0\xa4\x9c" // U+F091C
+#define ICON_MDI_WALL_SCONCE_FLAT "\xf3\xb0\xa4\x9d" // U+F091D
+#define ICON_MDI_WALL_SCONCE_FLAT_OUTLINE "\xf3\xb1\x9f\x89" // U+F17C9
+#define ICON_MDI_WALL_SCONCE_FLAT_VARIANT "\xf3\xb0\x90\x9c" // U+F041C
+#define ICON_MDI_WALL_SCONCE_FLAT_VARIANT_OUTLINE "\xf3\xb1\x9f\x8a" // U+F17CA
+#define ICON_MDI_WALL_SCONCE_OUTLINE "\xf3\xb1\x9f\x8b" // U+F17CB
+#define ICON_MDI_WALL_SCONCE_ROUND "\xf3\xb0\x9d\x88" // U+F0748
+#define ICON_MDI_WALL_SCONCE_ROUND_OUTLINE "\xf3\xb1\x9f\x8c" // U+F17CC
+#define ICON_MDI_WALL_SCONCE_ROUND_VARIANT "\xf3\xb0\xa4\x9e" // U+F091E
+#define ICON_MDI_WALL_SCONCE_ROUND_VARIANT_OUTLINE "\xf3\xb1\x9f\x8d" // U+F17CD
+#define ICON_MDI_WALLET "\xf3\xb0\x96\x84" // U+F0584
+#define ICON_MDI_WALLET_BIFOLD "\xf3\xb1\xb1\x98" // U+F1C58
+#define ICON_MDI_WALLET_BIFOLD_OUTLINE "\xf3\xb1\xb1\x99" // U+F1C59
+#define ICON_MDI_WALLET_GIFTCARD "\xf3\xb0\x96\x85" // U+F0585
+#define ICON_MDI_WALLET_MEMBERSHIP "\xf3\xb0\x96\x86" // U+F0586
+#define ICON_MDI_WALLET_OUTLINE "\xf3\xb0\xaf\x9d" // U+F0BDD
+#define ICON_MDI_WALLET_PLUS "\xf3\xb0\xbe\x8e" // U+F0F8E
+#define ICON_MDI_WALLET_PLUS_OUTLINE "\xf3\xb0\xbe\x8f" // U+F0F8F
+#define ICON_MDI_WALLET_TRAVEL "\xf3\xb0\x96\x87" // U+F0587
+#define ICON_MDI_WALLPAPER "\xf3\xb0\xb8\x89" // U+F0E09
+#define ICON_MDI_WAN "\xf3\xb0\x96\x88" // U+F0588
+#define ICON_MDI_WARDROBE "\xf3\xb0\xbe\x90" // U+F0F90
+#define ICON_MDI_WARDROBE_OUTLINE "\xf3\xb0\xbe\x91" // U+F0F91
+#define ICON_MDI_WAREHOUSE "\xf3\xb0\xbe\x81" // U+F0F81
+#define ICON_MDI_WASHING_MACHINE "\xf3\xb0\x9c\xaa" // U+F072A
+#define ICON_MDI_WASHING_MACHINE_ALERT "\xf3\xb1\x86\xbc" // U+F11BC
+#define ICON_MDI_WASHING_MACHINE_OFF "\xf3\xb1\x86\xbd" // U+F11BD
+#define ICON_MDI_WATCH "\xf3\xb0\x96\x89" // U+F0589
+#define ICON_MDI_WATCH_EXPORT "\xf3\xb0\x96\x8a" // U+F058A
+#define ICON_MDI_WATCH_EXPORT_VARIANT "\xf3\xb0\xa2\x95" // U+F0895
+#define ICON_MDI_WATCH_IMPORT "\xf3\xb0\x96\x8b" // U+F058B
+#define ICON_MDI_WATCH_IMPORT_VARIANT "\xf3\xb0\xa2\x96" // U+F0896
+#define ICON_MDI_WATCH_VARIANT "\xf3\xb0\xa2\x97" // U+F0897
+#define ICON_MDI_WATCH_VIBRATE "\xf3\xb0\x9a\xb1" // U+F06B1
+#define ICON_MDI_WATCH_VIBRATE_OFF "\xf3\xb0\xb3\x9a" // U+F0CDA
+#define ICON_MDI_WATER "\xf3\xb0\x96\x8c" // U+F058C
+#define ICON_MDI_WATER_ALERT "\xf3\xb1\x94\x82" // U+F1502
+#define ICON_MDI_WATER_ALERT_OUTLINE "\xf3\xb1\x94\x83" // U+F1503
+#define ICON_MDI_WATER_BOILER "\xf3\xb0\xbe\x92" // U+F0F92
+#define ICON_MDI_WATER_BOILER_ALERT "\xf3\xb1\x86\xb3" // U+F11B3
+#define ICON_MDI_WATER_BOILER_AUTO "\xf3\xb1\xae\x98" // U+F1B98
+#define ICON_MDI_WATER_BOILER_OFF "\xf3\xb1\x86\xb4" // U+F11B4
+#define ICON_MDI_WATER_CHECK "\xf3\xb1\x94\x84" // U+F1504
+#define ICON_MDI_WATER_CHECK_OUTLINE "\xf3\xb1\x94\x85" // U+F1505
+#define ICON_MDI_WATER_CIRCLE "\xf3\xb1\xa0\x86" // U+F1806
+#define ICON_MDI_WATER_MINUS "\xf3\xb1\x94\x86" // U+F1506
+#define ICON_MDI_WATER_MINUS_OUTLINE "\xf3\xb1\x94\x87" // U+F1507
+#define ICON_MDI_WATER_OFF "\xf3\xb0\x96\x8d" // U+F058D
+#define ICON_MDI_WATER_OFF_OUTLINE "\xf3\xb1\x94\x88" // U+F1508
+#define ICON_MDI_WATER_OPACITY "\xf3\xb1\xa1\x95" // U+F1855
+#define ICON_MDI_WATER_OUTLINE "\xf3\xb0\xb8\x8a" // U+F0E0A
+#define ICON_MDI_WATER_PERCENT "\xf3\xb0\x96\x8e" // U+F058E
+#define ICON_MDI_WATER_PERCENT_ALERT "\xf3\xb1\x94\x89" // U+F1509
+#define ICON_MDI_WATER_PLUS "\xf3\xb1\x94\x8a" // U+F150A
+#define ICON_MDI_WATER_PLUS_OUTLINE "\xf3\xb1\x94\x8b" // U+F150B
+#define ICON_MDI_WATER_POLO "\xf3\xb1\x8a\xa0" // U+F12A0
+#define ICON_MDI_WATER_PUMP "\xf3\xb0\x96\x8f" // U+F058F
+#define ICON_MDI_WATER_PUMP_OFF "\xf3\xb0\xbe\x93" // U+F0F93
+#define ICON_MDI_WATER_REMOVE "\xf3\xb1\x94\x8c" // U+F150C
+#define ICON_MDI_WATER_REMOVE_OUTLINE "\xf3\xb1\x94\x8d" // U+F150D
+#define ICON_MDI_WATER_SYNC "\xf3\xb1\x9f\x86" // U+F17C6
+#define ICON_MDI_WATER_THERMOMETER "\xf3\xb1\xaa\x85" // U+F1A85
+#define ICON_MDI_WATER_THERMOMETER_OUTLINE "\xf3\xb1\xaa\x86" // U+F1A86
+#define ICON_MDI_WATER_WELL "\xf3\xb1\x81\xab" // U+F106B
+#define ICON_MDI_WATER_WELL_OUTLINE "\xf3\xb1\x81\xac" // U+F106C
+#define ICON_MDI_WATERFALL "\xf3\xb1\xa1\x89" // U+F1849
+#define ICON_MDI_WATERING_CAN "\xf3\xb1\x92\x81" // U+F1481
+#define ICON_MDI_WATERING_CAN_OUTLINE "\xf3\xb1\x92\x82" // U+F1482
+#define ICON_MDI_WATERMARK "\xf3\xb0\x98\x92" // U+F0612
+#define ICON_MDI_WAVE "\xf3\xb0\xbc\xae" // U+F0F2E
+#define ICON_MDI_WAVE_ARROW_DOWN "\xf3\xb1\xb2\xb0" // U+F1CB0
+#define ICON_MDI_WAVE_ARROW_UP "\xf3\xb1\xb2\xb1" // U+F1CB1
+#define ICON_MDI_WAVE_UNDERCURRENT "\xf3\xb1\xb3\x80" // U+F1CC0
+#define ICON_MDI_WAVEFORM "\xf3\xb1\x91\xbd" // U+F147D
+#define ICON_MDI_WAVES "\xf3\xb0\x9e\x8d" // U+F078D
+#define ICON_MDI_WAVES_ARROW_LEFT "\xf3\xb1\xa1\x99" // U+F1859
+#define ICON_MDI_WAVES_ARROW_RIGHT "\xf3\xb1\xa1\x9a" // U+F185A
+#define ICON_MDI_WAVES_ARROW_UP "\xf3\xb1\xa1\x9b" // U+F185B
+#define ICON_MDI_WAZE "\xf3\xb0\xaf\x9e" // U+F0BDE
+#define ICON_MDI_WEATHER_CLOUDY "\xf3\xb0\x96\x90" // U+F0590
+#define ICON_MDI_WEATHER_CLOUDY_ALERT "\xf3\xb0\xbc\xaf" // U+F0F2F
+#define ICON_MDI_WEATHER_CLOUDY_ARROW_RIGHT "\xf3\xb0\xb9\xae" // U+F0E6E
+#define ICON_MDI_WEATHER_CLOUDY_CLOCK "\xf3\xb1\xa3\xb6" // U+F18F6
+#define ICON_MDI_WEATHER_DUST "\xf3\xb1\xad\x9a" // U+F1B5A
+#define ICON_MDI_WEATHER_FOG "\xf3\xb0\x96\x91" // U+F0591
+#define ICON_MDI_WEATHER_HAIL "\xf3\xb0\x96\x92" // U+F0592
+#define ICON_MDI_WEATHER_HAZY "\xf3\xb0\xbc\xb0" // U+F0F30
+#define ICON_MDI_WEATHER_HURRICANE "\xf3\xb0\xa2\x98" // U+F0898
+#define ICON_MDI_WEATHER_HURRICANE_OUTLINE "\xf3\xb1\xb1\xb8" // U+F1C78
+#define ICON_MDI_WEATHER_LIGHTNING "\xf3\xb0\x96\x93" // U+F0593
+#define ICON_MDI_WEATHER_LIGHTNING_RAINY "\xf3\xb0\x99\xbe" // U+F067E
+#define ICON_MDI_WEATHER_NIGHT "\xf3\xb0\x96\x94" // U+F0594
+#define ICON_MDI_WEATHER_NIGHT_PARTLY_CLOUDY "\xf3\xb0\xbc\xb1" // U+F0F31
+#define ICON_MDI_WEATHER_PARTLY_CLOUDY "\xf3\xb0\x96\x95" // U+F0595
+#define ICON_MDI_WEATHER_PARTLY_LIGHTNING "\xf3\xb0\xbc\xb2" // U+F0F32
+#define ICON_MDI_WEATHER_PARTLY_RAINY "\xf3\xb0\xbc\xb3" // U+F0F33
+#define ICON_MDI_WEATHER_PARTLY_SNOWY "\xf3\xb0\xbc\xb4" // U+F0F34
+#define ICON_MDI_WEATHER_PARTLY_SNOWY_RAINY "\xf3\xb0\xbc\xb5" // U+F0F35
+#define ICON_MDI_WEATHER_POURING "\xf3\xb0\x96\x96" // U+F0596
+#define ICON_MDI_WEATHER_RAINY "\xf3\xb0\x96\x97" // U+F0597
+#define ICON_MDI_WEATHER_SNOWY "\xf3\xb0\x96\x98" // U+F0598
+#define ICON_MDI_WEATHER_SNOWY_HEAVY "\xf3\xb0\xbc\xb6" // U+F0F36
+#define ICON_MDI_WEATHER_SNOWY_RAINY "\xf3\xb0\x99\xbf" // U+F067F
+#define ICON_MDI_WEATHER_SUNNY "\xf3\xb0\x96\x99" // U+F0599
+#define ICON_MDI_WEATHER_SUNNY_ALERT "\xf3\xb0\xbc\xb7" // U+F0F37
+#define ICON_MDI_WEATHER_SUNNY_OFF "\xf3\xb1\x93\xa4" // U+F14E4
+#define ICON_MDI_WEATHER_SUNSET "\xf3\xb0\x96\x9a" // U+F059A
+#define ICON_MDI_WEATHER_SUNSET_DOWN "\xf3\xb0\x96\x9b" // U+F059B
+#define ICON_MDI_WEATHER_SUNSET_UP "\xf3\xb0\x96\x9c" // U+F059C
+#define ICON_MDI_WEATHER_TORNADO "\xf3\xb0\xbc\xb8" // U+F0F38
+#define ICON_MDI_WEATHER_WINDY "\xf3\xb0\x96\x9d" // U+F059D
+#define ICON_MDI_WEATHER_WINDY_VARIANT "\xf3\xb0\x96\x9e" // U+F059E
+#define ICON_MDI_WEB "\xf3\xb0\x96\x9f" // U+F059F
+#define ICON_MDI_WEB_BOX "\xf3\xb0\xbe\x94" // U+F0F94
+#define ICON_MDI_WEB_CANCEL "\xf3\xb1\x9e\x90" // U+F1790
+#define ICON_MDI_WEB_CHECK "\xf3\xb0\x9e\x89" // U+F0789
+#define ICON_MDI_WEB_CLOCK "\xf3\xb1\x89\x8a" // U+F124A
+#define ICON_MDI_WEB_MINUS "\xf3\xb1\x82\xa0" // U+F10A0
+#define ICON_MDI_WEB_OFF "\xf3\xb0\xaa\x8e" // U+F0A8E
+#define ICON_MDI_WEB_PLUS "\xf3\xb0\x80\xb3" // U+F0033
+#define ICON_MDI_WEB_REFRESH "\xf3\xb1\x9e\x91" // U+F1791
+#define ICON_MDI_WEB_REMOVE "\xf3\xb0\x95\x91" // U+F0551
+#define ICON_MDI_WEB_SYNC "\xf3\xb1\x9e\x92" // U+F1792
+#define ICON_MDI_WEBCAM "\xf3\xb0\x96\xa0" // U+F05A0
+#define ICON_MDI_WEBCAM_OFF "\xf3\xb1\x9c\xb7" // U+F1737
+#define ICON_MDI_WEBHOOK "\xf3\xb0\x98\xaf" // U+F062F
+#define ICON_MDI_WEBPACK "\xf3\xb0\x9c\xab" // U+F072B
+#define ICON_MDI_WEBRTC "\xf3\xb1\x89\x88" // U+F1248
+#define ICON_MDI_WECHAT "\xf3\xb0\x98\x91" // U+F0611
+#define ICON_MDI_WEIGHT "\xf3\xb0\x96\xa1" // U+F05A1
+#define ICON_MDI_WEIGHT_GRAM "\xf3\xb0\xb4\xbf" // U+F0D3F
+#define ICON_MDI_WEIGHT_KILOGRAM "\xf3\xb0\x96\xa2" // U+F05A2
+#define ICON_MDI_WEIGHT_LIFTER "\xf3\xb1\x85\x9d" // U+F115D
+#define ICON_MDI_WEIGHT_POUND "\xf3\xb0\xa6\xb5" // U+F09B5
+#define ICON_MDI_WHATSAPP "\xf3\xb0\x96\xa3" // U+F05A3
+#define ICON_MDI_WHEEL_BARROW "\xf3\xb1\x93\xb2" // U+F14F2
+#define ICON_MDI_WHEELCHAIR "\xf3\xb1\xaa\x87" // U+F1A87
+#define ICON_MDI_WHEELCHAIR_ACCESSIBILITY "\xf3\xb0\x96\xa4" // U+F05A4
+#define ICON_MDI_WHISTLE "\xf3\xb0\xa6\xb6" // U+F09B6
+#define ICON_MDI_WHISTLE_OUTLINE "\xf3\xb1\x8a\xbc" // U+F12BC
+#define ICON_MDI_WHITE_BALANCE_AUTO "\xf3\xb0\x96\xa5" // U+F05A5
+#define ICON_MDI_WHITE_BALANCE_INCANDESCENT "\xf3\xb0\x96\xa6" // U+F05A6
+#define ICON_MDI_WHITE_BALANCE_IRIDESCENT "\xf3\xb0\x96\xa7" // U+F05A7
+#define ICON_MDI_WHITE_BALANCE_SUNNY "\xf3\xb0\x96\xa8" // U+F05A8
+#define ICON_MDI_WIDGETS "\xf3\xb0\x9c\xac" // U+F072C
+#define ICON_MDI_WIDGETS_OUTLINE "\xf3\xb1\x8d\x95" // U+F1355
+#define ICON_MDI_WIFI "\xf3\xb0\x96\xa9" // U+F05A9
+#define ICON_MDI_WIFI_ALERT "\xf3\xb1\x9a\xb5" // U+F16B5
+#define ICON_MDI_WIFI_ARROW_DOWN "\xf3\xb1\x9a\xb6" // U+F16B6
+#define ICON_MDI_WIFI_ARROW_LEFT "\xf3\xb1\x9a\xb7" // U+F16B7
+#define ICON_MDI_WIFI_ARROW_LEFT_RIGHT "\xf3\xb1\x9a\xb8" // U+F16B8
+#define ICON_MDI_WIFI_ARROW_RIGHT "\xf3\xb1\x9a\xb9" // U+F16B9
+#define ICON_MDI_WIFI_ARROW_UP "\xf3\xb1\x9a\xba" // U+F16BA
+#define ICON_MDI_WIFI_ARROW_UP_DOWN "\xf3\xb1\x9a\xbb" // U+F16BB
+#define ICON_MDI_WIFI_CANCEL "\xf3\xb1\x9a\xbc" // U+F16BC
+#define ICON_MDI_WIFI_CHECK "\xf3\xb1\x9a\xbd" // U+F16BD
+#define ICON_MDI_WIFI_COG "\xf3\xb1\x9a\xbe" // U+F16BE
+#define ICON_MDI_WIFI_LOCK "\xf3\xb1\x9a\xbf" // U+F16BF
+#define ICON_MDI_WIFI_LOCK_OPEN "\xf3\xb1\x9b\x80" // U+F16C0
+#define ICON_MDI_WIFI_MARKER "\xf3\xb1\x9b\x81" // U+F16C1
+#define ICON_MDI_WIFI_MINUS "\xf3\xb1\x9b\x82" // U+F16C2
+#define ICON_MDI_WIFI_OFF "\xf3\xb0\x96\xaa" // U+F05AA
+#define ICON_MDI_WIFI_PLUS "\xf3\xb1\x9b\x83" // U+F16C3
+#define ICON_MDI_WIFI_REFRESH "\xf3\xb1\x9b\x84" // U+F16C4
+#define ICON_MDI_WIFI_REMOVE "\xf3\xb1\x9b\x85" // U+F16C5
+#define ICON_MDI_WIFI_SETTINGS "\xf3\xb1\x9b\x86" // U+F16C6
+#define ICON_MDI_WIFI_STAR "\xf3\xb0\xb8\x8b" // U+F0E0B
+#define ICON_MDI_WIFI_STRENGTH_1 "\xf3\xb0\xa4\x9f" // U+F091F
+#define ICON_MDI_WIFI_STRENGTH_1_ALERT "\xf3\xb0\xa4\xa0" // U+F0920
+#define ICON_MDI_WIFI_STRENGTH_1_LOCK "\xf3\xb0\xa4\xa1" // U+F0921
+#define ICON_MDI_WIFI_STRENGTH_1_LOCK_OPEN "\xf3\xb1\x9b\x8b" // U+F16CB
+#define ICON_MDI_WIFI_STRENGTH_2 "\xf3\xb0\xa4\xa2" // U+F0922
+#define ICON_MDI_WIFI_STRENGTH_2_ALERT "\xf3\xb0\xa4\xa3" // U+F0923
+#define ICON_MDI_WIFI_STRENGTH_2_LOCK "\xf3\xb0\xa4\xa4" // U+F0924
+#define ICON_MDI_WIFI_STRENGTH_2_LOCK_OPEN "\xf3\xb1\x9b\x8c" // U+F16CC
+#define ICON_MDI_WIFI_STRENGTH_3 "\xf3\xb0\xa4\xa5" // U+F0925
+#define ICON_MDI_WIFI_STRENGTH_3_ALERT "\xf3\xb0\xa4\xa6" // U+F0926
+#define ICON_MDI_WIFI_STRENGTH_3_LOCK "\xf3\xb0\xa4\xa7" // U+F0927
+#define ICON_MDI_WIFI_STRENGTH_3_LOCK_OPEN "\xf3\xb1\x9b\x8d" // U+F16CD
+#define ICON_MDI_WIFI_STRENGTH_4 "\xf3\xb0\xa4\xa8" // U+F0928
+#define ICON_MDI_WIFI_STRENGTH_4_ALERT "\xf3\xb0\xa4\xa9" // U+F0929
+#define ICON_MDI_WIFI_STRENGTH_4_LOCK "\xf3\xb0\xa4\xaa" // U+F092A
+#define ICON_MDI_WIFI_STRENGTH_4_LOCK_OPEN "\xf3\xb1\x9b\x8e" // U+F16CE
+#define ICON_MDI_WIFI_STRENGTH_ALERT_OUTLINE "\xf3\xb0\xa4\xab" // U+F092B
+#define ICON_MDI_WIFI_STRENGTH_LOCK_OPEN_OUTLINE "\xf3\xb1\x9b\x8f" // U+F16CF
+#define ICON_MDI_WIFI_STRENGTH_LOCK_OUTLINE "\xf3\xb0\xa4\xac" // U+F092C
+#define ICON_MDI_WIFI_STRENGTH_OFF "\xf3\xb0\xa4\xad" // U+F092D
+#define ICON_MDI_WIFI_STRENGTH_OFF_OUTLINE "\xf3\xb0\xa4\xae" // U+F092E
+#define ICON_MDI_WIFI_STRENGTH_OUTLINE "\xf3\xb0\xa4\xaf" // U+F092F
+#define ICON_MDI_WIFI_SYNC "\xf3\xb1\x9b\x87" // U+F16C7
+#define ICON_MDI_WIKIPEDIA "\xf3\xb0\x96\xac" // U+F05AC
+#define ICON_MDI_WIND_POWER "\xf3\xb1\xaa\x88" // U+F1A88
+#define ICON_MDI_WIND_POWER_OUTLINE "\xf3\xb1\xaa\x89" // U+F1A89
+#define ICON_MDI_WIND_TURBINE "\xf3\xb0\xb6\xa5" // U+F0DA5
+#define ICON_MDI_WIND_TURBINE_ALERT "\xf3\xb1\xa6\xab" // U+F19AB
+#define ICON_MDI_WIND_TURBINE_CHECK "\xf3\xb1\xa6\xac" // U+F19AC
+#define ICON_MDI_WINDOW_CLOSE "\xf3\xb0\x96\xad" // U+F05AD
+#define ICON_MDI_WINDOW_CLOSED "\xf3\xb0\x96\xae" // U+F05AE
+#define ICON_MDI_WINDOW_CLOSED_VARIANT "\xf3\xb1\x87\x9b" // U+F11DB
+#define ICON_MDI_WINDOW_MAXIMIZE "\xf3\xb0\x96\xaf" // U+F05AF
+#define ICON_MDI_WINDOW_MINIMIZE "\xf3\xb0\x96\xb0" // U+F05B0
+#define ICON_MDI_WINDOW_OPEN "\xf3\xb0\x96\xb1" // U+F05B1
+#define ICON_MDI_WINDOW_OPEN_VARIANT "\xf3\xb1\x87\x9c" // U+F11DC
+#define ICON_MDI_WINDOW_RESTORE "\xf3\xb0\x96\xb2" // U+F05B2
+#define ICON_MDI_WINDOW_SHUTTER "\xf3\xb1\x84\x9c" // U+F111C
+#define ICON_MDI_WINDOW_SHUTTER_ALERT "\xf3\xb1\x84\x9d" // U+F111D
+#define ICON_MDI_WINDOW_SHUTTER_AUTO "\xf3\xb1\xae\xa3" // U+F1BA3
+#define ICON_MDI_WINDOW_SHUTTER_COG "\xf3\xb1\xaa\x8a" // U+F1A8A
+#define ICON_MDI_WINDOW_SHUTTER_OPEN "\xf3\xb1\x84\x9e" // U+F111E
+#define ICON_MDI_WINDOW_SHUTTER_SETTINGS "\xf3\xb1\xaa\x8b" // U+F1A8B
+#define ICON_MDI_WINDSOCK "\xf3\xb1\x97\xba" // U+F15FA
+#define ICON_MDI_WIPER "\xf3\xb0\xab\xa9" // U+F0AE9
+#define ICON_MDI_WIPER_WASH "\xf3\xb0\xb6\xa6" // U+F0DA6
+#define ICON_MDI_WIPER_WASH_ALERT "\xf3\xb1\xa3\x9f" // U+F18DF
+#define ICON_MDI_WIZARD_HAT "\xf3\xb1\x91\xb7" // U+F1477
+#define ICON_MDI_WORDPRESS "\xf3\xb0\x96\xb4" // U+F05B4
+#define ICON_MDI_WRAP "\xf3\xb0\x96\xb6" // U+F05B6
+#define ICON_MDI_WRAP_DISABLED "\xf3\xb0\xaf\x9f" // U+F0BDF
+#define ICON_MDI_WRENCH "\xf3\xb0\x96\xb7" // U+F05B7
+#define ICON_MDI_WRENCH_CHECK "\xf3\xb1\xae\x8f" // U+F1B8F
+#define ICON_MDI_WRENCH_CHECK_OUTLINE "\xf3\xb1\xae\x90" // U+F1B90
+#define ICON_MDI_WRENCH_CLOCK "\xf3\xb1\xa6\xa3" // U+F19A3
+#define ICON_MDI_WRENCH_CLOCK_OUTLINE "\xf3\xb1\xae\x93" // U+F1B93
+#define ICON_MDI_WRENCH_COG "\xf3\xb1\xae\x91" // U+F1B91
+#define ICON_MDI_WRENCH_COG_OUTLINE "\xf3\xb1\xae\x92" // U+F1B92
+#define ICON_MDI_WRENCH_OUTLINE "\xf3\xb0\xaf\xa0" // U+F0BE0
+#define ICON_MDI_XAMARIN "\xf3\xb0\xa1\x85" // U+F0845
+#define ICON_MDI_XML "\xf3\xb0\x97\x80" // U+F05C0
+#define ICON_MDI_XMPP "\xf3\xb0\x9f\xbf" // U+F07FF
+#define ICON_MDI_YAHOO "\xf3\xb0\xad\x8f" // U+F0B4F
+#define ICON_MDI_YEAST "\xf3\xb0\x97\x81" // U+F05C1
+#define ICON_MDI_YIN_YANG "\xf3\xb0\x9a\x80" // U+F0680
+#define ICON_MDI_YOGA "\xf3\xb1\x85\xbc" // U+F117C
+#define ICON_MDI_YOUTUBE "\xf3\xb0\x97\x83" // U+F05C3
+#define ICON_MDI_YOUTUBE_GAMING "\xf3\xb0\xa1\x88" // U+F0848
+#define ICON_MDI_YOUTUBE_STUDIO "\xf3\xb0\xa1\x87" // U+F0847
+#define ICON_MDI_YOUTUBE_SUBSCRIPTION "\xf3\xb0\xb5\x80" // U+F0D40
+#define ICON_MDI_YOUTUBE_TV "\xf3\xb0\x91\x88" // U+F0448
+#define ICON_MDI_YURT "\xf3\xb1\x94\x96" // U+F1516
+#define ICON_MDI_Z_WAVE "\xf3\xb0\xab\xaa" // U+F0AEA
+#define ICON_MDI_ZEND "\xf3\xb0\xab\xab" // U+F0AEB
+#define ICON_MDI_ZIGBEE "\xf3\xb0\xb5\x81" // U+F0D41
+#define ICON_MDI_ZIP_BOX "\xf3\xb0\x97\x84" // U+F05C4
+#define ICON_MDI_ZIP_BOX_OUTLINE "\xf3\xb0\xbf\xba" // U+F0FFA
+#define ICON_MDI_ZIP_DISK "\xf3\xb0\xa8\xa3" // U+F0A23
+#define ICON_MDI_ZODIAC_AQUARIUS "\xf3\xb0\xa9\xbd" // U+F0A7D
+#define ICON_MDI_ZODIAC_ARIES "\xf3\xb0\xa9\xbe" // U+F0A7E
+#define ICON_MDI_ZODIAC_CANCER "\xf3\xb0\xa9\xbf" // U+F0A7F
+#define ICON_MDI_ZODIAC_CAPRICORN "\xf3\xb0\xaa\x80" // U+F0A80
+#define ICON_MDI_ZODIAC_GEMINI "\xf3\xb0\xaa\x81" // U+F0A81
+#define ICON_MDI_ZODIAC_LEO "\xf3\xb0\xaa\x82" // U+F0A82
+#define ICON_MDI_ZODIAC_LIBRA "\xf3\xb0\xaa\x83" // U+F0A83
+#define ICON_MDI_ZODIAC_PISCES "\xf3\xb0\xaa\x84" // U+F0A84
+#define ICON_MDI_ZODIAC_SAGITTARIUS "\xf3\xb0\xaa\x85" // U+F0A85
+#define ICON_MDI_ZODIAC_SCORPIO "\xf3\xb0\xaa\x86" // U+F0A86
+#define ICON_MDI_ZODIAC_TAURUS "\xf3\xb0\xaa\x87" // U+F0A87
+#define ICON_MDI_ZODIAC_VIRGO "\xf3\xb0\xaa\x88" // U+F0A88
+#define ICON_MDI_BLANK "\xef\x9a\x8c" // U+F68C
+#line 0
+// editor_script
+#define GLEQ_IMPLEMENTATION
+#line 1 "3rd_lite_sys_gleq.h"
+/*
+ * GLEQ - A basic event queue for GLFW 3
+ * Copyright © Camilla Löwy
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would
+ * be appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ */
+
+#ifndef GLEQ_HEADER_FILE
+#define GLEQ_HEADER_FILE
+
+// #include
+
+#ifdef GLEQ_STATIC
+ #define GLEQDEF static
+#else
+ #define GLEQDEF extern
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum
+{
+ GLEQ_NONE = 0,
+ GLEQ_WINDOW_MOVED = 1<<1,
+ GLEQ_WINDOW_RESIZED = 1<<2,
+ GLEQ_WINDOW_CLOSED = 1<<3,
+ GLEQ_WINDOW_REFRESH = 1<<4,
+ GLEQ_WINDOW_FOCUSED = 1<<5,
+ GLEQ_WINDOW_DEFOCUSED = 1<<6,
+ GLEQ_WINDOW_ICONIFIED = 1<<7,
+ GLEQ_WINDOW_UNICONIFIED = 1<<8,
+ GLEQ_FRAMEBUFFER_RESIZED = 1<<9,
+ GLEQ_BUTTON_PRESSED = 1<<10,
+ GLEQ_BUTTON_RELEASED = 1<<11,
+ GLEQ_CURSOR_MOVED = 1<<12,
+ GLEQ_CURSOR_ENTERED = 1<<13,
+ GLEQ_CURSOR_LEFT = 1<<14,
+ GLEQ_SCROLLED = 1<<15,
+ GLEQ_KEY_PRESSED = 1<<16,
+ GLEQ_KEY_REPEATED = 1<<17,
+ GLEQ_KEY_RELEASED = 1<<18,
+ GLEQ_CODEPOINT_INPUT = 1<<19,
+ GLEQ_MONITOR_CONNECTED = 1<<20,
+ GLEQ_MONITOR_DISCONNECTED = 1<<21,
+#if GLFW_VERSION_MINOR >= 1
+ GLEQ_FILE_DROPPED = 1<<22,
+#endif
+#if GLFW_VERSION_MINOR >= 2
+ GLEQ_JOYSTICK_CONNECTED = 1<<23,
+ GLEQ_JOYSTICK_DISCONNECTED = 1<<24,
+#endif
+#if GLFW_VERSION_MINOR >= 3
+ GLEQ_WINDOW_MAXIMIZED = 1<<25,
+ GLEQ_WINDOW_UNMAXIMIZED = 1<<26,
+ GLEQ_WINDOW_SCALE_CHANGED = 1<<27,
+#endif
+} GLEQtype;
+
+typedef struct GLEQevent
+{
+ unsigned/*GLEQtype*/ type;
+ union {
+ GLFWwindow* window;
+ GLFWmonitor* monitor;
+ int joystick;
+ };
+ union {
+ struct {
+ int x;
+ int y;
+ } pos;
+ struct {
+ int width;
+ int height;
+ } size;
+ struct {
+ double x;
+ double y;
+ } scroll;
+ struct {
+ int key;
+ int scancode;
+ int mods;
+ } keyboard;
+ struct {
+ int button;
+ int mods;
+ } mouse;
+ unsigned int codepoint;
+#if GLFW_VERSION_MINOR >= 1
+ struct {
+ char** paths;
+ int count;
+ } file;
+#endif
+#if GLFW_VERSION_MINOR >= 3
+ struct {
+ float x;
+ float y;
+ } scale;
+#endif
+ };
+} GLEQevent;
+
+GLEQDEF void gleqInit(void);
+GLEQDEF void gleqTrackWindow(GLFWwindow* window);
+
+GLEQDEF int gleqNextEvent(GLEQevent* event);
+GLEQDEF void gleqFreeEvent(GLEQevent* event);
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef GLEQ_IMPLEMENTATION
+
+#include
+#include
+#include
+
+#ifndef GLEQ_CAPACITY
+ #define GLEQ_CAPACITY 1024
+#endif
+
+static struct
+{
+ GLEQevent events[GLEQ_CAPACITY];
+ size_t head;
+ size_t tail;
+} gleq_queue = { {0}, 0, 0 };
+
+static char* gleq_strdup(const char* string)
+{
+ const size_t size = strlen(string) + 1;
+ char* result = (char*) malloc(size);
+ memcpy(result, string, size);
+ return result;
+}
+
+static GLEQevent* gleq_new_event(void)
+{
+ GLEQevent* event = gleq_queue.events + gleq_queue.head;
+ gleq_queue.head = (gleq_queue.head + 1) % GLEQ_CAPACITY;
+ assert(gleq_queue.head != gleq_queue.tail);
+ memset(event, 0, sizeof(GLEQevent));
+ return event;
+}
+
+static void gleq_window_pos_callback(GLFWwindow* window, int x, int y)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_WINDOW_MOVED;
+ event->window = window;
+ event->pos.x = x;
+ event->pos.y = y;
+}
+
+static void gleq_window_size_callback(GLFWwindow* window, int width, int height)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_WINDOW_RESIZED;
+ event->window = window;
+ event->size.width = width;
+ event->size.height = height;
+}
+
+static void gleq_window_close_callback(GLFWwindow* window)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_WINDOW_CLOSED;
+ event->window = window;
+}
+
+static void gleq_window_refresh_callback(GLFWwindow* window)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_WINDOW_REFRESH;
+ event->window = window;
+}
+
+static void gleq_window_focus_callback(GLFWwindow* window, int focused)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+
+ if (focused)
+ event->type = GLEQ_WINDOW_FOCUSED;
+ else
+ event->type = GLEQ_WINDOW_DEFOCUSED;
+}
+
+static void gleq_window_iconify_callback(GLFWwindow* window, int iconified)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+
+ if (iconified)
+ event->type = GLEQ_WINDOW_ICONIFIED;
+ else
+ event->type = GLEQ_WINDOW_UNICONIFIED;
+}
+
+static void gleq_framebuffer_size_callback(GLFWwindow* window, int width, int height)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_FRAMEBUFFER_RESIZED;
+ event->window = window;
+ event->size.width = width;
+ event->size.height = height;
+}
+
+static void gleq_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+ event->mouse.button = button;
+ event->mouse.mods = mods;
+
+ if (action == GLFW_PRESS)
+ event->type = GLEQ_BUTTON_PRESSED;
+ else if (action == GLFW_RELEASE)
+ event->type = GLEQ_BUTTON_RELEASED;
+}
+
+static void gleq_cursor_pos_callback(GLFWwindow* window, double x, double y)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_CURSOR_MOVED;
+ event->window = window;
+ event->pos.x = (int) x;
+ event->pos.y = (int) y;
+}
+
+static void gleq_cursor_enter_callback(GLFWwindow* window, int entered)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+
+ if (entered)
+ event->type = GLEQ_CURSOR_ENTERED;
+ else
+ event->type = GLEQ_CURSOR_LEFT;
+}
+
+static void gleq_scroll_callback(GLFWwindow* window, double x, double y)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_SCROLLED;
+ event->window = window;
+ event->scroll.x = x;
+ event->scroll.y = y;
+}
+
+static void gleq_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+ event->keyboard.key = key;
+ event->keyboard.scancode = scancode;
+ event->keyboard.mods = mods;
+
+ if (action == GLFW_PRESS)
+ event->type = GLEQ_KEY_PRESSED;
+ else if (action == GLFW_RELEASE)
+ event->type = GLEQ_KEY_RELEASED;
+ else if (action == GLFW_REPEAT)
+ event->type = GLEQ_KEY_REPEATED;
+}
+
+static void gleq_char_callback(GLFWwindow* window, unsigned int codepoint)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_CODEPOINT_INPUT;
+ event->window = window;
+ event->codepoint = codepoint;
+}
+
+static void gleq_monitor_callback(GLFWmonitor* monitor, int action)
+{
+ GLEQevent* event = gleq_new_event();
+ event->monitor = monitor;
+
+ if (action == GLFW_CONNECTED)
+ event->type = GLEQ_MONITOR_CONNECTED;
+ else if (action == GLFW_DISCONNECTED)
+ event->type = GLEQ_MONITOR_DISCONNECTED;
+}
+
+#if GLFW_VERSION_MINOR >= 1
+static void gleq_file_drop_callback(GLFWwindow* window, int count, const char** paths)
+{
+ GLEQevent* event = gleq_new_event();
+ event->type = GLEQ_FILE_DROPPED;
+ event->window = window;
+ event->file.paths = (char**) malloc(count * sizeof(char*));
+ event->file.count = count;
+
+ while (count--)
+ event->file.paths[count] = gleq_strdup(paths[count]);
+}
+#endif
+
+#if GLFW_VERSION_MINOR >= 2
+static void gleq_joystick_callback(int jid, int action)
+{
+ GLEQevent* event = gleq_new_event();
+ event->joystick = jid;
+
+ if (action == GLFW_CONNECTED)
+ event->type = GLEQ_JOYSTICK_CONNECTED;
+ else if (action == GLFW_DISCONNECTED)
+ event->type = GLEQ_JOYSTICK_DISCONNECTED;
+}
+#endif
+
+#if GLFW_VERSION_MINOR >= 3
+static void gleq_window_maximize_callback(GLFWwindow* window, int maximized)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+
+ if (maximized)
+ event->type = GLEQ_WINDOW_MAXIMIZED;
+ else
+ event->type = GLEQ_WINDOW_UNMAXIMIZED;
+}
+
+static void gleq_window_content_scale_callback(GLFWwindow* window, float xscale, float yscale)
+{
+ GLEQevent* event = gleq_new_event();
+ event->window = window;
+ event->type = GLEQ_WINDOW_SCALE_CHANGED;
+ event->scale.x = xscale;
+ event->scale.y = yscale;
+}
+#endif
+
+GLEQDEF void gleqInit(void)
+{
+ glfwSetMonitorCallback(gleq_monitor_callback);
+#if GLFW_VERSION_MINOR >= 2
+ glfwSetJoystickCallback(gleq_joystick_callback);
+#endif
+}
+
+GLEQDEF void gleqTrackWindow(GLFWwindow* window)
+{
+ glfwSetWindowPosCallback(window, gleq_window_pos_callback);
+ glfwSetWindowSizeCallback(window, gleq_window_size_callback);
+ glfwSetWindowCloseCallback(window, gleq_window_close_callback);
+ glfwSetWindowRefreshCallback(window, gleq_window_refresh_callback);
+ glfwSetWindowFocusCallback(window, gleq_window_focus_callback);
+ glfwSetWindowIconifyCallback(window, gleq_window_iconify_callback);
+ glfwSetFramebufferSizeCallback(window, gleq_framebuffer_size_callback);
+ glfwSetMouseButtonCallback(window, gleq_mouse_button_callback);
+ glfwSetCursorPosCallback(window, gleq_cursor_pos_callback);
+ glfwSetCursorEnterCallback(window, gleq_cursor_enter_callback);
+ glfwSetScrollCallback(window, gleq_scroll_callback);
+ glfwSetKeyCallback(window, gleq_key_callback);
+ glfwSetCharCallback(window, gleq_char_callback);
+#if GLFW_VERSION_MINOR >= 1
+ glfwSetDropCallback(window, gleq_file_drop_callback);
+#endif
+#if GLFW_VERSION_MINOR >= 3
+ glfwSetWindowMaximizeCallback(window, gleq_window_maximize_callback);
+ glfwSetWindowContentScaleCallback(window, gleq_window_content_scale_callback);
+#endif
+}
+
+GLEQDEF int gleqNextEvent(GLEQevent* event)
+{
+ memset(event, 0, sizeof(GLEQevent));
+
+ if (gleq_queue.head != gleq_queue.tail)
+ {
+ *event = gleq_queue.events[gleq_queue.tail];
+ gleq_queue.tail = (gleq_queue.tail + 1) % GLEQ_CAPACITY;
+ }
+
+ return event->type != GLEQ_NONE;
+}
+
+GLEQDEF void gleqFreeEvent(GLEQevent* event)
+{
+#if GLFW_VERSION_MINOR >= 1
+ if (event->type == GLEQ_FILE_DROPPED)
+ {
+ while (event->file.count--)
+ free(event->file.paths[event->file.count]);
+
+ free(event->file.paths);
+ }
+#endif
+
+ memset(event, 0, sizeof(GLEQevent));
+}
+
+#endif /* GLEQ_IMPLEMENTATION */
+
+#endif /* GLEQ_HEADER_FILE */
+#line 0
+#line 1 "3rd_lite_sys.h"
+// lite editor, platform details
+// - rlyeh, public domain
+
+#define LT_DATAPATH "/lite"
+
+#define lt_assert(x) ASSERT(x)
+
+#define lt_realpath(p, q) file_pathabs(p)
+#define lt_realpath_free(p)
+
+#define lt_malloc(n) MALLOC(n)
+#define lt_calloc(n,m) CALLOC(n,m)
+#define lt_free(p) FREE(p)
+#define lt_memcpy(d,s,c) memcpy(d,s,c)
+#define lt_memset(p,ch,c) memset(p,ch,c)
+
+#define lt_time_ms() time_ms()
+#define lt_sleep_ms(ms) sleep_ms(ms)
+
+#define lt_getclipboard(w) window_clipboard()
+#define lt_setclipboard(w,s) window_setclipboard(s)
+
+#define lt_window() window_handle()
+#define lt_setwindowmode(m) window_fullscreen(m == 2), (m < 2 && (window_maximize(m),1)) // 0:normal,1:maximized,2:fullscreen
+#define lt_setwindowtitle(t) //window_title(t)
+#define lt_haswindowfocus() window_has_focus()
+#define lt_setcursor(shape) window_cursor_shape(lt_events & (1<<31) ? CURSOR_SW_AUTO : shape+1) // 0:arrow,1:ibeam,2:sizeh,3:sizev,4:hand
+
+#define lt_prompt(msg,title) ifndef(win32, 0, (MessageBoxA(0, msg, title, MB_YESNO | MB_ICONWARNING) == IDYES))
+
+unsigned lt_events = ~0u;
+int lt_mx = 0, lt_my = 0, lt_wx = 0, lt_wy = 0, lt_ww = 0, lt_wh = 0;
+
+typedef struct lt_surface {
+ unsigned w, h;
+ void *pixels;
+ texture_t t;
+} lt_surface;
+
+typedef struct lt_rect {
+ int x, y, width, height;
+} lt_rect;
+
+lt_surface *lt_getsurface(void *window) {
+ static lt_surface s = {0};
+ return &s;
+}
+void lt_updatesurfacerects(lt_surface *s, lt_rect* rects, unsigned count) {
+ if(0)
+ for( int i = 0; i < count; ++i ) {
+ memset( (unsigned*)s->pixels + (rects[i].x + rects[i].y * s->w), 0xFF, rects[i].width*4 );
+ memset( (unsigned*)s->pixels + (rects[i].x + (rects[i].y + (rects[i].height-1)) * s->w), 0xFF, rects[i].width*4 );
+ for( int y = 1; y < (rects[i].height-1); ++y ) {
+ ((unsigned*)s->pixels)[ rects[i].x + y * s->w ] =
+ ((unsigned*)s->pixels)[ rects[i].x + (rects[i].width-1) + y * s->w ] = 0xFFFFFFFF;
+ }
+ }
+
+ // update contents
+ texture_update(&s->t, s->w, s->h, 4, s->pixels, TEXTURE_LINEAR|TEXTURE_BGRA);
+}
+
+void ren_set_clip_rect(struct lt_rect rect);
+void rencache_invalidate(void);
+int lt_resizesurface(lt_surface *s, int ww, int wh) {
+ s->w = ww, s->h = wh;
+ if( s->t.id == 0 || s->w != s->t.w || s->h != s->t.h ) {
+ // invalidate tiles
+ ren_set_clip_rect( (lt_rect) { 0, 0, s->w, s->h } );
+ rencache_invalidate();
+
+ // texture clear
+ if( !s->t.id ) s->t = texture_create(1, 1, 4, " ", TEXTURE_LINEAR|TEXTURE_RGBA|TEXTURE_BYTE );
+ s->pixels = REALLOC(s->pixels, s->w * s->h * 4);
+ memset(s->pixels, 0, s->w * s->h * 4);
+
+ // texture update
+ lt_updatesurfacerects(s,0,0);
+ return 1; // resized
+ }
+ return 0; // unchanged
+}
+
+void *lt_load_file(const char *filename, int *size) {
+ int datalen; char *data = file_load(filename, &datalen);
+ if( !data || !datalen ) {
+ filename = (const char *)file_normalize(filename);
+ if( strbegi(filename, app_path()) ) filename += strlen(app_path());
+ data = vfs_load(filename, &datalen);
+ }
+ if (size) *size = 0;
+ if (!data) { return NULL; }
+ if (size) *size = datalen;
+ // return permanent buffers here, as file_load() and vfs_load() do return temporaries
+ data = memcpy(MALLOC(datalen+1), data, datalen);
+ data[datalen] = 0;
+ return data;
+}
+
+const char* lt_button_name(int button) {
+ if(button == GLFW_MOUSE_BUTTON_LEFT) return "left";
+ if(button == GLFW_MOUSE_BUTTON_RIGHT) return "right";
+ if(button == GLFW_MOUSE_BUTTON_MIDDLE) return "middle";
+ return "?";
+}
+
+char* lt_key_name(char *dst, int key, int vk, int mods) {
+ // @todo: "altgr" -> left ctrl + right alt
+
+ if( key == GLFW_KEY_UP ) return "up";
+ if( key == GLFW_KEY_DOWN ) return "down";
+ if( key == GLFW_KEY_LEFT ) return "left";
+ if( key == GLFW_KEY_RIGHT ) return "right";
+ if( key == GLFW_KEY_LEFT_ALT ) return "left alt";
+ if( key == GLFW_KEY_RIGHT_ALT ) return "right alt";
+ if( key == GLFW_KEY_LEFT_SHIFT ) return "left shift";
+ if( key == GLFW_KEY_RIGHT_SHIFT ) return "right shift";
+ if( key == GLFW_KEY_LEFT_CONTROL ) return "left ctrl";
+ if( key == GLFW_KEY_RIGHT_CONTROL ) return "right ctrl";
+ if( key == GLFW_KEY_LEFT_SUPER ) return "left windows";
+ if( key == GLFW_KEY_RIGHT_SUPER ) return "left windows";
+ if( key == GLFW_KEY_MENU ) return "menu";
+
+ if( key == GLFW_KEY_ESCAPE ) return "escape";
+ if( key == GLFW_KEY_BACKSPACE ) return "backspace";
+ if( key == GLFW_KEY_ENTER ) return "return";
+ if( key == GLFW_KEY_KP_ENTER ) return "keypad enter";
+ if( key == GLFW_KEY_TAB ) return "tab";
+ if( key == GLFW_KEY_CAPS_LOCK ) return "capslock";
+
+ if( key == GLFW_KEY_HOME ) return "home";
+ if( key == GLFW_KEY_END ) return "end";
+ if( key == GLFW_KEY_INSERT ) return "insert";
+ if( key == GLFW_KEY_DELETE ) return "delete";
+ if( key == GLFW_KEY_PAGE_UP ) return "pageup";
+ if( key == GLFW_KEY_PAGE_DOWN ) return "pagedown";
+
+ if( key == GLFW_KEY_F1 ) return "f1";
+ if( key == GLFW_KEY_F2 ) return "f2";
+ if( key == GLFW_KEY_F3 ) return "f3";
+ if( key == GLFW_KEY_F4 ) return "f4";
+ if( key == GLFW_KEY_F5 ) return "f5";
+ if( key == GLFW_KEY_F6 ) return "f6";
+ if( key == GLFW_KEY_F7 ) return "f7";
+ if( key == GLFW_KEY_F8 ) return "f8";
+ if( key == GLFW_KEY_F9 ) return "f9";
+ if( key == GLFW_KEY_F10 ) return "f10";
+ if( key == GLFW_KEY_F11 ) return "f11";
+ if( key == GLFW_KEY_F12 ) return "f12";
+
+ const char *name = glfwGetKeyName(key, vk);
+ strcpy(dst, name ? name : "");
+ char *p = dst;
+ while (*p) {
+ *p = tolower(*p);
+ p++;
+ }
+ return dst;
+}
+
+void lt_globpath(struct lua_State*L, const char *path) {
+ unsigned j = 0;
+
+ if(!strend(path, "/")) path = (const char *)va("%s/", path);
+ for( dir *d = dir_open(path, ""); d; dir_close(d), d = 0 ) {
+ for( unsigned i = 0, end = dir_count(d); i < end; ++i ) {
+ char *name = dir_name(d,i);
+ char *last = name + strlen(name) - 1;
+ if( *last == '/' ) *last = '\0';
+ name = file_name(name);
+ lua_pushstring(L, name);
+ lua_rawseti(L, -2, ++j);
+ }
+ }
+
+ for( const char *section = strstri(path, LT_DATAPATH); section && section[sizeof(LT_DATAPATH)-1] == '/'; section = 0) {
+ array(char*) list = vfs_list("**");
+ for( unsigned i = 0, end = array_count(list); i < end; ++i ) {
+ char *name = list[i];
+ if( !strstri(name, section+1) ) continue;
+ lua_pushstring(L, file_name(name));
+ lua_rawseti(L, -2, ++j);
+ }
+ if( array_count(list) ) return;
+ }
+}
+
+int lt_emit_event(lua_State *L, const char *event_name, const char *event_fmt, ...) {
+ int count = 0;
+ lua_pushstring(L, event_name);
+ if( event_fmt ) {
+ va_list va;
+ va_start(va, event_fmt);
+ for( ; event_fmt[count]; ++count ) {
+ /**/ if( event_fmt[count] == 'd' ) { int d = va_arg(va, int); lua_pushnumber(L, d); }
+ else if( event_fmt[count] == 'f' ) { double f = va_arg(va, double); lua_pushnumber(L, f); }
+ else if( event_fmt[count] == 's' ) { const char *s = va_arg(va, const char *); lua_pushstring(L, s); }
+ }
+ va_end(va);
+ }
+ return 1+count;
+}
+
+int printi(int i) {
+ // printf("clicks: %d\n", i);
+ return i;
+}
+
+static const char* codepoint_to_utf8(unsigned c);
+int lt_poll_event(lua_State *L) { // init.lua > core.step() wakes on mousemoved || inputtext
+ int rc = 0;
+ char buf[16];
+ static int prevx = 0, prevy = 0;
+
+ static unsigned clicks_time = 0, clicks = 0;
+ if( (lt_time_ms() - clicks_time) > 400 ) clicks = 0;
+
+ //
+
+ for( GLEQevent e; gleqNextEvent(&e); gleqFreeEvent(&e) )
+ if( lt_events & e.type )
+ switch (e.type) {
+ default:
+ break; case GLEQ_WINDOW_CLOSED: // it used to be ok. depends on window_swap() flow
+ rc += lt_emit_event(L, "quit", NULL);
+ return rc;
+
+ break; case GLEQ_WINDOW_MOVED:
+ lt_wx = e.pos.x;
+ lt_wy = e.pos.y;
+
+ break; case GLEQ_WINDOW_RESIZED:
+ rc += lt_emit_event(L, "resized", "dd", lt_ww = e.size.width, lt_wh = e.size.height);
+ lt_resizesurface(lt_getsurface(lt_window()), lt_ww, lt_wh);
+
+ break; case GLEQ_WINDOW_REFRESH:
+ rc += lt_emit_event(L, "exposed", NULL);
+ rencache_invalidate();
+
+ break; case GLEQ_FILE_DROPPED:
+ rc += lt_emit_event(L, "filedropped", "sdd", e.file.paths[0], lt_mx, lt_my);
+
+ break; case GLEQ_KEY_PRESSED:
+ case GLEQ_KEY_REPEATED:
+ rc += lt_emit_event(L, "keypressed", "s", lt_key_name(buf, e.keyboard.key, e.keyboard.scancode, e.keyboard.mods));
+ goto bottom;
+
+ break; case GLEQ_KEY_RELEASED:
+ rc += lt_emit_event(L, "keyreleased", "s", lt_key_name(buf, e.keyboard.key, e.keyboard.scancode, e.keyboard.mods));
+ goto bottom;
+
+ break; case GLEQ_CODEPOINT_INPUT:
+ rc += lt_emit_event(L, "textinput", "s", codepoint_to_utf8(e.codepoint));
+
+ break; case GLEQ_BUTTON_PRESSED:
+ rc += lt_emit_event(L, "mousepressed", "sddd", lt_button_name(e.mouse.button), lt_mx, lt_my, printi(1 + clicks));
+
+ break; case GLEQ_BUTTON_RELEASED:
+ clicks += e.mouse.button == GLFW_MOUSE_BUTTON_1;
+ clicks_time = lt_time_ms();
+ rc += lt_emit_event(L, "mousereleased", "sdd", lt_button_name(e.mouse.button), lt_mx, lt_my);
+
+ break; case GLEQ_CURSOR_MOVED:
+ lt_mx = e.pos.x - lt_wx, lt_my = e.pos.y - lt_wy;
+ rc += lt_emit_event(L, "mousemoved", "dddd", lt_mx, lt_my, lt_mx - prevx, lt_my - prevy);
+ prevx = lt_mx, prevy = lt_my;
+
+ break; case GLEQ_SCROLLED:
+ rc += lt_emit_event(L, "mousewheel", "f", e.scroll.y);
+ }
+
+bottom:;
+
+ return rc;
+}
+#line 0
+#line 1 "3rd_lite.h"
+// Copyright (c) 2020 rxi
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+// [doc] https://rxi.github.io/lite_an_implementation_overview.html
+// [chg] differences from https://github.com/rxi/lite listed below:
+//
+// a) amalgamated as single-file source.
+// b) platform agnostic now (no more specific SDL calls; tested with GLFW backend).
+// c) specific `lt_` platform bits have been moved out to an external file (lite_sys.h)
+// d) lua, stb-truetype and lite_sys headers *must be included* beforehand.
+// e) embeddable: reverted loop handler from framework to library mode. see: lt_init/lt_tick
+// f) data folders reorganized as data/themes, data/languages/ and data/plugins/.
+// g) DATADIR path can be specified now and no longer forced to be EXEDIR/data/.
+// h) packaged with a bunch of handy plugins from https://github.com/rxi/lite-plugins
+// i) packaged with all color themes from https://github.com/rxi/lite-colors
+// j) merged a few pending PRs and pending fixes from original repo.
+// k) Lua sources fixed for Lua >= 5.2
+//
+// All contributions released under same MIT licensing terms than original code.
+// - rlyeh.
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef S_ISDIR
+#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+
+#ifndef S_ISREG
+#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+
+// ----------------------------------------------------------------------------
+// lite/api.h
+
+#define API_TYPE_FONT "Font"
+
+// ----------------------------------------------------------------------------
+// lite/renderer.h
+
+typedef struct RenImage RenImage;
+typedef struct RenFont RenFont;
+
+typedef struct { uint8_t b, g, r, a; } RenColor;
+//typedef struct { int x, y, width, height; } RenRect;
+typedef lt_rect RenRect;
+
+
+void ren_init(void *win);
+void ren_update_rects(RenRect *rects, int count);
+void ren_set_clip_rect(RenRect rect);
+void ren_get_size(int *x, int *y);
+
+RenImage* ren_new_image(int width, int height);
+void ren_free_image(RenImage *image);
+
+RenFont* ren_load_font(const char *filename, float size);
+void ren_free_font(RenFont *font);
+void ren_set_font_tab_width(RenFont *font, int n);
+int ren_get_font_tab_width(RenFont *font);
+int ren_get_font_width(RenFont *font, const char *text);
+int ren_get_font_height(RenFont *font);
+
+void ren_draw_rect(RenRect rect, RenColor color);
+void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color);
+int ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color);
+
+// ----------------------------------------------------------------------------
+// lite/rencache.h
+
+void rencache_show_debug(bool enable);
+void rencache_free_font(RenFont *font);
+void rencache_set_clip_rect(RenRect rect);
+void rencache_draw_rect(RenRect rect, RenColor color);
+int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor color);
+void rencache_invalidate(void);
+void rencache_begin_frame(void);
+void rencache_end_frame(void);
+
+// ----------------------------------------------------------------------------
+// lite/renderer.c
+
+#define MAX_GLYPHSET 256
+
+struct RenImage {
+ RenColor *pixels;
+ int width, height;
+};
+
+typedef struct {
+ RenImage *image;
+ stbtt_bakedchar glyphs[256];
+} GlyphSet;
+
+struct RenFont {
+ void *data;
+ stbtt_fontinfo stbfont;
+ GlyphSet *sets[MAX_GLYPHSET];
+ float size;
+ int height;
+};
+
+static struct { int left, top, right, bottom; } lt_clip;
+
+static const char* codepoint_to_utf8(unsigned c) { //< @r-lyeh
+ static char s[4+1];
+ lt_memset(s, 0, 5);
+ /**/ if (c < 0x80) s[0] = c, s[1] = 0;
+ else if (c < 0x800) s[0] = 0xC0 | ((c >> 6) & 0x1F), s[1] = 0x80 | ( c & 0x3F), s[2] = 0;
+ else if (c < 0x10000) s[0] = 0xE0 | ((c >> 12) & 0x0F), s[1] = 0x80 | ((c >> 6) & 0x3F), s[2] = 0x80 | ( c & 0x3F), s[3] = 0;
+ else if (c < 0x110000) s[0] = 0xF0 | ((c >> 18) & 0x07), s[1] = 0x80 | ((c >> 12) & 0x3F), s[2] = 0x80 | ((c >> 6) & 0x3F), s[3] = 0x80 | (c & 0x3F), s[4] = 0;
+ return s;
+}
+static const char* utf8_to_codepoint(const char *p, unsigned *dst) {
+ unsigned res, n;
+ switch (*p & 0xf0) {
+ case 0xf0 : res = *p & 0x07; n = 3; break;
+ case 0xe0 : res = *p & 0x0f; n = 2; break;
+ case 0xd0 :
+ case 0xc0 : res = *p & 0x1f; n = 1; break;
+ default : res = *p; n = 0; break;
+ }
+ while (n-- && *p++) { //< https://github.com/rxi/lite/issues/262
+ res = (res << 6) | (*p & 0x3f); //< https://github.com/rxi/lite/issues/262
+ }
+ *dst = res;
+ return p + 1;
+}
+
+void ren_init(void *win) {
+ lt_surface *surf = lt_getsurface(lt_window());
+ ren_set_clip_rect( (RenRect) { 0, 0, surf->w, surf->h } );
+}
+
+
+void ren_update_rects(RenRect *rects, int count) {
+ lt_updatesurfacerects(lt_getsurface(lt_window()), (lt_rect*) rects, count);
+}
+
+
+void ren_set_clip_rect(RenRect rect) {
+ lt_clip.left = rect.x;
+ lt_clip.top = rect.y;
+ lt_clip.right = rect.x + rect.width;
+ lt_clip.bottom = rect.y + rect.height;
+}
+
+
+void ren_get_size(int *x, int *y) {
+ lt_surface *surf = lt_getsurface(lt_window());
+ *x = surf->w;
+ *y = surf->h;
+}
+
+
+RenImage* ren_new_image(int width, int height) {
+ lt_assert(width > 0 && height > 0);
+ RenImage *image = lt_malloc(sizeof(RenImage) + width * height * sizeof(RenColor));
+ image->pixels = (void*) (image + 1);
+ image->width = width;
+ image->height = height;
+ return image;
+}
+
+
+void ren_free_image(RenImage *image) {
+ lt_free(image);
+}
+
+
+static GlyphSet* load_glyphset(RenFont *font, int idx) {
+ GlyphSet *set = lt_calloc(1, sizeof(GlyphSet));
+
+ /* init image */
+ int width = 128;
+ int height = 128;
+retry:
+ set->image = ren_new_image(width, height);
+
+ /* load glyphs */
+ float s =
+ stbtt_ScaleForMappingEmToPixels(&font->stbfont, 1) /
+ stbtt_ScaleForPixelHeight(&font->stbfont, 1);
+ int res = stbtt_BakeFontBitmap(
+ font->data, 0, font->size * s, (void*) set->image->pixels,
+ width, height, idx * 256, 256, set->glyphs);
+
+ /* retry with a larger image buffer if the buffer wasn't large enough */
+ if (res < 0) {
+ width *= 2;
+ height *= 2;
+ ren_free_image(set->image);
+ goto retry;
+ }
+
+ /* adjust glyph yoffsets and xadvance */
+ int ascent, descent, linegap;
+ stbtt_GetFontVMetrics(&font->stbfont, &ascent, &descent, &linegap);
+ float scale = stbtt_ScaleForMappingEmToPixels(&font->stbfont, font->size);
+ int scaled_ascent = ascent * scale + 0.5;
+ for (int i = 0; i < 256; i++) {
+ set->glyphs[i].yoff += scaled_ascent;
+ set->glyphs[i].xadvance = floor(set->glyphs[i].xadvance);
+ }
+
+ /* convert 8bit data to 32bit */
+ for (int i = width * height - 1; i >= 0; i--) {
+ uint8_t n = *((uint8_t*) set->image->pixels + i);
+ set->image->pixels[i] = (RenColor) { .r = 255, .g = 255, .b = 255, .a = n };
+ }
+
+ return set;
+}
+
+
+static GlyphSet* get_glyphset(RenFont *font, int codepoint) {
+ int idx = (codepoint >> 8) % MAX_GLYPHSET;
+ if (!font->sets[idx]) {
+ font->sets[idx] = load_glyphset(font, idx);
+ }
+ return font->sets[idx];
+}
+
+
+RenFont* ren_load_font(const char *filename, float size) {
+ /* load font into buffer */ //< @r-lyeh: load font file before allocating `font`
+ char *fontdata = lt_load_file(filename, NULL);
+ if( !fontdata ) return NULL;
+
+ RenFont *font = NULL;
+
+ /* init font */
+ font = lt_calloc(1, sizeof(RenFont));
+ font->size = size;
+ font->data = fontdata;
+
+ /* init stbfont */
+ int ok = stbtt_InitFont(&font->stbfont, font->data, 0);
+ if (!ok) {
+ if (font) { lt_free(font->data); }
+ lt_free(font);
+ return NULL;
+ }
+
+ /* get height and scale */
+ int ascent, descent, linegap;
+ stbtt_GetFontVMetrics(&font->stbfont, &ascent, &descent, &linegap);
+ float scale = stbtt_ScaleForMappingEmToPixels(&font->stbfont, size);
+ font->height = (ascent - descent + linegap) * scale + 0.5;
+
+ /* make tab and newline glyphs invisible */
+ stbtt_bakedchar *g = get_glyphset(font, '\n')->glyphs;
+ g['\t'].x1 = g['\t'].x0;
+ g['\n'].x1 = g['\n'].x0;
+
+ return font;
+}
+
+
+void ren_free_font(RenFont *font) {
+ for (int i = 0; i < MAX_GLYPHSET; i++) {
+ GlyphSet *set = font->sets[i];
+ if (set) {
+ ren_free_image(set->image);
+ lt_free(set);
+ }
+ }
+ lt_free(font->data);
+ lt_free(font);
+}
+
+
+void ren_set_font_tab_width(RenFont *font, int n) {
+ GlyphSet *set = get_glyphset(font, '\t');
+ set->glyphs['\t'].xadvance = n;
+}
+
+
+int ren_get_font_tab_width(RenFont *font) {
+ GlyphSet *set = get_glyphset(font, '\t');
+ return set->glyphs['\t'].xadvance;
+}
+
+
+int ren_get_font_width(RenFont *font, const char *text) {
+ int x = 0;
+ const char *p = text;
+ unsigned codepoint;
+ while (*p) {
+ p = utf8_to_codepoint(p, &codepoint);
+ GlyphSet *set = get_glyphset(font, codepoint);
+ stbtt_bakedchar *g = &set->glyphs[codepoint & 0xff];
+ x += g->xadvance;
+ }
+ return x;
+}
+
+
+int ren_get_font_height(RenFont *font) {
+ return font->height;
+}
+
+
+static inline RenColor blend_pixel(RenColor dst, RenColor src) {
+ int ia = 0xff - src.a;
+ dst.r = ((src.r * src.a) + (dst.r * ia)) >> 8;
+ dst.g = ((src.g * src.a) + (dst.g * ia)) >> 8;
+ dst.b = ((src.b * src.a) + (dst.b * ia)) >> 8;
+ return dst;
+}
+
+
+static inline RenColor blend_pixel2(RenColor dst, RenColor src, RenColor color) {
+ src.a = (src.a * color.a) >> 8;
+ int ia = 0xff - src.a;
+ dst.r = ((src.r * color.r * src.a) >> 16) + ((dst.r * ia) >> 8);
+ dst.g = ((src.g * color.g * src.a) >> 16) + ((dst.g * ia) >> 8);
+ dst.b = ((src.b * color.b * src.a) >> 16) + ((dst.b * ia) >> 8);
+ return dst;
+}
+
+
+#define rect_draw_loop(expr) \
+ for (int j = y1; j < y2; j++) { \
+ for (int i = x1; i < x2; i++) { \
+ *d = expr; \
+ d++; \
+ } \
+ d += dr; \
+ }
+
+void ren_draw_rect(RenRect rect, RenColor color) {
+ if (color.a == 0) { return; }
+
+ int x1 = rect.x < lt_clip.left ? lt_clip.left : rect.x;
+ int y1 = rect.y < lt_clip.top ? lt_clip.top : rect.y;
+ int x2 = rect.x + rect.width;
+ int y2 = rect.y + rect.height;
+ x2 = x2 > lt_clip.right ? lt_clip.right : x2;
+ y2 = y2 > lt_clip.bottom ? lt_clip.bottom : y2;
+
+ lt_surface *surf = lt_getsurface(lt_window());
+ RenColor *d = (RenColor*) surf->pixels;
+ d += x1 + y1 * surf->w;
+ int dr = surf->w - (x2 - x1);
+
+ if (color.a == 0xff) {
+ rect_draw_loop(color);
+ } else {
+ rect_draw_loop(blend_pixel(*d, color));
+ }
+}
+
+
+void ren_draw_image(RenImage *image, RenRect *sub, int x, int y, RenColor color) {
+ if (color.a == 0) { return; }
+
+ /* clip */
+ int n;
+ if ((n = lt_clip.left - x) > 0) { sub->width -= n; sub->x += n; x += n; }
+ if ((n = lt_clip.top - y) > 0) { sub->height -= n; sub->y += n; y += n; }
+ if ((n = x + sub->width - lt_clip.right ) > 0) { sub->width -= n; }
+ if ((n = y + sub->height - lt_clip.bottom) > 0) { sub->height -= n; }
+
+ if (sub->width <= 0 || sub->height <= 0) {
+ return;
+ }
+
+ /* draw */
+ lt_surface *surf = lt_getsurface(lt_window());
+ RenColor *s = image->pixels;
+ RenColor *d = (RenColor*) surf->pixels;
+ s += sub->x + sub->y * image->width;
+ d += x + y * surf->w;
+ int sr = image->width - sub->width;
+ int dr = surf->w - sub->width;
+
+ for (int j = 0; j < sub->height; j++) {
+ for (int i = 0; i < sub->width; i++) {
+ *d = blend_pixel2(*d, *s, color);
+ d++;
+ s++;
+ }
+ d += dr;
+ s += sr;
+ }
+}
+
+
+int ren_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) {
+ RenRect rect;
+ const char *p = text;
+ unsigned codepoint;
+ while (*p) {
+ p = utf8_to_codepoint(p, &codepoint);
+ GlyphSet *set = get_glyphset(font, codepoint);
+ stbtt_bakedchar *g = &set->glyphs[codepoint & 0xff];
+ rect.x = g->x0;
+ rect.y = g->y0;
+ rect.width = g->x1 - g->x0;
+ rect.height = g->y1 - g->y0;
+ ren_draw_image(set->image, &rect, x + g->xoff, y + g->yoff, color);
+ x += g->xadvance;
+ }
+ return x;
+}
+
+// ----------------------------------------------------------------------------
+// lite/renderer_font.c
+
+static int f_load(lua_State *L) {
+ const char *filename = luaL_checkstring(L, 1);
+ float size = luaL_checknumber(L, 2);
+ RenFont **self = lua_newuserdata(L, sizeof(*self));
+ luaL_setmetatable(L, API_TYPE_FONT);
+ *self = ren_load_font(filename, size);
+ if (!*self) { luaL_error(L, "failed to load font"); }
+ return 1;
+}
+
+
+static int f_set_tab_width(lua_State *L) {
+ RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT);
+ int n = luaL_checknumber(L, 2);
+ ren_set_font_tab_width(*self, n);
+ return 0;
+}
+
+
+static int f_GC(lua_State *L) {
+ RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT);
+ if (*self) { rencache_free_font(*self); }
+ return 0;
+}
+
+
+static int f_get_width(lua_State *L) {
+ RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT);
+ const char *text = luaL_checkstring(L, 2);
+ lua_pushnumber(L, ren_get_font_width(*self, text) );
+ return 1;
+}
+
+
+static int f_get_height(lua_State *L) {
+ RenFont **self = luaL_checkudata(L, 1, API_TYPE_FONT);
+ lua_pushnumber(L, ren_get_font_height(*self) );
+ return 1;
+}
+
+
+int luaopen_renderer_font(lua_State *L) {
+ static const luaL_Reg lib[] = {
+ { "__gc", f_GC },
+ { "load", f_load },
+ { "set_tab_width", f_set_tab_width },
+ { "get_width", f_get_width },
+ { "get_height", f_get_height },
+ { NULL, NULL }
+ };
+ luaL_newmetatable(L, API_TYPE_FONT);
+ luaL_setfuncs(L, lib, 0);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ return 1;
+}
+
+// ----------------------------------------------------------------------------
+// lite/renderer_api.c
+
+static RenColor checkcolor(lua_State *L, int idx, int def) {
+ RenColor color;
+ if (lua_isnoneornil(L, idx)) {
+ return (RenColor) { def, def, def, 255 };
+ }
+ lua_rawgeti(L, idx, 1);
+ lua_rawgeti(L, idx, 2);
+ lua_rawgeti(L, idx, 3);
+ lua_rawgeti(L, idx, 4);
+ color.r = luaL_checknumber(L, -4);
+ color.g = luaL_checknumber(L, -3);
+ color.b = luaL_checknumber(L, -2);
+ color.a = luaL_optnumber(L, -1, 255);
+ lua_pop(L, 4);
+ return color;
+}
+
+
+static int f_show_debug(lua_State *L) {
+ luaL_checkany(L, 1);
+ rencache_show_debug(lua_toboolean(L, 1));
+ return 0;
+}
+
+
+static int f_get_size(lua_State *L) {
+ int w, h;
+ ren_get_size(&w, &h);
+ lua_pushnumber(L, w);
+ lua_pushnumber(L, h);
+ return 2;
+}
+
+
+static int f_begin_frame(lua_State *L) {
+ rencache_begin_frame();
+ return 0;
+}
+
+
+static int f_end_frame(lua_State *L) {
+ rencache_end_frame();
+ return 0;
+}
+
+
+static int f_set_clip_rect(lua_State *L) {
+ RenRect rect;
+ rect.x = luaL_checknumber(L, 1);
+ rect.y = luaL_checknumber(L, 2);
+ rect.width = luaL_checknumber(L, 3);
+ rect.height = luaL_checknumber(L, 4);
+ rencache_set_clip_rect(rect);
+ return 0;
+}
+
+
+static int f_draw_rect(lua_State *L) {
+ RenRect rect;
+ rect.x = luaL_checknumber(L, 1);
+ rect.y = luaL_checknumber(L, 2);
+ rect.width = luaL_checknumber(L, 3);
+ rect.height = luaL_checknumber(L, 4);
+ RenColor color = checkcolor(L, 5, 255);
+ rencache_draw_rect(rect, color);
+ return 0;
+}
+
+
+static int f_draw_text(lua_State *L) {
+ RenFont **font = luaL_checkudata(L, 1, API_TYPE_FONT);
+ const char *text = luaL_checkstring(L, 2);
+ int x = luaL_checknumber(L, 3);
+ int y = luaL_checknumber(L, 4);
+ RenColor color = checkcolor(L, 5, 255);
+ x = rencache_draw_text(*font, text, x, y, color);
+ lua_pushnumber(L, x);
+ return 1;
+}
+
+int luaopen_renderer(lua_State *L) {
+ static const luaL_Reg lib[] = {
+ { "show_debug", f_show_debug },
+ { "get_size", f_get_size },
+ { "begin_frame", f_begin_frame },
+ { "end_frame", f_end_frame },
+ { "set_clip_rect", f_set_clip_rect },
+ { "draw_rect", f_draw_rect },
+ { "draw_text", f_draw_text },
+ { NULL, NULL }
+ };
+ luaL_newlib(L, lib);
+ luaopen_renderer_font(L);
+ lua_setfield(L, -2, "font");
+ return 1;
+}
+
+// ----------------------------------------------------------------------------
+// lite/rencache.c
+
+/* a cache over the software renderer -- all drawing operations are stored as
+** commands when issued. At the end of the frame we write the commands to a grid
+** of hash values, take the cells that have changed since the previous frame,
+** merge them into dirty rectangles and redraw only those regions */
+
+#define CELLS_X 80
+#define CELLS_Y 50
+#define CELL_SIZE 96
+#define COMMAND_BUF_SIZE (1024 * 512)
+
+enum { FREE_FONT, SET_CLIP, DRAW_TEXT, DRAW_RECT };
+
+typedef struct {
+ int type, size;
+ RenRect rect;
+ RenColor color;
+ RenFont *font;
+ int tab_width;
+ char text[0];
+} Command;
+
+
+static unsigned cells_buf1[CELLS_X * CELLS_Y];
+static unsigned cells_buf2[CELLS_X * CELLS_Y];
+static unsigned *cells_prev = cells_buf1;
+static unsigned *cells = cells_buf2;
+static RenRect rect_buf[CELLS_X * CELLS_Y / 2];
+static char command_buf[COMMAND_BUF_SIZE];
+static int command_buf_idx;
+static RenRect screen_rect;
+static bool show_debug;
+
+
+/* 32bit fnv-1a hash */
+#define HASH_INITIAL 2166136261
+
+static void hash(unsigned *h, const void *data, int size) {
+ const unsigned char *p = data;
+ while (size--) {
+ *h = (*h ^ *p++) * 16777619;
+ }
+}
+
+
+static inline int cell_idx(int x, int y) {
+ return x + y * CELLS_X;
+}
+
+
+static inline bool rects_overlap(RenRect a, RenRect b) {
+ return b.x + b.width >= a.x && b.x <= a.x + a.width
+ && b.y + b.height >= a.y && b.y <= a.y + a.height;
+}
+
+
+static RenRect intersect_rects(RenRect a, RenRect b) {
+ int x1 = maxi(a.x, b.x);
+ int y1 = maxi(a.y, b.y);
+ int x2 = mini(a.x + a.width, b.x + b.width);
+ int y2 = mini(a.y + a.height, b.y + b.height);
+ return (RenRect) { x1, y1, max(0, x2 - x1), max(0, y2 - y1) };
+}
+
+
+static RenRect merge_rects(RenRect a, RenRect b) {
+ int x1 = mini(a.x, b.x);
+ int y1 = mini(a.y, b.y);
+ int x2 = maxi(a.x + a.width, b.x + b.width);
+ int y2 = maxi(a.y + a.height, b.y + b.height);
+ return (RenRect) { x1, y1, x2 - x1, y2 - y1 };
+}
+
+
+static Command* push_command(int type, int size) {
+ size_t alignment = 7; // alignof(max_align_t) - 1; //< C11 https://github.com/rxi/lite/pull/292/commits/ad1bdf56e3f212446e1c61fd45de8b94de5e2bc3
+ size = (size + alignment) & ~alignment; //< https://github.com/rxi/lite/pull/292/commits/ad1bdf56e3f212446e1c61fd45de8b94de5e2bc3
+ Command *cmd = (Command*) (command_buf + command_buf_idx);
+ int n = command_buf_idx + size;
+ if (n > COMMAND_BUF_SIZE) {
+ fprintf(stderr, "Warning: (" __FILE__ "): exhausted command buffer\n");
+ return NULL;
+ }
+ command_buf_idx = n;
+ lt_memset(cmd, 0, sizeof(Command));
+ cmd->type = type;
+ cmd->size = size;
+ return cmd;
+}
+
+
+static bool next_command(Command **prev) {
+ if (*prev == NULL) {
+ *prev = (Command*) command_buf;
+ } else {
+ *prev = (Command*) (((char*) *prev) + (*prev)->size);
+ }
+ return *prev != ((Command*) (command_buf + command_buf_idx));
+}
+
+
+void rencache_show_debug(bool enable) {
+ show_debug = enable;
+}
+
+
+void rencache_free_font(RenFont *font) {
+ Command *cmd = push_command(FREE_FONT, sizeof(Command));
+ if (cmd) { cmd->font = font; }
+}
+
+
+void rencache_set_clip_rect(RenRect rect) {
+ Command *cmd = push_command(SET_CLIP, sizeof(Command));
+ if (cmd) { cmd->rect = intersect_rects(rect, screen_rect); }
+}
+
+
+void rencache_draw_rect(RenRect rect, RenColor color) {
+ if (!rects_overlap(screen_rect, rect)) { return; }
+ Command *cmd = push_command(DRAW_RECT, sizeof(Command));
+ if (cmd) {
+ cmd->rect = rect;
+ cmd->color = color;
+ }
+}
+
+
+int rencache_draw_text(RenFont *font, const char *text, int x, int y, RenColor color) {
+ RenRect rect;
+ rect.x = x;
+ rect.y = y;
+ rect.width = ren_get_font_width(font, text);
+ rect.height = ren_get_font_height(font);
+
+ if (rects_overlap(screen_rect, rect)) {
+ int sz = strlen(text) + 1;
+ Command *cmd = push_command(DRAW_TEXT, sizeof(Command) + sz);
+ if (cmd) {
+ memcpy(cmd->text, text, sz);
+ cmd->color = color;
+ cmd->font = font;
+ cmd->rect = rect;
+ cmd->tab_width = ren_get_font_tab_width(font);
+ }
+ }
+
+ return x + rect.width;
+}
+
+
+void rencache_invalidate(void) {
+ lt_memset(cells_prev, 0xff, sizeof(cells_buf1));
+}
+
+
+void rencache_begin_frame(void) {
+ /* reset all cells if the screen width/height has changed */
+ int w, h;
+ ren_get_size(&w, &h);
+ if (screen_rect.width != w || h != screen_rect.height) {
+ screen_rect.width = w;
+ screen_rect.height = h;
+ rencache_invalidate();
+ }
+}
+
+
+static void update_overlapping_cells(RenRect r, unsigned h) {
+ int x1 = r.x / CELL_SIZE;
+ int y1 = r.y / CELL_SIZE;
+ int x2 = (r.x + r.width) / CELL_SIZE;
+ int y2 = (r.y + r.height) / CELL_SIZE;
+
+ for (int y = y1; y <= y2; y++) {
+ for (int x = x1; x <= x2; x++) {
+ int idx = cell_idx(x, y);
+ hash(&cells[idx], &h, sizeof(h));
+ }
+ }
+}
+
+
+static void push_rect(RenRect r, int *count) {
+ /* try to merge with existing rectangle */
+ for (int i = *count - 1; i >= 0; i--) {
+ RenRect *rp = &rect_buf[i];
+ if (rects_overlap(*rp, r)) {
+ *rp = merge_rects(*rp, r);
+ return;
+ }
+ }
+ /* couldn't merge with previous rectangle: push */
+ rect_buf[(*count)++] = r;
+}
+
+
+void rencache_end_frame(void) {
+ /* update cells from commands */
+ Command *cmd = NULL;
+ RenRect cr = screen_rect;
+ while (next_command(&cmd)) {
+ if (cmd->type == SET_CLIP) { cr = cmd->rect; }
+ RenRect r = intersect_rects(cmd->rect, cr);
+ if (r.width == 0 || r.height == 0) { continue; }
+ unsigned h = HASH_INITIAL;
+ hash(&h, cmd, cmd->size);
+ update_overlapping_cells(r, h);
+ }
+
+ /* push rects for all cells changed from last frame, reset cells */
+ int rect_count = 0;
+ int max_x = screen_rect.width / CELL_SIZE + 1;
+ int max_y = screen_rect.height / CELL_SIZE + 1;
+ for (int y = 0; y < max_y; y++) {
+ for (int x = 0; x < max_x; x++) {
+ /* compare previous and current cell for change */
+ int idx = cell_idx(x, y);
+ if (cells[idx] != cells_prev[idx]) {
+ push_rect((RenRect) { x, y, 1, 1 }, &rect_count);
+ }
+ cells_prev[idx] = HASH_INITIAL;
+ }
+ }
+
+ /* expand rects from cells to pixels */
+ for (int i = 0; i < rect_count; i++) {
+ RenRect *r = &rect_buf[i];
+ r->x *= CELL_SIZE;
+ r->y *= CELL_SIZE;
+ r->width *= CELL_SIZE;
+ r->height *= CELL_SIZE;
+ *r = intersect_rects(*r, screen_rect);
+ }
+
+ /* redraw updated regions */
+ bool has_free_commands = false;
+ for (int i = 0; i < rect_count; i++) {
+ /* draw */
+ RenRect r = rect_buf[i];
+ ren_set_clip_rect(r);
+
+ cmd = NULL;
+ while (next_command(&cmd)) {
+ switch (cmd->type) {
+ case FREE_FONT:
+ has_free_commands = true;
+ break;
+ case SET_CLIP:
+ ren_set_clip_rect(intersect_rects(cmd->rect, r));
+ break;
+ case DRAW_RECT:
+ ren_draw_rect(cmd->rect, cmd->color);
+ break;
+ case DRAW_TEXT:
+ ren_set_font_tab_width(cmd->font, cmd->tab_width);
+ ren_draw_text(cmd->font, cmd->text, cmd->rect.x, cmd->rect.y, cmd->color);
+ break;
+ }
+ }
+
+ if (show_debug) {
+ RenColor color = { rand(), rand(), rand(), 50 };
+ ren_draw_rect(r, color);
+ }
+ }
+
+ /* update dirty rects */
+ if (rect_count > 0) {
+ ren_update_rects(rect_buf, rect_count);
+ }
+
+ /* free fonts */
+ if (has_free_commands) {
+ cmd = NULL;
+ while (next_command(&cmd)) {
+ if (cmd->type == FREE_FONT) {
+ ren_free_font(cmd->font);
+ }
+ }
+ }
+
+ /* swap cell buffer and reset */
+ unsigned *tmp = cells;
+ cells = cells_prev;
+ cells_prev = tmp;
+ command_buf_idx = 0;
+}
+
+// ----------------------------------------------------------------------------
+// lite/system.c
+
+static int f_set_cursor(lua_State *L) {
+ static const char *cursor_opts[] = {
+ "arrow",
+ "ibeam",
+ "sizeh",
+ "sizev",
+ "hand",
+ NULL
+ };
+ int n = luaL_checkoption(L, 1, "arrow", cursor_opts);
+ lt_setcursor(n);
+ return 0;
+}
+
+static int f_set_window_title(lua_State *L) {
+ const char *title = luaL_checkstring(L, 1);
+ lt_setwindowtitle(title);
+ return 0;
+}
+static int f_set_window_mode(lua_State *L) {
+ static const char *window_opts[] = { "normal", "maximized", "fullscreen", 0 };
+ enum { WIN_NORMAL, WIN_MAXIMIZED, WIN_FULLSCREEN };
+ int n = luaL_checkoption(L, 1, "normal", window_opts);
+ lt_setwindowmode(n);
+ return 0;
+}
+static int f_window_has_focus(lua_State *L) {
+ unsigned flags = lt_haswindowfocus();
+ lua_pushboolean(L, flags);
+ return 1;
+}
+
+static int f_show_confirm_dialog(lua_State *L) {
+ const char *title = luaL_checkstring(L, 1);
+ const char *msg = luaL_checkstring(L, 2);
+ int id = lt_prompt(msg, title); // 0:no, 1:yes
+ lua_pushboolean(L, !!id);
+ return 1;
+}
+
+static int f_chdir(lua_State *L) {
+ const char *path = luaL_checkstring(L, 1);
+ int err = chdir(path);
+ if (err) { luaL_error(L, "chdir() failed"); }
+ return 0;
+}
+static int f_list_dir(lua_State *L) {
+ const char *path = luaL_checkstring(L, 1);
+ lua_newtable(L);
+ lt_globpath(L, path);
+ return 1;
+}
+static int f_absolute_path(lua_State *L) {
+ const char *path = luaL_checkstring(L, 1);
+ char *res = lt_realpath(path, NULL);
+ if (!res) { return 0; }
+ lua_pushstring(L, res);
+ lt_realpath_free(res);
+ return 1;
+}
+static int f_get_file_info(lua_State *L) {
+ const char *path = luaL_checkstring(L, 1);
+
+ struct stat s;
+ int err = stat(path, &s);
+ if (err < 0) {
+ lua_pushnil(L);
+ lua_pushstring(L, strerror(errno));
+ return 2;
+ }
+
+ lua_newtable(L);
+ lua_pushnumber(L, s.st_mtime);
+ lua_setfield(L, -2, "modified");
+
+ lua_pushnumber(L, s.st_size);
+ lua_setfield(L, -2, "size");
+
+ if (S_ISREG(s.st_mode)) {
+ lua_pushstring(L, "file");
+ } else if (S_ISDIR(s.st_mode)) {
+ lua_pushstring(L, "dir");
+ } else {
+ lua_pushnil(L);
+ }
+ lua_setfield(L, -2, "type");
+
+ return 1;
+}
+
+
+static int f_get_clipboard(lua_State *L) {
+ const char *text = lt_getclipboard(lt_window());
+ if (!text) { return 0; }
+ lua_pushstring(L, text);
+ return 1;
+}
+static int f_set_clipboard(lua_State *L) {
+ const char *text = luaL_checkstring(L, 1);
+ lt_setclipboard(lt_window(), text);
+ return 0;
+}
+
+
+static int f_get_time(lua_State *L) {
+ double ss = lt_time_ms() / 1000.0;
+ lua_pushnumber(L, ss);
+ return 1;
+}
+static int f_sleep(lua_State *L) {
+ double ss = luaL_checknumber(L, 1);
+ lt_sleep_ms(ss * 1000);
+ return 0;
+}
+
+
+static int f_exec(lua_State *L) {
+ size_t len;
+ const char *cmd = luaL_checklstring(L, 1, &len);
+ char *buf = lt_malloc(len + 32);
+ if (!buf) { luaL_error(L, "buffer allocation failed"); }
+#if _WIN32
+ sprintf(buf, "cmd /c \"%s\"", cmd);
+ WinExec(buf, SW_HIDE);
+#else
+ sprintf(buf, "%s &", cmd);
+ int res = system(buf);
+#endif
+ lt_free(buf);
+ return 0;
+}
+
+
+static int f_fuzzy_match(lua_State *L) {
+ const char *str = luaL_checkstring(L, 1);
+ const char *ptn = luaL_checkstring(L, 2);
+ int score = 0;
+ int run = 0;
+
+ while (*str && *ptn) {
+ while (*str == ' ') { str++; }
+ while (*ptn == ' ') { ptn++; }
+ if (tolower(*str) == tolower(*ptn)) {
+ score += run * 10 - (*str != *ptn);
+ run++;
+ ptn++;
+ } else {
+ score -= 10;
+ run = 0;
+ }
+ str++;
+ }
+ if (*ptn) { return 0; }
+
+ lua_pushnumber(L, score - (int) strlen(str));
+ return 1;
+}
+
+static int f_poll_event(lua_State *L) { // init.lua > core.step() wakes on mousemoved || inputtext
+ int rc = lt_poll_event(L);
+ return rc;
+}
+
+int luaopen_system(lua_State *L) {
+ static const luaL_Reg lib[] = {
+ { "poll_event", f_poll_event },
+ { "set_cursor", f_set_cursor },
+ { "set_window_title", f_set_window_title },
+ { "set_window_mode", f_set_window_mode },
+ { "window_has_focus", f_window_has_focus },
+ { "show_confirm_dialog", f_show_confirm_dialog },
+ { "chdir", f_chdir },
+ { "list_dir", f_list_dir },
+ { "absolute_path", f_absolute_path },
+ { "get_file_info", f_get_file_info },
+ { "get_clipboard", f_get_clipboard },
+ { "set_clipboard", f_set_clipboard },
+ { "get_time", f_get_time },
+ { "sleep", f_sleep },
+ { "exec", f_exec },
+ { "fuzzy_match", f_fuzzy_match },
+ { NULL, NULL }
+ };
+ luaL_newlib(L, lib);
+ return 1;
+}
+
+// ----------------------------------------------------------------------------
+// lite/api/api.c
+
+void api_load_libs(lua_State *L) {
+ static const luaL_Reg libs[] = {
+ { "system", luaopen_system },
+ { "renderer", luaopen_renderer },
+ { NULL, NULL }
+ };
+ for (int i = 0; libs[i].name; i++) {
+ luaL_requiref(L, libs[i].name, libs[i].func, 1);
+ }
+}
+
+// ----------------------------------------------------------------------------
+// lite/main.c
+
+void lt_init(lua_State *L, void *handle, const char *pathdata, int argc, char **argv, float scale, const char *platform, const char *pathexe) {
+ // setup renderer
+ ren_init(handle);
+
+ // setup lua context
+ api_load_libs(L);
+
+ lua_newtable(L);
+ for (int i = 0; i < argc; i++) {
+ lua_pushstring(L, argv[i]);
+ lua_rawseti(L, -2, i + 1);
+ }
+ lua_setglobal(L, "ARGS");
+
+ lua_pushstring(L, "1.11");
+ lua_setglobal(L, "VERSION");
+
+ lua_pushstring(L, platform);
+ lua_setglobal(L, "PLATFORM");
+
+ lua_pushnumber(L, scale);
+ lua_setglobal(L, "SCALE");
+
+ lua_pushstring(L, pathdata);
+ lua_setglobal(L, "DATADIR");
+
+ lua_pushstring(L, pathexe);
+ lua_setglobal(L, "EXEFILE");
+
+ // init lite
+ luaL_dostring(L, "core = {}");
+ luaL_dostring(L,
+ "xpcall(function()\n"
+ " SCALE = tonumber(os.getenv(\"LITE_SCALE\")) or SCALE\n"
+ " PATHSEP = package.config:sub(1, 1)\n"
+ " EXEDIR = EXEFILE:match(\"^(.+)[/\\\\].*$\")\n"
+ " USERDIR = EXEDIR .. 'data/user/'\n"
+ " package.path = EXEDIR .. '/data/?.lua;' .. package.path\n"
+ " package.path = EXEDIR .. '/data/?/init.lua;' .. package.path\n"
+ " core = require('core')\n"
+ " core.init()\n"
+ "end, function(err)\n"
+ " print('Error: ' .. tostring(err))\n"
+ " print(debug.traceback(nil, 2))\n"
+ " if core and core.on_error then\n"
+ " pcall(core.on_error, err)\n"
+ " end\n"
+ " os.exit(1)\n"
+ "end)"
+ );
+}
+void lt_tick(struct lua_State *L) {
+ luaL_dostring(L,
+ "xpcall(function()\n"
+ " core.run1()\n"
+ "end, function(err)\n"
+ " print('Error: ' .. tostring(err))\n"
+ " print(debug.traceback(nil, 2))\n"
+ " if core and core.on_error then\n"
+ " pcall(core.on_error, err)\n"
+ " end\n"
+ " os.exit(1)\n"
+ "end)"
+ );
+}
+#line 0
+
#endif // V4K_3RD
diff --git a/engine/v4k.c b/engine/v4k.c
index b10c17f..b748f28 100644
--- a/engine/v4k.c
+++ b/engine/v4k.c
@@ -101,7 +101,7 @@
//-----------------------------------------------------------------------------
// C files
-#line 1 "engine/split/v4k_begin.c"
+#line 1 "v4k_begin.c"
#define do_threadlock(mutexptr) \
for( int init_ = !!(mutexptr) || (thread_mutex_init( (mutexptr) = CALLOC(1, sizeof(thread_mutex_t)) ), 1); init_; init_ = 0) \
for( int lock_ = (thread_mutex_lock( mutexptr ), 1); lock_; lock_ = (thread_mutex_unlock( mutexptr ), 0) )
@@ -110,7 +110,7 @@
((struct nk_color){ ((color>>0))&255,((color>>8))&255,((color>>16))&255,((color>>24))&255 })
#line 0
-#line 1 "engine/split/v4k_ds.c"
+#line 1 "v4k_ds.c"
// -----------------------------------------------------------------------------
// sort/less
@@ -500,7 +500,7 @@ void (set_free)(set* m) {
}
#line 0
-#line 1 "engine/split/v4k_string.c"
+#line 1 "v4k_string.c"
#include
char* tempvl(const char *fmt, va_list vl) {
@@ -921,9 +921,158 @@ AUTORUN {
test( !strcmp("Hello happy world.", buf) );
}
#endif
+
+// ----------------------------------------------------------------------------
+// localization kit
+
+static const char *kit_lang = "enUS", *kit_langs =
+ "enUS,enGB,"
+ "frFR,"
+ "esES,esAR,esMX,"
+ "deDE,deCH,deAT,"
+ "itIT,itCH,"
+ "ptBR,ptPT,"
+ "zhCN,zhSG,zhTW,zhHK,zhMO,"
+ "ruRU,elGR,trTR,daDK,noNB,svSE,nlNL,plPL,fiFI,jaJP,"
+ "koKR,csCZ,huHU,roRO,thTH,bgBG,heIL"
+;
+
+static map(char*,char*) kit_ids;
+static map(char*,char*) kit_vars;
+
+#ifndef KIT_FMT_ID2
+#define KIT_FMT_ID2 "%s.%s"
+#endif
+
+void kit_init() {
+ do_once map_init(kit_ids, less_str, hash_str);
+ do_once map_init(kit_vars, less_str, hash_str);
+}
+
+void kit_insert( const char *id, const char *translation) {
+ char *id2 = va(KIT_FMT_ID2, kit_lang, id);
+
+ char **found = map_find_or_add_allocated_key(kit_ids, STRDUP(id2), NULL);
+ if(*found) FREE(*found);
+ *found = STRDUP(translation);
+}
+
+bool kit_merge( const char *filename ) {
+ // @todo: xlsx2ini
+ return false;
+}
+
+void kit_clear() {
+ map_clear(kit_ids);
+}
+
+bool kit_load( const char *filename ) {
+ return kit_clear(), kit_merge( filename );
+}
+
+void kit_set( const char *key, const char *value ) {
+ value = value && value[0] ? value : "";
+
+ char **found = map_find_or_add_allocated_key(kit_vars, STRDUP(key), NULL );
+ if(*found) FREE(*found);
+ *found = STRDUP(value);
+}
+
+void kit_reset() {
+ map_clear(kit_vars);
+}
+
+char *kit_translate2( const char *id, const char *lang ) {
+ char *id2 = va(KIT_FMT_ID2, lang, id);
+
+ char **found = map_find(kit_ids, id2);
+
+ // return original [[ID]] if no translation is found
+ if( !found ) return va("[[%s]]", id);
+
+ // return translation if no {{moustaches}} are found
+ if( !strstr(*found, "{{") ) return *found;
+
+ // else replace all found {{moustaches}} with context vars
+ {
+ // make room
+ static __thread char *results[16] = {0};
+ static __thread unsigned counter = 0; counter = (counter+1) % 16;
+
+ char *buffer = results[ counter ];
+ if( buffer ) FREE(buffer), buffer = 0;
+
+ // iterate moustaches
+ const char *begin, *end, *text = *found;
+ while( NULL != (begin = strstr(text, "{{")) ) {
+ end = strstr(begin+2, "}}");
+ if( end ) {
+ char *var = va("%.*s", (int)(end - (begin+2)), begin+2);
+ char **found_var = map_find(kit_vars, var);
+
+ if( found_var && 0[*found_var] ) {
+ strcatf(&buffer, "%.*s%s", (int)(begin - text), text, *found_var);
+ } else {
+ strcatf(&buffer, "%.*s{{%s}}", (int)(begin - text), text, var);
+ }
+
+ text = end+2;
+ } else {
+ strcatf(&buffer, "%.*s", (int)(begin - text), text);
+
+ text = begin+2;
+ }
+ }
+
+ strcatf(&buffer, "%s", text);
+ return buffer;
+ }
+}
+
+char *kit_translate( const char *id ) {
+ return kit_translate2( id, kit_lang );
+}
+
+void kit_locale( const char *lang ) {
+ kit_lang = STRDUP(lang); // @leak
+}
+
+void kit_dump_state( FILE *fp ) {
+ for each_map(kit_ids, char *, k, char *, v) {
+ fprintf(fp, "[ID ] %s=%s\n", k, v);
+ }
+ for each_map(kit_vars, char *, k, char *, v) {
+ fprintf(fp, "[VAR] %s=%s\n", k, v);
+ }
+}
+
+/*
+int main() {
+ kit_init();
+
+ kit_locale("enUS");
+ kit_insert("HELLO_PLAYERS", "Hi {{PLAYER1}} and {{PLAYER2}}!");
+ kit_insert("GREET_PLAYERS", "Nice to meet you.");
+
+ kit_locale("esES");
+ kit_insert("HELLO_PLAYERS", "Hola {{PLAYER1}} y {{PLAYER2}}!");
+ kit_insert("GREET_PLAYERS", "Un placer conoceros.");
+
+ kit_locale("enUS");
+ printf("%s %s\n", kit_translate("HELLO_PLAYERS"), kit_translate("GREET_PLAYERS")); // Hi {{PLAYER1}} and {{PLAYER2}}! Nice to meet you.
+
+ kit_locale("esES");
+ kit_set("PLAYER1", "John");
+ kit_set("PLAYER2", "Karl");
+ printf("%s %s\n", kit_translate("HELLO_PLAYERS"), kit_translate("GREET_PLAYERS")); // Hola John y Karl! Un placer conoceros.
+
+ assert( 0 == strcmp(kit_translate("NON_EXISTING"), "[[NON_EXISTING]]")); // [[NON_EXISTING]]
+ assert(~puts("Ok"));
+}
+*/
#line 0
-#line 1 "engine/split/v4k_compat.c"
+#line 1 "v4k_compat.c"
//-----------------------------------------------------------------------------
// compat (unix & stdio.h)
@@ -1042,7 +1191,7 @@ static void v4k_pre_init();
static void v4k_post_init(float);
#line 0
-#line 1 "engine/split/v4k_ui.c"
+#line 1 "v4k_ui.c"
// ----------------------------------------------------------------------------------------
// ui extensions first
@@ -2946,8 +3095,8 @@ int ui_color4f(const char *label, float *color) {
nk_layout_row_dynamic(ui_ctx, 0, 2);
ui_label_(label, NK_TEXT_LEFT);
- struct nk_colorf after = { color[0]*ui_alpha, color[1]*ui_alpha, color[2]*ui_alpha, color[3] }, before = after;
- struct nk_colorf clamped = { clampf(color[0],0,1), clampf(color[1],0,1), clampf(color[2],0,1), clampf(color[3],0,1) };
+ struct nk_colorf after = { color[0]*ui_alpha, color[1]*ui_alpha, color[2]*ui_alpha, color[3]*ui_alpha }, before = after;
+ struct nk_colorf clamped = { clampf(after.r,0,1), clampf(after.g,0,1), clampf(after.b,0,1), clampf(after.a,0,1) };
if (nk_combo_begin_color(ui_ctx, nk_rgb_cf(clamped), nk_vec2(200,400))) {
nk_layout_row_dynamic(ui_ctx, 120, 1);
after = nk_color_picker(ui_ctx, after, NK_RGB);
@@ -3034,8 +3183,8 @@ int ui_color3f(const char *label, float *color) {
nk_layout_row_dynamic(ui_ctx, 0, 2);
ui_label_(label, NK_TEXT_LEFT);
- struct nk_colorf after = { color[0]*ui_alpha, color[1]*ui_alpha, color[2]*ui_alpha, ui_alpha }, before = after;
- struct nk_colorf clamped = { clampf(color[0],0,1), clampf(color[1],0,1), clampf(color[2],0,1), 1 };
+ struct nk_colorf after = { color[0]*ui_alpha, color[1]*ui_alpha, color[2]*ui_alpha, color[3]*ui_alpha }, before = after;
+ struct nk_colorf clamped = { clampf(after.r,0,1), clampf(after.g,0,1), clampf(after.b,0,1), ui_alpha };
if (nk_combo_begin_color(ui_ctx, nk_rgb_cf(clamped), nk_vec2(200,400))) {
nk_layout_row_dynamic(ui_ctx, 120, 1);
after = nk_color_picker(ui_ctx, after, NK_RGB);
@@ -3078,7 +3227,7 @@ int ui_color3(const char *label, unsigned *color) {
nk_layout_row_dynamic(ui_ctx, 0, 2);
ui_label_(label, NK_TEXT_LEFT);
- struct nk_colorf after = { r*ui_alpha, g*ui_alpha, b*ui_alpha, 1 }, before = after;
+ struct nk_colorf after = { r*ui_alpha/255, g*ui_alpha/255, b*ui_alpha/255, ui_alpha }, before = after;
if (nk_combo_begin_color(ui_ctx, nk_rgb_cf(after), nk_vec2(200,400))) {
nk_layout_row_dynamic(ui_ctx, 120, 1);
after = nk_color_picker(ui_ctx, after, NK_RGB);
@@ -3740,8 +3889,10 @@ int ui_demo(int do_windows) {
static float float2[2] = {1,2};
static float float3[3] = {1,2,3};
static float float4[4] = {1,2,3,4};
- static float rgb[3] = {0.84,0.67,0.17};
- static float rgba[4] = {0.67,0.90,0.12,1};
+ static float rgbf[3] = {0.84,0.67,0.17};
+ static float rgbaf[4] = {0.67,0.90,0.12,1};
+ static unsigned rgb = CYAN;
+ static unsigned rgba = PINK;
static float slider = 0.5f;
static float slider2 = 0.5f;
static char string[64] = "hello world 123";
@@ -3785,8 +3936,10 @@ int ui_demo(int do_windows) {
if( ui_list("my list", list, 3, &item ) ) puts("list changed");
if( ui_section("Colors")) {}
- if( ui_color3f("my color3", rgb) ) puts("color3 changed");
- if( ui_color4f("my color4@this is a tooltip", rgba) ) puts("color4 changed");
+ if( ui_color3("my color3", &rgb) ) puts("color3 changed");
+ if( ui_color4("my color4@this is a tooltip", &rgba) ) puts("color4 changed");
+ if( ui_color3f("my color3f", rgbf) ) puts("color3f changed");
+ if( ui_color4f("my color4f@this is a tooltip", rgbaf) ) puts("color4f changed");
if( ui_section("Sliders")) {}
if( ui_slider("my slider", &slider)) puts("slider changed");
@@ -3899,7 +4052,7 @@ int ui_demo(int do_windows) {
#line 0
-#line 1 "engine/split/v4k_audio.c"
+#line 1 "v4k_audio.c"
// @fixme: really shutdown audio & related threads before quitting. ma_dr_wav crashes.
@@ -4492,7 +4645,7 @@ int ui_audio() {
}
#line 0
-#line 1 "engine/split/v4k_collide.c"
+#line 1 "v4k_collide.c"
/* poly */
poly poly_alloc(int cnt) {
poly p = {0};
@@ -5920,7 +6073,7 @@ void collide_demo() { // debug draw collisions // @fixme: fix leaks: poly_free()
}
#line 0
-#line 1 "engine/split/v4k_cook.c"
+#line 1 "v4k_cook.c"
// data pipeline
// - rlyeh, public domain.
// ----------------------------------------------------------------------------
@@ -5934,7 +6087,7 @@ void collide_demo() { // debug draw collisions // @fixme: fix leaks: poly_free()
const char *ART = "art/";
const char *TOOLS = "tools/bin/";
-const char *EDITOR = "tools/editor/";
+const char *EDITOR = "tools/";
const char *COOK_INI = "tools/cook.ini";
static unsigned ART_SKIP_ROOT; // number of chars to skip the base root in ART folder
@@ -6431,11 +6584,14 @@ int cook(void *userdata) {
fclose(in);
}
+// if(array_count(uncooked))
+// PRINTF("cook_jobs[%d]=%d\n", job->threadid, array_count(uncooked));
+
// generate cook metrics. you usually do `game.exe --cook-stats && (type *.csv | sort /R > cook.csv)`
static __thread FILE *statsfile = 0;
if(flag("--cook-stats"))
fseek(statsfile = fopen(va("cook%d.csv",job->threadid), "a+t"), 0L, SEEK_END);
- if(statsfile && ftell(statsfile) == 0) fprintf(statsfile,"%10s,%10s,%10s,%10s,%10s, %s\n","+total_ms","gen_ms","exe_ms","zip_ms","pass","file");
+ if(statsfile && !job->threadid && ftell(statsfile) == 0) fprintf(statsfile,"%10s,%10s,%10s,%10s,%10s, %s\n","+total_ms","gen_ms","exe_ms","zip_ms","pass","file");
// added or changed files
for( int i = 0, end = array_count(uncooked); i < end && !cook_cancelling; ++i ) {
@@ -6748,10 +6904,8 @@ void cook_stop() {
int cook_progress() {
int count = 0, sum = 0;
for( int i = 0, end = cook_jobs(); i < end; ++i ) {
-// if( jobs[i].progress >= 0 ) {
sum += jobs[i].progress;
++count;
-// }
}
return cook_jobs() ? sum / (count+!count) : 100;
}
@@ -6779,7 +6933,7 @@ bool have_tools() {
}
#line 0
-#line 1 "engine/split/v4k_data.c"
+#line 1 "v4k_data.c"
static array(json5) roots;
static array(char*) sources;
@@ -7009,7 +7163,7 @@ bool data_tests() {
}
#line 0
-#line 1 "engine/split/v4k_extend.c"
+#line 1 "v4k_extend.c"
// dll ------------------------------------------------------------------------
/* deprecated
@@ -7300,7 +7454,7 @@ void *script_init_env(unsigned flags) {
}
#line 0
-#line 1 "engine/split/v4k_file.c"
+#line 1 "v4k_file.c"
// -----------------------------------------------------------------------------
// file
@@ -8187,7 +8341,7 @@ if( found && *found == 0 ) {
char *cmd = va("%scook" ifdef(osx,".osx",ifdef(linux,".linux",".exe"))" %s %s --cook-ini=%s --cook-additive --cook-jobs=1 --quiet", TOOLS, group1, group2, COOK_INI);
// cook groups
- int rc = atoi(app_exec(cmd));
+ int rc = system(cmd); // atoi(app_exec(cmd));
if(rc < 0) PANIC("cannot invoke `%scook` (return code %d)", TOOLS, rc);
vfs_reload(); // @todo: optimize me. it is waaay inefficent to reload the whole VFS layout after cooking a single asset
@@ -8453,7 +8607,7 @@ bool ini_write(const char *filename, const char *section, const char *key, const
#line 0
-#line 1 "engine/split/v4k_font.c"
+#line 1 "v4k_font.c"
// font framework. original code by Vassvik (UNLICENSED)
// - rlyeh, public domain.
//
@@ -10807,7 +10961,7 @@ vec2 font_rect(const char *str) {
}
#line 0
-#line 1 "engine/split/v4k_input.c"
+#line 1 "v4k_input.c"
// input framework
// - rlyeh, public domain
//
@@ -11572,7 +11726,7 @@ int ui_gamepads() {
}
#line 0
-#line 1 "engine/split/v4k_math.c"
+#line 1 "v4k_math.c"
// -----------------------------------------------------------------------------
// math framework: rand, ease, vec2, vec3, vec4, quat, mat2, mat33, mat34, mat4
// - rlyeh, public domain
@@ -12452,7 +12606,7 @@ AUTORUN {
}
#line 0
-#line 1 "engine/split/v4k_memory.c"
+#line 1 "v4k_memory.c"
size_t dlmalloc_usable_size(void*); // __ANDROID_API__
#if is(bsd) || is(osx) // bsd or osx
@@ -12461,9 +12615,10 @@ size_t dlmalloc_usable_size(void*); // __ANDROID_API__
# include
#endif
-#ifndef SYS_REALLOC
-#define SYS_REALLOC realloc
-#define SYS_MSIZE /* bsd/osx, then win32, then ems/__GLIBC__, then __ANDROID_API__ */ \
+#ifndef SYS_MEM_INIT
+#define SYS_MEM_INIT()
+#define SYS_MEM_REALLOC realloc
+#define SYS_MEM_SIZE /* bsd/osx, then win32, then ems/__GLIBC__, then __ANDROID_API__ */ \
ifdef(osx, malloc_size, ifdef(bsd, malloc_size, \
ifdef(win32, _msize, malloc_usable_size)))
#endif
@@ -12473,10 +12628,12 @@ size_t dlmalloc_usable_size(void*); // __ANDROID_API__
static __thread uint64_t xstats_current = 0, xstats_total = 0, xstats_allocs = 0;
void* xrealloc(void* oldptr, size_t size) {
+ static __thread int once = 0; for(;!once;once = 1) SYS_MEM_INIT();
+
// for stats
size_t oldsize = xsize(oldptr);
- void *ptr = SYS_REALLOC(oldptr, size);
+ void *ptr = SYS_MEM_REALLOC(oldptr, size);
if( !ptr && size ) {
PANIC("Not memory enough (trying to allocate %u bytes)", (unsigned)size);
}
@@ -12501,7 +12658,7 @@ void* xrealloc(void* oldptr, size_t size) {
return ptr;
}
size_t xsize(void* p) {
- if( p ) return SYS_MSIZE(p);
+ if( p ) return SYS_MEM_SIZE(p);
return 0;
}
char *xstats(void) {
@@ -12553,7 +12710,7 @@ void* forget( void *ptr ) {
}
#line 0
-#line 1 "engine/split/v4k_network.c"
+#line 1 "v4k_network.c"
#if is(tcc) && is(win32) // @fixme: https lib is broken with tcc. replaced with InternetReadFile() api for now
@@ -12850,7 +13007,7 @@ static void network_init() {
}
#line 0
-#line 1 "engine/split/v4k_track.c"
+#line 1 "v4k_track.c"
static __thread int track__sock = -1;
//~ Lifecycle methods
@@ -12987,7 +13144,7 @@ int track_event_props(char const *event_id, char const *user_id, const track_pro
#undef TRACK__APPEND_SAFE_EX
#line 0
-#line 1 "engine/split/v4k_netsync.c"
+#line 1 "v4k_netsync.c"
typedef void* (*rpc_function)();
typedef struct rpc_call {
@@ -13673,7 +13830,7 @@ void network_rpc_send(unsigned id, const char *cmdline) {
}
#line 0
-#line 1 "engine/split/v4k_pack.c"
+#line 1 "v4k_pack.c"
// -----------------------------------------------------------------------------
// semantic versioning in a single byte (octal)
// - rlyeh, public domain.
@@ -16046,7 +16203,7 @@ AUTORUN {
#endif
#line 0
-#line 1 "engine/split/v4k_reflect.c"
+#line 1 "v4k_reflect.c"
// C reflection: enums, functions, structs, members and anotations.
// - rlyeh, public domain
//
@@ -16240,7 +16397,7 @@ AUTOTEST {
}
#line 0
-#line 1 "engine/split/v4k_render.c"
+#line 1 "v4k_render.c"
// -----------------------------------------------------------------------------
// opengl
@@ -17672,1110 +17829,6 @@ void fullscreen_quad_ycbcr_flipped( texture_t textureYCbCr[3], float gamma ) {
// glDisable( GL_BLEND );
}
-// ----------------------------------------------------------------------------
-// sprites
-
-typedef struct sprite_t {
- float px, py, pz; // origin x, y, depth
- float ox, oy, cos, sin; // offset x, offset y, cos/sin of rotation degree
- float sx, sy; // scale x,y
- uint32_t rgba; // vertex color
- float cellw, cellh; // dimensions of any cell in spritesheet
-
- union {
- struct {
- int frame, ncx, ncy; // frame in a (num cellx, num celly) spritesheet
- };
- struct {
- float x, y, w, h; // normalized[0..1] within texture bounds
- };
- };
-} sprite_t;
-
-// sprite batching
-typedef struct batch_t { array(sprite_t) sprites; mesh_t mesh; int dirty; } batch_t;
-typedef map(int, batch_t) batch_group_t; // mapkey is anything that forces a flush. texture_id for now, might be texture_id+program_id soon
-
-// sprite stream
-typedef struct sprite_vertex { vec3 pos; vec2 uv; uint32_t rgba; } sprite_vertex;
-typedef struct sprite_index { GLuint triangle[3]; } sprite_index;
-
-#define sprite_vertex(...) C_CAST(sprite_vertex, __VA_ARGS__)
-#define sprite_index(...) C_CAST(sprite_index, __VA_ARGS__)
-
-// sprite impl
-static int sprite_count = 0;
-static int sprite_program = -1;
-static array(sprite_index) sprite_indices = 0;
-static array(sprite_vertex) sprite_vertices = 0;
-static batch_group_t sprite_additive_group = {0}; // (w/2,h/2) centered
-static batch_group_t sprite_translucent_group = {0}; // (w/2,h/2) centered
-static batch_group_t sprite_00_translucent_group = {0}; // (0,0) centered
-
-void sprite( texture_t texture, float position[3], float rotation, uint32_t color ) {
- float offset[2] = {0,0}, scale[2] = {1,1}, spritesheet[3] = {0,0,0};
- sprite_sheet( texture, spritesheet, position, rotation, offset, scale, 0, color, false );
-}
-
-// rect(x,y,w,h) is [0..1] normalized, z-index, pos(x,y,scalex,scaley), rotation (degrees), color (rgba)
-void sprite_rect( texture_t t, vec4 rect, float zindex, vec4 pos, float tilt_deg, unsigned tint_rgba) {
- // do not queue if either alpha or scale is zero
- if( 0 == (pos.z * pos.w * ((tint_rgba>>24) & 255)) ) return;
-
- sprite_t s = {0};
-
- s.px = pos.x, s.py = pos.y, s.pz = zindex;
- s.sx = pos.z, s.sy = pos.w;
-
- s.x = rect.x, s.y = rect.y, s.w = rect.z, s.h = rect.w;
- s.cellw = s.w * s.sx * t.w, s.cellh = s.h * s.sy * t.h;
-
- s.rgba = tint_rgba;
- s.ox = 0/*ox*/ * s.sx;
- s.oy = 0/*oy*/ * s.sy;
- if( tilt_deg ) {
- tilt_deg = (tilt_deg + 0) * ((float)C_PI / 180);
- s.cos = cosf(tilt_deg);
- s.sin = sinf(tilt_deg);
- } else {
- s.cos = 1;
- s.sin = 0;
- }
-
- batch_group_t *batches = &sprite_00_translucent_group;
- batch_t *found = map_find_or_add(*batches, t.id, (batch_t){0});
-
- array_push(found->sprites, s);
-}
-
-void sprite_sheet( texture_t texture, float spritesheet[3], float position[3], float rotation, float offset[2], float scale[2], int is_additive, uint32_t rgba, int resolution_independant) {
- const float px = position[0], py = position[1], pz = position[2];
- const float ox = offset[0], oy = offset[1], sx = scale[0], sy = scale[1];
- const float frame = spritesheet[0], xcells = spritesheet[1], ycells = spritesheet[2];
-
- if (frame < 0) return;
- if (frame > 0 && frame >= (xcells * ycells)) return;
-
- // no need to queue if alpha or scale are zero
- if( sx && sy && alpha(rgba) ) {
- vec3 bak = camera_get_active()->position;
- if( resolution_independant ) { // @todo: optimize me
- sprite_flush();
- camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
- }
-
- sprite_t s;
- s.px = px;
- s.py = py;
- s.pz = pz;
- s.frame = frame;
- s.ncx = xcells ? xcells : 1;
- s.ncy = ycells ? ycells : 1;
- s.sx = sx;
- s.sy = sy;
- s.ox = ox * sx;
- s.oy = oy * sy;
- s.cellw = (texture.x * sx / s.ncx);
- s.cellh = (texture.y * sy / s.ncy);
- s.rgba = rgba;
- s.cos = 1;
- s.sin = 0;
- if(rotation) {
- rotation = (rotation + 0) * ((float)C_PI / 180);
- s.cos = cosf(rotation);
- s.sin = sinf(rotation);
- }
-
- batch_group_t *batches = is_additive ? &sprite_additive_group : &sprite_translucent_group;
-#if 0
- batch_t *found = map_find(*batches, texture.id);
- if( !found ) found = map_insert(*batches, texture.id, (batch_t){0});
-#else
- batch_t *found = map_find_or_add(*batches, texture.id, (batch_t){0});
-#endif
-
- array_push(found->sprites, s);
-
- if( resolution_independant ) { // @todo: optimize me
- sprite_flush();
- camera_get_active()->position = bak;
- }
- }
-}
-
-static void sprite_rebuild_meshes() {
- sprite_count = 0;
-
- batch_group_t* list[] = { &sprite_additive_group, &sprite_translucent_group };
- for( int l = 0; l < countof(list); ++l) {
- for each_map_ptr(*list[l], int,_, batch_t,bt) {
-
- bt->dirty = array_count(bt->sprites) ? 1 : 0;
- if( !bt->dirty ) continue;
-
- int index = 0;
- array_clear(sprite_indices);
- array_clear(sprite_vertices);
-
- array_foreach_ptr(bt->sprites, sprite_t,it ) {
- float x0 = it->ox - it->cellw/2, x3 = x0 + it->cellw;
- float y0 = it->oy - it->cellh/2, y3 = y0;
- float x1 = x0, x2 = x3;
- float y1 = y0 + it->cellh, y2 = y1;
-
- // @todo: move this affine transform into glsl shader
- vec3 v0 = { it->px + ( x0 * it->cos - y0 * it->sin ), it->py + ( x0 * it->sin + y0 * it->cos ), it->pz };
- vec3 v1 = { it->px + ( x1 * it->cos - y1 * it->sin ), it->py + ( x1 * it->sin + y1 * it->cos ), it->pz };
- vec3 v2 = { it->px + ( x2 * it->cos - y2 * it->sin ), it->py + ( x2 * it->sin + y2 * it->cos ), it->pz };
- vec3 v3 = { it->px + ( x3 * it->cos - y3 * it->sin ), it->py + ( x3 * it->sin + y3 * it->cos ), it->pz };
-
- float cx = (1.0f / it->ncx) - 1e-9f;
- float cy = (1.0f / it->ncy) - 1e-9f;
- int idx = (int)it->frame;
- int px = idx % it->ncx;
- int py = idx / it->ncx;
-
- float ux = px * cx, uy = py * cy;
- float vx = ux + cx, vy = uy + cy;
-
- vec2 uv0 = vec2(ux, uy);
- vec2 uv1 = vec2(ux, vy);
- vec2 uv2 = vec2(vx, vy);
- vec2 uv3 = vec2(vx, uy);
-
- array_push( sprite_vertices, sprite_vertex(v0, uv0, it->rgba) ); // Vertex 0 (A)
- array_push( sprite_vertices, sprite_vertex(v1, uv1, it->rgba) ); // Vertex 1 (B)
- array_push( sprite_vertices, sprite_vertex(v2, uv2, it->rgba) ); // Vertex 2 (C)
- array_push( sprite_vertices, sprite_vertex(v3, uv3, it->rgba) ); // Vertex 3 (D)
-
- // A--B A A-B
- // quad | | becomes triangle |\ and triangle \|
- // D--C D-C C
- GLuint A = (index+0), B = (index+1), C = (index+2), D = (index+3); index += 4;
-
- array_push( sprite_indices, sprite_index(C, D, A) ); // Triangle 1
- array_push( sprite_indices, sprite_index(C, A, B) ); // Triangle 2
- }
-
- mesh_update(&bt->mesh, "p3 t2 c4B", 0,array_count(sprite_vertices),sprite_vertices, 3*array_count(sprite_indices),sprite_indices, MESH_STATIC);
-
- // clear elements from queue
- sprite_count += array_count(bt->sprites);
- array_clear(bt->sprites);
- }
- }
-
- batch_group_t* list2[] = { &sprite_00_translucent_group };
- for( int l = 0; l < countof(list2); ++l) {
- for each_map_ptr(*list2[l], int,_, batch_t,bt) {
-
- bt->dirty = array_count(bt->sprites) ? 1 : 0;
- if( !bt->dirty ) continue;
-
- int index = 0;
- array_clear(sprite_indices);
- array_clear(sprite_vertices);
-
- array_foreach_ptr(bt->sprites, sprite_t,it ) {
- float x0 = it->ox - it->cellw/2, x3 = x0 + it->cellw;
- float y0 = it->oy - it->cellh/2, y3 = y0;
- float x1 = x0, x2 = x3;
- float y1 = y0 + it->cellh, y2 = y1;
-
- // @todo: move this affine transform into glsl shader
- vec3 v0 = { it->px + ( x0 * it->cos - y0 * it->sin ), it->py + ( x0 * it->sin + y0 * it->cos ), it->pz };
- vec3 v1 = { it->px + ( x1 * it->cos - y1 * it->sin ), it->py + ( x1 * it->sin + y1 * it->cos ), it->pz };
- vec3 v2 = { it->px + ( x2 * it->cos - y2 * it->sin ), it->py + ( x2 * it->sin + y2 * it->cos ), it->pz };
- vec3 v3 = { it->px + ( x3 * it->cos - y3 * it->sin ), it->py + ( x3 * it->sin + y3 * it->cos ), it->pz };
-
- float ux = it->x, vx = ux + it->w;
- float uy = it->y, vy = uy + it->h;
-
- vec2 uv0 = vec2(ux, uy);
- vec2 uv1 = vec2(ux, vy);
- vec2 uv2 = vec2(vx, vy);
- vec2 uv3 = vec2(vx, uy);
-
- array_push( sprite_vertices, sprite_vertex(v0, uv0, it->rgba) ); // Vertex 0 (A)
- array_push( sprite_vertices, sprite_vertex(v1, uv1, it->rgba) ); // Vertex 1 (B)
- array_push( sprite_vertices, sprite_vertex(v2, uv2, it->rgba) ); // Vertex 2 (C)
- array_push( sprite_vertices, sprite_vertex(v3, uv3, it->rgba) ); // Vertex 3 (D)
-
- // A--B A A-B
- // quad | | becomes triangle |\ and triangle \|
- // D--C D-C C
- GLuint A = (index+0), B = (index+1), C = (index+2), D = (index+3); index += 4;
-
- array_push( sprite_indices, sprite_index(C, D, A) ); // Triangle 1
- array_push( sprite_indices, sprite_index(C, A, B) ); // Triangle 2
- }
-
- mesh_update(&bt->mesh, "p3 t2 c4B", 0,array_count(sprite_vertices),sprite_vertices, 3*array_count(sprite_indices),sprite_indices, MESH_STATIC);
-
- // clear elements from queue
- sprite_count += array_count(bt->sprites);
- array_clear(bt->sprites);
- }
- }
-}
-
-static void sprite_render_meshes() {
- if( map_count(sprite_additive_group) <= 0 )
- if( map_count(sprite_translucent_group) <= 0 )
- if( map_count(sprite_00_translucent_group) <= 0 )
- return;
-
- if( sprite_program < 0 ) {
- sprite_program = shader( vfs_read("shaders/vs_324_24_sprite.glsl"), vfs_read("shaders/fs_24_4_sprite.glsl"),
- "att_Position,att_TexCoord,att_Color",
- "fragColor", NULL
- );
- }
-
- // use the shader and bind the texture @ unit 0
- shader_bind(sprite_program);
- glActiveTexture(GL_TEXTURE0);
-
- // setup rendering state
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_BLEND);
- glDepthFunc(GL_LEQUAL); // try to help with zfighting
-
- // update camera
- // camera_fps(camera_get_active(), 0,0);
- vec3 pos = camera_get_active()->position;
- float zoom = absf(pos.z); if(zoom < 0.1f) zoom = 0.1f; zoom = 1.f / (zoom + !zoom);
- float width = window_width();
- float height = window_height();
-
- // set mvp in the uniform. (0,0) is center of screen.
- mat44 mvp2d;
- float zdepth_max = window_height(); // 1;
- float l = pos.x - width * zoom / 2;
- float r = pos.x + width * zoom / 2;
- float b = pos.y + height * zoom / 2;
- float t = pos.y - height * zoom / 2;
- ortho44(mvp2d, l,r,b,t, -zdepth_max, +zdepth_max);
-
- shader_mat44("u_mvp", mvp2d);
-
- // set (unit 0) in the uniform texture sampler, and render batch
- // for all additive then translucent groups
-
- if( map_count(sprite_additive_group) > 0 ) {
- glBlendFunc( GL_SRC_ALPHA, GL_ONE );
- for each_map_ptr(sprite_additive_group, int,texture_id, batch_t,bt) {
- if( bt->dirty ) {
- shader_texture_unit("u_texture", *texture_id, 0);
- mesh_render(&bt->mesh);
- }
- }
-// map_clear(sprite_additive_group);
- }
-
- if( map_count(sprite_translucent_group) > 0 ) {
- glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
- for each_map_ptr(sprite_translucent_group, int,texture_id, batch_t,bt) {
- if( bt->dirty ) {
- shader_texture_unit("u_texture", *texture_id, 0);
- mesh_render(&bt->mesh);
- }
- }
-// map_clear(sprite_translucent_group);
- }
-
- if( map_count(sprite_00_translucent_group) > 0 ) {
- glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
- for each_map_ptr(sprite_00_translucent_group, int,texture_id, batch_t,bt) {
- if( bt->dirty ) {
- shader_texture_unit("u_texture", *texture_id, 0);
- mesh_render(&bt->mesh);
- }
- }
-// map_clear(sprite_00_translucent_group);
- }
-
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_BLEND);
- glDepthFunc(GL_LESS);
- glUseProgram(0);
-}
-
-static void sprite_init() {
- do_once {
- map_init(sprite_00_translucent_group, less_int, hash_int);
- map_init(sprite_translucent_group, less_int, hash_int);
- map_init(sprite_additive_group, less_int, hash_int);
- }
-}
-
-void sprite_flush() {
- profile("Sprite.rebuild_time") {
- sprite_rebuild_meshes();
- }
- profile("Sprite.render_time") {
- sprite_render_meshes();
- }
-}
-
-// -----------------------------------------------------------------------------
-// tilemaps
-
-tilemap_t tilemap(const char *map, int blank_chr, int linefeed_chr) {
- tilemap_t t = {0};
- t.tint = ~0u; // WHITE
- t.blank_chr = blank_chr;
- for( ; *map ; ++map ) {
- if( map[0] == linefeed_chr ) ++t.rows;
- else {
- array_push(t.map, map[0]);
- ++t.cols;
- }
- }
- return t;
-}
-
-void tilemap_render_ext( tilemap_t m, tileset_t t, float zindex, float xy_zoom[3], float tilt, unsigned tint, bool is_additive ) {
- vec3 old_pos = camera_get_active()->position;
- sprite_flush();
- camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
-
- float scale[2] = {xy_zoom[2], xy_zoom[2]};
- xy_zoom[2] = zindex;
-
- float offset[2] = {0,0};
- float spritesheet[3] = {0,t.cols,t.rows}; // selected tile index and spritesheet dimensions (cols,rows)
-
- for( unsigned y = 0, c = 0; y < m.rows; ++y ) {
- for( unsigned x = 0; x < m.cols; ++x, ++c ) {
- if( m.map[c] != m.blank_chr ) {
- spritesheet[0] = m.map[c];
- sprite_sheet(t.tex, spritesheet, xy_zoom, tilt, offset, scale, is_additive, tint, false);
- }
- offset[0] += t.tile_w;
- }
- offset[0] = 0, offset[1] += t.tile_h;
- }
-
- sprite_flush();
- camera_get_active()->position = old_pos;
-}
-
-void tilemap_render( tilemap_t map, tileset_t set ) {
- map.position.x += set.tile_w;
- map.position.y += set.tile_h;
- tilemap_render_ext( map, set, map.zindex, &map.position.x, map.tilt, map.tint, map.is_additive );
-}
-
-tileset_t tileset(texture_t tex, unsigned tile_w, unsigned tile_h, unsigned cols, unsigned rows) {
- tileset_t t = {0};
- t.tex = tex;
- t.cols = cols, t.rows = rows;
- t.tile_w = tile_w, t.tile_h = tile_h;
- return t;
-}
-
-int ui_tileset( tileset_t t ) {
- ui_subimage(va("Selection #%d (%d,%d)", t.selected, t.selected % t.cols, t.selected / t.cols), t.tex.id, t.tex.w, t.tex.h, (t.selected % t.cols) * t.tile_w, (t.selected / t.cols) * t.tile_h, t.tile_w, t.tile_h);
- int choice;
- if( (choice = ui_image(0, t.tex.id, t.tex.w,t.tex.h)) ) {
- int px = ((choice / 100) / 100.f) * t.tex.w / t.tile_w;
- int py = ((choice % 100) / 100.f) * t.tex.h / t.tile_h;
- t.selected = px + py * t.cols;
- }
- // if( (choice = ui_buttons(3, "load", "save", "clear")) ) {}
- return t.selected;
-}
-
-// -----------------------------------------------------------------------------
-// tiled
-
-tiled_t tiled(const char *file_tmx) {
- tiled_t zero = {0}, ti = zero;
-
- // read file and parse json
- if( !xml_push(file_tmx) ) return zero;
-
- // sanity checks
- bool supported = !strcmp(xml_string("/map/@orientation"), "orthogonal") && !strcmp(xml_string("/map/@renderorder"), "right-down");
- if( !supported ) return xml_pop(), zero;
-
- // tileset
- const char *file_tsx = xml_string("/map/tileset/@source");
- if( !xml_push(vfs_read(file_tsx)) ) return zero;
- const char *set_src = xml_string("/tileset/image/@source");
- int set_w = xml_int("/tileset/@tilewidth");
- int set_h = xml_int("/tileset/@tileheight");
- int set_c = xml_int("/tileset/@columns");
- int set_r = xml_int("/tileset/@tilecount") / set_c;
- tileset_t set = tileset(texture(set_src,0), set_w, set_h, set_c, set_r );
- xml_pop();
-
- // actual parsing
- ti.w = xml_int("/map/@width");
- ti.h = xml_int("/map/@height");
- ti.tilew = xml_int("/map/@tilewidth");
- ti.tileh = xml_int("/map/@tileheight");
- ti.first_gid = xml_int("/map/tileset/@firstgid");
- ti.map_name = STRDUP( xml_string("/map/tileset/@source") ); // @leak
-
- for(int l = 0, layers = xml_count("/map/layer"); l < layers; ++l ) {
- if( strcmp(xml_string("/map/layer[%d]/data/@encoding",l), "base64") || strcmp(xml_string("/map/layer[%d]/data/@compression",l), "zlib") ) {
- PRINTF("Warning: layer encoding not supported: '%s' -> layer '%s'\n", file_tmx, *array_back(ti.names));
- continue;
- }
-
- int cols = xml_int("/map/layer[%d]/@width",l);
- int rows = xml_int("/map/layer[%d]/@height",l);
-
- tilemap_t tm = tilemap("", ' ', '\n');
- tm.blank_chr = ~0u; //ti.first_gid - 1;
- tm.cols = cols;
- tm.rows = rows;
- array_resize(tm.map, tm.cols * tm.rows);
- memset(tm.map, 0xFF, tm.cols * tm.rows * sizeof(int));
-
- for( int c = 0, chunks = xml_count("/map/layer[%d]/data/chunk", l); c <= chunks; ++c ) {
- int cw, ch;
- int cx, cy;
- array(char) b64 = 0;
-
- if( !chunks ) { // non-infinite mode
- b64 = xml_blob("/map/layer[%d]/data/$",l);
- cw = tm.cols, ch = tm.rows;
- cx = 0, cy = 0;
- } else { // infinite mode
- b64 = xml_blob("/map/layer[%d]/data/chunk[%d]/$",l,c);
- cw = xml_int("/map/layer[%d]/data/chunk[%d]/@width",l,c), ch = xml_int("/map/layer[%d]/data/chunk[%d]/@height",l,c); // 20x20
- cx = xml_int("/map/layer[%d]/data/chunk[%d]/@x",l,c), cy = xml_int("/map/layer[%d]/data/chunk[%d]/@y",l,c); // (-16,-32)
- cx = abs(cx), cy = abs(cy);
- }
-
- int outlen = cw * ch * 4;
- static __thread int *out = 0; out = (int *)REALLOC( 0, outlen + zexcess(COMPRESS_ZLIB) ); // @leak
- if( zdecode( out, outlen, b64, array_count(b64), COMPRESS_ZLIB ) > 0 ) {
- for( int y = 0, p = 0; y < ch; ++y ) {
- for( int x = 0; x < cw; ++x, ++p ) {
- if( out[p] >= ti.first_gid ) {
- int offset = (x + cx) + (y + cy) * tm.cols;
- if( offset >= 0 && offset < (cw * ch) )
- tm.map[ offset ] = out[ p ] - ti.first_gid;
- }
- }
- }
- }
- else {
- PRINTF("Warning: bad zlib stream: '%s' -> layer #%d -> chunk #%d\n", file_tmx, l, c);
- }
-
- array_free(b64);
- }
-
- array_push(ti.layers, tm);
- array_push(ti.names, STRDUP(xml_string("/map/layer[%d]/@name",l)));
- array_push(ti.visible, true);
- array_push(ti.sets, set);
- }
-
- xml_pop();
- return ti;
-}
-
-void tiled_render(tiled_t tmx, vec3 pos) {
- for( unsigned i = 0, end = array_count(tmx.layers); i < end; ++i ) {
- tmx.layers[i].position = pos; // add3(camera_get_active()->position, pos);
- if( tmx.parallax ) tmx.layers[i].position.x /= (3+i), tmx.layers[i].position.y /= (5+i);
- if( tmx.visible[i] ) tilemap_render(tmx.layers[i], tmx.sets[i]);
- }
-}
-
-void ui_tiled(tiled_t *t) {
- ui_label2("Loaded map", t->map_name ? t->map_name : "(none)");
- ui_label2("Map dimensions", va("%dx%d", t->w, t->h));
- ui_label2("Tile dimensions", va("%dx%d", t->tilew, t->tileh));
- ui_separator();
- ui_bool("Parallax", &t->parallax);
- ui_separator();
- ui_label2("Layers", va("%d", array_count(t->layers)));
- for( int i = 0; i < array_count(t->layers); ++i ) {
- if( ui_label2_toolbar(va("- %s (%dx%d)", t->names[i], t->layers[i].cols, t->layers[i].rows ), t->visible[i] ? "\xee\xa3\xb4" : "\xee\xa3\xb5") > 0 ) { // ICON_MD_VISIBILITY / ICON_MD_VISIBILITY_OFF
- t->visible[i] ^= true;
- }
- }
- ui_separator();
- if( ui_collapse(va("Sets: %d", array_count(t->layers)), va("%p",t))) {
- for( int i = 0; i < array_count(t->layers); ++i ) {
- if( ui_collapse(va("%d", i+1), va("%p%d",t,i)) ) {
- t->sets[i].selected = ui_tileset( t->sets[i] );
- ui_collapse_end();
- }
- }
- ui_collapse_end();
- }
-}
-
-// -----------------------------------------------------------------------------
-// spine json loader (wip)
-// - rlyeh, public domain
-//
-// [ref] http://es.esotericsoftware.com/spine-json-format
-//
-// notable misses:
-// - mesh deforms
-// - cubic beziers
-// - shears
-// - bounding boxes
-
-enum { SPINE_MAX_BONES = 64 }; // max bones
-
-typedef struct spine_bone_t {
- char *name, *parent;
- struct spine_bone_t *parent_bone;
-
- float z; // draw order usually matches bone-id. ie, zindex == bone_id .. root(0) < chest (mid) < finger(top)
-
- float len;
- float x, y, deg; // base
- float x2, y2, deg2; // accum / temporaries during bone transform time
- float x3, y3, deg3; // values from timeline
-
- unsigned rect_id;
- unsigned atlas_id;
-} spine_bone_t;
-
-typedef struct spine_slot_t {
- char *name, *bone, *attach;
-} spine_slot_t;
-
-typedef struct spine_rect_t {
- char *name;
- float x,y,w,h,sx,sy,deg;
-} spine_rect_t;
-
-typedef struct spine_skin_t {
- char *name;
- array(spine_rect_t) rects;
-} spine_skin_t;
-
-typedef struct spine_animkey_t { // offline; only during loading
- float time, curve[4]; // time is mandatory, curve is optional
- union {
- char *name; // type: attachment (mode-1)
- struct { float deg; }; // type: rotate (mode-2)
- struct { float x,y; }; // type: translate (mode-3)
- };
-} spine_animkey_t;
-
-#if 0
-typedef struct spine_pose_t { // runtime; only during playing
- unsigned frame;
- array(vec4) xform; // entry per bone. translation(x,y),rotation(z),attachment-id(w)
-} spine_pose_t;
-#endif
-
-typedef struct spine_anim_t {
- char *name;
- union {
-#if 0
- struct {
- unsigned frames;
- array(spine_pose_t) poses;
- };
-#endif
- struct {
- array(spine_animkey_t) attach_keys[SPINE_MAX_BONES];
- array(spine_animkey_t) rotate_keys[SPINE_MAX_BONES];
- array(spine_animkey_t) translate_keys[SPINE_MAX_BONES];
- };
- };
-} spine_anim_t;
-
-typedef struct spine_atlas_t {
- char *name;
- float x,y,w,h,deg;
-} spine_atlas_t;
-
-typedef struct spine_t {
- char *name;
- texture_t texture;
- unsigned skin;
- array(spine_bone_t) bones;
- array(spine_slot_t) slots;
- array(spine_skin_t) skins;
- array(spine_anim_t) anims;
- array(spine_atlas_t) atlas;
- // anim controller
- unsigned inuse;
- float time, maxtime;
- unsigned debug_atlas_id;
-} spine_t;
-
-// ---
-
-static
-void spine_convert_animkeys_to_animpose(spine_anim_t *input) {
- spine_anim_t copy = *input; // @todo
- // @leak: attach/rot/tra keys
-}
-
-static
-int find_bone_id(spine_t *s, const char *bone_name) {
- for( unsigned i = 0, end = array_count(s->bones); i < end; ++i )
- if( !strcmp(s->bones[i].name, bone_name)) return i;
- return -1;
-}
-static
-spine_bone_t *find_bone(spine_t *s, const char *bone_name) {
- int bone_id = find_bone_id(s, bone_name);
- return bone_id >= 0 ? &s->bones[bone_id] : NULL;
-}
-
-void spine_skin(spine_t *p, unsigned skin) {
- if( !p->texture.id ) return;
- if( skin >= array_count(p->skins) ) return;
-
- p->skin = skin;
-
- char *skin_name = va("%s/", p->skins[skin].name);
- int header = strlen(skin_name);
-
- for( int i = 0; i < array_count(p->atlas); ++i) {
- if(!strbeg(p->atlas[i].name, skin_name)) continue;
-
- int bone_id = find_bone_id(p, p->atlas[i].name+header );
- if( bone_id < 0 ) continue;
-
- p->bones[bone_id].atlas_id = i;
- }
-
- for( int i = 0; i < array_count(p->skins[p->skin].rects); ++i) {
- int bone_id = find_bone_id(p, p->skins[p->skin].rects[i].name );
- if( bone_id < 0 ) continue;
-
- p->bones[bone_id].rect_id = i;
- }
-}
-
-static
-bool spine_(spine_t *t, const char *file_json, const char *file_atlas, unsigned flags) {
- char *atlas = vfs_read(file_atlas);
- if(!atlas || !atlas[0]) return false;
-
- memset(t, 0, sizeof(spine_t));
-
- // goblins.png
- // size: 1024, 128
- // filter: Linear, Linear
- // pma: true
- // dagger
- // bounds: 2, 18, 26, 108
- // goblin/eyes-closed
- // bounds: 2, 4, 34, 12
- spine_atlas_t *sa = 0;
- const char *last_id = 0;
- const char *texture_name = 0;
- const char *texture_filter = 0;
- const char *texture_format = 0;
- const char *texture_repeat = 0;
- float texture_width = 0, texture_height = 0, temp;
- for each_substring(atlas, "\r\n", it) {
- it += strspn(it, " \t\f\v");
- /**/ if( strbeg(it, "pma:" ) || strbeg(it, "index:") ) {} // ignored
- else if( strbeg(it, "size:" ) ) sscanf(it+5, "%f,%f", &texture_width, &texture_height);
- else if( strbeg(it, "rotate:" ) ) { float tmp; tmp=sa->w,sa->w=sa->h,sa->h=tmp; sa->deg = 90; } // assert(val==90)
- else if( strbeg(it, "repeat:" ) ) texture_repeat = it+7; // temp string
- else if( strbeg(it, "filter:" ) ) texture_filter = it+7; // temp string
- else if( strbeg(it, "format:" ) ) texture_format = it+7; // temp string
- else if( strbeg(it, "bounds:" ) ) {
- sscanf(it+7, "%f,%f,%f,%f", &sa->x, &sa->y, &sa->w, &sa->h);
- }
- else if( !texture_name ) texture_name = va("%s", it);
- else {
- array_push(t->atlas, ((spine_atlas_t){0}) );
- sa = &t->atlas[array_count(t->atlas) - 1];
- sa->name = STRDUP(it);
- }
- }
- for( int i = 0; i < array_count(t->atlas); ++i ) {
- sa = &t->atlas[i];
- sa->x /= texture_width, sa->y /= texture_height;
- sa->w /= texture_width, sa->h /= texture_height;
- }
-
- if(!texture_name) return false;
-
- t->texture = texture(texture_name, TEXTURE_LINEAR);
-
- json_push(vfs_read(file_json)); // @fixme: json_push_from_file() ?
-
- array_resize(t->bones, json_count("/bones"));
- array_reserve(t->slots, json_count("/slots"));
- array_resize(t->skins, json_count("/skins"));
- array_resize(t->anims, json_count("/animations"));
-
- for( int i = 0, end = json_count("/bones"); i < end; ++i ) {
- spine_bone_t v = {0};
- v.name = STRDUP(json_string("/bones[%d]/name", i));
- v.parent = STRDUP(json_string("/bones[%d]/parent", i));
- v.x = json_float("/bones[%d]/x", i);
- v.y = json_float("/bones[%d]/y", i);
- v.z = i;
- v.len = json_float("/bones[%d]/length", i);
- v.deg = json_float("/bones[%d]/rotation", i);
- t->bones[i] = v;
-
- for( int j = i-1; j > 0; --j ) {
- if( strcmp(t->bones[j].name,v.parent) ) continue;
- t->bones[i].parent_bone = &t->bones[j];
- break;
- }
- }
-
- for( int i = 0, end = json_count("/slots"); i < end; ++i ) {
- spine_slot_t v = {0};
- v.name = STRDUP(json_string("/slots[%d]/name", i));
- v.bone = STRDUP(json_string("/slots[%d]/bone", i));
- v.attach = STRDUP(json_string("/slots[%d]/attachment", i));
-
- array_push(t->slots, v);
-
- // slots define draw-order. so, update draw-order/zindex in bone
- spine_bone_t *b = find_bone(t, v.name);
- if( b ) b->z = i;
- }
-
- for( int i = 0, end = json_count("/skins"); i < end; ++i ) {
- spine_skin_t v = {0};
- v.name = STRDUP(json_string("/skins[%d]/name", i));
-
- for( int j = 0, jend = json_count("/skins[%d]/attachments",i); j < jend; ++j ) // /skins/default/
- for( int k = 0, kend = json_count("/skins[%d]/attachments[%d]",i,j); k < kend; ++k ) { // /skins/default/left hand item/
- spine_rect_t r = {0};
- r.name = STRDUP(json_key("/skins[%d]/attachments[%d][%d]",i,j,k)); // stringf("%s-%s-%s", json_key("/skins[%d]",i), json_key("/skins[%d][%d]",i,j), json_key("/skins[%d][%d][%d]",i,j,k));
- r.x = json_float("/skins[%d]/attachments[%d][%d]/x",i,j,k);
- r.y = json_float("/skins[%d]/attachments[%d][%d]/y",i,j,k);
- r.sx= json_float("/skins[%d]/attachments[%d][%d]/scaleX",i,j,k); r.sx += !r.sx;
- r.sy= json_float("/skins[%d]/attachments[%d][%d]/scaleY",i,j,k); r.sy += !r.sy;
- r.w = json_float("/skins[%d]/attachments[%d][%d]/width",i,j,k);
- r.h = json_float("/skins[%d]/attachments[%d][%d]/height",i,j,k);
- r.deg = json_float("/skins[%d]/attachments[%d][%d]/rotation",i,j,k);
- array_push(v.rects, r);
- }
-
- t->skins[i] = v;
- }
-
-#if 1
- // simplify:
- // merge /skins/default into existing /skins/*, then delete /skins/default
- if( array_count(t->skins) > 1 ) {
- for( int i = 1; i < array_count(t->skins); ++i ) {
- for( int j = 0; j < array_count(t->skins[0].rects); ++j ) {
- array_push(t->skins[i].rects, t->skins[0].rects[j]);
- }
- }
- // @leak @fixme: FREE(t->skins[0])
- for( int i = 0; i < array_count(t->skins)-1; ++i ) {
- t->skins[i] = t->skins[i+1];
- }
- array_pop(t->skins);
- }
-#endif
-
- for( int i = 0, end = json_count("/animations"); i < end; ++i ) {
- int id;
- const char *name;
-
- spine_anim_t v = {0};
- v.name = STRDUP(json_key("/animations[%d]", i));
-
- // slots / attachments
-
- for( int j = 0, jend = json_count("/animations[%d]/slots",i); j < jend; ++j )
- for( int k = 0, kend = json_count("/animations[%d]/slots[%d]",i,j); k < kend; ++k ) // ids
- {
- int bone_id = find_bone_id(t, json_key("/animations[%d]/bones[%d]",i,j));
- if( bone_id < 0 ) continue;
-
- for( int l = 0, lend = json_count("/animations[%d]/slots[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
- spine_animkey_t key = {0};
-
- key.name = STRDUP(json_string("/animations[%d]/slots[%d][%d][%d]/name",i,j,k,l));
- key.time = json_float("/animations[%d]/slots[%d][%d][%d]/time",i,j,k,l);
- if( json_count("/animations[%d]/slots[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
- key.curve[0] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[0]",i,j,k,l);
- key.curve[1] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[1]",i,j,k,l);
- key.curve[2] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[2]",i,j,k,l);
- key.curve[3] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[3]",i,j,k,l);
- }
-
- // @todo: convert name to id
- // for(id = 0; t->bones[id].name && strcmp(t->bones[id].name,key.name); ++id)
- // printf("%s vs %s\n", key.name, t->bones[id].name);
-
- array_push(v.attach_keys[bone_id], key);
- }
- }
-
- // bones
-
- for( int j = 0, jend = json_count("/animations[%d]/bones",i); j < jend; ++j ) // slots or bones
- for( int k = 0, kend = json_count("/animations[%d]/bones[%d]",i,j); k < kend; ++k ) { // bone ids
- int bone_id = find_bone_id(t, json_key("/animations[%d]/bones[%d]",i,j));
- if( bone_id < 0 ) continue;
-
- // parse bones
- for( int l = 0, lend = json_count("/animations[%d]/bones[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
- const char *channel = json_key("/animations[%d]/bones[%d][%d]",i,j,k);
- int track = !strcmp(channel, "rotate") ? 1 : !strcmp(channel, "translate") ? 2 : 0;
- if( !track ) continue;
-
- spine_animkey_t key = {0};
-
- key.time = json_float("/animations[%d]/bones[%d][%d][%d]/time",i,j,k,l);
- if( json_count("/animations[%d]/bones[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
- key.curve[0] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[0]",i,j,k,l);
- key.curve[1] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[1]",i,j,k,l);
- key.curve[2] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[2]",i,j,k,l);
- key.curve[3] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[3]",i,j,k,l);
- }
-
- if( track == 1 )
- key.deg = json_float("/animations[%d]/bones[%d][%d][%d]/value",i,j,k,l), // "/angle"
- array_push(v.rotate_keys[bone_id], key);
- else
- key.x = json_float("/animations[%d]/bones[%d][%d][%d]/x",i,j,k,l),
- key.y = json_float("/animations[%d]/bones[%d][%d][%d]/y",i,j,k,l),
- array_push(v.translate_keys[bone_id], key);
- }
- }
-
- t->anims[i] = v;
- }
-
- json_pop();
-
- spine_skin(t, 0);
-
- return true;
-}
-
-spine_t* spine(const char *file_json, const char *file_atlas, unsigned flags) {
- spine_t *t = MALLOC(sizeof(spine_t));
- if( !spine_(t, file_json, file_atlas, flags) ) return FREE(t), NULL;
- return t;
-}
-
-void spine_render(spine_t *p, vec3 offset, unsigned flags) {
- if( !p->texture.id ) return;
- if( !flags ) return;
-
- ddraw_push_2d();
- // if( flags & 2 ) ddraw_line(vec3(0,0,0), vec3(window_width(),window_height(),0));
- // if( flags & 2 ) ddraw_line(vec3(window_width(),0,0), vec3(0,window_height(),0));
-
- // int already_computed[SPINE_MAX_BONES] = {0}; // @fixme: optimize: update longest chains first, then remnant branches
-
- for( int i = 1; i < array_count(p->bones); ++i ) {
- spine_bone_t *self = &p->bones[i];
- if( !self->rect_id ) continue;
-
- int num_bones = 0;
- static array(spine_bone_t*) chain = 0; array_resize(chain, 0);
- for( spine_bone_t *next = self; next ; next = next->parent_bone, ++num_bones ) {
- array_push(chain, next);
- }
-
- vec3 target = {0}, prev = {0};
- for( int j = 0, end = array_count(chain); j < end; ++j ) { // traverse from root(skipped) -> `i` bone direction
- int j_opposite = end - 1 - j;
-
- spine_bone_t *b = chain[j_opposite]; // bone
- spine_bone_t *pb = b->parent_bone; // parent bone
-
- float pb_x2 = 0, pb_y2 = 0, pb_deg2 = 0;
- if( pb ) pb_x2 = pb->x2, pb_y2 = pb->y2, pb_deg2 = pb->deg2;
-
- const float deg2rad = C_PI / 180;
- b->x2 = b->x3 + pb_x2 + b->x * cos( -pb_deg2 * deg2rad ) - b->y * sin( -pb_deg2 * deg2rad );
- b->y2 = -b->y3 + pb_y2 - b->y * cos( pb_deg2 * deg2rad ) + b->x * sin( pb_deg2 * deg2rad );
- b->deg2 = -b->deg3 + pb_deg2 - b->deg;
-
- prev = target;
- target = vec3(b->x2,b->y2,b->deg2);
- }
-
- target.z = 0;
- target = add3(target, offset);
- prev.z = 0;
- prev = add3(prev, offset);
-
- if( flags & 2 ) {
- ddraw_point( target );
- ddraw_text( target, -0.25f, self->name );
- ddraw_bone( prev, target ); // from parent to bone
- }
- if( flags & 1 ) {
- spine_atlas_t *a = &p->atlas[self->atlas_id];
- spine_rect_t *r = &p->skins[p->skin].rects[self->rect_id];
-
- vec4 rect = ptr4(&a->x);
- float zindex = self->z;
- float offsx = 0;
- float offsy = 0;
- float tilt = self->deg2 + (a->deg - r->deg);
- unsigned tint = self->atlas_id == p->debug_atlas_id ? 0xFF<<24 | 0xFF : ~0u;
-
- if( 1 ) {
- vec3 dir = vec3(r->x,r->y,0);
- dir = rotatez3(dir, self->deg2);
- offsx = dir.x * r->sx;
- offsy = dir.y * r->sy;
- }
-
- sprite_rect(p->texture, rect, zindex, add4(vec4(target.x,target.y,1,1),vec4(offsx,offsy,0,0)), tilt, tint);
- }
- }
-
- ddraw_pop_2d();
- ddraw_flush();
-}
-
-static
-void spine_animate_(spine_t *p, float *time, float *maxtime, float delta) {
- if( !p->texture.id ) return;
-
- if( delta > 1/120.f ) delta = 1/120.f;
- if( *time >= *maxtime ) *time = 0; else *time += delta;
-
- // reset root // needed?
- p->bones[0].x2 = 0;
- p->bones[0].y2 = 0;
- p->bones[0].deg2 = 0;
- p->bones[0].x3 = 0;
- p->bones[0].y3 = 0;
- p->bones[0].deg3 = 0;
-
- for( int i = 0, end = array_count(p->bones); i < end; ++i) {
- // @todo: attach channel
- // @todo: per channel: if curve == linear || curve == stepped || array_count(curve) == 4 {...}
- for each_array_ptr(p->anims[p->inuse].rotate_keys[i], spine_animkey_t, r) {
- double r0 = r->time;
- *maxtime = maxf( *maxtime, r0 );
- if( absf(*time - r0) < delta ) {
- p->bones[i].deg3 = r->deg;
- }
- }
- for each_array_ptr(p->anims[p->inuse].translate_keys[i], spine_animkey_t, r) {
- double r0 = r->time;
- *maxtime = maxf( *maxtime, r0 );
- if( absf(*time - r0) < delta ) {
- p->bones[i].x3 = r->x;
- p->bones[i].y3 = r->y;
- }
- }
- }
-}
-
-void spine_animate(spine_t *p, float delta) {
- spine_animate_(p, &p->time, &p->maxtime, delta);
-}
-
-void ui_spine(spine_t *p) {
- if( ui_collapse(va("Anims: %d", array_count(p->anims)), va("%p-a", p))) {
- for each_array_ptr(p->anims, spine_anim_t, q) {
- if(ui_slider2("", &p->time, va("%.2f/%.0f %.2f%%", p->time, p->maxtime, p->time * 100.f))) {
- spine_animate(p, 0);
- }
-
- int choice = ui_label2_toolbar(q->name, ICON_MD_PAUSE_CIRCLE " " ICON_MD_PLAY_CIRCLE);
- if( choice == 1 ) window_pause( 0 ); // play
- if( choice == 2 ) window_pause( 1 ); // pause
-
- for( int i = 0; i < SPINE_MAX_BONES; ++i ) {
- ui_separator();
- ui_label(va("Bone %d: Attachment keys", i));
- for each_array_ptr(q->attach_keys[i], spine_animkey_t, r) {
- ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %s", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->name));
- }
- ui_label(va("Bone %d: Rotate keys", i));
- for each_array_ptr(q->rotate_keys[i], spine_animkey_t, r) {
- ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %.2f deg", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->deg));
- }
- ui_label(va("Bone %d: Translate keys", i));
- for each_array_ptr(q->translate_keys[i], spine_animkey_t, r) {
- ui_label(va("%.2f [%.2f %.2f %.2f %.2f] (%.2f,%.2f)", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->x, r->y));
- }
- }
- }
- ui_collapse_end();
- }
- if( ui_collapse(va("Bones: %d", array_count(p->bones)), va("%p-b", p))) {
- for each_array_ptr(p->bones, spine_bone_t, q)
- if( ui_collapse(q->name, va("%p-b2", q)) ) {
- ui_label2("Parent:", q->parent);
- ui_label2("X:", va("%.2f", q->x));
- ui_label2("Y:", va("%.2f", q->y));
- ui_label2("Length:", va("%.2f", q->len));
- ui_label2("Rotation:", va("%.2f", q->deg));
- ui_collapse_end();
- }
- ui_collapse_end();
- }
- if( ui_collapse(va("Slots: %d", array_count(p->slots)), va("%p-s", p))) {
- for each_array_ptr(p->slots, spine_slot_t, q)
- if( ui_collapse(q->name, va("%p-s2", q)) ) {
- ui_label2("Bone:", q->bone);
- ui_label2("Attachment:", q->attach);
- ui_collapse_end();
- }
- ui_collapse_end();
- }
- if( ui_collapse(va("Skins: %d", array_count(p->skins)), va("%p-k", p))) {
- for each_array_ptr(p->skins, spine_skin_t, q)
- if( ui_collapse(q->name, va("%p-k2", q)) ) {
- for each_array_ptr(q->rects, spine_rect_t, r)
- if( ui_collapse(r->name, va("%p-k3", r)) ) {
- ui_label2("X:", va("%.2f", r->x));
- ui_label2("Y:", va("%.2f", r->y));
- ui_label2("Scale X:", va("%.2f", r->sx));
- ui_label2("Scale Y:", va("%.2f", r->sy));
- ui_label2("Width:", va("%.2f", r->w));
- ui_label2("Height:", va("%.2f", r->h));
- ui_label2("Rotation:", va("%.2f", r->deg));
- ui_collapse_end();
-
- spine_bone_t *b = find_bone(p, r->name);
- if( b ) {
- p->debug_atlas_id = b->atlas_id;
-
- static float tilt = 0;
- if( input(KEY_LCTRL) ) tilt += 60*1/60.f; else tilt = 0;
- spine_atlas_t *r = p->atlas + b->atlas_id;
- sprite_flush();
- camera_get_active()->position = vec3(0,0,2);
- vec4 rect = ptr4(&r->x); float zindex = 0; vec3 xy_zoom = vec3(0,0,0); unsigned tint = ~0u;
- sprite_rect(p->texture,
- // rect: vec4(r->x*1.0/p->texture.w,r->y*1.0/p->texture.h,(r->x+r->w)*1.0/p->texture.w,(r->y+r->h)*1.0/p->texture.h),
- ptr4(&r->x), // atlas
- 0, vec4(0,0,1,1), r->deg + tilt, tint);
- sprite_flush();
- camera_get_active()->position = vec3(+window_width()/3,window_height()/2.25,2);
- }
- }
- ui_collapse_end();
- }
- ui_collapse_end();
- }
-
- if( ui_int("Use skin", &p->skin) ) {
- p->skin = clampf(p->skin, 0, array_count(p->skins) - 1);
- spine_skin(p, p->skin);
- }
-
- if( p->texture.id ) ui_texture(0, p->texture);
-}
-
// -----------------------------------------------------------------------------
// cubemaps
@@ -21054,7 +20107,7 @@ anims_t animations(const char *pathfile, int flags) {
}
#line 0
-#line 1 "engine/split/v4k_renderdd.c"
+#line 1 "v4k_renderdd.c"
static const char *dd_vs = "//" FILELINE "\n"
"in vec3 att_position;\n"
"uniform mat4 u_MVP;\n"
@@ -21902,7 +20955,7 @@ void ddraw_demo() {
}
#line 0
-#line 1 "engine/split/v4k_scene.c"
+#line 1 "v4k_scene.c"
//
// @todo: remove explicit GL code from here
@@ -22474,7 +21527,1476 @@ void scene_render(int flags) {
}
#line 0
-#line 1 "engine/split/v4k_system.c"
+#line 1 "v4k_sprite.c"
+// ----------------------------------------------------------------------------
+// sprites
+
+typedef struct sprite_static_t {
+ float px, py, pz; // origin x, y, depth
+ float ox, oy, cos, sin; // offset x, offset y, cos/sin of rotation degree
+ float sx, sy; // scale x,y
+ float cellw, cellh; // dimensions of any cell in spritesheet
+
+ union {
+ struct {
+ int frame, ncx, ncy; // frame in a (num cellx, num celly) spritesheet
+ };
+ struct {
+ float x, y, w, h; // normalized[0..1] within texture bounds
+ };
+ };
+
+ uint32_t rgba, flags; // vertex color and flags
+} sprite_static_t;
+
+// sprite batching
+typedef struct batch_t { array(sprite_static_t) sprites; mesh_t mesh; int dirty; } batch_t;
+typedef map(int, batch_t) batch_group_t; // mapkey is anything that forces a flush. texture_id for now, might be texture_id+program_id soon
+
+// sprite stream
+typedef struct sprite_vertex { vec3 pos; vec2 uv; uint32_t rgba; } sprite_vertex;
+typedef struct sprite_index { GLuint triangle[3]; } sprite_index;
+
+#define sprite_vertex(...) C_CAST(sprite_vertex, __VA_ARGS__)
+#define sprite_index(...) C_CAST(sprite_index, __VA_ARGS__)
+
+// sprite impl
+static int sprite_count = 0;
+static int sprite_program = -1;
+static array(sprite_index) sprite_indices = 0;
+static array(sprite_vertex) sprite_vertices = 0;
+
+// center_wh << 2 | additive << 1 | projected << 0
+static batch_group_t sprite_group[8] = {0};
+
+// rect(x,y,w,h) is [0..1] normalized, pos(xyz,z-index), scale_offset(sx,sy,offx,offy), rotation (degrees), color (rgba)
+void sprite_rect( texture_t t, vec4 rect, vec4 pos, vec4 scale_offset, float tilt_deg, unsigned tint_rgba, unsigned flags) {
+ float zindex = pos.w;
+ float scalex = scale_offset.x;
+ float scaley = scale_offset.y;
+ float offsetx = scale_offset.z;
+ float offsety = scale_offset.w;
+
+ // do not queue if either scales or alpha are zero
+ if( 0 == (scalex * scaley * ((tint_rgba>>24) & 255)) ) return;
+
+ ASSERT( (flags & SPRITE_CENTERED) == 0 );
+ if( flags & SPRITE_PROJECTED ) {
+ tilt_deg += 180, scalex = -scalex; // flip texture Y on mvp3d (same than turn 180º then flip X)
+ }
+
+ sprite_static_t s = {0};
+
+ s.px = pos.x, s.py = pos.y, s.pz = pos.z - zindex;
+ s.sx = scalex, s.sy = scaley;
+
+ s.x = rect.x, s.y = rect.y, s.w = rect.z, s.h = rect.w;
+ s.cellw = s.w * s.sx * t.w, s.cellh = s.h * s.sy * t.h;
+
+ s.rgba = tint_rgba;
+ s.flags = flags;
+
+#if 0
+ s.ox = 0/*ox*/ * s.sx;
+ s.oy = 0/*oy*/ * s.sy;
+#else
+ s.ox += offsetx * scalex;
+ s.oy += offsety * scaley;
+#endif
+
+ if( tilt_deg ) {
+ tilt_deg = (tilt_deg + 0) * ((float)C_PI / 180);
+ s.cos = cosf(tilt_deg);
+ s.sin = sinf(tilt_deg);
+ } else {
+ s.cos = 1;
+ s.sin = 0;
+ }
+
+ batch_group_t *batches = &sprite_group[ flags & 7 ];
+ batch_t *found = map_find_or_add(*batches, t.id, (batch_t){0});
+
+ array_push(found->sprites, s);
+}
+
+void sprite_sheet( texture_t texture, float spritesheet[3], float position[3], float rotation, float offset[2], float scale[2], unsigned rgba, unsigned flags) {
+ flags |= SPRITE_CENTERED;
+ ASSERT( flags & SPRITE_CENTERED );
+
+ const float px = position[0], py = position[1], pz = position[2];
+ const float ox = offset[0], oy = offset[1], sx = scale[0], sy = scale[1];
+ const float frame = spritesheet[0], xcells = spritesheet[1], ycells = spritesheet[2];
+
+ if (frame < 0) return;
+ if (frame > 0 && frame >= (xcells * ycells)) return;
+
+ // no need to queue if alpha or scale are zero
+ if( sx && sy && alpha(rgba) ) {
+ vec3 bak = camera_get_active()->position;
+ if( flags & SPRITE_RESOLUTION_INDEPENDANT ) { // @todo: optimize me
+ sprite_flush();
+ camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
+ }
+
+ sprite_static_t s;
+ s.px = px;
+ s.py = py;
+ s.pz = pz;
+ s.frame = frame;
+ s.ncx = xcells ? xcells : 1;
+ s.ncy = ycells ? ycells : 1;
+ s.sx = sx;
+ s.sy = sy;
+ s.ox = ox * sx;
+ s.oy = oy * sy;
+ s.cellw = (texture.x * sx / s.ncx);
+ s.cellh = (texture.y * sy / s.ncy);
+ s.rgba = rgba;
+ s.flags = flags;
+ s.cos = 1;
+ s.sin = 0;
+ if(rotation) {
+ rotation = (rotation + 0) * ((float)C_PI / 180);
+ s.cos = cosf(rotation);
+ s.sin = sinf(rotation);
+ }
+
+ batch_group_t *batches = &sprite_group[ flags & 7 ];
+#if 0
+ batch_t *found = map_find(*batches, texture.id);
+ if( !found ) found = map_insert(*batches, texture.id, (batch_t){0});
+#else
+ batch_t *found = map_find_or_add(*batches, texture.id, (batch_t){0});
+#endif
+
+ array_push(found->sprites, s);
+
+ if( flags & SPRITE_RESOLUTION_INDEPENDANT ) { // @todo: optimize me
+ sprite_flush();
+ camera_get_active()->position = bak;
+ }
+ }
+}
+
+void sprite( texture_t texture, float position[3], float rotation, unsigned color, unsigned flags) {
+ float offset[2] = {0,0}, scale[2] = {1,1}, spritesheet[3] = {0,0,0};
+ sprite_sheet( texture, spritesheet, position, rotation, offset, scale, color, flags );
+}
+
+static void sprite_rebuild_meshes() {
+ sprite_count = 0;
+
+ // w/2,h/2 centered
+ for( int l = countof(sprite_group) / 2; l < countof(sprite_group); ++l) {
+ for each_map_ptr(sprite_group[l], int,_, batch_t,bt) {
+
+ bt->dirty = array_count(bt->sprites) ? 1 : 0;
+ if( !bt->dirty ) continue;
+
+ int index = 0;
+ array_clear(sprite_indices);
+ array_clear(sprite_vertices);
+
+ array_foreach_ptr(bt->sprites, sprite_static_t,it ) {
+ float x0 = it->ox - it->cellw/2, x3 = x0 + it->cellw;
+ float y0 = it->oy - it->cellh/2, y3 = y0;
+ float x1 = x0, x2 = x3;
+ float y1 = y0 + it->cellh, y2 = y1;
+
+ // @todo: move this affine transform into glsl shader
+ vec3 v0 = { it->px + ( x0 * it->cos - y0 * it->sin ), it->py + ( x0 * it->sin + y0 * it->cos ), it->pz };
+ vec3 v1 = { it->px + ( x1 * it->cos - y1 * it->sin ), it->py + ( x1 * it->sin + y1 * it->cos ), it->pz };
+ vec3 v2 = { it->px + ( x2 * it->cos - y2 * it->sin ), it->py + ( x2 * it->sin + y2 * it->cos ), it->pz };
+ vec3 v3 = { it->px + ( x3 * it->cos - y3 * it->sin ), it->py + ( x3 * it->sin + y3 * it->cos ), it->pz };
+
+ float cx = (1.0f / it->ncx) - 1e-9f;
+ float cy = (1.0f / it->ncy) - 1e-9f;
+ int idx = (int)it->frame;
+ int px = idx % it->ncx;
+ int py = idx / it->ncx;
+
+ float ux = px * cx, uy = py * cy;
+ float vx = ux + cx, vy = uy + cy;
+
+ vec2 uv0 = vec2(ux, uy);
+ vec2 uv1 = vec2(ux, vy);
+ vec2 uv2 = vec2(vx, vy);
+ vec2 uv3 = vec2(vx, uy);
+
+ array_push( sprite_vertices, sprite_vertex(v0, uv0, it->rgba) ); // Vertex 0 (A)
+ array_push( sprite_vertices, sprite_vertex(v1, uv1, it->rgba) ); // Vertex 1 (B)
+ array_push( sprite_vertices, sprite_vertex(v2, uv2, it->rgba) ); // Vertex 2 (C)
+ array_push( sprite_vertices, sprite_vertex(v3, uv3, it->rgba) ); // Vertex 3 (D)
+
+ // A--B A A-B
+ // quad | | becomes triangle |\ and triangle \|
+ // D--C D-C C
+ GLuint A = (index+0), B = (index+1), C = (index+2), D = (index+3); index += 4;
+
+ array_push( sprite_indices, sprite_index(C, D, A) ); // Triangle 1
+ array_push( sprite_indices, sprite_index(C, A, B) ); // Triangle 2
+ }
+
+ mesh_update(&bt->mesh, "p3 t2 c4B", 0,array_count(sprite_vertices),sprite_vertices, 3*array_count(sprite_indices),sprite_indices, MESH_STATIC);
+
+ // clear elements from queue
+ sprite_count += array_count(bt->sprites);
+ array_clear(bt->sprites);
+ }
+ }
+
+ // (0,0) centered
+ for( int l = 0; l < countof(sprite_group) / 2; ++l) {
+ for each_map_ptr(sprite_group[l], int,_, batch_t,bt) {
+
+ bt->dirty = array_count(bt->sprites) ? 1 : 0;
+ if( !bt->dirty ) continue;
+
+ int index = 0;
+ array_clear(sprite_indices);
+ array_clear(sprite_vertices);
+
+ array_foreach_ptr(bt->sprites, sprite_static_t,it ) {
+ float x0 = it->ox - it->cellw/2, x3 = x0 + it->cellw;
+ float y0 = it->oy - it->cellh/2, y3 = y0;
+ float x1 = x0, x2 = x3;
+ float y1 = y0 + it->cellh, y2 = y1;
+
+ // @todo: move this affine transform into glsl shader
+ vec3 v0 = { it->px + ( x0 * it->cos - y0 * it->sin ), it->py + ( x0 * it->sin + y0 * it->cos ), it->pz };
+ vec3 v1 = { it->px + ( x1 * it->cos - y1 * it->sin ), it->py + ( x1 * it->sin + y1 * it->cos ), it->pz };
+ vec3 v2 = { it->px + ( x2 * it->cos - y2 * it->sin ), it->py + ( x2 * it->sin + y2 * it->cos ), it->pz };
+ vec3 v3 = { it->px + ( x3 * it->cos - y3 * it->sin ), it->py + ( x3 * it->sin + y3 * it->cos ), it->pz };
+
+ float ux = it->x, vx = ux + it->w;
+ float uy = it->y, vy = uy + it->h;
+
+ vec2 uv0 = vec2(ux, uy);
+ vec2 uv1 = vec2(ux, vy);
+ vec2 uv2 = vec2(vx, vy);
+ vec2 uv3 = vec2(vx, uy);
+
+ array_push( sprite_vertices, sprite_vertex(v0, uv0, it->rgba) ); // Vertex 0 (A)
+ array_push( sprite_vertices, sprite_vertex(v1, uv1, it->rgba) ); // Vertex 1 (B)
+ array_push( sprite_vertices, sprite_vertex(v2, uv2, it->rgba) ); // Vertex 2 (C)
+ array_push( sprite_vertices, sprite_vertex(v3, uv3, it->rgba) ); // Vertex 3 (D)
+
+ // A--B A A-B
+ // quad | | becomes triangle |\ and triangle \|
+ // D--C D-C C
+ GLuint A = (index+0), B = (index+1), C = (index+2), D = (index+3); index += 4;
+
+ array_push( sprite_indices, sprite_index(C, D, A) ); // Triangle 1
+ array_push( sprite_indices, sprite_index(C, A, B) ); // Triangle 2
+ }
+
+ mesh_update(&bt->mesh, "p3 t2 c4B", 0,array_count(sprite_vertices),sprite_vertices, 3*array_count(sprite_indices),sprite_indices, MESH_STATIC);
+
+ // clear elements from queue
+ sprite_count += array_count(bt->sprites);
+ array_clear(bt->sprites);
+ }
+ }
+}
+
+static void sprite_render_meshes_group(batch_group_t* sprites, int alpha_key, int alpha_value, float mvp[16]) {
+ if( map_count(*sprites) > 0 ) {
+ // setup shader
+ if( sprite_program < 0 ) {
+ sprite_program = shader( vfs_read("shaders/vs_324_24_sprite.glsl"), vfs_read("shaders/fs_24_4_sprite.glsl"),
+ "att_Position,att_TexCoord,att_Color",
+ "fragColor", NULL
+ );
+ }
+ shader_bind(sprite_program);
+ shader_mat44("u_mvp", mvp);
+
+ // set (unit 0) in the uniform texture sampler, and render batch
+ glActiveTexture(GL_TEXTURE0);
+ glBlendFunc( alpha_key, alpha_value );
+
+ for each_map_ptr(*sprites, int,texture_id, batch_t,bt) {
+ if( bt->dirty ) {
+ shader_texture_unit("u_texture", *texture_id, 0);
+ mesh_render(&bt->mesh);
+ }
+ }
+// map_clear(*sprites);
+ }
+}
+
+static void sprite_init() {
+ do_once for(int i = 0; i < countof(sprite_group); ++i) {
+ map_init(sprite_group[i], less_int, hash_int);
+ }
+}
+
+void sprite_flush() {
+ profile("Sprite.rebuild_time") {
+ sprite_rebuild_meshes();
+ }
+ profile("Sprite.render_time") {
+ // setup rendering state
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+ glDepthFunc(GL_LEQUAL); // try to help with zfighting
+
+ // 3d
+ mat44 mvp3d; multiply44x2(mvp3d, camera_get_active()->proj, camera_get_active()->view);
+ // render all additive then translucent groups
+ sprite_render_meshes_group(&sprite_group[SPRITE_PROJECTED], GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, mvp3d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_PROJECTED|SPRITE_CENTERED], GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, mvp3d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_PROJECTED|SPRITE_CENTERED|SPRITE_ADDITIVE], GL_SRC_ALPHA, GL_ONE, mvp3d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_PROJECTED|SPRITE_ADDITIVE], GL_SRC_ALPHA, GL_ONE, mvp3d );
+
+ // 2d: (0,0) is center of screen
+ mat44 mvp2d;
+ vec3 pos = camera_get_active()->position;
+ float zoom = absf(pos.z); if(zoom < 0.1f) zoom = 0.1f; zoom = 1.f / (zoom + !zoom);
+ float zdepth_max = window_height(); // 1;
+ float l = pos.x - window_width() * zoom / 2;
+ float r = pos.x + window_width() * zoom / 2;
+ float b = pos.y + window_height() * zoom / 2;
+ float t = pos.y - window_height() * zoom / 2;
+ ortho44(mvp2d, l,r,b,t, -zdepth_max, +zdepth_max);
+ // render all additive then translucent groups
+ sprite_render_meshes_group(&sprite_group[0], GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, mvp2d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_CENTERED], GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, mvp2d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_CENTERED|SPRITE_ADDITIVE], GL_SRC_ALPHA, GL_ONE, mvp2d );
+ sprite_render_meshes_group(&sprite_group[SPRITE_ADDITIVE], GL_SRC_ALPHA, GL_ONE, mvp2d );
+
+ // restore rendering state
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ glDepthFunc(GL_LESS);
+ glUseProgram(0);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// tilemaps
+
+tilemap_t tilemap(const char *map, int blank_chr, int linefeed_chr) {
+ tilemap_t t = {0};
+ t.tint = ~0u; // WHITE
+ t.blank_chr = blank_chr;
+ for( ; *map ; ++map ) {
+ if( map[0] == linefeed_chr ) ++t.rows;
+ else {
+ array_push(t.map, map[0]);
+ ++t.cols;
+ }
+ }
+ return t;
+}
+
+void tilemap_render_ext( tilemap_t m, tileset_t t, float zindex, float xy_zoom[3], float tilt, unsigned tint, bool is_additive ) {
+ vec3 old_pos = camera_get_active()->position;
+ sprite_flush();
+ camera_get_active()->position = vec3(window_width()/2,window_height()/2,1);
+
+ float scale[2] = {xy_zoom[2], xy_zoom[2]};
+ xy_zoom[2] = zindex;
+
+ float offset[2] = {0,0};
+ float spritesheet[3] = {0,t.cols,t.rows}; // selected tile index and spritesheet dimensions (cols,rows)
+
+ for( unsigned y = 0, c = 0; y < m.rows; ++y ) {
+ for( unsigned x = 0; x < m.cols; ++x, ++c ) {
+ if( m.map[c] != m.blank_chr ) {
+ spritesheet[0] = m.map[c];
+ sprite_sheet(t.tex, spritesheet, xy_zoom, tilt, offset, scale, tint, is_additive ? SPRITE_ADDITIVE : 0);
+ }
+ offset[0] += t.tile_w;
+ }
+ offset[0] = 0, offset[1] += t.tile_h;
+ }
+
+ sprite_flush();
+ camera_get_active()->position = old_pos;
+}
+
+void tilemap_render( tilemap_t map, tileset_t set ) {
+ map.position.x += set.tile_w;
+ map.position.y += set.tile_h;
+ tilemap_render_ext( map, set, map.zindex, &map.position.x, map.tilt, map.tint, map.is_additive );
+}
+
+tileset_t tileset(texture_t tex, unsigned tile_w, unsigned tile_h, unsigned cols, unsigned rows) {
+ tileset_t t = {0};
+ t.tex = tex;
+ t.cols = cols, t.rows = rows;
+ t.tile_w = tile_w, t.tile_h = tile_h;
+ return t;
+}
+
+int ui_tileset( tileset_t t ) {
+ ui_subimage(va("Selection #%d (%d,%d)", t.selected, t.selected % t.cols, t.selected / t.cols), t.tex.id, t.tex.w, t.tex.h, (t.selected % t.cols) * t.tile_w, (t.selected / t.cols) * t.tile_h, t.tile_w, t.tile_h);
+ int choice;
+ if( (choice = ui_image(0, t.tex.id, t.tex.w,t.tex.h)) ) {
+ int px = ((choice / 100) / 100.f) * t.tex.w / t.tile_w;
+ int py = ((choice % 100) / 100.f) * t.tex.h / t.tile_h;
+ t.selected = px + py * t.cols;
+ }
+ // if( (choice = ui_buttons(3, "load", "save", "clear")) ) {}
+ return t.selected;
+}
+
+// -----------------------------------------------------------------------------
+// tiled
+
+tiled_t tiled(const char *file_tmx) {
+ tiled_t zero = {0}, ti = zero;
+
+ // read file and parse json
+ if( !xml_push(file_tmx) ) return zero;
+
+ // sanity checks
+ bool supported = !strcmp(xml_string("/map/@orientation"), "orthogonal") && !strcmp(xml_string("/map/@renderorder"), "right-down");
+ if( !supported ) return xml_pop(), zero;
+
+ // tileset
+ const char *file_tsx = xml_string("/map/tileset/@source");
+ if( !xml_push(vfs_read(file_tsx)) ) return zero;
+ const char *set_src = xml_string("/tileset/image/@source");
+ int set_w = xml_int("/tileset/@tilewidth");
+ int set_h = xml_int("/tileset/@tileheight");
+ int set_c = xml_int("/tileset/@columns");
+ int set_r = xml_int("/tileset/@tilecount") / set_c;
+ tileset_t set = tileset(texture(set_src,0), set_w, set_h, set_c, set_r );
+ xml_pop();
+
+ // actual parsing
+ ti.w = xml_int("/map/@width");
+ ti.h = xml_int("/map/@height");
+ ti.tilew = xml_int("/map/@tilewidth");
+ ti.tileh = xml_int("/map/@tileheight");
+ ti.first_gid = xml_int("/map/tileset/@firstgid");
+ ti.map_name = STRDUP( xml_string("/map/tileset/@source") ); // @leak
+
+ for(int l = 0, layers = xml_count("/map/layer"); l < layers; ++l ) {
+ if( strcmp(xml_string("/map/layer[%d]/data/@encoding",l), "base64") || strcmp(xml_string("/map/layer[%d]/data/@compression",l), "zlib") ) {
+ PRINTF("Warning: layer encoding not supported: '%s' -> layer '%s'\n", file_tmx, *array_back(ti.names));
+ continue;
+ }
+
+ int cols = xml_int("/map/layer[%d]/@width",l);
+ int rows = xml_int("/map/layer[%d]/@height",l);
+
+ tilemap_t tm = tilemap("", ' ', '\n');
+ tm.blank_chr = ~0u; //ti.first_gid - 1;
+ tm.cols = cols;
+ tm.rows = rows;
+ array_resize(tm.map, tm.cols * tm.rows);
+ memset(tm.map, 0xFF, tm.cols * tm.rows * sizeof(int));
+
+ for( int c = 0, chunks = xml_count("/map/layer[%d]/data/chunk", l); c <= chunks; ++c ) {
+ int cw, ch;
+ int cx, cy;
+ array(char) b64 = 0;
+
+ if( !chunks ) { // non-infinite mode
+ b64 = xml_blob("/map/layer[%d]/data/$",l);
+ cw = tm.cols, ch = tm.rows;
+ cx = 0, cy = 0;
+ } else { // infinite mode
+ b64 = xml_blob("/map/layer[%d]/data/chunk[%d]/$",l,c);
+ cw = xml_int("/map/layer[%d]/data/chunk[%d]/@width",l,c), ch = xml_int("/map/layer[%d]/data/chunk[%d]/@height",l,c); // 20x20
+ cx = xml_int("/map/layer[%d]/data/chunk[%d]/@x",l,c), cy = xml_int("/map/layer[%d]/data/chunk[%d]/@y",l,c); // (-16,-32)
+ cx = abs(cx), cy = abs(cy);
+ }
+
+ int outlen = cw * ch * 4;
+ static __thread int *out = 0; out = (int *)REALLOC( 0, outlen + zexcess(COMPRESS_ZLIB) ); // @leak
+ if( zdecode( out, outlen, b64, array_count(b64), COMPRESS_ZLIB ) > 0 ) {
+ for( int y = 0, p = 0; y < ch; ++y ) {
+ for( int x = 0; x < cw; ++x, ++p ) {
+ if( out[p] >= ti.first_gid ) {
+ int offset = (x + cx) + (y + cy) * tm.cols;
+ if( offset >= 0 && offset < (cw * ch) )
+ tm.map[ offset ] = out[ p ] - ti.first_gid;
+ }
+ }
+ }
+ }
+ else {
+ PRINTF("Warning: bad zlib stream: '%s' -> layer #%d -> chunk #%d\n", file_tmx, l, c);
+ }
+
+ array_free(b64);
+ }
+
+ array_push(ti.layers, tm);
+ array_push(ti.names, STRDUP(xml_string("/map/layer[%d]/@name",l)));
+ array_push(ti.visible, true);
+ array_push(ti.sets, set);
+ }
+
+ xml_pop();
+ return ti;
+}
+
+void tiled_render(tiled_t tmx, vec3 pos) {
+ for( unsigned i = 0, end = array_count(tmx.layers); i < end; ++i ) {
+ tmx.layers[i].position = pos; // add3(camera_get_active()->position, pos);
+ if( tmx.parallax ) tmx.layers[i].position.x /= (3+i), tmx.layers[i].position.y /= (5+i);
+ if( tmx.visible[i] ) tilemap_render(tmx.layers[i], tmx.sets[i]);
+ }
+}
+
+void ui_tiled(tiled_t *t) {
+ ui_label2("Loaded map", t->map_name ? t->map_name : "(none)");
+ ui_label2("Map dimensions", va("%dx%d", t->w, t->h));
+ ui_label2("Tile dimensions", va("%dx%d", t->tilew, t->tileh));
+ ui_separator();
+ ui_bool("Parallax", &t->parallax);
+ ui_separator();
+ ui_label2("Layers", va("%d", array_count(t->layers)));
+ for( int i = 0; i < array_count(t->layers); ++i ) {
+ if( ui_label2_toolbar(va("- %s (%dx%d)", t->names[i], t->layers[i].cols, t->layers[i].rows ), t->visible[i] ? "\xee\xa3\xb4" : "\xee\xa3\xb5") > 0 ) { // ICON_MD_VISIBILITY / ICON_MD_VISIBILITY_OFF
+ t->visible[i] ^= true;
+ }
+ }
+ ui_separator();
+ if( ui_collapse(va("Sets: %d", array_count(t->layers)), va("%p",t))) {
+ for( int i = 0; i < array_count(t->layers); ++i ) {
+ if( ui_collapse(va("%d", i+1), va("%p%d",t,i)) ) {
+ t->sets[i].selected = ui_tileset( t->sets[i] );
+ ui_collapse_end();
+ }
+ }
+ ui_collapse_end();
+ }
+}
+
+// -----------------------------------------------------------------------------
+// spine json loader (wip)
+// - rlyeh, public domain
+//
+// [ref] http://es.esotericsoftware.com/spine-json-format
+//
+// notable misses:
+// - mesh deforms
+// - cubic beziers
+// - shears
+// - bounding boxes
+
+enum { SPINE_MAX_BONES = 64 }; // max bones
+
+typedef struct spine_bone_t {
+ char *name, *parent;
+ struct spine_bone_t *parent_bone;
+
+ float z; // draw order usually matches bone-id. ie, zindex == bone_id .. root(0) < chest (mid) < finger(top)
+
+ float len;
+ float x, y, deg; // base
+ float x2, y2, deg2; // accum / temporaries during bone transform time
+ float x3, y3, deg3; // values from timeline
+
+ unsigned rect_id;
+ unsigned atlas_id;
+} spine_bone_t;
+
+typedef struct spine_slot_t {
+ char *name, *bone, *attach;
+} spine_slot_t;
+
+typedef struct spine_rect_t {
+ char *name;
+ float x,y,w,h,sx,sy,deg;
+} spine_rect_t;
+
+typedef struct spine_skin_t {
+ char *name;
+ array(spine_rect_t) rects;
+} spine_skin_t;
+
+typedef struct spine_animkey_t { // offline; only during loading
+ float time, curve[4]; // time is mandatory, curve is optional
+ union {
+ char *name; // type: attachment (mode-1)
+ struct { float deg; }; // type: rotate (mode-2)
+ struct { float x,y; }; // type: translate (mode-3)
+ };
+} spine_animkey_t;
+
+#if 0
+typedef struct spine_pose_t { // runtime; only during playing
+ unsigned frame;
+ array(vec4) xform; // entry per bone. translation(x,y),rotation(z),attachment-id(w)
+} spine_pose_t;
+#endif
+
+typedef struct spine_anim_t {
+ char *name;
+ union {
+#if 0
+ struct {
+ unsigned frames;
+ array(spine_pose_t) poses;
+ };
+#endif
+ struct {
+ array(spine_animkey_t) attach_keys[SPINE_MAX_BONES];
+ array(spine_animkey_t) rotate_keys[SPINE_MAX_BONES];
+ array(spine_animkey_t) translate_keys[SPINE_MAX_BONES];
+ };
+ };
+} spine_anim_t;
+
+typedef struct spine_atlas_t {
+ char *name;
+ float x,y,w,h,deg;
+} spine_atlas_t;
+
+typedef struct spine_t {
+ char *name;
+ texture_t texture;
+ unsigned skin;
+ array(spine_bone_t) bones;
+ array(spine_slot_t) slots;
+ array(spine_skin_t) skins;
+ array(spine_anim_t) anims;
+ array(spine_atlas_t) atlas;
+ // anim controller
+ unsigned inuse;
+ float time, maxtime;
+ unsigned debug_atlas_id;
+} spine_t;
+
+// ---
+
+static
+void spine_convert_animkeys_to_animpose(spine_anim_t *input) {
+ spine_anim_t copy = *input; // @todo
+ // @leak: attach/rot/tra keys
+}
+
+static
+int find_bone_id(spine_t *s, const char *bone_name) {
+ for( unsigned i = 0, end = array_count(s->bones); i < end; ++i )
+ if( !strcmp(s->bones[i].name, bone_name)) return i;
+ return -1;
+}
+static
+spine_bone_t *find_bone(spine_t *s, const char *bone_name) {
+ int bone_id = find_bone_id(s, bone_name);
+ return bone_id >= 0 ? &s->bones[bone_id] : NULL;
+}
+
+void spine_skin(spine_t *p, unsigned skin) {
+ if( !p->texture.id ) return;
+ if( skin >= array_count(p->skins) ) return;
+
+ p->skin = skin;
+
+ char *skin_name = va("%s/", p->skins[skin].name);
+ int header = strlen(skin_name);
+
+ for( int i = 0; i < array_count(p->atlas); ++i) {
+ if(!strbeg(p->atlas[i].name, skin_name)) continue;
+
+ int bone_id = find_bone_id(p, p->atlas[i].name+header );
+ if( bone_id < 0 ) continue;
+
+ p->bones[bone_id].atlas_id = i;
+ }
+
+ for( int i = 0; i < array_count(p->skins[p->skin].rects); ++i) {
+ int bone_id = find_bone_id(p, p->skins[p->skin].rects[i].name );
+ if( bone_id < 0 ) continue;
+
+ p->bones[bone_id].rect_id = i;
+ }
+}
+
+static
+bool spine_(spine_t *t, const char *file_json, const char *file_atlas, unsigned flags) {
+ char *atlas = vfs_read(file_atlas);
+ if(!atlas || !atlas[0]) return false;
+
+ memset(t, 0, sizeof(spine_t));
+
+ // goblins.png
+ // size: 1024, 128
+ // filter: Linear, Linear
+ // pma: true
+ // dagger
+ // bounds: 2, 18, 26, 108
+ // goblin/eyes-closed
+ // bounds: 2, 4, 34, 12
+ spine_atlas_t *sa = 0;
+ const char *last_id = 0;
+ const char *texture_name = 0;
+ const char *texture_filter = 0;
+ const char *texture_format = 0;
+ const char *texture_repeat = 0;
+ float texture_width = 0, texture_height = 0, temp;
+ for each_substring(atlas, "\r\n", it) {
+ it += strspn(it, " \t\f\v");
+ /**/ if( strbeg(it, "pma:" ) || strbeg(it, "index:") ) {} // ignored
+ else if( strbeg(it, "size:" ) ) sscanf(it+5, "%f,%f", &texture_width, &texture_height);
+ else if( strbeg(it, "rotate:" ) ) { float tmp; tmp=sa->w,sa->w=sa->h,sa->h=tmp; sa->deg = 90; } // assert(val==90)
+ else if( strbeg(it, "repeat:" ) ) texture_repeat = it+7; // temp string
+ else if( strbeg(it, "filter:" ) ) texture_filter = it+7; // temp string
+ else if( strbeg(it, "format:" ) ) texture_format = it+7; // temp string
+ else if( strbeg(it, "bounds:" ) ) {
+ sscanf(it+7, "%f,%f,%f,%f", &sa->x, &sa->y, &sa->w, &sa->h);
+ }
+ else if( !texture_name ) texture_name = va("%s", it);
+ else {
+ array_push(t->atlas, ((spine_atlas_t){0}) );
+ sa = &t->atlas[array_count(t->atlas) - 1];
+ sa->name = STRDUP(it);
+ }
+ }
+ for( int i = 0; i < array_count(t->atlas); ++i ) {
+ sa = &t->atlas[i];
+ sa->x /= texture_width, sa->y /= texture_height;
+ sa->w /= texture_width, sa->h /= texture_height;
+ }
+
+ if(!texture_name) return false;
+
+ t->texture = texture(texture_name, TEXTURE_LINEAR);
+
+ json_push(vfs_read(file_json)); // @fixme: json_push_from_file() ?
+
+ array_resize(t->bones, json_count("/bones"));
+ array_reserve(t->slots, json_count("/slots"));
+ array_resize(t->skins, json_count("/skins"));
+ array_resize(t->anims, json_count("/animations"));
+
+ for( int i = 0, end = json_count("/bones"); i < end; ++i ) {
+ spine_bone_t v = {0};
+ v.name = STRDUP(json_string("/bones[%d]/name", i));
+ v.parent = STRDUP(json_string("/bones[%d]/parent", i));
+ v.x = json_float("/bones[%d]/x", i);
+ v.y = json_float("/bones[%d]/y", i);
+ v.z = i;
+ v.len = json_float("/bones[%d]/length", i);
+ v.deg = json_float("/bones[%d]/rotation", i);
+ t->bones[i] = v;
+
+ for( int j = i-1; j > 0; --j ) {
+ if( strcmp(t->bones[j].name,v.parent) ) continue;
+ t->bones[i].parent_bone = &t->bones[j];
+ break;
+ }
+ }
+
+ for( int i = 0, end = json_count("/slots"); i < end; ++i ) {
+ spine_slot_t v = {0};
+ v.name = STRDUP(json_string("/slots[%d]/name", i));
+ v.bone = STRDUP(json_string("/slots[%d]/bone", i));
+ v.attach = STRDUP(json_string("/slots[%d]/attachment", i));
+
+ array_push(t->slots, v);
+
+ // slots define draw-order. so, update draw-order/zindex in bone
+ spine_bone_t *b = find_bone(t, v.name);
+ if( b ) b->z = i;
+ }
+
+ for( int i = 0, end = json_count("/skins"); i < end; ++i ) {
+ spine_skin_t v = {0};
+ v.name = STRDUP(json_string("/skins[%d]/name", i));
+
+ for( int j = 0, jend = json_count("/skins[%d]/attachments",i); j < jend; ++j ) // /skins/default/
+ for( int k = 0, kend = json_count("/skins[%d]/attachments[%d]",i,j); k < kend; ++k ) { // /skins/default/left hand item/
+ spine_rect_t r = {0};
+ r.name = STRDUP(json_key("/skins[%d]/attachments[%d][%d]",i,j,k)); // stringf("%s-%s-%s", json_key("/skins[%d]",i), json_key("/skins[%d][%d]",i,j), json_key("/skins[%d][%d][%d]",i,j,k));
+ r.x = json_float("/skins[%d]/attachments[%d][%d]/x",i,j,k);
+ r.y = json_float("/skins[%d]/attachments[%d][%d]/y",i,j,k);
+ r.sx= json_float("/skins[%d]/attachments[%d][%d]/scaleX",i,j,k); r.sx += !r.sx;
+ r.sy= json_float("/skins[%d]/attachments[%d][%d]/scaleY",i,j,k); r.sy += !r.sy;
+ r.w = json_float("/skins[%d]/attachments[%d][%d]/width",i,j,k);
+ r.h = json_float("/skins[%d]/attachments[%d][%d]/height",i,j,k);
+ r.deg = json_float("/skins[%d]/attachments[%d][%d]/rotation",i,j,k);
+ array_push(v.rects, r);
+ }
+
+ t->skins[i] = v;
+ }
+
+#if 1
+ // simplify:
+ // merge /skins/default into existing /skins/*, then delete /skins/default
+ if( array_count(t->skins) > 1 ) {
+ for( int i = 1; i < array_count(t->skins); ++i ) {
+ for( int j = 0; j < array_count(t->skins[0].rects); ++j ) {
+ array_push(t->skins[i].rects, t->skins[0].rects[j]);
+ }
+ }
+ // @leak @fixme: FREE(t->skins[0])
+ for( int i = 0; i < array_count(t->skins)-1; ++i ) {
+ t->skins[i] = t->skins[i+1];
+ }
+ array_pop(t->skins);
+ }
+#endif
+
+ for( int i = 0, end = json_count("/animations"); i < end; ++i ) {
+ int id;
+ const char *name;
+
+ spine_anim_t v = {0};
+ v.name = STRDUP(json_key("/animations[%d]", i));
+
+ // slots / attachments
+
+ for( int j = 0, jend = json_count("/animations[%d]/slots",i); j < jend; ++j )
+ for( int k = 0, kend = json_count("/animations[%d]/slots[%d]",i,j); k < kend; ++k ) // ids
+ {
+ int bone_id = find_bone_id(t, json_key("/animations[%d]/bones[%d]",i,j));
+ if( bone_id < 0 ) continue;
+
+ for( int l = 0, lend = json_count("/animations[%d]/slots[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
+ spine_animkey_t key = {0};
+
+ key.name = STRDUP(json_string("/animations[%d]/slots[%d][%d][%d]/name",i,j,k,l));
+ key.time = json_float("/animations[%d]/slots[%d][%d][%d]/time",i,j,k,l);
+ if( json_count("/animations[%d]/slots[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
+ key.curve[0] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[0]",i,j,k,l);
+ key.curve[1] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[1]",i,j,k,l);
+ key.curve[2] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[2]",i,j,k,l);
+ key.curve[3] = json_float("/animations[%d]/slots[%d][%d][%d]/curve[3]",i,j,k,l);
+ }
+
+ // @todo: convert name to id
+ // for(id = 0; t->bones[id].name && strcmp(t->bones[id].name,key.name); ++id)
+ // printf("%s vs %s\n", key.name, t->bones[id].name);
+
+ array_push(v.attach_keys[bone_id], key);
+ }
+ }
+
+ // bones
+
+ for( int j = 0, jend = json_count("/animations[%d]/bones",i); j < jend; ++j ) // slots or bones
+ for( int k = 0, kend = json_count("/animations[%d]/bones[%d]",i,j); k < kend; ++k ) { // bone ids
+ int bone_id = find_bone_id(t, json_key("/animations[%d]/bones[%d]",i,j));
+ if( bone_id < 0 ) continue;
+
+ // parse bones
+ for( int l = 0, lend = json_count("/animations[%d]/bones[%d][%d]",i,j,k); l < lend; ++l ) { // channels (rot,tra,attach)
+ const char *channel = json_key("/animations[%d]/bones[%d][%d]",i,j,k);
+ int track = !strcmp(channel, "rotate") ? 1 : !strcmp(channel, "translate") ? 2 : 0;
+ if( !track ) continue;
+
+ spine_animkey_t key = {0};
+
+ key.time = json_float("/animations[%d]/bones[%d][%d][%d]/time",i,j,k,l);
+ if( json_count("/animations[%d]/bones[%d][%d][%d]/curve",i,j,k,l) == 4 ) {
+ key.curve[0] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[0]",i,j,k,l);
+ key.curve[1] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[1]",i,j,k,l);
+ key.curve[2] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[2]",i,j,k,l);
+ key.curve[3] = json_float("/animations[%d]/bones[%d][%d][%d]/curve[3]",i,j,k,l);
+ }
+
+ if( track == 1 )
+ key.deg = json_float("/animations[%d]/bones[%d][%d][%d]/value",i,j,k,l), // "/angle"
+ array_push(v.rotate_keys[bone_id], key);
+ else
+ key.x = json_float("/animations[%d]/bones[%d][%d][%d]/x",i,j,k,l),
+ key.y = json_float("/animations[%d]/bones[%d][%d][%d]/y",i,j,k,l),
+ array_push(v.translate_keys[bone_id], key);
+ }
+ }
+
+ t->anims[i] = v;
+ }
+
+ json_pop();
+
+ spine_skin(t, 0);
+
+ return true;
+}
+
+spine_t* spine(const char *file_json, const char *file_atlas, unsigned flags) {
+ spine_t *t = MALLOC(sizeof(spine_t));
+ if( !spine_(t, file_json, file_atlas, flags) ) return FREE(t), NULL;
+ return t;
+}
+
+void spine_render(spine_t *p, vec3 offset, unsigned flags) {
+ if( !p->texture.id ) return;
+ if( !flags ) return;
+
+ ddraw_push_2d();
+ // if( flags & 2 ) ddraw_line(vec3(0,0,0), vec3(window_width(),window_height(),0));
+ // if( flags & 2 ) ddraw_line(vec3(window_width(),0,0), vec3(0,window_height(),0));
+
+ // int already_computed[SPINE_MAX_BONES] = {0}; // @fixme: optimize: update longest chains first, then remnant branches
+
+ for( int i = 1; i < array_count(p->bones); ++i ) {
+ spine_bone_t *self = &p->bones[i];
+ if( !self->rect_id ) continue;
+
+ int num_bones = 0;
+ static array(spine_bone_t*) chain = 0; array_resize(chain, 0);
+ for( spine_bone_t *next = self; next ; next = next->parent_bone, ++num_bones ) {
+ array_push(chain, next);
+ }
+
+ vec3 target = {0}, prev = {0};
+ for( int j = 0, end = array_count(chain); j < end; ++j ) { // traverse from root(skipped) -> `i` bone direction
+ int j_opposite = end - 1 - j;
+
+ spine_bone_t *b = chain[j_opposite]; // bone
+ spine_bone_t *pb = b->parent_bone; // parent bone
+
+ float pb_x2 = 0, pb_y2 = 0, pb_deg2 = 0;
+ if( pb ) pb_x2 = pb->x2, pb_y2 = pb->y2, pb_deg2 = pb->deg2;
+
+ const float deg2rad = C_PI / 180;
+ b->x2 = b->x3 + pb_x2 + b->x * cos( -pb_deg2 * deg2rad ) - b->y * sin( -pb_deg2 * deg2rad );
+ b->y2 = -b->y3 + pb_y2 - b->y * cos( pb_deg2 * deg2rad ) + b->x * sin( pb_deg2 * deg2rad );
+ b->deg2 = -b->deg3 + pb_deg2 - b->deg;
+
+ prev = target;
+ target = vec3(b->x2,b->y2,b->deg2);
+ }
+
+ target.z = 0;
+ target = add3(target, offset);
+ prev.z = 0;
+ prev = add3(prev, offset);
+
+ if( flags & 2 ) {
+ ddraw_point( target );
+ ddraw_text( target, -0.25f, self->name );
+ ddraw_bone( prev, target ); // from parent to bone
+ }
+ if( flags & 1 ) {
+ spine_atlas_t *a = &p->atlas[self->atlas_id];
+ spine_rect_t *r = &p->skins[p->skin].rects[self->rect_id];
+
+ vec4 rect = ptr4(&a->x);
+ float zindex = self->z;
+ float offsx = 0;
+ float offsy = 0;
+ float tilt = self->deg2 + (a->deg - r->deg);
+ unsigned tint = self->atlas_id == p->debug_atlas_id ? 0xFF<<24 | 0xFF : ~0u;
+
+ if( 1 ) {
+ vec3 dir = vec3(r->x,r->y,0);
+ dir = rotatez3(dir, self->deg2);
+ offsx = dir.x * r->sx;
+ offsy = dir.y * r->sy;
+ }
+
+ sprite_rect(p->texture, rect, vec4(target.x,target.y,0,zindex), vec4(1,1,offsx,offsy), tilt, tint, 0);
+ }
+ }
+
+ ddraw_pop_2d();
+ ddraw_flush();
+}
+
+static
+void spine_animate_(spine_t *p, float *time, float *maxtime, float delta) {
+ if( !p->texture.id ) return;
+
+ if( delta > 1/120.f ) delta = 1/120.f;
+ if( *time >= *maxtime ) *time = 0; else *time += delta;
+
+ // reset root // needed?
+ p->bones[0].x2 = 0;
+ p->bones[0].y2 = 0;
+ p->bones[0].deg2 = 0;
+ p->bones[0].x3 = 0;
+ p->bones[0].y3 = 0;
+ p->bones[0].deg3 = 0;
+
+ for( int i = 0, end = array_count(p->bones); i < end; ++i) {
+ // @todo: attach channel
+ // @todo: per channel: if curve == linear || curve == stepped || array_count(curve) == 4 {...}
+ for each_array_ptr(p->anims[p->inuse].rotate_keys[i], spine_animkey_t, r) {
+ double r0 = r->time;
+ *maxtime = maxf( *maxtime, r0 );
+ if( absf(*time - r0) < delta ) {
+ p->bones[i].deg3 = r->deg;
+ }
+ }
+ for each_array_ptr(p->anims[p->inuse].translate_keys[i], spine_animkey_t, r) {
+ double r0 = r->time;
+ *maxtime = maxf( *maxtime, r0 );
+ if( absf(*time - r0) < delta ) {
+ p->bones[i].x3 = r->x;
+ p->bones[i].y3 = r->y;
+ }
+ }
+ }
+}
+
+void spine_animate(spine_t *p, float delta) {
+ spine_animate_(p, &p->time, &p->maxtime, delta);
+}
+
+void ui_spine(spine_t *p) {
+ if( ui_collapse(va("Anims: %d", array_count(p->anims)), va("%p-a", p))) {
+ for each_array_ptr(p->anims, spine_anim_t, q) {
+ if(ui_slider2("", &p->time, va("%.2f/%.0f %.2f%%", p->time, p->maxtime, p->time * 100.f))) {
+ spine_animate(p, 0);
+ }
+
+ int choice = ui_label2_toolbar(q->name, ICON_MD_PAUSE_CIRCLE " " ICON_MD_PLAY_CIRCLE);
+ if( choice == 1 ) window_pause( 0 ); // play
+ if( choice == 2 ) window_pause( 1 ); // pause
+
+ for( int i = 0; i < SPINE_MAX_BONES; ++i ) {
+ ui_separator();
+ ui_label(va("Bone %d: Attachment keys", i));
+ for each_array_ptr(q->attach_keys[i], spine_animkey_t, r) {
+ ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %s", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->name));
+ }
+ ui_label(va("Bone %d: Rotate keys", i));
+ for each_array_ptr(q->rotate_keys[i], spine_animkey_t, r) {
+ ui_label(va("%.2f [%.2f %.2f %.2f %.2f] %.2f deg", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->deg));
+ }
+ ui_label(va("Bone %d: Translate keys", i));
+ for each_array_ptr(q->translate_keys[i], spine_animkey_t, r) {
+ ui_label(va("%.2f [%.2f %.2f %.2f %.2f] (%.2f,%.2f)", r->time, r->curve[0], r->curve[1], r->curve[2], r->curve[3], r->x, r->y));
+ }
+ }
+ }
+ ui_collapse_end();
+ }
+ if( ui_collapse(va("Bones: %d", array_count(p->bones)), va("%p-b", p))) {
+ for each_array_ptr(p->bones, spine_bone_t, q)
+ if( ui_collapse(q->name, va("%p-b2", q)) ) {
+ ui_label2("Parent:", q->parent);
+ ui_label2("X:", va("%.2f", q->x));
+ ui_label2("Y:", va("%.2f", q->y));
+ ui_label2("Length:", va("%.2f", q->len));
+ ui_label2("Rotation:", va("%.2f", q->deg));
+ ui_collapse_end();
+ }
+ ui_collapse_end();
+ }
+ if( ui_collapse(va("Slots: %d", array_count(p->slots)), va("%p-s", p))) {
+ for each_array_ptr(p->slots, spine_slot_t, q)
+ if( ui_collapse(q->name, va("%p-s2", q)) ) {
+ ui_label2("Bone:", q->bone);
+ ui_label2("Attachment:", q->attach);
+ ui_collapse_end();
+ }
+ ui_collapse_end();
+ }
+ if( ui_collapse(va("Skins: %d", array_count(p->skins)), va("%p-k", p))) {
+ for each_array_ptr(p->skins, spine_skin_t, q)
+ if( ui_collapse(q->name, va("%p-k2", q)) ) {
+ for each_array_ptr(q->rects, spine_rect_t, r)
+ if( ui_collapse(r->name, va("%p-k3", r)) ) {
+ ui_label2("X:", va("%.2f", r->x));
+ ui_label2("Y:", va("%.2f", r->y));
+ ui_label2("Scale X:", va("%.2f", r->sx));
+ ui_label2("Scale Y:", va("%.2f", r->sy));
+ ui_label2("Width:", va("%.2f", r->w));
+ ui_label2("Height:", va("%.2f", r->h));
+ ui_label2("Rotation:", va("%.2f", r->deg));
+ ui_collapse_end();
+
+ spine_bone_t *b = find_bone(p, r->name);
+ if( b ) {
+ p->debug_atlas_id = b->atlas_id;
+
+ static float tilt = 0;
+ if( input(KEY_LCTRL) ) tilt += 60*1/60.f; else tilt = 0;
+ spine_atlas_t *r = p->atlas + b->atlas_id;
+ sprite_flush();
+ camera_get_active()->position = vec3(0,0,2);
+ vec4 rect = ptr4(&r->x); float zindex = 0; vec4 scale_offset = vec4(1,1,0,0);
+ sprite_rect(p->texture, ptr4(&r->x), vec4(0,0,0,zindex), scale_offset, r->deg + tilt, ~0u, 0);
+ sprite_flush();
+ camera_get_active()->position = vec3(+window_width()/3,window_height()/2.25,2);
+ }
+ }
+ ui_collapse_end();
+ }
+ ui_collapse_end();
+ }
+
+ if( ui_int("Use skin", &p->skin) ) {
+ p->skin = clampf(p->skin, 0, array_count(p->skins) - 1);
+ spine_skin(p, p->skin);
+ }
+
+ if( p->texture.id ) ui_texture(0, p->texture);
+}
+
+// ----------------------------------------------------------------------------
+
+// texture_t texture_createclip(unsigned cx,unsigned cy,unsigned cw,unsigned ch, unsigned tw,unsigned th,unsigned tn,void *pixels, unsigned flags) {
+// return texture_create(tw,th,tn,pixels,flags);
+// static array(unsigned) clip = 0;
+// array_resize(clip, cw*ch*4);
+// for( unsigned y = 0; y < ch; ++y )
+// memcpy((char *)clip + (0+(0+y)*cw)*tn, (char*)pixels + (cx+(cy+y)*tw)*tn, cw*tn);
+// return texture_create(cw,ch,tn,clip,flags);
+// }
+
+typedef unsigned quark_t;
+
+#define array_reserve_(arr,x) (array_count(arr) > (x) ? (arr) : array_resize(arr, 1+(x)))
+
+#define ui_array(label,type,ptr) do { \
+ int changed = 0; \
+ if( ui_collapse(label, va(#type "%p",ptr)) ) { \
+ char label_ex[8]; \
+ for( int idx = 0, iend = array_count(*(ptr)); idx < iend; ++idx ) { \
+ type* it = *(ptr) + idx; \
+ snprintf(label_ex, sizeof(label_ex), "[%d]", idx); \
+ changed |= ui_##type(label_ex, it); \
+ } \
+ ui_collapse_end(); \
+ } \
+} while(0)
+
+int ui_vec2i(const char *label, vec2i *v) { return ui_unsigned2(label, (unsigned*)v); }
+int ui_vec3i(const char *label, vec3i *v) { return ui_unsigned3(label, (unsigned*)v); }
+int ui_vec2(const char *label, vec2 *v) { return ui_float2(label, (float*)v); }
+int ui_vec3(const char *label, vec3 *v) { return ui_float3(label, (float*)v); }
+int ui_vec4(const char *label, vec4 *v) { return ui_float4(label, (float*)v); }
+
+char *trimspace(char *str) {
+ for( char *s = str; *s; ++s )
+ if(*s <= 32) memmove(s, s+1, strlen(s));
+ return str;
+}
+
+char *file_parent(const char *f) { // folder/folder/abc
+ char *p = file_path(f); // folder/folder/
+ char *last = strrchr(p, '/'); // ^
+ if( !last ) return p; // return parent if no sep
+ *last = '\0'; // folder/folder
+ last = strrchr(p, '/'); // ^
+ return last ? last + 1 : p; // return parent if no sep
+}
+
+int ui_obj(const char *fmt, obj *o) {
+ int changed = 0, item = 1;
+ for each_objmember(o, TYPE,NAME,PTR) {
+ char *label = va(fmt, NAME);
+ /**/ if(!strcmp(TYPE,"float")) { if(ui_float(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"int")) { if(ui_int(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"unsigned")) { if(ui_unsigned(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"vec2")) { if(ui_float2(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"vec3")) { if(ui_float3(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"vec4")) { if(ui_float4(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"rgb")) { if(ui_color3(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"rgba")) { if(ui_color4(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"color")) { if(ui_color4f(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"color3f")) { if(ui_color3f(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"color4f")) { if(ui_color4f(label, PTR)) changed = item; }
+ else if(!strcmp(TYPE,"char*")) { if(ui_string(label, PTR)) changed = item; }
+ else ui_label2(label, va("(%s)", TYPE)); // INFO instead of (TYPE)?
+ ++item;
+ }
+ return changed;
+}
+
+#define OBJTYPEDEF2(...) OBJTYPEDEF(__VA_ARGS__); AUTORUN
+
+// ----------------------------------------------------------------------------
+// atlas
+
+typedef struct atlas_frame_t {
+ unsigned delay;
+ vec4 sheet;
+ vec2 anchor; // @todo
+ array(vec3i) indices;
+ array(vec2) coords;
+ array(vec2) uvs;
+} atlas_frame_t;
+
+typedef struct atlas_anim_t {
+ quark_t name;
+ array(unsigned) frames;
+} atlas_anim_t;
+
+typedef struct atlas_t {
+ texture_t tex;
+
+ array(atlas_frame_t) frames;
+ array(atlas_anim_t) anims;
+
+ quarks_db db;
+} atlas_t;
+
+int ui_atlas_frame(atlas_frame_t *f) {
+ ui_unsigned("delay", &f->delay);
+ ui_vec4("sheet", &f->sheet);
+ ui_array("indices", vec3i, &f->indices);
+ ui_array("coords", vec2, &f->coords);
+ ui_array("uvs", vec2, &f->uvs);
+ return 0;
+}
+
+int ui_atlas(atlas_t *a) {
+ int changed = 0;
+ ui_texture(NULL, a->tex);
+ for( int i = 0; i < array_count(a->anims); ++i ) {
+ if( ui_collapse(quark_string(&a->db, a->anims[i].name), va("%p%d", a, a->anims[i].name) ) ) {
+ changed = i+1;
+ for( int j = 0; j < array_count(a->anims[i].frames); ++j ) {
+ if( ui_collapse(va("[%d]",j), va("%p%d.%d", a, a->anims[i].name,j) ) ) {
+ ui_unsigned("Frame", &a->anims[i].frames[j]);
+ ui_atlas_frame(a->frames + a->anims[i].frames[j]);
+ ui_collapse_end();
+ }
+ }
+ ui_collapse_end();
+ }
+ }
+ return changed;
+}
+
+void atlas_destroy(atlas_t *a) {
+ if( a ) {
+ texture_destroy(&a->tex);
+ memset(a, 0, sizeof(atlas_t));
+ }
+}
+atlas_t atlas_create(const char *inifile, unsigned flags) {
+ atlas_t a = {0};
+ int padding = 0, border = 0;
+
+ ini_t kv = ini(inifile);
+ for each_map(kv, char*,k, char*,v ) {
+ unsigned index = atoi(k);
+ /**/ if( strend(k, ".name") ) {
+ array_reserve_(a.anims, index);
+
+ a.anims[index].name = quark_intern(&a.db, v);
+ }
+ else if( strend(k, ".frames") ) {
+ array_reserve_(a.anims, index);
+
+ array(char*) pairs = strsplit(v, ",");
+ for( int i = 0, end = array_count(pairs); i < end; i += 2 ) {
+ unsigned frame = atoi(pairs[i]);
+ unsigned delay = atoi(pairs[i+1]);
+
+ array_reserve_(a.frames, frame);
+ a.frames[frame].delay = delay;
+
+ array_push(a.anims[index].frames, frame);
+ }
+ }
+ else if( strend(k, ".sheet") ) {
+ array_reserve_(a.frames, index);
+
+ vec4 sheet = atof4(v); //x,y,x2+2,y2+2 -> x,y,w,h (for 2,2 padding)
+ a.frames[index].sheet = vec4(sheet.x,sheet.y,sheet.z-sheet.x,sheet.w-sheet.y);
+ }
+ else if( strend(k, ".indices") ) {
+ array_reserve_(a.frames, index);
+
+ const char *text = v;
+ array(char*) tuples = strsplit(text, ",");
+ for( int i = 0, end = array_count(tuples); i < end; i += 3 ) {
+ unsigned p1 = atoi(tuples[i]);
+ unsigned p2 = atoi(tuples[i+1]);
+ unsigned p3 = atoi(tuples[i+2]);
+ array_push(a.frames[index].indices, vec3i(p1,p2,p3));
+ }
+ }
+ else if( strend(k, ".coords") ) {
+ array_reserve_(a.frames, index);
+
+ const char *text = v;
+ array(char*) pairs = strsplit(text, ",");
+ for( int i = 0, end = array_count(pairs); i < end; i += 2 ) {
+ unsigned x = atoi(pairs[i]);
+ unsigned y = atoi(pairs[i+1]);
+ array_push(a.frames[index].coords, vec2(x,y));
+ }
+ }
+ else if( strend(k, ".uvs") ) {
+ array_reserve_(a.frames, index);
+
+ const char *text = v;
+ array(char*) pairs = strsplit(text, ",");
+ for( int i = 0, end = array_count(pairs); i < end; i += 2 ) {
+ unsigned u = atoi(pairs[i]);
+ unsigned v = atoi(pairs[i+1]);
+ array_push(a.frames[index].uvs, vec2(u,v));
+ }
+ }
+ else if( strend(k, "padding") ) {
+ padding = atoi(v);
+ }
+ else if( strend(k, "border") ) {
+ border = atoi(v);
+ }
+ else if( strend(k, "file") ) {
+ a.tex = texture(v, 0);
+ }
+ else if( strend(k, "bitmap") ) {
+ const char *text = v;
+ array(char) bin = base64_decode(text, strlen(text));
+ a.tex = texture_from_mem(bin, array_count(bin), 0);
+ array_free(bin);
+ }
+#if 0
+ else if( strend(k, ".frame") ) {
+ array_reserve_(a.frames, index);
+ puts(k), puts(v);
+ }
+#endif
+ }
+
+ // post-process: normalize uvs and coords into [0..1] ranges
+ for each_array_ptr(a.frames, atlas_frame_t, f) {
+ for each_array_ptr(f->uvs, vec2, uv) {
+ uv->x /= a.tex.w;
+ uv->y /= a.tex.h;
+ }
+ for each_array_ptr(f->coords, vec2, xy) {
+ xy->x /= a.tex.w;
+ xy->y /= a.tex.h;
+ }
+ // @todo: adjust padding/border
+ }
+#if 0
+ // post-process: specify an anchor for each anim based on 1st frame dims
+ for each_array_ptr(a.anims, atlas_anim_t, anim) {
+ atlas_frame_t *first = a.frames + *anim->frames;
+ for( int i = 0; i < array_count(anim->frames); i += 2) {
+ atlas_frame_t *ff = a.frames + anim->frames[ i ];
+ ff->anchor.x = (ff->sheet.z - first->sheet.z) / 2;
+ ff->anchor.y = (ff->sheet.w - first->sheet.w) / 2;
+ }
+ }
+#endif
+
+ return a;
+}
+
+// ----------------------------------------------------------------------------
+// sprite v2
+
+void sprite_ctor(sprite_t *s) {
+ s->tint = WHITE;
+ s->timer_ms = 100;
+ s->flipped = 1;
+ s->sca.x += !s->sca.x;
+ s->sca.y += !s->sca.y;
+}
+void sprite_dtor(sprite_t *s) {
+ memset(s, 0, sizeof(*s));
+}
+void sprite_tick(sprite_t *s) {
+ int right = input(s->gamepad.array[3]) - input(s->gamepad.array[2]); // RIGHT - LEFT
+ int forward = input(s->gamepad.array[1]) - input(s->gamepad.array[0]); // DOWN - UP
+ int move = right || forward;
+ int dt = 16; // window_delta() * 1000;
+
+ unsigned over = (s->timer - dt) > s->timer;
+ if(!s->paused) s->timer -= dt;
+ if( over ) {
+ int len = array_count(s->a->anims[s->play].frames);
+ unsigned next = (s->frame + 1) % (len + !len);
+ unsigned eoa = next < s->frame;
+ s->frame = next;
+
+ atlas_frame_t *f = &s->a->frames[ s->a->anims[s->play].frames[s->frame] ];
+ s->timer_ms = f->delay;
+ s->timer += s->timer_ms;
+ }
+
+ if( s->play == 0 && move ) sprite_setanim(s, 1);
+ if( s->play == 1 ) { //<
+ if(right) s->flip_ = right < 0, sprite_setanim(s, 1);
+ if(!right && !forward) sprite_setanim(s, 0);
+
+ float speed = s->sca.x*2;
+ s->pos = add4(s->pos, scale4(norm4(vec4(right,0,forward,0)),speed));
+ }
+}
+void sprite_draw(sprite_t *s) {
+ atlas_frame_t *f = &s->a->frames[ s->a->anims[s->play].frames[s->frame] ];
+
+#if 1
+ // @todo {
+ unsigned sample = s->a->anims[s->play].frames[s->frame];
+ sample = 0;
+ f->anchor.x = (-s->a->frames[sample].sheet.z + f->sheet.z) / 2;
+ f->anchor.y = (+s->a->frames[sample].sheet.w - f->sheet.w) / 2;
+ // }
+#endif
+
+ // rect(x,y,w,h) is [0..1] normalized, z-index, pos(x,y,scale), rotation (degrees), color (rgba)
+ vec4 rect = { f->sheet.x / s->a->tex.w, f->sheet.y / s->a->tex.h, f->sheet.z / s->a->tex.w, f->sheet.w / s->a->tex.h };
+ sprite_rect(s->a->tex, rect, s->pos, vec4(s->flip_ ^ s->flipped?s->sca.x:-s->sca.x,s->sca.y,f->anchor.x,f->anchor.y), s->tilt, s->tint, 0|SPRITE_PROJECTED);
+}
+void sprite_edit(sprite_t *s) {
+ const char *name = obj_name(s);
+ const char *id = vac("%p", s);
+ if( s && ui_collapse(name ? name : id, id) ) {
+ ui_obj("%s", (obj*)s);
+
+ ui_bool("paused", &s->paused);
+ ui_label(va("frame anim [%d]", s->a->anims[s->play].frames[s->frame]));
+
+ int k = s->play;
+ if( ui_int("anim", &k) ) {
+ sprite_setanim(s, k);
+ }
+
+ int selected = ui_atlas(s->a);
+ if( selected ) sprite_setanim(s, selected - 1);
+
+ ui_collapse_end();
+ }
+}
+
+sprite_t* sprite_new(const char *ase, int bindings[6]) {
+ sprite_t *s = obj_new(sprite_t, {bindings[0],bindings[1],bindings[2],bindings[3]}, {bindings[4],bindings[5]});
+ atlas_t own = atlas_create(ase, 0);
+ memcpy(s->a = MALLOC(sizeof(atlas_t)), &own, sizeof(atlas_t)); // s->a = &s->own;
+ return s;
+}
+void sprite_del(sprite_t *s) {
+ if( s ) {
+ if( s->a ) atlas_destroy(s->a), FREE(s->a); // if( s->a == &s->own )
+ obj_free(s);
+ memset(s, 0, sizeof(sprite_t));
+ }
+}
+void sprite_setanim(sprite_t *s, unsigned name) {
+ if( s->play != name ) {
+ s->play = name;
+ s->frame = 0;
+
+ atlas_frame_t *f = &s->a->frames[ s->a->anims[s->play].frames[s->frame] ];
+
+ s->timer_ms = f->delay;
+ s->timer = s->timer_ms;
+ }
+}
+
+AUTORUN {
+ STRUCT(sprite_t, vec4, pos);
+ STRUCT(sprite_t, vec2, sca);
+ STRUCT(sprite_t, float, tilt);
+ STRUCT(sprite_t, vec4, gamepad);
+ STRUCT(sprite_t, vec2, fire);
+ STRUCT(sprite_t, rgba, tint);
+ STRUCT(sprite_t, unsigned, frame);
+ STRUCT(sprite_t, unsigned, timer);
+ STRUCT(sprite_t, unsigned, timer_ms);
+ STRUCT(sprite_t, unsigned, flipped);
+ STRUCT(sprite_t, unsigned, play);
+ EXTEND_T(sprite, ctor,edit,draw,tick);
+}
+#line 0
+
+#line 1 "v4k_system.c"
#if (is(tcc) && is(linux)) || (is(gcc) && !is(mingw)) // || is(clang)
int __argc; char **__argv;
#if !is(ems)
@@ -22677,8 +23199,8 @@ static char **backtrace_symbols(void *const *list,int size) {
static __thread char **symbols = 0; //[32][64] = {0};
if( !symbols ) {
- symbols = SYS_REALLOC(0, 128 * sizeof(char*));
- for( int i = 0; i < 128; ++i) symbols[i] = SYS_REALLOC(0, 128 * sizeof(char));
+ symbols = SYS_MEM_REALLOC(0, 128 * sizeof(char*));
+ for( int i = 0; i < 128; ++i) symbols[i] = SYS_MEM_REALLOC(0, 128 * sizeof(char));
}
if(size > 128) size = 128;
@@ -22711,7 +23233,7 @@ static char **backtrace_symbols(void *const *sym,int num) { return 0; }
char *callstack( int traces ) {
static __thread char *output = 0;
- if(!output ) output = SYS_REALLOC( 0, 128 * (64+2) );
+ if(!output ) output = SYS_MEM_REALLOC( 0, 128 * (64+2) );
if( output ) output[0] = '\0';
char *ptr = output;
@@ -23270,7 +23792,7 @@ int (PRINTF)(const char *text, const char *stack, const char *file, int line, co
static void *panic_oom_reserve; // for out-of-memory recovery
int (PANIC)(const char *error, const char *file, int line) {
- panic_oom_reserve = SYS_REALLOC(panic_oom_reserve, 0);
+ panic_oom_reserve = SYS_MEM_REALLOC(panic_oom_reserve, 0);
tty_color(RED);
@@ -23446,7 +23968,7 @@ int (test)(const char *file, int line, const char *expr, bool result) {
}
#line 0
-#line 1 "engine/split/v4k_time.c"
+#line 1 "v4k_time.c"
// ----------------------------------------------------------------------------
// time
@@ -24086,7 +24608,7 @@ void curve_destroy(curve_t *c) {
}
#line 0
-#line 1 "engine/split/v4k_profile.c"
+#line 1 "v4k_profile.c"
#if ENABLE_PROFILER
profiler_t profiler;
int profiler_enabled = 1;
@@ -24144,7 +24666,7 @@ void (ui_profiler)() {
#endif
#line 0
-#line 1 "engine/split/v4k_video.c"
+#line 1 "v4k_video.c"
// tip: convert video to x265/mp4. note: higher crf to increase compression (default crf is 28)
// ffmpeg -i {{infile}} -c:v libx265 -crf 24 -c:a copy {{outfile}}
@@ -24376,7 +24898,7 @@ void record_frame() {
}
#line 0
-#line 1 "engine/split/v4k_window.c"
+#line 1 "v4k_window.c"
//-----------------------------------------------------------------------------
// fps locking
@@ -24803,7 +25325,7 @@ bool window_create_from_handle(void *handle, float scale, unsigned flags) {
#define ddraw_progress_bar(JOB_ID, JOB_MAX, PERCENT) do { \
/* NDC coordinates (2d): bottom-left(-1,-1), center(0,0), top-right(+1,+1) */ \
float progress = (PERCENT+1) / 100.f; if(progress > 1) progress = 1; \
- float speed = progress < 1 ? 0.2f : 0.5f; \
+ float speed = progress < 1 ? 0.05f : 0.75f; \
float smooth = previous[JOB_ID] = progress * speed + previous[JOB_ID] * (1-speed); \
\
float pixel = 2.f / window_height(), dist = smooth*2-1, y = pixel*3*JOB_ID; \
@@ -25465,7 +25987,7 @@ double window_scale() { // ok? @testme
}
#line 0
-#line 1 "engine/split/v4k_obj.c"
+#line 1 "v4k_obj.c"
// -----------------------------------------------------------------------------
// factory of handle ids, based on code by randy gaul (PD/Zlib licensed)
// - rlyeh, public domain
@@ -26477,7 +26999,7 @@ void *obj_make(const char *str) {
}
#line 0
-#line 1 "engine/split/v4k_ai.c"
+#line 1 "v4k_ai.c"
// AI framework
// - rlyeh, public domain.
//
@@ -27315,7 +27837,7 @@ int ui_bt(bt_t *b) {
}
#line 0
-#line 1 "engine/split/v4k_editor.c"
+#line 1 "v4k_editor0.c"
// editing:
// nope > functions: add/rem property
@@ -27848,158 +28370,9 @@ int gizmo(vec3 *pos, vec3 *rot, vec3 *sca) {
return modified;
}
-// -- localization kit
-
-static const char *kit_lang = "enUS", *kit_langs =
- "enUS,enGB,"
- "frFR,"
- "esES,esAR,esMX,"
- "deDE,deCH,deAT,"
- "itIT,itCH,"
- "ptBR,ptPT,"
- "zhCN,zhSG,zhTW,zhHK,zhMO,"
- "ruRU,elGR,trTR,daDK,noNB,svSE,nlNL,plPL,fiFI,jaJP,"
- "koKR,csCZ,huHU,roRO,thTH,bgBG,heIL"
-;
-
-static map(char*,char*) kit_ids;
-static map(char*,char*) kit_vars;
-
-#ifndef KIT_FMT_ID2
-#define KIT_FMT_ID2 "%s.%s"
-#endif
-
-void kit_init() {
- do_once map_init(kit_ids, less_str, hash_str);
- do_once map_init(kit_vars, less_str, hash_str);
-}
-
-void kit_insert( const char *id, const char *translation) {
- char *id2 = va(KIT_FMT_ID2, kit_lang, id);
-
- char **found = map_find_or_add_allocated_key(kit_ids, STRDUP(id2), NULL);
- if(*found) FREE(*found);
- *found = STRDUP(translation);
-}
-
-bool kit_merge( const char *filename ) {
- // @todo: xlsx2ini
- return false;
-}
-
-void kit_clear() {
- map_clear(kit_ids);
-}
-
-bool kit_load( const char *filename ) {
- return kit_clear(), kit_merge( filename );
-}
-
-void kit_set( const char *key, const char *value ) {
- value = value && value[0] ? value : "";
-
- char **found = map_find_or_add_allocated_key(kit_vars, STRDUP(key), NULL );
- if(*found) FREE(*found);
- *found = STRDUP(value);
-}
-
-void kit_reset() {
- map_clear(kit_vars);
-}
-
-char *kit_translate2( const char *id, const char *lang ) {
- char *id2 = va(KIT_FMT_ID2, lang, id);
-
- char **found = map_find(kit_ids, id2);
-
- // return original [[ID]] if no translation is found
- if( !found ) return va("[[%s]]", id);
-
- // return translation if no {{moustaches}} are found
- if( !strstr(*found, "{{") ) return *found;
-
- // else replace all found {{moustaches}} with context vars
- {
- // make room
- static __thread char *results[16] = {0};
- static __thread unsigned counter = 0; counter = (counter+1) % 16;
-
- char *buffer = results[ counter ];
- if( buffer ) FREE(buffer), buffer = 0;
-
- // iterate moustaches
- const char *begin, *end, *text = *found;
- while( NULL != (begin = strstr(text, "{{")) ) {
- end = strstr(begin+2, "}}");
- if( end ) {
- char *var = va("%.*s", (int)(end - (begin+2)), begin+2);
- char **found_var = map_find(kit_vars, var);
-
- if( found_var && 0[*found_var] ) {
- strcatf(&buffer, "%.*s%s", (int)(begin - text), text, *found_var);
- } else {
- strcatf(&buffer, "%.*s{{%s}}", (int)(begin - text), text, var);
- }
-
- text = end+2;
- } else {
- strcatf(&buffer, "%.*s", (int)(begin - text), text);
-
- text = begin+2;
- }
- }
-
- strcatf(&buffer, "%s", text);
- return buffer;
- }
-}
-
-char *kit_translate( const char *id ) {
- return kit_translate2( id, kit_lang );
-}
-
-void kit_locale( const char *lang ) {
- kit_lang = STRDUP(lang); // @leak
-}
-
-void kit_dump_state( FILE *fp ) {
- for each_map(kit_ids, char *, k, char *, v) {
- fprintf(fp, "[ID ] %s=%s\n", k, v);
- }
- for each_map(kit_vars, char *, k, char *, v) {
- fprintf(fp, "[VAR] %s=%s\n", k, v);
- }
-}
-
-/*
-int main() {
- kit_init();
-
- kit_locale("enUS");
- kit_insert("HELLO_PLAYERS", "Hi {{PLAYER1}} and {{PLAYER2}}!");
- kit_insert("GREET_PLAYERS", "Nice to meet you.");
-
- kit_locale("esES");
- kit_insert("HELLO_PLAYERS", "Hola {{PLAYER1}} y {{PLAYER2}}!");
- kit_insert("GREET_PLAYERS", "Un placer conoceros.");
-
- kit_locale("enUS");
- printf("%s %s\n", kit_translate("HELLO_PLAYERS"), kit_translate("GREET_PLAYERS")); // Hi {{PLAYER1}} and {{PLAYER2}}! Nice to meet you.
-
- kit_locale("esES");
- kit_set("PLAYER1", "John");
- kit_set("PLAYER2", "Karl");
- printf("%s %s\n", kit_translate("HELLO_PLAYERS"), kit_translate("GREET_PLAYERS")); // Hola John y Karl! Un placer conoceros.
-
- assert( 0 == strcmp(kit_translate("NON_EXISTING"), "[[NON_EXISTING]]")); // [[NON_EXISTING]]
- assert(~puts("Ok"));
-}
-*/
#line 0
-// editor is last in place, so it can use all internals from above headers
-
-#line 1 "engine/split/v4k_main.c"
+#line 1 "v4k_main.c"
// ----------------------------------------------------------------------------
static void v4k_pre_init() {
@@ -28066,7 +28439,7 @@ void v4k_init() {
ifdef(debug, trap_install());
// init panic handler
- panic_oom_reserve = SYS_REALLOC(panic_oom_reserve, 1<<20); // 1MiB
+ panic_oom_reserve = SYS_MEM_REALLOC(panic_oom_reserve, 1<<20); // 1MiB
// init glfw
glfw_init();
@@ -28092,7 +28465,2155 @@ void v4k_init() {
}
#line 0
-#line 1 "engine/split/v4k_end.c"
+// editor is last in place, so it can use all internals from above headers
+#line 1 "v4k_editor.c"
+// ## Editor long-term plan
+// - editor = tree of nodes. levels and objects are nodes, and their widgets are also nodes
+// - you can perform actions on nodes, with or without descendants, top-bottom or bottom-top
+// - these operations include load/save, undo/redo, reset, play/render, ddraw, etc
+// - nodes are saved to disk as a filesystem layout: parents are folders, and leafs are files
+// - network replication can be done by external tools by comparing the filesystems and by sending the resulting diff zipped
+//
+// ## Editor roadmap
+// - Gizmos?, scene tree, property editor?, load/save?, undo/redo?, copy/paste, on/off (vis,tick,ddraw,log), vcs.
+// - Scenenode pass: node singleton display, node console, node labels, node outlines?.
+// - Render pass: billboards?, materials, un/lit, cast shadows, wireframe, skybox?/mie?, fog/atmosphere
+// - Level pass: volumes, triggers, platforms, level streaming, collide?, physics
+// - Edit pass: Procedural content, brushes, noise and CSG.
+// - GUI pass: timeline and data tracks, node graphs.
+
+// ## Alt plan
+// editor is a database + window/tile manager + ui toolkit; all network driven.
+// to be precise, editor is a dumb app and ...
+// - does not know a thing about what it stores.
+// - does not know how to render the game graphics.
+// - does not know how to run the game logic.
+//
+// the editor will create a canvas for your game to render.
+// your game will be responsible to tick the logic and render the window inside the editor.
+//
+// that being said, editor...
+// - can store datas hierarchically.
+// - can perform diffs and merges, and version the datas into repositories.
+// - can be instructed to render UI on top of game and window views.
+// - can download new .natvis and plugins quickly.
+// - can dump whole project in a filesystem form (zip).
+
+// - editor reflects database contents up-to-date.
+// - database can be queried and modified via OSC(UDP) commands.
+
+// editor database uses one table, and stores two kind of payload types:
+// - classes: defines typename and dna. class names are prefixed by '@'
+// - instances: defines typename and datas. instance names are as-is, not prefixed.
+//
+// every save contains 5Ws: what, who, when, where, how,
+// every save can be diffed/merged.
+
+// ----------------------------------------------------------------------------
+
+#define EDITOR_VERSION "2023.10"
+
+// ----------------------------------------------------------------------------
+
+typedef struct editor_bind_t {
+ const char *command;
+ const char *bindings;
+ void (*fn)();
+} editor_bind_t;
+
+array(editor_bind_t) editor_binds;
+
+#define EDITOR_BIND(CMD,KEYS,...) void macro(editor_bind_##CMD##_fn_)() { __VA_ARGS__ }; AUTORUN { array_push(editor_binds, ((editor_bind_t){#CMD,KEYS,macro(editor_bind_##CMD##_fn_)}) ); }
+
+// ----------------------------------------------------------------------------
+
+typedef void (*editor_no_property)(void *);
+array(void*) editor_persist_kv;
+array(editor_no_property) editor_no_properties;
+
+#define EDITOR_PROPERTY(property_name,T,defaults) \
+typedef map(void*,T) editor_##property_name##_map_t; \
+editor_##property_name##_map_t *editor_##property_name##_map() { \
+ static editor_##property_name##_map_t map = 0; do_once map_init_ptr(map); \
+ return ↦ \
+} \
+T editor_##property_name(const void *obj) { \
+ return *map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) defaults)); \
+} \
+void editor_set##property_name(const void *obj, T value) { \
+ *map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) value)) = ((T) value); \
+} \
+void editor_alt##property_name(const void *obj) { \
+ T* found = map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) defaults)); \
+ *found = (T)(uintptr_t)!(*found); \
+} \
+void editor_no##property_name(void *obj) { \
+ T* found = map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) defaults)); \
+ map_erase(*editor_##property_name##_map(), (void*)obj); \
+} \
+AUTORUN { array_push(editor_persist_kv, #T); array_push(editor_persist_kv, editor_##property_name##_map()); array_push(editor_no_properties, editor_no##property_name); }
+
+EDITOR_PROPERTY(open, int, 0); // whether object is tree opened in tree editor
+EDITOR_PROPERTY(selected, int, 0); // whether object is displaying a contextual popup or not
+EDITOR_PROPERTY(changed, int, 0); // whether object is displaying a contextual popup or not
+EDITOR_PROPERTY(popup, int, 0); // whether object is displaying a contextual popup or not
+EDITOR_PROPERTY(visible, int, 0);
+EDITOR_PROPERTY(script, int, 0);
+EDITOR_PROPERTY(event, int, 0);
+EDITOR_PROPERTY(iconinstance, char*, 0);
+EDITOR_PROPERTY(iconclass, char*, 0);
+EDITOR_PROPERTY(treeoffsety, int, 0);
+// new prop: breakpoint: request to break on any given node
+// new prop: persist: objects with this property will be saved on disk
+
+void editor_destroy_properties(void *o) {
+ for each_array(editor_no_properties,editor_no_property,fn) {
+ fn(o);
+ }
+}
+
+void editor_load_on_boot(void) {
+}
+void editor_save_on_quit(void) {
+}
+AUTORUN {
+ editor_load_on_boot();
+ (atexit)(editor_save_on_quit);
+}
+
+// ----------------------------------------------------------------------------
+
+typedef int(*subeditor)(int mode);
+
+struct editor_t {
+ // time
+ unsigned frame;
+ double t, dt, slomo;
+ // controls
+ int transparent;
+ int attached;
+ int active; // focus? does_grabinput instead?
+ int key;
+ vec2 mouse; // 2d coord for ray/picking
+ bool gamepad; // mask instead? |1|2|4|8
+ int hz_high, hz_medium, hz_low;
+ int filter;
+ bool battery; // battery mode: low fps
+ bool unlit;
+ bool ddraw;
+ // event root nodes
+ obj* root;
+ obj* on_init;
+ obj* on_tick;
+ obj* on_draw;
+ obj* on_edit;
+ obj* on_quit;
+ // all of them (hierarchical)
+ array(obj*) objs; // @todo:set() world?
+ // all of them (flat)
+ set(obj*) world;
+ //
+ array(char*) cmds;
+ // subeditors
+ array(subeditor) subeditors;
+} editor = {
+ .active = 1,
+ .gamepad = 1,
+ .hz_high = 60, .hz_medium = 18, .hz_low = 5,
+};
+
+enum {
+ EDITOR_PANEL,
+ EDITOR_WINDOW,
+ EDITOR_WINDOW_NK,
+ EDITOR_WINDOW_NK_SMALL,
+};
+
+int editor_begin(const char *title, int mode) {
+ if( mode == 0 ) return ui_panel(title, PANEL_OPEN);
+ if( mode == 1 ) return ui_window(title, 0);
+
+ int ww = window_width(), w = ww * 0.66;
+ int hh = window_height(), h = hh * 0.66;
+
+ struct nk_rect position = { (ww-w)/2,(hh-h)/2, w,h };
+ nk_flags win_flags = NK_WINDOW_TITLE | NK_WINDOW_BORDER |
+ NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE |
+ NK_WINDOW_CLOSABLE | NK_WINDOW_MINIMIZABLE |
+ // NK_WINDOW_SCALE_LEFT|NK_WINDOW_SCALE_TOP| //< @fixme: move this logic into nuklear
+ // NK_WINDOW_MAXIMIZABLE | NK_WINDOW_PINNABLE |
+ 0; // NK_WINDOW_SCROLL_AUTO_HIDE;
+
+ if( mode == 3 ) {
+ mode = 2, position.x = input(MOUSE_X), position.w = w/3, win_flags =
+ NK_WINDOW_TITLE|NK_WINDOW_CLOSABLE|
+ NK_WINDOW_SCALABLE|NK_WINDOW_MOVABLE| //< nuklear requires these two to `remember` popup rects
+ 0;
+ }
+
+ if( mode == 2 || mode == 3 )
+ if (nk_begin(ui_ctx, title, position, win_flags))
+ return 1;
+ else
+ return nk_end(ui_ctx), 0;
+
+ return 0;
+}
+int editor_end(int mode) {
+ if( mode == 0 ) return ui_panel_end();
+ if( mode == 1 ) return ui_window_end();
+ if( mode == 2 ) nk_end(ui_ctx);
+ if( mode == 3 ) nk_end(ui_ctx);
+ return 0;
+}
+
+#if 0 // deprecate
+bool editor_active() {
+ return ui_hover() || ui_active() || gizmo_active() ? editor.active : 0;
+}
+#endif
+
+int editor_filter() {
+ if( editor.filter ) {
+ if (nk_begin(ui_ctx, "Filter", nk_rect(window_width()-window_width()*0.33,32, window_width()*0.33, 40),
+ NK_WINDOW_NO_SCROLLBAR)) {
+
+ char *bak = ui_filter; ui_filter = 0;
+ ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &bak);
+ ui_filter = bak;
+
+ if( input(KEY_ESC) || ( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 )) {
+ if( ui_filter ) ui_filter[0] = '\0';
+ editor.filter = 0;
+ }
+ }
+ nk_end(ui_ctx);
+ }
+
+ return editor.filter;
+ }
+
+static
+int editor_select_(void *o, const char *mask) {
+ int matches = 0;
+ int off = mask[0] == '!', inv = mask[0] == '~';
+ int match = strmatchi(obj_type(o), mask+off+inv) || strmatchi(obj_name(o), mask+off+inv);
+ if( match ) {
+ editor_setselected(o, inv ? editor_selected(o) ^ 1 : !off);
+ ++matches;
+ }
+ for each_objchild(o, obj*, oo) {
+ matches += editor_select_(oo, mask);
+ }
+ return matches;
+}
+void editor_select(const char *mask) {
+ for each_array( editor.objs, obj*, o )
+ editor_select_(o, mask);
+}
+void editor_unselect() { // same than editor_select("!**");
+ for each_map_ptr(*editor_selected_map(), void*,o, int, k) {
+ if( *k ) *k = 0;
+ }
+ }
+
+void editor_select_aabb(aabb box) {
+ int is_inv = input_held(KEY_CTRL);
+ int is_add = input_held(KEY_SHIFT);
+ if( !is_inv && !is_add ) editor_unselect();
+
+ aabb item = {0};
+ for each_set_ptr( editor.world, obj*, o ) {
+ if( obj_hasmethod(*o,aabb) && obj_aabb(*o, &item) ) {
+ if( aabb_test_aabb(item, box) ) {
+ if( is_inv )
+ editor_altselected(*o);
+ else
+ editor_setselected(*o, 1);
+ }
+ }
+ }
+}
+
+static obj* active_ = 0;
+static void editor_selectgroup_(obj *o, obj *first, obj *last) {
+ // printf("%s (looking for %s in [%s..%s])\n", obj_name(o), active_ ? obj_name(active_) : "", obj_name(first), obj_name(last));
+ if( !active_ ) if( o == first || o == last ) active_ = o == first ? last : first;
+ if( active_ ) editor_setselected(o, 1);
+ if( o == active_ ) active_ = 0;
+ for each_objchild(o, obj*, oo) {
+ editor_selectgroup_(oo, first, last);
+ }
+}
+void editor_selectgroup(obj *first, obj *last) {
+ if( last ) {
+ if( !first ) first = array_count(editor.objs) ? editor.objs[0] : NULL;
+ if( !first ) editor_setselected(last, 1);
+ else {
+ active_ = 0;
+ for each_array(editor.objs,obj*,o) {
+ editor_selectgroup_(o, first, last);
+ }
+ }
+ }
+ }
+
+static obj *find_any_selected_(obj *o) {
+ if( editor_selected(o) ) return o;
+ for each_objchild(o,obj*,oo) {
+ obj *ooo = find_any_selected_(oo);
+ if( ooo )
+ return ooo;
+ }
+ return 0;
+}
+void* editor_first_selected() {
+ for each_array(editor.objs,obj*,o) {
+ obj *oo = find_any_selected_(o);
+ // if( oo ) printf("1st found: %s\n", obj_name(oo));
+ if( oo ) return oo;
+}
+ return 0;
+}
+
+static obj *find_last_selected_(obj *o) {
+ void *last = 0;
+ if( editor_selected(o) ) last = o;
+ for each_objchild(o,obj*,oo) {
+ obj *ooo = find_last_selected_(oo);
+ if( ooo )
+ last = ooo;
+}
+ return last;
+}
+void* editor_last_selected() {
+ void *last = 0;
+ for each_array(editor.objs,obj*,o) {
+ obj *oo = find_last_selected_(o);
+ // if( oo ) printf("last found: %s\n", obj_name(oo));
+ if( oo ) last = oo;
+}
+ return last;
+}
+
+// ----------------------------------------------------------------------------------------
+
+void editor_addtoworld(obj *o) {
+ set_find_or_add(editor.world, o);
+ for each_objchild(o, obj*, oo) {
+ editor_addtoworld(oo);
+}
+}
+
+void editor_watch(const void *o) {
+ array_push(editor.objs, (obj*)o);
+ obj_push(o); // save state
+
+ editor_addtoworld((obj*)o);
+}
+void* editor_spawn(const char *ini) { // deprecate?
+ obj *o = obj_make(ini);
+ editor_watch(o);
+ return o;
+}
+void editor_spawn1() {
+ obj *selected = editor_first_selected();
+ obj *o = selected ? obj_make(obj_saveini(selected)) : obj_new(obj);
+ if( selected ) obj_attach(selected, o), editor_setopen(selected, 1);
+ else
+ editor_watch(o);
+
+ editor_unselect();
+ editor_setselected(o, 1);
+}
+
+typedef set(obj*) set_objp_t;
+static
+void editor_glob_recurse(set_objp_t*list, obj *o) {
+ set_find_or_add(*list, o);
+ for each_objchild(o,obj*,oo) {
+ editor_glob_recurse(list, oo);
+ }
+}
+void editor_destroy_selected() {
+ set_objp_t list = 0;
+ set_init_ptr(list);
+ for each_map_ptr(*editor_selected_map(), obj*,o, int,selected) {
+ if( *selected ) { editor_glob_recurse(&list, *o); }
+ }
+ for each_set(list, obj*, o) {
+ obj_detach(o);
+ }
+ for each_set(list, obj*, o) {
+ // printf("deleting %p %s\n", o, obj_name(o));
+ // remove from watched items
+ for (int i = 0, end = array_count(editor.objs); i < end; ++i) {
+ if (editor.objs[i] == o) {
+ editor.objs[i] = 0;
+ array_erase_slow(editor.objs, i);
+ --end;
+ --i;
+ }
+ }
+ // delete from world
+ set_erase(editor.world, o);
+ // delete properties + obj
+ editor_destroy_properties(o);
+ obj_free(o);
+ }
+ set_free(list);
+}
+void editor_inspect(obj *o) {
+ ui_section(va("%s (%s)", obj_type(o), obj_name(o)));
+
+ if( obj_hasmethod(o, menu) ) {
+ obj_menu(o);
+ }
+
+ for each_objmember(o,TYPE,NAME,PTR) {
+ if( !editor_changed(PTR) ) {
+ obj_push(o);
+ }
+ ui_label_icon_highlight = editor_changed(PTR); // @hack: remove ui_label_icon_highlight hack
+ char *label = va(ICON_MD_UNDO "%s", NAME);
+ int changed = 0;
+ /**/ if( !strcmp(TYPE,"float") ) changed = ui_float(label, PTR);
+ else if( !strcmp(TYPE,"int") ) changed = ui_int(label, PTR);
+ else if( !strcmp(TYPE,"vec2") ) changed = ui_float2(label, PTR);
+ else if( !strcmp(TYPE,"vec3") ) changed = ui_float3(label, PTR);
+ else if( !strcmp(TYPE,"vec4") ) changed = ui_float4(label, PTR);
+ else if( !strcmp(TYPE,"rgb") ) changed = ui_color3(label, PTR);
+ else if( !strcmp(TYPE,"rgba") ) changed = ui_color4(label, PTR);
+ else if( !strcmp(TYPE,"color") ) changed = ui_color4f(label, PTR);
+ else if( !strcmp(TYPE,"color3f") ) changed = ui_color3f(label, PTR);
+ else if( !strcmp(TYPE,"color4f") ) changed = ui_color4f(label, PTR);
+ else if( !strcmp(TYPE,"char*") ) changed = ui_string(label, PTR);
+ else ui_label2(label, va("(%s)", TYPE)); // INFO instead of (TYPE)?
+ if( changed ) {
+ editor_setchanged(PTR, 1);
+ }
+ if( ui_label_icon_highlight )
+ if( ui_label_icon_clicked_L.x >= 6 && ui_label_icon_clicked_L.x <= 26 ) { // @hack: if clicked on UNDO icon (1st icon)
+ editor_setchanged(PTR, 0);
+ }
+ if( !editor_changed(PTR) ) {
+ obj_pop(o);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------------------
+// tty
+
+static thread_mutex_t *console_lock;
+static array(char*) editor_jobs;
+int editor_send(const char *cmd) { // return job-id
+ int skip = strspn(cmd, " \t\r\n");
+ char *buf = STRDUP(cmd + skip);
+ strswap(buf, "\r\n", "");
+ int jobid;
+ do_threadlock(console_lock) {
+ array_push(editor_jobs, buf);
+ jobid = array_count(editor_jobs) - 1;
+ }
+ return jobid;
+}
+const char* editor_recv(int jobid, double timeout_ss) {
+ char *answer = 0;
+
+ while(!answer && timeout_ss >= 0 ) {
+ do_threadlock(console_lock) {
+ if( editor_jobs[jobid][0] == '\0' )
+ answer = editor_jobs[jobid];
+ }
+ timeout_ss -= 0.1;
+ if( timeout_ss > 0 ) sleep_ms(100); // thread_yield()
+ }
+
+ return answer + 1;
+}
+
+// plain and ctrl keys
+EDITOR_BIND(play, "down(F5)", { window_pause(0); /* if(!editor.slomo) editor.active = 0; */ editor.slomo = 1; } );
+EDITOR_BIND(stop, "down(ESC)", { if(editor.t > 0) { window_pause(1), editor.frame = 0, editor.t = 0, editor.dt = 0, editor.slomo = 0, editor.active = 1; editor_select("**"); editor_destroy_selected(); }} );
+EDITOR_BIND(eject, "down(F1)", { /*window_pause(!editor.active); editor.slomo = !!editor.active;*/ editor.active ^= 1; } );
+EDITOR_BIND(pause, "(held(CTRL) & down(P)) | down(PAUSE)", { window_pause( window_has_pause() ^ 1 ); } );
+EDITOR_BIND(frame, "held(CTRL) & down(LEFT)", { window_pause(1); editor.frame++, editor.t += (editor.dt = 1/60.f); } );
+EDITOR_BIND(slomo, "held(CTRL) & down(RIGHT)", { window_pause(0); editor.slomo = maxf(fmod(editor.slomo * 2, 16), 0.125); } );
+EDITOR_BIND(reload, "held(CTRL) & down(F5)", { window_reload(); } );
+EDITOR_BIND(filter, "held(CTRL) & down(F)", { editor.filter ^= 1; } );
+
+// alt keys
+EDITOR_BIND(quit, "held(ALT) & down(F4)", { record_stop(), exit(0); } );
+EDITOR_BIND(mute, "held(ALT) & down(M)", { audio_volume_master( 1 ^ !!audio_volume_master(-1) ); } );
+EDITOR_BIND(gamepad, "held(ALT) & down(G)", { editor.gamepad ^= 1; } );
+EDITOR_BIND(transparent, "held(ALT) & down(T)", { editor.transparent ^= 1; } );
+EDITOR_BIND(record, "held(ALT) & down(Z)", { if(record_active()) record_stop(), ui_notify(va("Video recorded"), date_string()); else { char *name = file_counter(va("%s.mp4",app_name())); app_beep(), window_record(name); } } );
+EDITOR_BIND(screenshot, "held(ALT) & down(S)", { char *name = file_counter(va("%s.png",app_name())); window_screenshot(name), ui_notify(va("Screenshot: %s", name), date_string()); } );
+EDITOR_BIND(battery, "held(ALT) & down(B)", { editor.battery ^= 1; } );
+EDITOR_BIND(outliner, "held(ALT) & down(O)", { ui_show("Outliner", ui_visible("Outliner") ^ true); } );
+EDITOR_BIND(profiler, "held(ALT) & down(P)", { ui_show("Profiler", profiler_enable(ui_visible("Profiler") ^ true)); } );
+EDITOR_BIND(fullscreen, "(held(ALT)&down(ENTER))|down(F11)",{ record_stop(), window_fullscreen( window_has_fullscreen() ^ 1 ); } ); // close any recording before framebuffer resizing, which would corrupt video stream
+EDITOR_BIND(unlit, "held(ALT) & down(U)", { editor.unlit ^= 1; } );
+EDITOR_BIND(ddraw, "held(ALT) & down(D)", { editor.ddraw ^= 1; } );
+
+void editor_pump() {
+ for each_array(editor_binds,editor_bind_t,b) {
+ if( input_eval(b.bindings) ) {
+ editor_send(b.command);
+ }
+ }
+
+ do_threadlock(console_lock) {
+ for each_array_ptr(editor_jobs,char*,cmd) {
+ if( (*cmd)[0] ) {
+ int found = 0;
+ for each_array(editor_binds,editor_bind_t,b) {
+ if( !strcmpi(b.command, *cmd)) {
+ b.fn();
+ found = 1;
+ break;
+ }
+ }
+
+ if( !found ) {
+ // alert(va("Editor: could not handle `%s` command.", *cmd));
+ (*cmd)[0] = '\0'; strcatf(&(*cmd), "\1%s\n", "Err\n"); (*cmd)[0] = '\0';
+ }
+
+ if( (*cmd)[0] ) {
+ (*cmd)[0] = '\0'; strcatf(&(*cmd), "\1%s\n", "Ok\n"); (*cmd)[0] = '\0';
+ }
+ }
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------------------
+
+void editor_symbol(int x, int y, const char *sym) {
+ #define FONT_SYMBOLS FONT_FACE2
+ #define FONT_WHITE FONT_COLOR1
+ #define FONT_YELLOW FONT_COLOR2
+ #define FONT_ORANGE FONT_COLOR3
+ #define FONT_CYAN FONT_COLOR4
+ // style: atlas size, unicode ranges and 6 font faces max
+ do_once font_face(FONT_SYMBOLS, "MaterialIconsSharp-Regular.otf", 24.f, FONT_EM|FONT_2048);
+ // style: 10 colors max
+ do_once font_color(FONT_WHITE, WHITE);
+ do_once font_color(FONT_YELLOW, YELLOW);
+ do_once font_color(FONT_CYAN, CYAN);
+ do_once font_color(FONT_ORANGE, ORANGE);
+ font_goto(x,y);
+ font_print(va(FONT_SYMBOLS FONT_WHITE FONT_H1 "%s", sym));
+}
+
+void editor_frame( void (*game)(unsigned, float, double) ) {
+ do_once {
+ set_init_ptr(editor.world);
+ //set_init_ptr(editor.selection);
+ profiler_enable( false );
+
+ window_pause( true );
+ window_cursor_shape(CURSOR_SW_AUTO);
+ editor.hz_high = window_fps_target();
+
+ fx_load("editorOutline.fs");
+ fx_enable(0, 1);
+
+ obj_setname(editor.root = obj_new(obj), "Signals");
+ obj_setname(editor.on_init = obj_new(obj), "onInit");
+ obj_setname(editor.on_tick = obj_new(obj), "onTick");
+ obj_setname(editor.on_draw = obj_new(obj), "onDraw");
+ obj_setname(editor.on_edit = obj_new(obj), "onEdit");
+ obj_setname(editor.on_quit = obj_new(obj), "onQuit");
+
+ obj_attach(editor.root, editor.on_init);
+ obj_attach(editor.root, editor.on_tick);
+ obj_attach(editor.root, editor.on_draw);
+ obj_attach(editor.root, editor.on_edit);
+ obj_attach(editor.root, editor.on_quit);
+
+ editor_seticoninstance(editor.root, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_init, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_tick, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_draw, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_edit, ICON_MDI_SIGNAL_VARIANT);
+ editor_seticoninstance(editor.on_quit, ICON_MDI_SIGNAL_VARIANT);
+
+ editor_seticonclass(obj_type(editor.root), ICON_MDI_CUBE_OUTLINE);
+ }
+
+ // game tick
+ game(editor.frame, editor.dt, editor.t);
+
+ // timing
+ editor.dt = clampf(window_delta(), 0, 1/60.f) * !window_has_pause() * editor.slomo;
+ editor.t += editor.dt;
+ editor.frame += !window_has_pause();
+ editor.frame += !editor.frame;
+
+ // process inputs & messages
+ editor_pump();
+
+ // adaptive framerate
+ int app_on_background = !window_has_focus();
+ int hz = app_on_background ? editor.hz_low : editor.battery ? editor.hz_medium : editor.hz_high;
+ window_fps_lock( hz < 5 ? 5 : hz );
+
+ // draw menubar
+ static int stats_mode = 1;
+ static double last_fps = 0; if(!window_has_pause()) last_fps = window_fps();
+ const char *STATS = va("x%4.3f %03d.%03dss %02dF %s",
+ editor.slomo, (int)editor.t, (int)(1000 * (editor.t - (int)editor.t)),
+ (editor.frame-1) % ((int)window_fps_target() + !(int)window_fps_target()),
+ stats_mode == 1 ? va("%5.2f/%dfps", last_fps, (int)window_fps_target()) : stats_mode == 0 ? "0/0 KiB" : xstats());
+ const char *ICON_PL4Y = window_has_pause() ? ICON_MDI_PLAY : ICON_MDI_PAUSE;
+ const char *ICON_SKIP = window_has_pause() ? ICON_MDI_STEP_FORWARD/*ICON_MDI_SKIP_NEXT*/ : ICON_MDI_FAST_FORWARD;
+
+ int is_borderless = !glfwGetWindowAttrib(window, GLFW_DECORATED);
+ int ingame = !editor.active;
+ static double clicked_titlebar = 0;
+ UI_MENU(14+is_borderless, \
+ if(ingame) ui_disable(); \
+ UI_MENU_ITEM(ICON_MDI_FILE_TREE, editor_send("scene")) \
+ if(ingame) ui_enable(); \
+ UI_MENU_ITEM(ICON_PL4Y, if(editor.t == 0) editor_send("eject"); editor_send(window_has_pause() ? "play" : "pause")) \
+ UI_MENU_ITEM(ICON_SKIP, editor_send(window_has_pause() ? "frame" : "slomo")) \
+ UI_MENU_ITEM(ICON_MDI_STOP, editor_send("stop")) \
+ UI_MENU_ITEM(ICON_MDI_EJECT, editor_send("eject")) \
+ UI_MENU_ITEM(STATS, stats_mode = (++stats_mode) % 3) \
+ UI_MENU_ALIGN_RIGHT(32+32+32+32+32+32+34 + 32*is_borderless, clicked_titlebar = time_ms()) \
+ if(ingame) ui_disable(); \
+ UI_MENU_ITEM(ICON_MD_FOLDER_SPECIAL, editor_send("browser")) \
+ UI_MENU_ITEM(ICON_MDI_SCRIPT_TEXT, editor_send("script")) \
+ UI_MENU_ITEM(ICON_MDI_CHART_TIMELINE, editor_send("timeline")) \
+ UI_MENU_ITEM(ICON_MDI_CONSOLE, editor_send("console")) \
+ UI_MENU_ITEM(ICON_MDI_GRAPH, editor_send("nodes")) \
+ UI_MENU_ITEM(ICON_MD_SEARCH, editor_send("filter")) \
+ UI_MENU_POPUP(ICON_MD_SETTINGS, vec2(0.33,1.00), ui_debug()) \
+ if(ingame) ui_enable(); \
+ UI_MENU_ITEM(ICON_MD_CLOSE, editor_send("quit")) \
+ );
+
+ if( is_borderless ) {
+ static vec3 drag = {0};
+ if( clicked_titlebar ) {
+ static double clicks = 0;
+ if( input_up(MOUSE_L) ) ++clicks;
+ if( input_up(MOUSE_L) && clicks == 2 ) window_visible(false), window_maximize( window_has_maximize() ^ 1 ), window_visible(true);
+ if( (time_ms() - clicked_titlebar) > 400 ) clicks = 0, clicked_titlebar = 0;
+
+ if( input_down(MOUSE_L) ) drag = vec3(input(MOUSE_X), input(MOUSE_Y), 1);
+ }
+ if( drag.z *= !input_up(MOUSE_L) ) {
+ int wx = 0, wy = 0;
+ glfwGetWindowPos(window_handle(), &wx, &wy);
+ glfwSetWindowPos(window_handle(), wx + input(MOUSE_X) - drag.x, wy + input(MOUSE_Y) - drag.y);
+ }
+ }
+
+ if( !editor.active ) return;
+
+ // draw edit view (gizmos, position markers, etc).
+ for each_set_ptr(editor.world,obj*,o) {
+ if( obj_hasmethod(*o,edit) ) {
+ obj_edit(*o);
+ }
+}
+
+ // draw silhouettes
+ sprite_flush();
+ fx_begin();
+ for each_map_ptr(*editor_selected_map(),void*,o,int,selected) {
+ if( !*selected ) continue;
+ if( obj_hasmethod(*o,draw) ) {
+ obj_draw(*o);
+ }
+ if( obj_hasmethod(*o,edit) ) {
+ obj_edit(*o);
+}
+}
+ sprite_flush();
+ fx_end();
+
+ // draw box selection
+ if( !ui_active() ) { //< check that we're not moving a window
+ static vec2 from = {0}, to = {0};
+ if( input_down(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y)), from = to;
+ if( input(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y));
+ if( len2sq(sub2(from,to)) > 0 ) {
+ vec2 a = min2(from, to), b = max2(from, to);
+ ddraw_push_2d();
+ ddraw_color_push(YELLOW);
+ ddraw_line( vec3(a.x,a.y,0),vec3(b.x-1,a.y,0) );
+ ddraw_line( vec3(b.x,a.y,0),vec3(b.x,b.y-1,0) );
+ ddraw_line( vec3(b.x,b.y,0),vec3(a.x-1,b.y,0) );
+ ddraw_line( vec3(a.x,b.y,0),vec3(a.x,a.y-1,0) );
+ ddraw_color_pop();
+ ddraw_pop_2d();
+ }
+ if( input_up(MOUSE_L) ) {
+ vec2 a = min2(from, to), b = max2(from, to);
+ from = to = vec2(0,0);
+
+ editor_select_aabb(aabb(vec3(a.x,a.y,0),vec3(b.x,b.y,0)));
+ }
+ }
+
+ // draw mouse aabb
+ aabb mouse = { vec3(input(MOUSE_X),input(MOUSE_Y),0), vec3(input(MOUSE_X),input(MOUSE_Y),1)};
+ if( 1 ) {
+ ddraw_color_push(YELLOW);
+ ddraw_push_2d();
+ ddraw_aabb(mouse.min, mouse.max);
+ ddraw_pop_2d();
+ ddraw_color_pop();
+ }
+
+ // tick mouse aabb selection and contextual tab (RMB)
+ aabb box = {0};
+ for each_set(editor.world,obj*,o) {
+ if( !obj_hasmethod(o, aabb) ) continue;
+ if( !obj_aabb(o, &box) ) continue;
+
+ // trigger contextual inspector
+ if( input_down(MOUSE_R) ) {
+ int is_selected = editor_selected(o);
+ editor_setpopup(o, is_selected);
+ }
+
+ // draw contextual inspector
+ if( editor_popup(o) ) {
+ if( editor_begin(va("%s (%s)", obj_name(o), obj_type(o)),EDITOR_WINDOW_NK_SMALL) ) {
+ ui_label2(obj_name(o), obj_type(o));
+ editor_inspect(o);
+ editor_end(EDITOR_WINDOW_NK_SMALL);
+ } else {
+ editor_setpopup(o, 0);
+ }
+ }
+}
+
+
+ // draw subeditors
+ static int preferred_window_mode = EDITOR_WINDOW;
+ static struct nk_color bak, *on = 0; do_once bak = ui_ctx->style.window.fixed_background.data.color; // ui_ctx->style.window.fixed_background.data.color = !!(on = (on ? NULL : &bak)) ? AS_NKCOLOR(0) : bak; };
+ if( editor.transparent ) ui_ctx->style.window.fixed_background.data.color = AS_NKCOLOR(0);
+ for each_array(editor.subeditors, subeditor, fn) {
+ fn(preferred_window_mode);
+ }
+ ui_ctx->style.window.fixed_background.data.color = bak;
+
+ // draw ui filter (note: render at end-of-frame, so it's hopefully on-top)
+ editor_filter();
+}
+#line 0
+#line 1 "v4k_editor_scene.h"
+#define SCENE_ICON ICON_MDI_FILE_TREE
+#define SCENE_TITLE "Scene " SCENE_ICON
+
+EDITOR_BIND(scene, "held(CTRL)&down(1)", { ui_show(SCENE_TITLE, ui_visible(SCENE_TITLE) ^ true); });
+
+EDITOR_PROPERTY(bookmarked, int, 0);
+
+EDITOR_BIND(node_new, "down(INS)", { editor_spawn1(); } );
+EDITOR_BIND(node_del, "down(DEL)", { editor_destroy_selected(); } );
+EDITOR_BIND(node_save, "held(CTRL)&down(S)", { puts("@todo"); } );
+EDITOR_BIND(scene_save, "held(CTRL)&down(S)&held(SHIFT)",{ puts("@todo"); } );
+EDITOR_BIND(select_all, "held(CTRL) & down(A)", { editor_select("**"); } );
+EDITOR_BIND(select_none, "held(CTRL) & down(D)", { editor_select("!**"); } );
+EDITOR_BIND(select_invert, "held(CTRL) & down(I)", { editor_select("~**"); } );
+EDITOR_BIND(bookmark, "held(CTRL) & down(B)", { editor_selected_map_t *map = editor_selected_map(); \
+ int on = 0; \
+ for each_map_ptr(*map,void*,o,int,selected) if(*selected) on |= !editor_bookmarked(*o); \
+ for each_map_ptr(*map,void*,o,int,selected) if(*selected) editor_setbookmarked(*o, on); \
+} );
+
+enum {
+ SCENE_RECURSE = 1,
+ SCENE_SELECTION = 2,
+ SCENE_CHECKBOX = 4,
+ SCENE_INDENT = 8,
+ SCENE_ALL = ~0u
+};
+
+static
+void editor_scene_(obj *o, unsigned flags) {
+ static unsigned tabs = ~0u;
+ ++tabs;
+
+ if( o ) {
+ unsigned do_tags = 1;
+ unsigned do_indent = !!(flags & SCENE_INDENT);
+ unsigned do_checkbox = !!(flags & SCENE_CHECKBOX);
+ unsigned do_recurse = !!(flags & SCENE_RECURSE);
+ unsigned do_selection = !!(flags & SCENE_SELECTION);
+
+ nk_layout_row_dynamic(ui_ctx, 25, 1);
+
+ const char *objicon = editor_iconinstance(o);
+ if(!objicon) objicon = editor_iconclass(obj_type(o));
+ if(!objicon) objicon = ICON_MDI_CUBE_OUTLINE;
+
+ const char *objname = va("%s (%s)", obj_type(o), obj_name(o));
+
+ const char *objchevron =
+ !do_recurse || array_count(*obj_children(o)) <= 1 ? ICON_MDI_CIRCLE_SMALL :
+ editor_open(o) ? ICON_MDI_CHEVRON_DOWN : ICON_MDI_CHEVRON_RIGHT;
+
+ char *label = va("%*s%s%s %s", do_indent*(4+2*tabs), "", objchevron, objicon, objname);
+
+ const char *iconsL =
+ //editor_selected(o) ? ICON_MD_CHECK_BOX : ICON_MD_CHECK_BOX_OUTLINE_BLANK;
+ editor_selected(o) ? ICON_MDI_CHECKBOX_MARKED : ICON_MDI_CHECKBOX_BLANK_OUTLINE;
+
+ const char *iconsR = va("%s%s%s",
+ editor_script(o) ? ICON_MDI_SCRIPT : ICON_MDI_CIRCLE_SMALL,
+ editor_event(o) ? ICON_MDI_CALENDAR : ICON_MDI_CIRCLE_SMALL,
+ editor_visible(o) ? ICON_MDI_EYE_OUTLINE : ICON_MDI_EYE_CLOSED );
+
+ UI_TOOLBAR_OVERLAY_DECLARE(int choiceL, choiceR);
+
+ struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
+ struct nk_rect bounds; nk_layout_peek(&bounds, ui_ctx);
+
+ int clicked = nk_hovered_text(ui_ctx, label, strlen(label), NK_TEXT_LEFT, editor_selected(o));
+ if( clicked && nk_input_is_mouse_hovering_rect(&ui_ctx->input, ((struct nk_rect) { bounds.x,bounds.y,bounds.w*0.66,bounds.h })) )
+ editor_altselected( o );
+
+ vec2i offset_in_tree = {0};
+
+ if( do_indent ) {
+ float thickness = 2.f;
+ struct nk_color color = {255,255,255,64};
+
+ int offsx = 30;
+ int spacx = 10;
+ int lenx = (tabs+1)*spacx;
+ int halfy = bounds.h / 2;
+ int offsy = halfy + 2;
+
+ offset_in_tree = vec2i(bounds.x+offsx+lenx-spacx,bounds.y+offsy);
+
+ editor_settreeoffsety(o, offset_in_tree.y);
+
+ for( obj *p = obj_parent(o); p ; p = 0 )
+ nk_stroke_line(canvas, offset_in_tree.x-6,offset_in_tree.y, offset_in_tree.x-spacx,offset_in_tree.y, thickness, color),
+ nk_stroke_line(canvas, offset_in_tree.x-spacx,offset_in_tree.y,offset_in_tree.x-spacx,editor_treeoffsety(p)+4, thickness, color);
+ }
+
+ if( ui_contextual() ) {
+ int choice = ui_label(ICON_MD_BOOKMARK_ADDED "Toggle bookmarks (CTRL+B)");
+ if( choice & 1 ) editor_send("bookmark");
+
+ ui_contextual_end(!!choice);
+ }
+
+ UI_TOOLBAR_OVERLAY(choiceL,iconsL,nk_rgba_f(1,1,1,do_checkbox*ui_alpha*0.65),NK_TEXT_LEFT);
+
+ if( do_tags )
+ UI_TOOLBAR_OVERLAY(choiceR,iconsR,nk_rgba_f(1,1,1,ui_alpha*0.65),NK_TEXT_RIGHT);
+
+ if( choiceR == 3 ) editor_altscript( o );
+ if( choiceR == 2 ) editor_altevent( o);
+ if( choiceR == 1 ) editor_altvisible( o );
+
+ if( do_recurse && editor_open(o) ) {
+ for each_objchild(o,obj*,oo) {
+ editor_scene_(oo,flags);
+ }
+ }
+
+ if( clicked && !choiceL && !choiceR ) {
+ int is_picking = input(KEY_CTRL);
+ if( !is_picking ) {
+ if( input(KEY_SHIFT) ) {
+ editor_selectgroup( editor_first_selected(), editor_last_selected() );
+ } else {
+ editor_unselect();
+ editor_setselected(o, 1);
+ }
+ }
+ for( obj *p = obj_parent(o); p; p = obj_parent(p) ) {
+ editor_setopen(p, 1);
+ }
+ if( nk_input_is_mouse_hovering_rect(&ui_ctx->input, ((struct nk_rect) { bounds.x,bounds.y,offset_in_tree.x-bounds.x+UI_ICON_FONTSIZE/2,bounds.h })) ) {
+ editor_altopen( o );
+ }
+ }
+ }
+
+ --tabs;
+}
+
+int editor_scene(int window_mode) {
+ window_mode = EDITOR_WINDOW; // force window
+
+ if( editor_begin(SCENE_TITLE, window_mode)) {
+ // #define HELP ICON_MDI_INFORMATION_OUTLINE "@-A\n-B\n-C\n" ";"
+ int choice = ui_toolbar(ICON_MDI_PLUS "@New node (CTRL+N);" ICON_MDI_DOWNLOAD "@Save node (CTRL+S);" ICON_MDI_DOWNLOAD "@Save scene (SHIFT+CTRL+S);" ICON_MD_BOOKMARK_ADDED "@Toggle Bookmark (CTRL+B);");
+ if( choice == 1 ) editor_send("node_new");
+ if( choice == 2 ) editor_send("node_save");
+ if( choice == 3 ) editor_send("scene_save");
+ if( choice == 4 ) editor_send("bookmark");
+
+ array(obj*) bookmarks = 0;
+ for each_map_ptr(*editor_bookmarked_map(), void*,o,int,bookmarked) {
+ if( *bookmarked ) {
+ array_push(bookmarks, *o);
+ }
+ }
+ if( ui_collapse("!" ICON_MD_BOOKMARK "Bookmarks", "DEBUG:BOOKMARK")) {
+ for each_array( bookmarks, obj*, o )
+ editor_scene_( o, SCENE_ALL & ~(SCENE_RECURSE|SCENE_INDENT|SCENE_CHECKBOX) );
+ ui_collapse_end();
+ }
+ array_free(bookmarks);
+
+ editor_scene_( editor.root, SCENE_ALL );
+
+ for each_array( editor.objs, obj*, o )
+ editor_scene_( o, SCENE_ALL );
+
+ ui_separator();
+
+ // edit selection
+ for each_map(*editor_selected_map(), void*,o, int, k) {
+ if( k ) editor_inspect(o);
+ }
+
+ editor_end(window_mode);
+ }
+
+ return 0;
+}
+
+AUTORUN {
+ array_push(editor.subeditors, editor_scene);
+}
+#line 0
+#line 1 "v4k_editor_browser.h"
+#define BROWSER_ICON ICON_MD_FOLDER_SPECIAL
+#define BROWSER_TITLE "Browser " BROWSER_ICON
+
+EDITOR_BIND(browser, "held(CTRL)&down(2)", { ui_show(BROWSER_TITLE, ui_visible(BROWSER_TITLE) ^ true); });
+
+int editor_browser(int window_mode) {
+ window_mode = EDITOR_WINDOW; // force window
+ if( editor_begin(BROWSER_TITLE, window_mode) ) {
+ const char *file = 0;
+ if( ui_browse(&file, NULL) ) {
+ const char *sep = ifdef(win32, "\"", "'");
+ app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep));
+ }
+ editor_end(window_mode);
+ }
+ return 0;
+}
+
+AUTORUN {
+ array_push(editor.subeditors, editor_browser);
+}
+#line 0
+#line 1 "v4k_editor_timeline.h"
+#define TIMELINE_ICON ICON_MDI_CHART_TIMELINE
+#define TIMELINE_TITLE "Timeline " TIMELINE_ICON
+
+EDITOR_BIND(timeline, "held(CTRL)&down(3)", { ui_show(TIMELINE_TITLE, ui_visible(TIMELINE_TITLE) ^ true); });
+
+int ui_tween(const char *label, tween_t *t) {
+ if( ui_filter && ui_filter[0] ) if( !strstr(label, ui_filter) ) return 0;
+
+ int expand_keys = label[0] == '!'; label += expand_keys;
+ const char *id = label;
+ if( strchr(id, '@') ) *strchr((char*)(id = (const char*)va("%s", label)), '@') = '\0';
+
+ enum { LABEL_SPACING = 250 };
+ enum { ROUNDING = 0 };
+ enum { THICKNESS = 1 };
+ enum { PIXELS_PER_SECOND = 60 };
+ enum { KEY_WIDTH = 5, KEY_HEIGHT = 5 };
+ enum { TIMELINE_HEIGHT = 25 };
+ enum { MARKER1_HEIGHT = 5, MARKER10_HEIGHT = 20, MARKER5_HEIGHT = (MARKER1_HEIGHT + MARKER10_HEIGHT) / 2 };
+ unsigned base_color = WHITE;
+ unsigned time_color = YELLOW;
+ unsigned duration_color = ORANGE;
+ unsigned key_color = GREEN;
+
+ int changed = 0;
+
+#if 0
+ // two rows with height:30 composed of three widgets
+ nk_layout_row_template_begin(ui_ctx, 30);
+ nk_layout_row_template_push_variable(ui_ctx, t->duration * PIXELS_PER_SECOND); // min 80px. can grow
+ nk_layout_row_template_end(ui_ctx);
+#endif
+
+ char *sid = va("%s.%d", id, 0);
+ uint64_t hash = 14695981039346656037ULL, mult = 0x100000001b3ULL;
+ for(int i = 0; sid[i]; ++i) hash = (hash ^ sid[i]) * mult;
+ ui_hue = (hash & 0x3F) / (float)0x3F; ui_hue += !ui_hue;
+
+ ui_label(label);
+
+ struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
+ struct nk_rect bounds; nk_layout_peek(&bounds, ui_ctx);
+ bounds.y -= 30;
+
+ struct nk_rect baseline = bounds; baseline.y += 30/2;
+ baseline.x += LABEL_SPACING;
+ baseline.w -= LABEL_SPACING;
+
+ // tween duration
+ {
+ struct nk_rect pos = baseline;
+ pos.w = pos.x + t->duration * PIXELS_PER_SECOND;
+ pos.y -= TIMELINE_HEIGHT/2;
+ pos.h = TIMELINE_HEIGHT;
+ nk_stroke_rect(canvas, pos, ROUNDING, THICKNESS*2, AS_NKCOLOR(duration_color));
+ }
+
+ // tween ranges
+ for(int i = 0, end = array_count(t->keyframes) - 1; i < end; ++i) {
+ tween_keyframe_t *k = t->keyframes + i;
+ tween_keyframe_t *next = k + 1;
+
+ struct nk_rect pos = baseline;
+ pos.x += k->t * PIXELS_PER_SECOND;
+ pos.w = (next->t - k->t) * PIXELS_PER_SECOND;
+ pos.y -= TIMELINE_HEIGHT/2;
+ pos.h = TIMELINE_HEIGHT;
+
+ char *sid = va("%s.%d", id, i);
+ uint64_t hash = 14695981039346656037ULL, mult = 0x100000001b3ULL;
+ for(int i = 0; sid[i]; ++i) hash = (hash ^ sid[i]) * mult;
+ ui_hue = (hash & 0x3F) / (float)0x3F; ui_hue += !ui_hue;
+
+ struct nk_color c = nk_hsva_f(ui_hue, 0.75f, 0.8f, ui_alpha);
+ nk_fill_rect(canvas, pos, ROUNDING, k->ease == EASE_NOP ? AS_NKCOLOR(0) : c); // AS_NKCOLOR(track_color));
+ }
+
+ // horizontal line
+ nk_stroke_line(canvas, baseline.x, baseline.y, baseline.x+baseline.w,baseline.y, THICKNESS, AS_NKCOLOR(base_color));
+
+ // unit, 5-unit and 10-unit markers
+ for( float i = 0, j = 0; i < baseline.w; i += PIXELS_PER_SECOND/10, ++j ) {
+ int len = !((int)j%10) ? MARKER10_HEIGHT : !((int)j%5) ? MARKER5_HEIGHT : MARKER1_HEIGHT;
+ nk_stroke_line(canvas, baseline.x+i, baseline.y-len, baseline.x+i, baseline.y+len, THICKNESS, AS_NKCOLOR(base_color));
+ }
+
+ // time marker
+ float px = t->time * PIXELS_PER_SECOND;
+ nk_stroke_line(canvas, baseline.x+px, bounds.y, baseline.x+px, bounds.y+bounds.h, THICKNESS*2, AS_NKCOLOR(time_color));
+ nk_draw_symbol(canvas, NK_SYMBOL_TRIANGLE_DOWN, ((struct nk_rect){ baseline.x+px-4,bounds.y-4-8,8,8}), /*bg*/AS_NKCOLOR(0), /*fg*/AS_NKCOLOR(time_color), 0.f/*border_width*/, ui_ctx->style.font);
+
+ // key markers
+ for each_array_ptr(t->keyframes, tween_keyframe_t, k) {
+ struct nk_rect pos = baseline;
+ pos.x += k->t * PIXELS_PER_SECOND;
+
+ vec2 romboid[] = {
+ {pos.x-KEY_WIDTH,pos.y}, {pos.x,pos.y-KEY_HEIGHT},
+ {pos.x+KEY_WIDTH,pos.y}, {pos.x,pos.y+KEY_HEIGHT}
+ };
+
+ nk_fill_polygon(canvas, (float*)romboid, countof(romboid), AS_NKCOLOR(key_color));
+ }
+
+ // keys ui
+ if( expand_keys )
+ for(int i = 0, end = array_count(t->keyframes); i < end; ++i) {
+ tween_keyframe_t *k = t->keyframes + i;
+ if( ui_collapse(va("Key %d", i), va("%s.%d", id, i))) {
+ changed |= ui_float("Time", &k->t);
+ changed |= ui_float3("Value", &k->v.x);
+ changed |= ui_list("Ease", ease_enums(), EASE_NUM, &k->ease );
+ ui_collapse_end();
+ }
+ }
+
+ return changed;
+}
+
+tween_t* rand_tween() {
+ tween_t demo = tween();
+ int num_keys = randi(2,8);
+ double t = 0;
+ for( int i = 0; i < num_keys; ++i) {
+ tween_setkey(&demo, t, scale3(vec3(randf(),randf(),randf()),randi(-5,5)), randi(0,EASE_NUM) );
+ t += randi(1,5) / ((float)(1 << randi(0,2)));
+ }
+ tween_t *p = CALLOC(1, sizeof(tween_t));
+ memcpy(p, &demo, sizeof(tween_t));
+ return p;
+}
+
+int editor_timeline(int window_mode) {
+ static array(tween_t*) tweens = 0;
+
+ do_once {
+ array_push(tweens, rand_tween());
+ }
+
+ if( editor.t == 0 )
+ for each_array(tweens, tween_t*,t) {
+ tween_reset(t);
+ }
+ else
+ for each_array(tweens, tween_t*,t) {
+ tween_update(t, editor.dt);
+ }
+
+ static void *selected = NULL;
+ if( editor_begin(TIMELINE_TITLE, window_mode) ) {
+
+ int choice = ui_toolbar(ICON_MDI_PLUS ";" ICON_MDI_MINUS );
+ if( choice == 1 ) array_push(tweens, rand_tween());
+ if( choice == 2 && selected ) {
+ int target = -1;
+ for( int i = 0, end = array_count(tweens); i < end; ++i ) if( tweens[i] == selected ) { target = i; break; }
+ if( target >= 0 ) { array_erase_slow(tweens, target); selected = NULL; }
+ }
+
+ for each_array(tweens, tween_t*,t) {
+ ui_tween(va("%s%p@%05.2fs Value: %s", t == selected ? "!":"", t, t->time, ftoa3(t->result)), t);
+ if(ui_label_icon_clicked_L.x) selected = (t != selected) ? t : NULL;
+ }
+
+ editor_end(window_mode);
+ }
+ return 0;
+}
+
+AUTORUN {
+ array_push(editor.subeditors, editor_timeline);
+}
+#line 0
+#line 1 "v4k_editor_console.h"
+#define CONSOLE_ICON ICON_MDI_CONSOLE
+#define CONSOLE_TITLE "Console " CONSOLE_ICON
+
+EDITOR_BIND(console, "held(CTRL)&down(4)", { ui_show(CONSOLE_TITLE, ui_visible(CONSOLE_TITLE) ^ true); });
+
+int editor_console(int window_mode) {
+ if( editor_begin(CONSOLE_TITLE, window_mode) ) {
+
+ // peek complete window space
+ struct nk_rect bounds = nk_window_get_content_region(ui_ctx);
+
+ enum { CONSOLE_LINE_HEIGHT = 20 };
+ static array(char*) lines = 0;
+ do_once {
+ array_push(lines, stringf("> Editor v%s. Type `%s` for help.", EDITOR_VERSION, ""));
+ }
+ int max_lines = (bounds.h - UI_ROW_HEIGHT) / (CONSOLE_LINE_HEIGHT * 2);
+ if( max_lines >= 1 ) {
+ nk_layout_row_static(ui_ctx, bounds.h - UI_ROW_HEIGHT, bounds.w, 1);
+ if(nk_group_begin(ui_ctx, "console.group", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {
+ nk_layout_row_static(ui_ctx, CONSOLE_LINE_HEIGHT, bounds.w, 1);
+ for( int i = array_count(lines); i < max_lines; ++i )
+ array_push_front(lines, 0);
+ for( int i = array_count(lines) - max_lines; i < array_count(lines); ++i ) {
+ if( !lines[i] ) {
+ #if 0 // debug
+ nk_label_wrap(ui_ctx, va("%d.A/%d",i+1,max_lines));
+ nk_label_wrap(ui_ctx, va("%d.B/%d",i+1,max_lines));
+ #else
+ nk_label_wrap(ui_ctx, "");
+ nk_label_wrap(ui_ctx, "");
+ #endif
+ } else {
+ nk_label_wrap(ui_ctx, lines[i]);
+ const char *answer = isdigit(*lines[i]) ? editor_recv( atoi(lines[i]), 0 ) : NULL;
+ nk_label_wrap(ui_ctx, answer ? answer : "");
+ }
+ }
+ nk_group_end(ui_ctx);
+ }
+ }
+ static char *cmd = 0;
+ if( ui_string(NULL, &cmd) ) {
+ int jobid = editor_send(cmd);
+ array_push(lines, stringf("%d> %s", jobid, cmd));
+ cmd[0] = 0;
+ }
+
+ editor_end(window_mode);
+ }
+ return 0;
+}
+
+AUTORUN {
+ array_push(editor.subeditors, editor_console);
+}
+#line 0
+#line 1 "v4k_editor_nodes.h"
+#define NODES_ICON ICON_MDI_GRAPH
+#define NODES_TITLE "Nodes " NODES_ICON
+
+EDITOR_BIND(nodes, "held(CTRL)&down(5)", { ui_show(NODES_TITLE, ui_visible(NODES_TITLE) ^ true); });
+
+/*
+A basic node-based UI built with Nuklear.
+Builds on the node editor example included in Nuklear v1.00, with the aim of
+being used as a prototype for implementing a functioning node editor.
+
+Features:
+- Nodes of different types. Currently their implementations are #included in
+ the main file, but they could easily be turned into eg. a plugin system.
+- Pins/pins of different types -- currently float values and colors.
+- Adding and removing nodes.
+- Linking nodes, with validation (one link per input, only link similar pins).
+- Detaching and moving links.
+- Evaluation of output values of connected nodes.
+- Memory management based on fixed size arrays for links and node pointers
+- Multiple node types
+- Multiple pin types
+- Linking between pins of the same type
+- Detaching and reattaching links
+- Getting value from linked node if pin is connected
+
+Todo:
+- Complete pin types.
+- Allow dragging from output to input pin.
+- Cut link by CTRL+clicking input pin.
+- Cut link by drawing intersect line on a link.
+- Group elemnts together with mouse, or LSHIFT+clicking.
+- Drag groups.
+- DEL elements.
+- DEL groups.
+- CTRL-C/CTRL-V/CTRL-X elements.
+- CTRL-C/CTRL-V/CTRL-X groups.
+- CTRL-Z,CTRL-Y.
+- CTRL-N.
+- CTRL-L,CTRL-S.
+- CTRL-F.
+- CTRL-Wheel Zooming.
+- Allow to extend node types from Lua.
+
+Extra todo:
+- Execution Flow (see: nk_stroke_triangle, nk_fill_triangle)
+- Complete missing nodes (see: nk_draw_image, nk_draw_text)
+- Right-click could visualize node/board diagram as Lua script.
+- Once that done, copy/pasting scripts should work within editor.
+
+Sources:
+- https://github.com/Immediate-Mode-UI/Nuklear/pull/561
+- https://github.com/vurtun/nuklear/blob/master/demo/node_editor.c
+*/
+
+typedef enum pin_type_t {
+ type_flow,
+ type_int,type_float,
+ type_block,type_texture,type_image,
+ type_color,
+ /*
+ type_bool,
+ type_char, type_string,
+ type_int2, type_int3, type_int4,
+ type_float2, type_float3, type_float4,
+ type_array, type_map,
+ */
+
+ type_total
+} pin_type_t;
+
+struct node_pin {
+ pin_type_t pin_type;
+ nk_bool is_connected;
+ struct node* connected_node;
+ int connected_pin;
+};
+
+struct node {
+ int ID;
+ char name[32];
+ struct nk_rect bounds;
+ int input_count;
+ int output_count;
+ struct node_pin *inputs;
+ struct node_pin *outputs;
+ struct {
+ float in_padding_x;
+ float in_padding_y;
+ float in_spacing_y;
+ float out_padding_x;
+ float out_padding_y;
+ float out_spacing_y;
+ } pin_spacing; /* Maybe this should be called "node_layout" and include the bounds? */
+ struct node *next; /* Z ordering only */
+ struct node *prev; /* Z ordering only */
+
+ void* (*eval_func)(struct node*, int oIndex);
+ void (*display_func)(struct nk_context*, struct node*);
+};
+
+struct node_link {
+ struct node* input_node;
+ int input_pin;
+ struct node* output_node;
+ int output_pin;
+ nk_bool is_active;
+};
+
+struct node_linking {
+ int active;
+ struct node *node;
+ int input_id;
+ int input_pin;
+};
+
+struct node_editor {
+ int initialized;
+ struct node *node_buf[32];
+ struct node_link links[64];
+ struct node *output_node;
+ struct node *begin;
+ struct node *end;
+ int node_count;
+ int link_count;
+ struct nk_rect bounds;
+ struct node *selected;
+ int show_grid;
+ struct nk_vec2 scrolling;
+ struct node_linking linking;
+};
+
+/* === PROTOTYPES === */
+/* The node implementations need these two functions. */
+/* These could/should go in a header file along with the node and node_pin structs and be #included in the node implementations */
+
+struct node* node_editor_add(struct node_editor *editor, size_t nodeSize, const char *name, struct nk_rect bounds, int in_count, int out_count);
+void* node_editor_eval_connected(struct node *node, int input_pin_number);
+/* ================== */
+
+/* === NODE TYPE IMPLEMENTATIONS === */
+
+#define NODE_DEFAULT_ROW_HEIGHT 25
+
+
+// ----------------------------------------------------------------------------------------------------
+// #include "node_output.h"
+
+struct node_type_output {
+ struct node node;
+ struct nk_colorf input_val;
+};
+
+struct nk_colorf *node_output_get(struct node* node) {
+ struct node_type_output *output_node = (struct node_type_output*)node;
+ if (!node->inputs[0].is_connected) {
+ struct nk_colorf black = {0.0f, 0.0f, 0.0f, 0.0f};
+ output_node->input_val = black;
+ }
+ return &output_node->input_val;
+}
+
+static void node_output_display(struct nk_context *ctx, struct node *node) {
+ if (node->inputs[0].is_connected) {
+ struct node_type_output *output_node = (struct node_type_output*)node;
+ output_node->input_val = *(struct nk_colorf*)node_editor_eval_connected(node, 0);
+ nk_layout_row_dynamic(ctx, 60, 1);
+ nk_button_color(ctx, nk_rgba_cf(output_node->input_val));
+ }
+}
+
+struct node* node_output_create(struct node_editor *editor, struct nk_vec2 position) {
+ struct node_type_output *output_node = (struct node_type_output*)node_editor_add(editor, sizeof(struct node_type_output), "Output", nk_rect(position.x, position.y, 100, 100), 1, 0);
+ if (output_node){
+ output_node->node.inputs[0].pin_type = type_color;
+ output_node->node.display_func = node_output_display;
+ }
+ return (struct node*)output_node;
+}
+
+// ----------------------------------------------------------------------------------------------------
+// #include "node_float.h"
+
+struct node_type_float {
+ struct node node;
+ float output_val;
+};
+
+static float *node_float_eval(struct node* node, int oIndex) {
+ struct node_type_float *float_node = (struct node_type_float*)node;
+ NK_ASSERT(oIndex == 0);
+ return &float_node->output_val;
+}
+
+static void node_float_draw(struct nk_context *ctx, struct node *node) {
+ struct node_type_float *float_node = (struct node_type_float*)node;
+ nk_layout_row_dynamic(ctx, NODE_DEFAULT_ROW_HEIGHT, 1);
+ float_node->output_val = nk_propertyf(ctx, "#Value:", 0.0f, float_node->output_val, 1.0f, 0.01f, 0.01f);
+}
+
+void node_float_create(struct node_editor *editor, struct nk_vec2 position) {
+ struct node_type_float *float_node = (struct node_type_float*)node_editor_add(editor, sizeof(struct node_type_float), "Float", nk_rect(position.x, position.y, 180, 75), 0, 1);
+ if (float_node)
+ {
+ float_node->output_val = 1.0f;
+ float_node->node.display_func = node_float_draw;
+ float_node->node.eval_func = (void*(*)(struct node*, int)) node_float_eval;
+ }
+}
+
+// ----------------------------------------------------------------------------------------------------
+// #include "node_color.h"
+
+struct node_type_color {
+ struct node node;
+ float input_val[4];
+ struct nk_colorf output_val;
+};
+
+static struct nk_colorf *node_color_eval(struct node* node, int oIndex)
+{
+ struct node_type_color *color_node = (struct node_type_color*)node;
+ NK_ASSERT(oIndex == 0); /* only one output connector */
+
+ return &color_node->output_val;
+}
+
+
+static void node_color_draw(struct nk_context *ctx, struct node *node)
+{
+ struct node_type_color *color_node = (struct node_type_color*)node;
+ float eval_result; /* Get the values from connected nodes into this so the inputs revert on disconnect */
+ const char* labels[4] = {"#R:","#G:","#B:","#A:"};
+ float color_val[4]; /* Because we can't just loop through the struct... */
+ nk_layout_row_dynamic(ctx, NODE_DEFAULT_ROW_HEIGHT, 1);
+ nk_button_color(ctx, nk_rgba_cf(color_node->output_val));
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (color_node->node.inputs[i].is_connected) {
+ eval_result = *(float*)node_editor_eval_connected(node, i);
+ eval_result = nk_propertyf(ctx, labels[i], eval_result, eval_result, eval_result, 0.01f, 0.01f);
+ color_val[i] = eval_result;
+ }
+ else {
+ color_node->input_val[i] = nk_propertyf(ctx, labels[i], 0.0f, color_node->input_val[i], 1.0f, 0.01f, 0.01f);
+ color_val[i] = color_node->input_val[i];
+ }
+ }
+
+ color_node->output_val.r = color_val[0];
+ color_node->output_val.g = color_val[1];
+ color_node->output_val.b = color_val[2];
+ color_node->output_val.a = color_val[3];
+}
+
+void node_color_create(struct node_editor *editor, struct nk_vec2 position)
+{
+ struct node_type_color *color_node = (struct node_type_color*)node_editor_add(editor, sizeof(struct node_type_color), "Color", nk_rect(position.x, position.y, 180, 190), 4, 1);
+ if (color_node)
+ {
+ const struct nk_colorf black = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ for (int i = 0; i < color_node->node.input_count; i++)
+ color_node->node.inputs[i].pin_type = type_float;
+ color_node->node.outputs[0].pin_type = type_color;
+
+ color_node->node.pin_spacing.in_padding_y += NODE_DEFAULT_ROW_HEIGHT;
+
+ color_node->input_val[0] = 0.0f;
+ color_node->input_val[1] = 0.0f;
+ color_node->input_val[2] = 0.0f;
+ color_node->input_val[3] = 1.0f;
+
+ color_node->output_val = black;
+
+ color_node->node.display_func = node_color_draw;
+ color_node->node.eval_func = (void*(*)(struct node*, int)) node_color_eval;
+ }
+}
+
+// ----------------------------------------------------------------------------------------------------
+// #include "node_blend.h"
+
+struct node_type_blend {
+ struct node node;
+ struct nk_colorf input_val[2];
+ struct nk_colorf output_val;
+ float blend_val;
+};
+
+static struct nk_colorf *node_blend_eval(struct node *node, int oIndex) {
+ struct node_type_blend* blend_node = (struct node_type_blend*)node;
+ return &blend_node->output_val;
+}
+
+static void node_blend_display(struct nk_context *ctx, struct node *node) {
+ struct node_type_blend *blend_node = (struct node_type_blend*)node;
+ const struct nk_colorf blank = {0.0f, 0.0f, 0.0f, 0.0f};
+ float blend_amnt;
+
+ nk_layout_row_dynamic(ctx, NODE_DEFAULT_ROW_HEIGHT, 1);
+ for (int i = 0; i < 2; i++){
+ if(node->inputs[i].is_connected) {
+ blend_node->input_val[i] = *(struct nk_colorf*)node_editor_eval_connected(node, i);
+ }
+ else {
+ blend_node->input_val[i] = blank;
+ }
+ nk_button_color(ctx, nk_rgba_cf(blend_node->input_val[i]));
+ }
+
+ if (node->inputs[2].is_connected) {
+ blend_amnt = *(float*)node_editor_eval_connected(node, 2);
+ blend_amnt = nk_propertyf(ctx, "#Blend", blend_amnt, blend_amnt, blend_amnt, 0.01f, 0.01f);
+ }
+ else {
+ blend_node->blend_val = nk_propertyf(ctx, "#Blend", 0.0f, blend_node->blend_val, 1.0f, 0.01f, 0.01f);
+ blend_amnt = blend_node->blend_val;
+ }
+
+
+ if(node->inputs[0].is_connected && node->inputs[1].is_connected) {
+ blend_node->output_val.r = blend_node->input_val[0].r * (1.0f-blend_amnt) + blend_node->input_val[1].r * blend_amnt;
+ blend_node->output_val.g = blend_node->input_val[0].g * (1.0f-blend_amnt) + blend_node->input_val[1].g * blend_amnt;
+ blend_node->output_val.b = blend_node->input_val[0].b * (1.0f-blend_amnt) + blend_node->input_val[1].b * blend_amnt;
+ blend_node->output_val.a = blend_node->input_val[0].a * (1.0f-blend_amnt) + blend_node->input_val[1].a * blend_amnt;
+ }
+ else {
+ blend_node->output_val = blank;
+ }
+}
+
+void node_blend_create(struct node_editor *editor, struct nk_vec2 position) {
+ struct node_type_blend* blend_node = (struct node_type_blend*)node_editor_add(editor, sizeof(struct node_type_blend), "Blend", nk_rect(position.x, position.y, 180, 130), 3, 1);
+ if (blend_node) {
+ const struct nk_colorf blank = {0.0f, 0.0f, 0.0f, 0.0f};
+ for (int i = 0; i < (int)NK_LEN(blend_node->input_val); i++)
+ blend_node->node.inputs[i].pin_type = type_color;
+ blend_node->node.outputs[0].pin_type = type_color;
+
+ // blend_node->node.pin_spacing.in_padding_y = 42.0f;
+ // blend_node->node.pin_spacing.in_spacing_y = 29.0f;
+
+ for (int i = 0; i < (int)NK_LEN(blend_node->input_val); i++)
+ blend_node->input_val[i] = blank;
+ blend_node->output_val = blank;
+
+ blend_node->blend_val = 0.5f;
+
+ blend_node->node.display_func = node_blend_display;
+ blend_node->node.eval_func = (void*(*)(struct node*, int)) node_blend_eval;
+
+ }
+}
+
+/* ================================= */
+
+#define NK_RGB3(r,g,b) {r,g,b,255}
+#define BG_COLOR ((struct nk_color){60,60,60,192}) // nk_rgba(0,0,0,192)
+
+static
+struct editor_node_style {
+ int pin_type;
+ const char *shape;
+ struct nk_color color_idle;
+ struct nk_color color_hover;
+} styles[] = {
+ // order matters:
+ { type_flow, "triangle_right", NK_RGB3(200,200,200), NK_RGB3(255,255,255) }, // if .num_links == 0
+ { type_int, "circle", NK_RGB3(33,227,175), NK_RGB3(135,239,195) },
+ { type_float, "circle", NK_RGB3(156,253,65), NK_RGB3(144,225,137) },
+ { type_block, "circle", NK_RGB3(6,165,239), NK_RGB3(137,196,247) },
+ { type_texture, "circle", NK_RGB3(148,0,0), NK_RGB3(183,137,137) },
+ { type_image, "circle", NK_RGB3(200,130,255), NK_RGB3(220,170,255) },
+ { type_color, "circle", NK_RGB3(252,200,35), NK_RGB3(255,217,140) },
+};
+
+#define COLOR_FLOW_HI styles[type_flow].color_hover
+#define COLOR_FLOW_LO styles[type_flow].color_idle
+
+#define GRID_SIZE 64.0f
+#define GRID_COLOR ((struct nk_color)NK_RGB3(80,80,120))
+#define GRID_THICKNESS 1.0f
+
+// 4 colors: top-left, top-right, bottom-right, bottom-left
+#define GRID_BG_COLORS ((struct nk_color){30,30,30,255}), ((struct nk_color){40,20,0,255}), ((struct nk_color){30,30,30,255}), ((struct nk_color){20,30,40,255})
+
+#define LINK_THICKNESS 1.0f
+#define LINK_DRAW(POINT_A,POINT_B,COLOR) do { \
+ vec2 a = (POINT_A); \
+ vec2 b = (POINT_B); \
+ nk_stroke_line(canvas, a.x, a.y, b.x, b.y, LINK_THICKNESS, COLOR); \
+} while(0)
+#undef LINK_DRAW
+#define LINK_DRAW(POINT_A,POINT_B,COLOR) do { \
+ vec2 a = (POINT_A); \
+ vec2 b = (POINT_B); \
+ nk_stroke_curve(canvas, a.x, a.y, a.x+50, a.y, b.x-50, b.y, b.x, b.y, LINK_THICKNESS, COLOR); \
+} while(0)
+#undef LINK_DRAW
+#define LINK_DRAW(POINT_A,POINT_B,COLOR) do { \
+ vec2 a = (POINT_A); \
+ vec2 b = (POINT_B); \
+ float dist2 = len2( sub2( ptr2(&b.x), ptr2(&a.x) ) ); \
+ vec2 mid_a = mix2( ptr2(&a.x), ptr2(&b.x), 0.25 ); mid_a.y += dist2/2; \
+ vec2 mid_b = mix2( ptr2(&a.x), ptr2(&b.x), 0.75 ); mid_b.y += dist2/3; \
+ nk_stroke_curve(canvas, a.x, a.y, mid_a.x, mid_a.y, mid_b.x, mid_b.y, b.x, b.y, LINK_THICKNESS, COLOR); \
+} while(0)
+
+
+#define PIN_RADIUS 12
+#define PIN_THICKNESS 1.0f
+#define PIN_DRAW(PIN_ADDR,POINT,RADIUS) do { \
+ circle.x = (POINT).x - (RADIUS) / 2; \
+ circle.y = (POINT).y - (RADIUS) / 2; \
+ circle.w = circle.h = (RADIUS); \
+ struct nk_color color = node_get_type_color((PIN_ADDR).pin_type); \
+ if((PIN_ADDR).is_connected) \
+ nk_fill_circle(canvas, circle, color); \
+ else \
+ nk_stroke_circle(canvas, circle, PIN_THICKNESS, color); \
+} while(0)
+
+
+static struct nk_color node_get_type_color(unsigned pin_type) {
+ for( int i = 0; i < type_total; ++i )
+ if( styles[i].pin_type == pin_type )
+ return styles[i].color_idle;
+ return ((struct nk_color)NK_RGB3(255,0,255));
+}
+
+static void node_editor_push(struct node_editor *editor, struct node *node) {
+ if (!editor->begin) {
+ node->next = NULL;
+ node->prev = NULL;
+ editor->begin = node;
+ editor->end = node;
+ } else {
+ node->prev = editor->end;
+ if (editor->end)
+ editor->end->next = node;
+ node->next = NULL;
+ editor->end = node;
+ }
+}
+
+static void node_editor_pop(struct node_editor *editor, struct node *node) {
+ if (node->next)
+ node->next->prev = node->prev;
+ if (node->prev)
+ node->prev->next = node->next;
+ if (editor->end == node)
+ editor->end = node->prev;
+ if (editor->begin == node)
+ editor->begin = node->next;
+ node->next = NULL;
+ node->prev = NULL;
+}
+
+static struct node* node_editor_find_by_id(struct node_editor *editor, int ID) {
+ struct node *iter = editor->begin;
+ while (iter) {
+ if (iter->ID == ID)
+ return iter;
+ iter = iter->next;
+ }
+ return NULL;
+}
+
+static struct node_link* node_editor_find_link_by_output(struct node_editor *editor, struct node *output_node, int node_input_connector) {
+ for( int i = 0; i < editor->link_count; i++ ) {
+ if (editor->links[i].output_node == output_node &&
+ editor->links[i].output_pin == node_input_connector &&
+ editor->links[i].is_active == nk_true) {
+ return &editor->links[i];
+ }
+ }
+ return NULL;
+}
+
+static struct node_link* node_editor_find_link_by_input(struct node_editor *editor, struct node *input_node, int node_output_connector) {
+ for( int i = 0; i < editor->link_count; i++ ) {
+ if (editor->links[i].input_node == input_node &&
+ editor->links[i].input_pin == node_output_connector &&
+ editor->links[i].is_active == nk_true) {
+ return &editor->links[i];
+ }
+ }
+ return NULL;
+}
+
+static void node_editor_delete_link(struct node_link *link) {
+ link->is_active = nk_false;
+ link->input_node->outputs[link->input_pin].is_connected = nk_false;
+ link->output_node->inputs[link->output_pin].is_connected = nk_false;
+}
+
+struct node* node_editor_add(struct node_editor *editor, size_t nodeSize, const char *name, struct nk_rect bounds, int in_count, int out_count) {
+ static int IDs = 0;
+ struct node *node = NULL;
+
+ if ((nk_size)editor->node_count < NK_LEN(editor->node_buf)) {
+ /* node_buf has unused pins */
+ node = MALLOC(nodeSize);
+ editor->node_buf[editor->node_count++] = node;
+ node->ID = IDs++;
+ } else {
+ /* check for freed up pins in node_buf */
+ for (int i = 0; i < editor->node_count; i++) {
+ if (editor->node_buf[i] == NULL) {
+ node = MALLOC(nodeSize);
+ editor->node_buf[i] = node;
+ node->ID = i;
+ break;
+ }
+ }
+ }
+ if (node == NULL) {
+ puts("Node creation failed");
+ return NULL;
+ }
+
+ node->bounds = bounds;
+
+ node->input_count = in_count;
+ node->output_count = out_count;
+
+ node->inputs = MALLOC(node->input_count * sizeof(struct node_pin));
+ node->outputs = MALLOC(node->output_count * sizeof(struct node_pin));
+
+ for (int i = 0; i < node->input_count; i++) {
+ node->inputs[i].is_connected = nk_false;
+ node->inputs[i].pin_type = type_float; /* default pin type */
+ }
+ for (int i = 0; i < node->output_count; i++) {
+ node->outputs[i].is_connected = nk_false;
+ node->outputs[i].pin_type = type_float; /* default pin type */
+ }
+
+ /* default pin spacing */
+ node->pin_spacing.in_padding_x = 2;
+ node->pin_spacing.in_padding_y = 32 + 25/2 + 6; // titlebar height + next half row + adjust
+ node->pin_spacing.in_spacing_y = 25; // row height+border
+ node->pin_spacing.out_padding_x = 3;
+ node->pin_spacing.out_padding_y = 32 + 25/2 + 6; // titlebar height + next half row + adjust
+ node->pin_spacing.out_spacing_y = 25; // row height+border
+
+ strcpy(node->name, name);
+ node_editor_push(editor, node);
+
+ return node;
+}
+
+void *node_editor_eval_connected(struct node* node, int input_pin_number) {
+ NK_ASSERT(node->inputs[input_pin_number].is_connected);
+ return node->inputs[input_pin_number].connected_node->eval_func(node->inputs[input_pin_number].connected_node, node->inputs[input_pin_number].connected_pin);
+}
+
+static void node_editor_link(struct node_editor *editor, struct node *in_node, int in_pin, struct node *out_node, int out_pin) {
+ /* Confusingly, in and out nodes/pins here refer to the inputs and outputs OF THE LINK ITSELF, not the nodes */
+ struct node_link *link = NULL;
+
+ if ((nk_size)editor->link_count < NK_LEN(editor->links)) {
+ link = &editor->links[editor->link_count++];
+ } else {
+ for (int i = 0; i < (int)NK_LEN(editor->links); i++)
+ {
+ if (editor->links[i].is_active == nk_false) {
+ link = &editor->links[i];
+ break;
+ }
+ }
+ }
+ if (link) {
+ out_node->inputs[out_pin].is_connected = nk_true;
+ in_node->outputs[in_pin].is_connected = nk_true;
+ out_node->inputs[out_pin].connected_node = in_node;
+ out_node->inputs[out_pin].connected_pin = in_pin;
+
+ link->input_node = in_node;
+ link->input_pin = in_pin;
+ link->output_node = out_node;
+ link->output_pin = out_pin;
+ link->is_active = nk_true;
+ } else {
+ puts("Too many links");
+ }
+}
+
+static void node_editor_init(struct node_editor *editor) {
+ if (editor->initialized) return;
+
+ struct nk_rect total_space = nk_window_get_content_region(ui_ctx);
+ struct nk_vec2 output_node_position = { total_space.w*2/3, total_space.h/3 };
+ struct nk_vec2 color_node_position = { total_space.w*1/4, total_space.h/3 };
+
+ memset(editor, 0, sizeof(*editor));
+
+ editor->output_node = node_output_create(editor, output_node_position);
+ node_color_create(editor, color_node_position);
+ editor->show_grid = nk_true;
+
+ editor->initialized = 1;
+}
+
+static int node_editor(struct node_editor *editor) {
+ int n = 0;
+ struct nk_rect total_space;
+ const struct nk_input *in = &ui_ctx->input;
+ struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
+ struct node *updated = 0;
+
+ node_editor_init(editor);
+
+ {
+ /* allocate complete window space */
+ total_space = nk_window_get_content_region(ui_ctx);
+ nk_layout_space_begin(ui_ctx, NK_STATIC, total_space.h, editor->node_count);
+ {
+ struct node *it = editor->begin;
+ struct nk_rect size = nk_layout_space_bounds(ui_ctx);
+ struct nk_panel *nodePanel = 0;
+
+ //nk_fill_rect(canvas, size, 0/*rounding*/, ((struct nk_color){30,30,30,255})); // 20,30,40,255
+ nk_fill_rect_multi_color(canvas, size, GRID_BG_COLORS);
+
+ if (editor->show_grid) {
+ /* display grid */
+ for (float x = (float)fmod(size.x - editor->scrolling.x, GRID_SIZE); x < size.w; x += GRID_SIZE)
+ nk_stroke_line(canvas, x+size.x, size.y, x+size.x, size.y+size.h, GRID_THICKNESS, GRID_COLOR);
+ for (float y = (float)fmod(size.y - editor->scrolling.y, GRID_SIZE); y < size.h; y += GRID_SIZE)
+ nk_stroke_line(canvas, size.x, y+size.y, size.x+size.w, y+size.y, GRID_THICKNESS, GRID_COLOR);
+ }
+
+ /* execute each node as a movable group */
+ /* loop through nodes */
+ while (it) {
+ /* Output node window should not have a close button */
+ nk_flags nodePanel_flags = NK_WINDOW_MOVABLE|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_TITLE;
+ if (it != editor->output_node)
+ nodePanel_flags |= NK_WINDOW_CLOSABLE;
+
+ /* calculate scrolled node window position and size */
+ nk_layout_space_push(ui_ctx, nk_rect(it->bounds.x - editor->scrolling.x,
+ it->bounds.y - editor->scrolling.y, it->bounds.w, it->bounds.h));
+
+ /* execute node window */
+ char *name = va(" " ICON_MD_MENU " %s",it->name); //< @r-lyeh added some spacing+icon because of our UI customizations
+
+struct nk_color bak = ui_ctx->style.window.fixed_background.data.color;
+ui_ctx->style.window.fixed_background.data.color = BG_COLOR;
+
+ if (nk_group_begin(ui_ctx, name, nodePanel_flags))
+ {
+ /* always have last selected node on top */
+
+ nodePanel = nk_window_get_panel(ui_ctx);
+ if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, nodePanel->bounds) &&
+ (!(it->prev && nk_input_mouse_clicked(in, NK_BUTTON_LEFT,
+ nk_layout_space_rect_to_screen(ui_ctx, nodePanel->bounds)))) &&
+ editor->end != it)
+ {
+ updated = it;
+ }
+
+ if ((nodePanel->flags & NK_WINDOW_HIDDEN)) /* Node close button has been clicked */
+ {
+ /* Delete node */
+ struct node_link *link_remove;
+ node_editor_pop(editor, it);
+ for (int n = 0; n < it->input_count; n++) {
+ if ((link_remove = node_editor_find_link_by_output(editor, it, n)))
+ {
+ node_editor_delete_link(link_remove);
+ }
+ }
+ for (int n = 0; n < it -> output_count; n++) {
+ while((link_remove = node_editor_find_link_by_input(editor, it, n)))
+ {
+ node_editor_delete_link(link_remove);
+ }
+ }
+ NK_ASSERT(editor->node_buf[it->ID] == it);
+ editor->node_buf[it->ID] = NULL;
+ FREE(it->inputs);
+ FREE(it->outputs);
+ FREE(it);
+ }
+ else {
+
+ /* ================= NODE CONTENT ===================== */
+
+ it->display_func(ui_ctx, it);
+
+ /* ==================================================== */
+
+ }
+ nk_group_end(ui_ctx);
+
+ }
+
+ui_ctx->style.window.fixed_background.data.color = bak;
+
+ if (!(nodePanel->flags & NK_WINDOW_HIDDEN))
+ {
+ /* node pin and linking */
+ struct nk_rect bounds;
+ bounds = nk_layout_space_rect_to_local(ui_ctx, nodePanel->bounds);
+ bounds.x += editor->scrolling.x;
+ bounds.y += editor->scrolling.y;
+ it->bounds = bounds;
+
+ /* output pins */
+ for (int n = 0; n < it->output_count; ++n) {
+ struct nk_rect circle;
+ struct nk_vec2 pt = {nodePanel->bounds.x, nodePanel->bounds.y};
+ pt.x += nodePanel->bounds.w - PIN_RADIUS / 2 + it->pin_spacing.out_padding_x;
+ pt.y += it->pin_spacing.out_padding_y + it->pin_spacing.out_spacing_y * (n);
+ PIN_DRAW(it->outputs[n],pt,PIN_RADIUS);
+
+ /* start linking process */
+ /* set linking active */
+ if (nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, circle, nk_true)) {
+ editor->linking.active = nk_true;
+ editor->linking.node = it;
+ editor->linking.input_id = it->ID;
+ editor->linking.input_pin = n;
+ }
+
+ /* draw link being dragged (from linked pin to mouse position) */
+ if (editor->linking.active && editor->linking.node == it &&
+ editor->linking.input_pin == n) {
+ LINK_DRAW(vec2(circle.x+3,circle.y+3),ptr2(&in->mouse.pos.x),COLOR_FLOW_HI);
+ }
+ }
+
+ /* input pins */
+ for (int n = 0; n < it->input_count; ++n) {
+ struct nk_rect circle;
+ struct nk_vec2 pt = {nodePanel->bounds.x, nodePanel->bounds.y};
+ pt.x += it->pin_spacing.in_padding_x;
+ pt.y += it->pin_spacing.in_padding_y + it->pin_spacing.in_spacing_y * (n);
+ PIN_DRAW(it->inputs[n],pt,PIN_RADIUS);
+
+ /* Detach link */
+ if (nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, circle, nk_true) &&
+ editor->linking.active == nk_false &&
+ it->inputs[n].is_connected == nk_true) {
+ struct node_link *node_relink = node_editor_find_link_by_output(editor, it, n);
+ editor->linking.active = nk_true;
+ editor->linking.node = node_relink->input_node;
+ editor->linking.input_id = node_relink->input_node->ID;
+ editor->linking.input_pin = node_relink->input_pin;
+ node_editor_delete_link(node_relink);
+ }
+
+ /* Create link */
+ if (nk_input_is_mouse_released(in, NK_BUTTON_LEFT) &&
+ nk_input_is_mouse_hovering_rect(in, circle) &&
+ editor->linking.active &&
+ editor->linking.node != it &&
+ it->inputs[n].pin_type == editor->linking.node->outputs[editor->linking.input_pin].pin_type &&
+ it->inputs[n].is_connected != nk_true) {
+ editor->linking.active = nk_false;
+
+ node_editor_link(editor, editor->linking.node,
+ editor->linking.input_pin, it, n);
+ }
+ }
+ }
+ it = it->next;
+ }
+
+ /* reset (output) linking connection */
+ if (editor->linking.active && (!!input(KEY_LCTRL) || !!input(KEY_RCTRL) || nk_input_is_mouse_released(in, NK_BUTTON_LEFT))) {
+ editor->linking.active = nk_false;
+ editor->linking.node = NULL;
+ }
+
+ /* draw each static link */
+ for (int n = 0; n < editor->link_count; ++n) {
+ struct node_link *link = &editor->links[n];
+ if (link->is_active == nk_true){
+ struct node *ni = link->input_node;
+ struct node *no = link->output_node;
+ struct nk_vec2 l0 = nk_layout_space_to_screen(ui_ctx, nk_vec2(ni->bounds.x + ni->bounds.w + ni->pin_spacing.out_padding_x, 3.0f + ni->bounds.y + ni->pin_spacing.out_padding_y + ni->pin_spacing.out_spacing_y * (link->input_pin)));
+ struct nk_vec2 l1 = nk_layout_space_to_screen(ui_ctx, nk_vec2(no->bounds.x + no->pin_spacing.in_padding_x, 3.0f + no->bounds.y + no->pin_spacing.in_padding_y + no->pin_spacing.in_spacing_y * (link->output_pin)));
+
+ l0.x -= editor->scrolling.x;
+ l0.y -= editor->scrolling.y;
+ l1.x -= editor->scrolling.x;
+ l1.y -= editor->scrolling.y;
+
+ struct nk_color color = node_get_type_color(no->inputs[link->output_pin].pin_type);
+ LINK_DRAW(ptr2(&l0.x), ptr2(&l1.x), color);
+ }
+ }
+
+ if (updated) {
+ /* reshuffle nodes to have least recently selected node on top */
+ node_editor_pop(editor, updated);
+ node_editor_push(editor, updated);
+ }
+
+ /* node selection */
+ if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, nk_layout_space_bounds(ui_ctx))) {
+ it = editor->begin;
+ editor->selected = NULL;
+ editor->bounds = nk_rect(in->mouse.pos.x, in->mouse.pos.y, 100, 200);
+ while (it) {
+ struct nk_rect b = nk_layout_space_rect_to_screen(ui_ctx, it->bounds);
+ b.x -= editor->scrolling.x;
+ b.y -= editor->scrolling.y;
+ if (nk_input_is_mouse_hovering_rect(in, b))
+ editor->selected = it;
+ it = it->next;
+ }
+ }
+
+ /* contextual menu */
+ if (nk_contextual_begin(ui_ctx, 0, nk_vec2(150, 220), nk_window_get_bounds(ui_ctx))) {
+ struct nk_vec2 wincoords = { in->mouse.pos.x-total_space.x-50, in->mouse.pos.y-total_space.y-32 };
+
+#if 1
+ static char *filter = 0;
+ static int do_filter = 0;
+ if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1;
+ int choice = ui_toolbar(ICON_MD_SEARCH ";");
+ if( choice == 1 ) do_filter = 1;
+ if( do_filter ) {
+ ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &filter);
+ if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon)
+ do_filter = 0;
+ }
+ } else {
+ if( filter ) filter[0] = '\0';
+ }
+ char *filter_mask = filter && filter[0] ? va("*%s*", filter) : "*";
+#endif
+
+ #define ui_label_filtered(lbl) (strmatchi(lbl,filter_mask) && ui_label(lbl))
+
+ int close = 0;
+ if (ui_label_filtered("=Add Color node")) close=1,node_color_create(editor, wincoords);
+ if (ui_label_filtered("=Add Float node")) close=1,node_float_create(editor, wincoords);
+ if (ui_label_filtered("=Add Blend Node")) close=1,node_blend_create(editor, wincoords);
+ if (ui_label_filtered(editor->show_grid ? "=Hide Grid" : "=Show Grid"))
+ close=1,editor->show_grid = !editor->show_grid;
+ if(close) do_filter = 0, (filter ? filter[0] = '\0' : '\0'), nk_contextual_close(ui_ctx);
+ nk_contextual_end(ui_ctx);
+ }
+ }
+ nk_layout_space_end(ui_ctx);
+
+ /* window content scrolling */
+ if (nk_input_is_mouse_hovering_rect(in, nk_window_get_bounds(ui_ctx)) &&
+ nk_input_is_mouse_down(in, NK_BUTTON_MIDDLE)) {
+ editor->scrolling.x += in->mouse.delta.x;
+ editor->scrolling.y += in->mouse.delta.y;
+ }
+ }
+
+ return !nk_window_is_closed(ui_ctx, "NodeEdit");
+}
+
+int editor_nodes(int window_mode) {
+ window_mode = EDITOR_WINDOW; // force window
+
+ if( editor_begin(NODES_TITLE, window_mode) ) {
+
+ static struct node_editor nodeEditor = {0};
+ node_editor(&nodeEditor);
+
+ editor_end(window_mode);
+ }
+ return 0;
+}
+
+AUTORUN {
+ array_push(editor.subeditors, editor_nodes);
+}
+#line 0
+#line 1 "v4k_editor_script.h"
+
+int ui_texture_fit(texture_t t, struct nk_rect bounds) {
+ // allocate complete window space
+ struct nk_rect total_space = nk_window_get_content_region(ui_ctx);
+ nk_layout_space_begin(ui_ctx, NK_DYNAMIC, total_space.h - 4, 1); // -4 to hide scrollbar Y
+ nk_layout_space_push(ui_ctx, nk_rect(0,0,1,1));
+
+ struct nk_command_buffer *canvas = nk_window_get_canvas(ui_ctx);
+ struct nk_image image = nk_image_id((int)t.id);
+ nk_draw_image(canvas, bounds, &image, nk_white);
+
+ nk_layout_space_end(ui_ctx);
+ return 0;
+}
+
+#define LITE_ICON ICON_MDI_SCRIPT_TEXT
+#define LITE_TITLE "Script " LITE_ICON
+
+EDITOR_BIND(script, "held(CTRL)&down(6)", { ui_show(LITE_TITLE, ui_visible(LITE_TITLE) ^ true); });
+
+int editor_scripted(int window_mode) {
+ window_mode = EDITOR_WINDOW; // force mode
+
+ static lua_State *L = 0;
+ do_once {
+ L = script_init_env(SCRIPT_LUA|SCRIPT_DEBUGGER);
+
+ const char *platform = "" // "Android" "FreeBSD" "OpenBSD" "NetBSD"
+ ifdef(ems, "Emscripten")
+ ifdef(linux, "Linux")
+ ifdef(osx, "macOS")
+ ifdef(win32, "Windows")
+ ;
+ const char *pathexe = vac("%s%s%s", app_path(), app_name(), ifdef(win32, ".exe", ""));
+
+ gleqInit();
+ gleqTrackWindow(window_handle());
+ lt_init(L, window_handle(), LT_DATAPATH, __argc, __argv, window_scale(), platform, pathexe);
+ }
+
+ unsigned lt_none = 0u;
+ unsigned lt_all = ~0u & ~(GLEQ_WINDOW_MOVED/*|GLEQ_WINDOW_RESIZED|GLEQ_WINDOW_REFRESH*/);
+ lt_events = lt_none;
+
+ int mouse_in_rect = 0;
+ if( editor_begin(LITE_TITLE, window_mode) ) {
+
+ lt_events = lt_all;
+ if( !nk_window_has_focus(ui_ctx) ) lt_events = lt_none;
+
+ struct nk_rect bounds = nk_window_get_content_region(ui_ctx);
+
+ lt_mx = input(MOUSE_X) - bounds.x;
+ lt_my = input(MOUSE_Y) - bounds.y;
+ lt_wx = bounds.x;
+ lt_wy = bounds.y;
+ lt_ww = bounds.w;
+ lt_wh = bounds.h;
+
+ if( lt_resizesurface(lt_getsurface(0), lt_ww, lt_wh) ) {
+ gleq_window_refresh_callback(window_handle());
+ }
+ // fullscreen_quad_rgb( lt_getsurface(0)->t, 1.2f );
+ ui_texture_fit(lt_getsurface(0)->t, bounds);
+
+ if( !!nk_input_is_mouse_hovering_rect(&ui_ctx->input, ((struct nk_rect){lt_wx+5,lt_wy+5,lt_ww-10,lt_wh-10})) ) {
+ lt_events &= ~(1<<31); // dont cursor shape
+ }
+
+ editor_end(window_mode);
+ }
+
+ lt_tick(L);
+ return 0;
+}
+
+AUTORUN {
+ array_push(editor.subeditors, editor_scripted);
+}
+#line 0
+
+#line 1 "v4k_end.c"
// Enable more performant GPUs on laptops. Does this work into a dll?
// int NvOptimusEnablement = 1;
// int AmdPowerXpressRequestHighPerformance = 1;
diff --git a/engine/v4k.h b/engine/v4k.h
index 6bb49ba..94e3bd1 100644
--- a/engine/v4k.h
+++ b/engine/v4k.h
@@ -95,7 +95,7 @@ extern "C" {
//-----------------------------------------------------------------------------
// Headers
-#line 1 "engine/split/v4k_config.h"
+#line 1 "v4k_config.h"
// -----------------------------------------------------------------------------
// config directives
@@ -510,7 +510,7 @@ typedef char bool;
#endif
#line 0
-#line 1 "engine/split/v4k_ds.h"
+#line 1 "v4k_ds.h"
// data structures and utils: array, set, map, hash, sort.
// - rlyeh, public domain
@@ -949,7 +949,7 @@ API bool (map_sort)(map* m);
API void (map_clear)(map* m);
#line 0
-#line 1 "engine/split/v4k_math.h"
+#line 1 "v4k_math.h"
// -----------------------------------------------------------------------------
// math framework: rand, ease, vec2, vec3, vec4, quat, mat2, mat33, mat34, mat4
// - rlyeh, public domain
@@ -1230,7 +1230,7 @@ API void print34( float *m );
API void print44( float *m );
#line 0
-#line 1 "engine/split/v4k_obj.h"
+#line 1 "v4k_obj.h"
// -----------------------------------------------------------------------------
// factory of handle ids
@@ -1394,6 +1394,7 @@ void* obj_free(void *o);
// --- syntax sugars
#define obj_extend(T,method) (obj_##method[OBJTYPE(T)] = (void*)T##_##method)
+#define obj_extend_t(T,method) (obj_##method[OBJTYPE(T##_t)] = (void*)T##_##method)
#define obj_method(method,o,...) (obj_##method[((struct obj*)(o))->objtype](o,##__VA_ARGS__)) // (obj_##method[((struct obj*)(o))->objtype]((o), ##__VA_ARGS__))
#define obj_hasmethod(o,method) (obj_typeid(o)[obj_##method])
@@ -1416,6 +1417,17 @@ void* obj_free(void *o);
#define EXTEND9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8)
#define EXTEND10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend(o,F1), obj_extend(o,F2), obj_extend(o,F3), obj_extend(o,F4), obj_extend(o,F5), obj_extend(o,F6), obj_extend(o,F7), obj_extend(o,F8), obj_extend(o,F9)
+#define EXTEND_T(...) EXPAND(EXTEND_T, __VA_ARGS__)
+#define EXTEND_T2(o,F1) obj_extend_t(o,F1)
+#define EXTEND_T3(o,F1,F2) obj_extend_t(o,F1), obj_extend_t(o,F2)
+#define EXTEND_T4(o,F1,F2,F3) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3)
+#define EXTEND_T5(o,F1,F2,F3,F4) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4)
+#define EXTEND_T6(o,F1,F2,F3,F4,F5) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5)
+#define EXTEND_T7(o,F1,F2,F3,F4,F5,F6) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6)
+#define EXTEND_T8(o,F1,F2,F3,F4,F5,F6,F7) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7)
+#define EXTEND_T9(o,F1,F2,F3,F4,F5,F6,F7,F8) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8)
+#define EXTEND_T10(o,F1,F2,F3,F4,F5,F6,F7,F8,F9) obj_extend_t(o,F1), obj_extend_t(o,F2), obj_extend_t(o,F3), obj_extend_t(o,F4), obj_extend_t(o,F5), obj_extend_t(o,F6), obj_extend_t(o,F7), obj_extend_t(o,F8), obj_extend_t(o,F9)
+
// --- declare vtables
API extern void (*obj_ctor[256])(); ///-
@@ -1434,6 +1446,8 @@ API extern int (*obj_lerp[256])(); ///-
API extern int (*obj_edit[256])(); ///-
API extern int (*obj_aabb[256])(); ///-
+API extern const char*OBJTYPES[256]; /// -
+
// ----------------------------------------------------------------------------
// core
@@ -1578,7 +1592,7 @@ typedef enum OBJTYPE_BUILTINS {
#line 0
-#line 1 "engine/split/v4k_ai.h"
+#line 1 "v4k_ai.h"
// AI framework
// - rlyeh, public domain.
//
@@ -1663,7 +1677,7 @@ API void swarm_update_acceleration_and_velocity_only(swarm_t *self, float del
API int ui_swarm(swarm_t *self);
#line 0
-#line 1 "engine/split/v4k_audio.h"
+#line 1 "v4k_audio.h"
// -----------------------------------------------------------------------------
// audio framework
// - rlyeh, public domain
@@ -1724,7 +1738,7 @@ enum AUDIO_FLAGS {
API int audio_queue( const void *samples, int num_samples, int flags );
#line 0
-#line 1 "engine/split/v4k_collide.h"
+#line 1 "v4k_collide.h"
// -----------------------------------------------------------------------------
// original code by @vurtun (PD) and @barerose (CC0).
// [src] https://gist.github.com/vurtun/95f088e4889da2474ad1ce82d7911fee
@@ -1885,7 +1899,7 @@ API poly diamond(vec3 from, vec3 to, float size); // poly_free() required
API void collide_demo(); // debug draw collisions
#line 0
-#line 1 "engine/split/v4k_cook.h"
+#line 1 "v4k_cook.h"
// -----------------------------------------------------------------------------
// asset pipeline framework
// - rlyeh, public domain.
@@ -1921,7 +1935,7 @@ API int cook_progress(); // [0..100]
API bool have_tools();
#line 0
-#line 1 "engine/split/v4k_data.h"
+#line 1 "v4k_data.h"
// -----------------------------------------------------------------------------
// data framework (json5, xml, compression) @todo:kvdb
// - rlyeh, public domain
@@ -1960,7 +1974,7 @@ API void xml_pop();
API bool data_tests();
#line 0
-#line 1 "engine/split/v4k_extend.h"
+#line 1 "v4k_extend.h"
// dll ------------------------------------------------------------------------
/// !!! `filename` must contain extension
@@ -1997,54 +2011,7 @@ enum {
API void *script_init_env(unsigned flags);
#line 0
-#line 1 "engine/split/v4k_editor.h"
-// -----------------------------------------------------------------------------
-// in-game editor
-// - rlyeh, public domain.
-//
-// @todo: merge editor1.c and editor3.c internals into this api
-
-//API void editor();
-//API bool editor_active();
-API vec3 editor_pick(float mouse_x, float mouse_y);
-API char* editor_path(const char *path);
-
-API float* engine_getf(const char *key);
-API int* engine_geti(const char *key);
-API char** engine_gets(const char *key);
-API int engine_send(const char *cmd, const char *optional_value);
-
-API int ui_debug();
-
-// open file dialog
-
-API char* dialog_load();
-API char* dialog_save();
-
-// transform gizmos
-
-API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca);
-API bool gizmo_active();
-API bool gizmo_hover();
-
-// localization kit (I18N, L10N)
-
-API bool kit_load( const char *filename ); // load translations file (xlsx)
-API bool kit_merge( const char *filename ); // merge translations file into existing context
-API void kit_insert( const char *id, const char *translation ); // insert single translation unit
-API void kit_clear(); // delete all translations
-
-API void kit_set( const char *variable, const char *value ); // set context variable
-API void kit_reset(); // reset all variables in context
-API void kit_dump_state( FILE *fp ); // debug
-
-API char* kit_translate2( const char *id, const char *langcode_iso639_1 ); // perform a translation given explicit locale
-
-API void kit_locale( const char *langcode_iso639_1 ); // set current locale: enUS, ptBR, esES, ...
-API char* kit_translate( const char *id ); // perform a translation, given current locale
-#line 0
-
-#line 1 "engine/split/v4k_file.h"
+#line 1 "v4k_file.h"
// -----------------------------------------------------------------------------
// files, cache and virtual filesystem (registered directories and/or compressed zip archives).
// - rlyeh, public domain.
@@ -2144,7 +2111,7 @@ API void ini_destroy(ini_t);
API bool ini_write(const char *filename, const char *section, const char *key, const char *value);
#line 0
-#line 1 "engine/split/v4k_font.h"
+#line 1 "v4k_font.h"
// -----------------------------------------------------------------------------
// font framework
// - rlyeh, public domain
@@ -2236,7 +2203,7 @@ API void* font_colorize(const char *text, const char *comma_types, const char *c
API vec2 font_highlight(const char *text, const void *colors);
#line 0
-#line 1 "engine/split/v4k_input.h"
+#line 1 "v4k_input.h"
// -----------------------------------------------------------------------------
// input framework
// - rlyeh, public domain
@@ -2363,7 +2330,7 @@ enum INPUT_ALIASES {
};
#line 0
-#line 1 "engine/split/v4k_memory.h"
+#line 1 "v4k_memory.h"
// -----------------------------------------------------------------------------
// memory framework
// - rlyeh, public domain
@@ -2403,7 +2370,7 @@ static FORCE_INLINE void *(CALLOC_)(size_t m, size_t n) { return n *= m, memset(
static FORCE_INLINE char *(STRDUP_)(const char *s) { size_t n = strlen(s)+1; return ((char*)memcpy(REALLOC(0,n), s, n)); } ///-
#line 0
-#line 1 "engine/split/v4k_network.h"
+#line 1 "v4k_network.h"
// -----------------------------------------------------------------------------
// network framework
// - rlyeh, public domain
@@ -2455,7 +2422,7 @@ API int tcp_debug(int); // toggle traffic monitoring on/off for given socket
//API int tcp_crypt(int,uint64_t); // set shared secret
#line 0
-#line 1 "engine/split/v4k_track.h"
+#line 1 "v4k_track.h"
#ifndef TRACK_SEND_BUFSIZE
#define TRACK_SEND_BUFSIZE 576
#endif
@@ -2516,7 +2483,7 @@ typedef struct track_prop {
API int track_event_props(char const *event_id, char const *user_id, const track_prop *props);
#line 0
-#line 1 "engine/split/v4k_netsync.h"
+#line 1 "v4k_netsync.h"
// high-level, socket-less networking api. inspired by Quake, MPI and RenderBuckets theories.
// - rlyeh, public domain
//
@@ -2602,7 +2569,7 @@ API int64_t client_join(const char *ip, int port);
#define LOCALHOST_IPV6 "::1"
#line 0
-#line 1 "engine/split/v4k_pack.h"
+#line 1 "v4k_pack.h"
// ----------------------------------------------------------------------------
// compression api
@@ -2731,25 +2698,25 @@ typedef struct double2 { double x,y; } double2;
typedef struct double3 { double x,y,z; } double3;
typedef struct double4 { double x,y,z,w; } double4;
-#define byte2(x,y) M_CAST(byte2, (uint8_t)(x), (uint8_t)(y) )
-#define byte3(x,y,z) M_CAST(byte3, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z) )
-#define byte4(x,y,z,w) M_CAST(byte4, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z), (uint8_t)(w) )
+#define byte2(x,y) C_CAST(byte2, (uint8_t)(x), (uint8_t)(y) )
+#define byte3(x,y,z) C_CAST(byte3, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z) )
+#define byte4(x,y,z,w) C_CAST(byte4, (uint8_t)(x), (uint8_t)(y), (uint8_t)(z), (uint8_t)(w) )
-#define int2(x,y) M_CAST(int2, (int)(x), (int)(y) )
-#define int3(x,y,z) M_CAST(int3, (int)(x), (int)(y), (int)(z) )
-#define int4(x,y,z,w) M_CAST(int4, (int)(x), (int)(y), (int)(z), (int)(w) )
+#define int2(x,y) C_CAST(int2, (int)(x), (int)(y) )
+#define int3(x,y,z) C_CAST(int3, (int)(x), (int)(y), (int)(z) )
+#define int4(x,y,z,w) C_CAST(int4, (int)(x), (int)(y), (int)(z), (int)(w) )
-#define uint2(x,y) M_CAST(uint2, (unsigned)(x), (unsigned)(y) )
-#define uint3(x,y,z) M_CAST(uint3, (unsigned)(x), (unsigned)(y), (unsigned)(z) )
-#define uint4(x,y,z,w) M_CAST(uint4, (unsigned)(x), (unsigned)(y), (unsigned)(z), (unsigned)(w) )
+#define uint2(x,y) C_CAST(uint2, (unsigned)(x), (unsigned)(y) )
+#define uint3(x,y,z) C_CAST(uint3, (unsigned)(x), (unsigned)(y), (unsigned)(z) )
+#define uint4(x,y,z,w) C_CAST(uint4, (unsigned)(x), (unsigned)(y), (unsigned)(z), (unsigned)(w) )
-#define float2(x,y) M_CAST(float2, (float)(x), (float)(y) )
-#define float3(x,y,z) M_CAST(float3, (float)(x), (float)(y), (float)(z) )
-#define float4(x,y,z,w) M_CAST(float4, (float)(x), (float)(y), (float)(z), (float)(w) )
+#define float2(x,y) C_CAST(float2, (float)(x), (float)(y) )
+#define float3(x,y,z) C_CAST(float3, (float)(x), (float)(y), (float)(z) )
+#define float4(x,y,z,w) C_CAST(float4, (float)(x), (float)(y), (float)(z), (float)(w) )
-#define double2(x,y) M_CAST(double2, (double)(x), (double)(y) )
-#define double3(x,y,z) M_CAST(double3, (double)(x), (double)(y), (double)(z) )
-#define double4(x,y,z,w) M_CAST(double4, (double)(x), (double)(y), (double)(z), (double)(w) )
+#define double2(x,y) C_CAST(double2, (double)(x), (double)(y) )
+#define double3(x,y,z) C_CAST(double3, (double)(x), (double)(y), (double)(z) )
+#define double4(x,y,z,w) C_CAST(double4, (double)(x), (double)(y), (double)(z), (double)(w) )
// -----------------------------------------------------------------------------
// compile-time fourcc, eightcc
@@ -2994,7 +2961,7 @@ API int loadb(const unsigned char *buf, const char *format, ...);
#line 0
-#line 1 "engine/split/v4k_profile.h"
+#line 1 "v4k_profile.h"
// -----------------------------------------------------------------------------
// profiler & stats (@fixme: threadsafe)
@@ -3026,7 +2993,7 @@ extern API int profiler_enabled; ///-
#endif
#line 0
-#line 1 "engine/split/v4k_reflect.h"
+#line 1 "v4k_reflect.h"
// C reflection: enums, functions, structs, members and anotations.
// - rlyeh, public domain
//
@@ -3093,7 +3060,7 @@ API const char* symbol_naked(const char *s);
API int ui_reflect(const char *mask); // *, model* or NULL
#line 0
-#line 1 "engine/split/v4k_render.h"
+#line 1 "v4k_render.h"
// -----------------------------------------------------------------------------
// naive rendering framework
// - rlyeh, public domain
@@ -3279,82 +3246,6 @@ API void fullscreen_quad_rgb_flipped( texture_t texture, float gamma );
API void fullscreen_quad_ycbcr( texture_t texture_YCbCr[3], float gamma );
API void fullscreen_quad_ycbcr_flipped( texture_t texture_YCbCr[3], float gamma );
-// -----------------------------------------------------------------------------
-// sprites
-
-// texture id, position(x,y,depth sort), tint color, rotation angle
-API void sprite( texture_t texture, float position[3], float rotation /*0*/, uint32_t color /*~0u*/);
-
-// texture id, rect(x,y,w,h) is [0..1] normalized, z-index, pos(xy,scale.xy), rotation (degrees), color (rgba)
-API void sprite_rect( texture_t t, vec4 rect, float zindex, vec4 pos, float tilt_deg, unsigned tint_rgba);
-
-// texture id, sheet(frameNumber,X,Y) (frame in a X*Y spritesheet), position(x,y,depth sort), rotation angle, offset(x,y), scale(x,y), is_additive, tint color
-API void sprite_sheet( texture_t texture, float sheet[3], float position[3], float rotation, float offset[2], float scale[2], int is_additive, uint32_t rgba, int resolution_independant);
-
-API void sprite_flush();
-
-// -----------------------------------------------------------------------------
-// tilemaps
-
-typedef struct tileset_t {
- texture_t tex; // spritesheet
- unsigned tile_w, tile_h; // dimensions per tile in pixels
- unsigned cols, rows; // tileset num_cols, num_rows
- unsigned selected; // active tile (while editing)
-} tileset_t;
-
-API tileset_t tileset(texture_t tex, unsigned tile_w, unsigned tile_h, unsigned cols, unsigned rows);
-
-API int ui_tileset( tileset_t t );
-
-typedef struct tilemap_t {
- int blank_chr; // transparent tile
- unsigned cols, rows; // map dimensions (in tiles)
- array(int) map;
-
- vec3 position; // x,y,scale
- float zindex;
- float tilt;
- unsigned tint;
- bool is_additive;
-} tilemap_t;
-
-API tilemap_t tilemap(const char *map, int blank_chr, int linefeed_chr);
-API void tilemap_render( tilemap_t m, tileset_t style );
-API void tilemap_render_ext( tilemap_t m, tileset_t style, float zindex, float xy_zoom[3], float tilt, unsigned tint, bool is_additive );
-
-// -----------------------------------------------------------------------------
-// tiled maps
-
-typedef struct tiled_t {
- char *map_name;
- unsigned first_gid, tilew, tileh, w, h;
-
- bool parallax;
- vec3 position;
- array(bool) visible;
- array(tilemap_t) layers;
- array(tileset_t) sets;
- array(char*) names;
-} tiled_t;
-
-API tiled_t tiled(const char *file_tmx);
-API void tiled_render(tiled_t tmx, vec3 pos);
-
-API void ui_tiled(tiled_t *t);
-
-// -----------------------------------------------------------------------------
-// spines
-
-typedef struct spine_t spine_t;
-
-API spine_t*spine(const char *file_json, const char *file_atlas, unsigned flags);
-API void spine_skin(spine_t *p, unsigned skin);
-API void spine_render(spine_t *p, vec3 offset, unsigned flags);
-API void spine_animate(spine_t *p, float delta);
-
-API void ui_spine(spine_t *p);
-
// -----------------------------------------------------------------------------
// cubemaps
@@ -3801,7 +3692,7 @@ API void* screenshot(int components); // 3 RGB, 4 RGBA, -3 BGR, -4 BGRA
API void* screenshot_async(int components); // 3 RGB, 4 RGBA, -3 BGR, -4 BGRA
#line 0
-#line 1 "engine/split/v4k_renderdd.h"
+#line 1 "v4k_renderdd.h"
// -----------------------------------------------------------------------------
// debugdraw framework
// - rlyeh, public domain.
@@ -3868,7 +3759,7 @@ API void ddraw_flush();
API void ddraw_flush_projview(mat44 proj, mat44 view);
#line 0
-#line 1 "engine/split/v4k_scene.h"
+#line 1 "v4k_scene.h"
// -----------------------------------------------------------------------------
// scene framework
// - rlyeh, public domain
@@ -4005,7 +3896,124 @@ API unsigned scene_count_light();
API light_t* scene_index_light(unsigned index);
#line 0
-#line 1 "engine/split/v4k_string.h"
+#line 1 "v4k_sprite.h"
+// -----------------------------------------------------------------------------
+// sprites
+
+typedef enum SPRITE_FLAGS {
+ SPRITE_PROJECTED = 1,
+ SPRITE_ADDITIVE = 2,
+ SPRITE_CENTERED = 4,
+ SPRITE_RESOLUTION_INDEPENDANT = 128,
+} SPRITE_FLAGS;
+
+// texture id, position(x,y,depth sort), tint color, rotation angle
+API void sprite( texture_t texture, float position[3], float rotation /*0*/, unsigned color /*~0u*/, unsigned flags);
+
+// texture id, rect(x,y,w,h) is [0..1] normalized, then: pos(xyz,z-index), (scale.xy,offset.xy), rotation (degrees), color (rgba)
+API void sprite_rect( texture_t t, vec4 rect, vec4 pos, vec4 scaleoff, float tilt_deg, unsigned tint_rgba, unsigned flags);
+
+// texture id, sheet(frameNumber,X,Y) (frame in a X*Y spritesheet), position(x,y,depth sort), rotation angle, offset(x,y), scale(x,y), is_additive, tint color
+API void sprite_sheet( texture_t texture, float sheet[3], float position[3], float rotation, float offset[2], float scale[2], unsigned rgba, unsigned flags);
+
+API void sprite_flush();
+
+// -----------------------------------------------------------------------------
+// tilemaps
+
+typedef struct tileset_t {
+ texture_t tex; // spritesheet
+ unsigned tile_w, tile_h; // dimensions per tile in pixels
+ unsigned cols, rows; // tileset num_cols, num_rows
+ unsigned selected; // active tile (while editing)
+} tileset_t;
+
+API tileset_t tileset(texture_t tex, unsigned tile_w, unsigned tile_h, unsigned cols, unsigned rows);
+
+API int ui_tileset( tileset_t t );
+
+typedef struct tilemap_t {
+ int blank_chr; // transparent tile
+ unsigned cols, rows; // map dimensions (in tiles)
+ array(int) map;
+
+ vec3 position; // x,y,scale
+ float zindex;
+ float tilt;
+ unsigned tint;
+ bool is_additive;
+} tilemap_t;
+
+API tilemap_t tilemap(const char *map, int blank_chr, int linefeed_chr);
+API void tilemap_render( tilemap_t m, tileset_t style );
+API void tilemap_render_ext( tilemap_t m, tileset_t style, float zindex, float xy_zoom[3], float tilt, unsigned tint, bool is_additive );
+
+// -----------------------------------------------------------------------------
+// tiled maps
+
+typedef struct tiled_t {
+ char *map_name;
+ unsigned first_gid, tilew, tileh, w, h;
+
+ bool parallax;
+ vec3 position;
+ array(bool) visible;
+ array(tilemap_t) layers;
+ array(tileset_t) sets;
+ array(char*) names;
+} tiled_t;
+
+API tiled_t tiled(const char *file_tmx);
+API void tiled_render(tiled_t tmx, vec3 pos);
+
+API void ui_tiled(tiled_t *t);
+
+// -----------------------------------------------------------------------------
+// spines
+
+typedef struct spine_t spine_t;
+
+API spine_t*spine(const char *file_json, const char *file_atlas, unsigned flags);
+API void spine_skin(spine_t *p, unsigned skin);
+API void spine_render(spine_t *p, vec3 offset, unsigned flags);
+API void spine_animate(spine_t *p, float delta);
+
+API void ui_spine(spine_t *p);
+
+// ----------------------------------------------------------------------------
+// sprite v2 api
+
+typedef struct sprite_t { OBJ
+ vec4 gamepad; // up,down,left,right
+ vec2 fire; // a,b
+
+ vec4 pos;
+ vec2 sca;
+ float tilt;
+ unsigned tint;
+ unsigned frame;
+ unsigned timer, timer_ms;
+ unsigned flip_, flipped;
+ unsigned play;
+ bool paused;
+ // array(unsigned) play_queue; or unsigned play_next;
+ struct atlas_t *a; // shared
+ //atlas_t own; // owned
+} sprite_t;
+
+OBJTYPEDEF(sprite_t,10);
+API void sprite_ctor(sprite_t *s);
+API void sprite_dtor(sprite_t *s);
+API void sprite_tick(sprite_t *s);
+API void sprite_draw(sprite_t *s);
+API void sprite_edit(sprite_t *s);
+
+API sprite_t*sprite_new(const char *ase, int bindings[6]);
+API void sprite_del(sprite_t *s);
+API void sprite_setanim(sprite_t *s, unsigned name);
+#line 0
+
+#line 1 "v4k_string.h"
// string framework
// - rlyeh, public domain
@@ -4098,9 +4106,26 @@ typedef struct quarks_db {
API unsigned quark_intern( quarks_db*, const char *string );
API const char *quark_string( quarks_db*, unsigned key );
+
+// -----------------------------------------------------------------------------
+// ## localization kit (I18N, L10N)
+
+API bool kit_load( const char *filename ); // load translations file (xlsx)
+API bool kit_merge( const char *filename ); // merge translations file into existing context
+API void kit_insert( const char *id, const char *translation ); // insert single translation unit
+API void kit_clear(); // delete all translations
+
+API void kit_set( const char *variable, const char *value ); // set context variable
+API void kit_reset(); // reset all variables in context
+API void kit_dump_state( FILE *fp ); // debug
+
+API char* kit_translate2( const char *id, const char *langcode_iso639_1 ); // perform a translation given explicit locale
+
+API void kit_locale( const char *langcode_iso639_1 ); // set current locale: enUS, ptBR, esES, ...
+API char* kit_translate( const char *id ); // perform a translation, given current locale
#line 0
-#line 1 "engine/split/v4k_system.h"
+#line 1 "v4k_system.h"
// -----------------------------------------------------------------------------
// system framework utils
// - rlyeh, public domain.
@@ -4187,7 +4212,7 @@ API int (test)(const char *file, int line, const char *expr, bool result);
#endif
#line 0
-#line 1 "engine/split/v4k_time.h"
+#line 1 "v4k_time.h"
// -----------------------------------------------------------------------------
// time framework utils
@@ -4346,7 +4371,7 @@ API vec3 curve_eval(curve_t *c, float dt, unsigned *color);
API void curve_destroy(curve_t *c);
#line 0
-#line 1 "engine/split/v4k_ui.h"
+#line 1 "v4k_ui.h"
// -----------------------------------------------------------------------------
// immediate ui framework
// - rlyeh, public domain
@@ -4440,7 +4465,7 @@ API int ui_demo(int do_windows);
API void *ui_handle();
#line 0
-#line 1 "engine/split/v4k_video.h"
+#line 1 "v4k_video.h"
// -----------------------------------------------------------------------------
// video decoder (mpeg)
// - rlyeh, public domain
@@ -4483,7 +4508,7 @@ API bool record_active();
API void record_stop(void);
#line 0
-#line 1 "engine/split/v4k_window.h"
+#line 1 "v4k_window.h"
// -----------------------------------------------------------------------------
// window framework
// - rlyeh, public domain
@@ -4587,6 +4612,39 @@ API void window_setclipboard(const char *text);
// ----
+#line 1 "v4k_editor.h"
+// -----------------------------------------------------------------------------
+// in-game editor
+// - rlyeh, public domain.
+
+API int editor_send(const char *command);
+
+//API void editor();
+//API bool editor_active();
+API vec3 editor_pick(float mouse_x, float mouse_y);
+API char* editor_path(const char *path);
+
+API float* engine_getf(const char *key);
+API int* engine_geti(const char *key);
+API char** engine_gets(const char *key);
+API int engine_send(const char *cmd, const char *optional_value);
+
+API int ui_debug();
+
+// open file dialog
+
+API char* dialog_load();
+API char* dialog_save();
+
+// transform gizmos
+
+API int gizmo(vec3 *pos, vec3 *rot, vec3 *sca);
+API bool gizmo_active();
+API bool gizmo_hover();
+#line 0
+
+// ----
+
#if is(cpp)
} // extern "C"
#endif
diff --git a/hello.c b/hello.c
index 31fad86..eb4b40a 100644
--- a/hello.c
+++ b/hello.c
@@ -16,17 +16,18 @@
int main() {
// options
+ unsigned no_flags = 0;
bool do_debugdraw = 0;
// window (80% sized, MSAA x4 flag)
window_create(80, WINDOW_MSAA4);
window_title(__FILE__);
- // load skybox: launch with --mie for rayleigh/mie scattering (no flags)
- skybox_t sky = skybox(flag("--mie") ? 0 : "cubemaps/stardust", 0);
+ // load skybox: launch with --mie for rayleigh/mie scattering
+ skybox_t sky = skybox(flag("--mie") ? 0 : "cubemaps/stardust", no_flags);
- // animated models loading (no flags)
- model_t girl = model("kgirl/kgirls01.fbx", 0);
+ // animated models loading
+ model_t girl = model("kgirl/kgirls01.fbx", no_flags);
compose44( girl.pivot, vec3(0,0,0), eulerq(vec3(-90,0,0)), vec3(2,2,2)); // position, rotation, scale
// camera
@@ -38,8 +39,8 @@ int main() {
// audio (both clips & streams)
audio_t SFX1 = audio_clip( "coin.wav" ), SFX2 = audio_clip( "pew.sfxr" );
audio_t BGM1 = audio_stream( "waterworld-map.fur" ), BGM2 = audio_stream( "larry.mid" ), BGM = BGM1;
- audio_play(SFX1, 0);
- audio_play(BGM, 0);
+ audio_play(SFX1, no_flags);
+ audio_play(BGM, no_flags);
// demo loop
while (window_swap())
@@ -76,7 +77,7 @@ int main() {
girl.curframe = model_animate(girl, girl.curframe + delta);
// draw girl
- model_render(girl, cam.proj, cam.view, girl.pivot, 0);
+ model_render(girl, cam.proj, cam.view, girl.pivot, no_flags);
// post-fxs end here
fx_end();
@@ -97,10 +98,10 @@ int main() {
if( ui_button("Test Lua") ) script_run("ui_notify(nil, \"Hello from Lua! Version: \" .. _VERSION)");
ui_section("Audio");
- if( ui_label2_toolbar("BGM: Waterworld Map", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = BGM1, 0);
- if( ui_label2_toolbar("BGM: Leisure Suit Larry", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = BGM2, 0);
- if( ui_label2_toolbar("SFX: Coin", ICON_MD_VOLUME_UP)) audio_play(SFX1, 0);
- if( ui_label2_toolbar("SFX: Pew", ICON_MD_VOLUME_UP)) audio_play(SFX2, 0);
+ if( ui_label2_toolbar("BGM: Waterworld Map", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = BGM1, no_flags);
+ if( ui_label2_toolbar("BGM: Leisure Suit Larry", ICON_MD_VOLUME_UP)) audio_stop(BGM), audio_play(BGM = BGM2, no_flags);
+ if( ui_label2_toolbar("SFX: Coin", ICON_MD_VOLUME_UP)) audio_play(SFX1, no_flags);
+ if( ui_label2_toolbar("SFX: Pew", ICON_MD_VOLUME_UP)) audio_play(SFX2, no_flags);
ui_panel_end();
}
diff --git a/tools/3rd_delaunay.h b/tools/3rd_delaunay.h
new file mode 100644
index 0000000..0ca03dc
--- /dev/null
+++ b/tools/3rd_delaunay.h
@@ -0,0 +1,1059 @@
+#ifndef DELAUNAY_H
+#define DELAUNAY_H
+
+/*
+** delaunay.c : compute 2D delaunay triangulation in the plane.
+** Copyright (C) 2005 Wael El Oraiby
+**
+**
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Affero General Public License for more details.
+**
+** You should have received a copy of the GNU Affero General Public License
+** along with this program. If not, see .
+*/
+
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef double real;
+
+typedef struct {
+ real x, y;
+} del_point2d_t;
+
+typedef struct {
+ /** input points count */
+ unsigned int num_points;
+
+ /** the input points */
+ del_point2d_t* points;
+
+ /** number of returned faces */
+ unsigned int num_faces;
+
+ /** the faces are given as a sequence: num verts, verts indices, num verts, verts indices...
+ * the first face is the external face */
+ unsigned int* faces;
+} delaunay2d_t;
+
+/*
+ * build the 2D Delaunay triangulation given a set of points of at least 3 points
+ *
+ * @points: point set given as a sequence of tuple x0, y0, x1, y1, ....
+ * @num_points: number of given point
+ * @preds: the incircle predicate
+ * @faces: the triangles given as a sequence: num verts, verts indices, num verts, verts indices.
+ * Note that the first face is the external face
+ * @return: the created topology
+ */
+delaunay2d_t* delaunay2d_from(del_point2d_t *points, unsigned int num_points);
+
+/*
+ * release a delaunay2d object
+ */
+void delaunay2d_release(delaunay2d_t* del);
+
+
+typedef struct {
+ /** input points count */
+ unsigned int num_points;
+
+ /** input points */
+ del_point2d_t* points;
+
+ /** number of triangles */
+ unsigned int num_triangles;
+
+ /** the triangles indices v0,v1,v2, v0,v1,v2 .... */
+ unsigned int* tris;
+} tri_delaunay2d_t;
+
+/**
+ * build a tri_delaunay2d_t out of a delaunay2d_t object
+ */
+tri_delaunay2d_t* tri_delaunay2d_from(delaunay2d_t* del);
+
+/**
+ * release a tri_delaunay2d_t object
+ */
+void tri_delaunay2d_release(tri_delaunay2d_t* tdel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // DELAUNAY_H
+
+#ifdef DELAUNAY_C
+
+/*
+** delaunay.c : compute 2D delaunay triangulation in the plane.
+** Copyright (C) 2005 Wael El Oraiby
+**
+**
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU Affero General Public License for more details.
+**
+** You should have received a copy of the GNU Affero General Public License
+** along with this program. If not, see .
+*/
+
+#include
+#include
+#include
+#include
+#include
+
+#define ON_RIGHT 1
+#define ON_SEG 0
+#define ON_LEFT -1
+
+#define OUTSIDE -1
+#define ON_CIRCLE 0
+#define INSIDE 1
+
+struct point2d_s;
+struct face_s;
+struct halfedge_s;
+struct delaunay_s;
+
+
+#define REAL_ZERO 0.0l
+#define REAL_ONE 1.0l
+#define REAL_TWO 2.0l
+#define REAL_FOUR 4.0l
+
+
+typedef struct point2d_s point2d_t;
+typedef struct face_s face_t;
+typedef struct halfedge_s halfedge_t;
+typedef struct delaunay_s delaunay_t;
+typedef struct working_set_s working_set_t;
+
+typedef long double lreal;
+typedef lreal mat3_t[3][3];
+
+struct point2d_s {
+ real x, y; /* point coordinates */
+ halfedge_t* he; /* point halfedge */
+ unsigned int idx; /* point index in input buffer */
+};
+
+struct face_s {
+ halfedge_t* he; /* a pointing half edge */
+ unsigned int num_verts; /* number of vertices on this face */
+};
+
+struct halfedge_s {
+ point2d_t* vertex; /* vertex */
+ halfedge_t* pair; /* pair */
+ halfedge_t* next; /* next */
+ halfedge_t* prev; /* next^-1 */
+ face_t* face; /* halfedge face */
+};
+
+struct delaunay_s {
+ halfedge_t* rightmost_he; /* right most halfedge */
+ halfedge_t* leftmost_he; /* left most halfedge */
+ point2d_t* points; /* pointer to points */
+ face_t* faces; /* faces of delaunay */
+ unsigned int num_faces; /* face count */
+ unsigned int start_point; /* start point index */
+ unsigned int end_point; /* end point index */
+};
+
+struct working_set_s {
+ halfedge_t* edges; /* all the edges (allocated in one shot) */
+ face_t* faces; /* all the faces (allocated in one shot) */
+
+ unsigned int max_edge; /* maximum edge count: 2 * 3 * n where n is point count */
+ unsigned int max_face; /* maximum face count: 2 * n where n is point count */
+
+ unsigned int num_edges; /* number of allocated edges */
+ unsigned int num_faces; /* number of allocated faces */
+
+ halfedge_t* free_edge; /* pointer to the first free edge */
+ face_t* free_face; /* pointer to the first free face */
+};
+
+/*
+* 3x3 matrix determinant
+*/
+static lreal det3(mat3_t m)
+{
+ lreal res = m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])
+ - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])
+ + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
+
+ return res;
+}
+
+/*
+* allocate a halfedge
+*/
+static halfedge_t* halfedge_alloc()
+{
+ halfedge_t* d;
+
+ d = (halfedge_t*)malloc(sizeof(halfedge_t));
+ assert( NULL != d );
+ memset(d, 0, sizeof(halfedge_t));
+
+ return d;
+}
+
+/*
+* free a halfedge
+*/
+static void halfedge_free( halfedge_t* d )
+{
+ assert( d != NULL );
+ memset(d, 0, sizeof(halfedge_t));
+ free(d);
+}
+
+/*
+* free all delaunay halfedges
+*/
+void del_free_halfedges( delaunay_t *del )
+{
+ unsigned int i;
+ halfedge_t *d, *sig;
+
+ /* if there is nothing to do */
+ if( del->points == NULL )
+ return;
+
+ for( i = 0; i <= (del->end_point - del->start_point); i++ )
+ {
+ /* free all the halfedges around the point */
+ d = del->points[i].he;
+ if( d != NULL )
+ {
+ do {
+ sig = d->next;
+ halfedge_free( d );
+ d = sig;
+ } while( d != del->points[i].he );
+ del->points[i].he = NULL;
+ }
+ }
+}
+
+/*
+* compare 2 points when sorting
+*/
+static int cmp_points( const void *_pt0, const void *_pt1 )
+{
+ point2d_t *pt0, *pt1;
+
+ pt0 = (point2d_t*)(_pt0);
+ pt1 = (point2d_t*)(_pt1);
+
+ if( pt0->x < pt1->x )
+ return -1;
+ else if( pt0->x > pt1->x )
+ return 1;
+ else if( pt0->y < pt1->y )
+ return -1;
+ else if( pt0->y > pt1->y )
+ return 1;
+ printf("2 or more points share the same exact coordinate: (%f,%f)(%f,%f)\n", pt0->x,pt0->y,pt1->x,pt1->y);
+ assert(0 && "2 or more points share the same exact coordinate");
+ return 0; /* Should not be given! */
+}
+
+/*
+* classify a point relative to a segment
+*/
+static int classify_point_seg( point2d_t *s, point2d_t *e, point2d_t *pt )
+{
+ lreal se_x, se_y, spt_x, spt_y;
+ lreal res;
+
+ se_x = e->x - s->x;
+ se_y = e->y - s->y;
+
+ spt_x = pt->x - s->x;
+ spt_y = pt->y - s->y;
+
+ res = (( se_x * spt_y ) - ( se_y * spt_x ));
+ if( res < REAL_ZERO )
+ return ON_RIGHT;
+ else if( res > REAL_ZERO )
+ return ON_LEFT;
+
+ return ON_SEG;
+}
+
+/*
+* classify a point relative to a halfedge, -1 is left, 0 is on, 1 is right
+*/
+static int del_classify_point( halfedge_t *d, point2d_t *pt )
+{
+ point2d_t *s, *e;
+
+ s = d->vertex;
+ e = d->pair->vertex;
+
+ return classify_point_seg(s, e, pt);
+}
+
+/*
+* test if a point is inside a circle given by 3 points, 1 if inside, 0 if outside
+*/
+static int in_circle( point2d_t *pt0, point2d_t *pt1, point2d_t *pt2, point2d_t *p )
+{
+ // reduce the computational complexity by substracting the last row of the matrix
+ // ref: https://www.cs.cmu.edu/~quake/robust.html
+ lreal p0p_x, p0p_y, p1p_x, p1p_y, p2p_x, p2p_y, p0p, p1p, p2p, res;
+ mat3_t m;
+
+ p0p_x = pt0->x - p->x;
+ p0p_y = pt0->y - p->y;
+
+ p1p_x = pt1->x - p->x;
+ p1p_y = pt1->y - p->y;
+
+ p2p_x = pt2->x - p->x;
+ p2p_y = pt2->y - p->y;
+
+ p0p = p0p_x * p0p_x + p0p_y * p0p_y;
+ p1p = p1p_x * p1p_x + p1p_y * p1p_y;
+ p2p = p2p_x * p2p_x + p2p_y * p2p_y;
+
+ m[0][0] = p0p_x;
+ m[0][1] = p0p_y;
+ m[0][2] = p0p;
+
+ m[1][0] = p1p_x;
+ m[1][1] = p1p_y;
+ m[1][2] = p1p;
+
+ m[2][0] = p2p_x;
+ m[2][1] = p2p_y;
+ m[2][2] = p2p;
+
+ res = -det3(m);
+
+ if( res < REAL_ZERO )
+ return INSIDE;
+ else if( res > REAL_ZERO )
+ return OUTSIDE;
+
+ return ON_CIRCLE;
+}
+
+/*
+* initialize delaunay segment
+*/
+static int del_init_seg( delaunay_t *del, int start )
+{
+ halfedge_t *d0, *d1;
+ point2d_t *pt0, *pt1;
+
+ /* init delaunay */
+ del->start_point = start;
+ del->end_point = start + 1;
+
+ /* setup pt0 and pt1 */
+ pt0 = &(del->points[start]);
+ pt1 = &(del->points[start + 1]);
+
+ /* allocate the halfedges and setup them */
+ d0 = halfedge_alloc();
+ d1 = halfedge_alloc();
+
+ d0->vertex = pt0;
+ d1->vertex = pt1;
+
+ d0->next = d0->prev = d0;
+ d1->next = d1->prev = d1;
+
+ d0->pair = d1;
+ d1->pair = d0;
+
+ pt0->he = d0;
+ pt1->he = d1;
+
+ del->rightmost_he = d1;
+ del->leftmost_he = d0;
+
+
+ return 0;
+}
+
+/*
+* initialize delaunay triangle
+*/
+static int del_init_tri( delaunay_t *del, int start )
+{
+ halfedge_t *d0, *d1, *d2, *d3, *d4, *d5;
+ point2d_t *pt0, *pt1, *pt2;
+
+ /* initiate delaunay */
+ del->start_point = start;
+ del->end_point = start + 2;
+
+ /* setup the points */
+ pt0 = &(del->points[start]);
+ pt1 = &(del->points[start + 1]);
+ pt2 = &(del->points[start + 2]);
+
+ /* allocate the 6 halfedges */
+ d0 = halfedge_alloc();
+ d1 = halfedge_alloc();
+ d2 = halfedge_alloc();
+ d3 = halfedge_alloc();
+ d4 = halfedge_alloc();
+ d5 = halfedge_alloc();
+
+ if( classify_point_seg(pt0, pt2, pt1) == ON_LEFT ) /* first case */
+ {
+ /* set halfedges points */
+ d0->vertex = pt0;
+ d1->vertex = pt2;
+ d2->vertex = pt1;
+
+ d3->vertex = pt2;
+ d4->vertex = pt1;
+ d5->vertex = pt0;
+
+ /* set points halfedges */
+ pt0->he = d0;
+ pt1->he = d2;
+ pt2->he = d1;
+
+ /* next and next -1 setup */
+ d0->next = d5;
+ d0->prev = d5;
+
+ d1->next = d3;
+ d1->prev = d3;
+
+ d2->next = d4;
+ d2->prev = d4;
+
+ d3->next = d1;
+ d3->prev = d1;
+
+ d4->next = d2;
+ d4->prev = d2;
+
+ d5->next = d0;
+ d5->prev = d0;
+
+ /* set halfedges pair */
+ d0->pair = d3;
+ d3->pair = d0;
+
+ d1->pair = d4;
+ d4->pair = d1;
+
+ d2->pair = d5;
+ d5->pair = d2;
+
+ del->rightmost_he = d1;
+ del->leftmost_he = d0;
+
+ } else /* 2nd case */
+ {
+ /* set halfedges points */
+ d0->vertex = pt0;
+ d1->vertex = pt1;
+ d2->vertex = pt2;
+
+ d3->vertex = pt1;
+ d4->vertex = pt2;
+ d5->vertex = pt0;
+
+ /* set points halfedges */
+ pt0->he = d0;
+ pt1->he = d1;
+ pt2->he = d2;
+
+ /* next and next -1 setup */
+ d0->next = d5;
+ d0->prev = d5;
+
+ d1->next = d3;
+ d1->prev = d3;
+
+ d2->next = d4;
+ d2->prev = d4;
+
+ d3->next = d1;
+ d3->prev = d1;
+
+ d4->next = d2;
+ d4->prev = d2;
+
+ d5->next = d0;
+ d5->prev = d0;
+
+ /* set halfedges pair */
+ d0->pair = d3;
+ d3->pair = d0;
+
+ d1->pair = d4;
+ d4->pair = d1;
+
+ d2->pair = d5;
+ d5->pair = d2;
+
+ del->rightmost_he = d2;
+ del->leftmost_he = d0;
+ }
+
+ return 0;
+}
+
+/*
+* remove an edge given a halfedge
+*/
+static void del_remove_edge( halfedge_t *d )
+{
+ halfedge_t *next, *prev, *pair, *orig_pair;
+
+ orig_pair = d->pair;
+
+ next = d->next;
+ prev = d->prev;
+ pair = d->pair;
+
+ assert(next != NULL);
+ assert(prev != NULL);
+
+ next->prev = prev;
+ prev->next = next;
+
+
+ /* check to see if we have already removed pair */
+ if( pair )
+ pair->pair = NULL;
+
+ /* check to see if the vertex points to this halfedge */
+ if( d->vertex->he == d )
+ d->vertex->he = next;
+
+ d->vertex = NULL;
+ d->next = NULL;
+ d->prev = NULL;
+ d->pair = NULL;
+
+ next = orig_pair->next;
+ prev = orig_pair->prev;
+ pair = orig_pair->pair;
+
+ assert(next != NULL);
+ assert(prev != NULL);
+
+ next->prev = prev;
+ prev->next = next;
+
+
+ /* check to see if we have already removed pair */
+ if( pair )
+ pair->pair = NULL;
+
+ /* check to see if the vertex points to this halfedge */
+ if( orig_pair->vertex->he == orig_pair )
+ orig_pair->vertex->he = next;
+
+ orig_pair->vertex = NULL;
+ orig_pair->next = NULL;
+ orig_pair->prev = NULL;
+ orig_pair->pair = NULL;
+
+
+ /* finally free the halfedges */
+ halfedge_free(d);
+ halfedge_free(orig_pair);
+}
+
+/*
+* pass through all the halfedges on the left side and validate them
+*/
+static halfedge_t* del_valid_left( halfedge_t* b )
+{
+ point2d_t *g, *d, *u, *v;
+ halfedge_t *c, *du, *dg;
+
+ g = b->vertex; /* base halfedge point */
+ dg = b;
+
+ d = b->pair->vertex; /* pair(halfedge) point */
+ b = b->next;
+
+ u = b->pair->vertex; /* next(pair(halfedge)) point */
+ du = b->pair;
+
+ v = b->next->pair->vertex; /* pair(next(next(halfedge)) point */
+
+ if( classify_point_seg(g, d, u) == ON_LEFT )
+ {
+ /* 3 points aren't colinear */
+ /* as long as the 4 points belong to the same circle, do the cleaning */
+ assert( v != u && "1: floating point precision error");
+ while( v != d && v != g && in_circle(g, d, u, v) == INSIDE )
+ {
+ c = b->next;
+ du = b->next->pair;
+ del_remove_edge(b);
+ b = c;
+ u = du->vertex;
+ v = b->next->pair->vertex;
+ }
+
+ assert( v != u && "2: floating point precision error");
+ if( v != d && v != g && in_circle(g, d, u, v) == ON_CIRCLE )
+ {
+ du = du->prev;
+ del_remove_edge(b);
+ }
+ } else /* treat the case where the 3 points are colinear */
+ du = dg;
+
+ assert(du->pair);
+ return du;
+}
+
+/*
+* pass through all the halfedges on the right side and validate them
+*/
+static halfedge_t* del_valid_right( halfedge_t *b )
+{
+ point2d_t *rv, *lv, *u, *v;
+ halfedge_t *c, *dd, *du;
+
+ b = b->pair;
+ rv = b->vertex;
+ dd = b;
+ lv = b->pair->vertex;
+ b = b->prev;
+ u = b->pair->vertex;
+ du = b->pair;
+
+ v = b->prev->pair->vertex;
+
+ if( classify_point_seg(lv, rv, u) == ON_LEFT )
+ {
+ assert( v != u && "1: floating point precision error");
+ while( v != lv && v != rv && in_circle(lv, rv, u, v) == INSIDE )
+ {
+ c = b->prev;
+ du = c->pair;
+ del_remove_edge(b);
+ b = c;
+ u = du->vertex;
+ v = b->prev->pair->vertex;
+ }
+
+ assert( v != u && "1: floating point precision error");
+ if( v != lv && v != rv && in_circle(lv, rv, u, v) == ON_CIRCLE )
+ {
+ du = du->next;
+ del_remove_edge(b);
+ }
+ } else
+ du = dd;
+
+ assert(du->pair);
+ return du;
+}
+
+
+/*
+* validate a link
+*/
+static halfedge_t* del_valid_link( halfedge_t *b )
+{
+ point2d_t *g, *g_p, *d, *d_p;
+ halfedge_t *gd, *dd, *new_gd, *new_dd;
+ int a;
+
+ g = b->vertex;
+ gd = del_valid_left(b);
+ g_p = gd->vertex;
+
+ assert(b->pair);
+ d = b->pair->vertex;
+ dd = del_valid_right(b);
+ d_p = dd->vertex;
+ assert(b->pair);
+
+ if( g != g_p && d != d_p ) {
+ a = in_circle(g, d, g_p, d_p);
+
+ if( a != ON_CIRCLE ) {
+ if( a == INSIDE ) {
+ g_p = g;
+ gd = b;
+ } else {
+ d_p = d;
+ dd = b->pair;
+ }
+ }
+ }
+
+ /* create the 2 halfedges */
+ new_gd = halfedge_alloc();
+ new_dd = halfedge_alloc();
+
+ /* setup new_gd and new_dd */
+
+ new_gd->vertex = gd->vertex;
+ new_gd->pair = new_dd;
+ new_gd->prev = gd;
+ new_gd->next = gd->next;
+ gd->next->prev = new_gd;
+ gd->next = new_gd;
+
+ new_dd->vertex = dd->vertex;
+ new_dd->pair = new_gd;
+ new_dd->prev = dd->prev;
+ dd->prev->next = new_dd;
+ new_dd->next = dd;
+ dd->prev = new_dd;
+
+ return new_gd;
+}
+
+/*
+* find the lower tangent between the two delaunay, going from left to right (returns the left half edge)
+*/
+static halfedge_t* del_get_lower_tangent( delaunay_t *left, delaunay_t *right )
+{
+ point2d_t *pl, *pr;
+ halfedge_t *right_d, *left_d, *new_ld, *new_rd;
+ int sl, sr;
+
+ left_d = left->rightmost_he;
+ right_d = right->leftmost_he;
+
+ do {
+ pl = left_d->prev->pair->vertex;
+ pr = right_d->pair->vertex;
+
+ if( (sl = classify_point_seg(left_d->vertex, right_d->vertex, pl)) == ON_RIGHT ) {
+ left_d = left_d->prev->pair;
+ }
+
+ if( (sr = classify_point_seg(left_d->vertex, right_d->vertex, pr)) == ON_RIGHT ) {
+ right_d = right_d->pair->next;
+ }
+
+ } while( sl == ON_RIGHT || sr == ON_RIGHT );
+
+ /* create the 2 halfedges */
+ new_ld = halfedge_alloc();
+ new_rd = halfedge_alloc();
+
+ /* setup new_gd and new_dd */
+ new_ld->vertex = left_d->vertex;
+ new_ld->pair = new_rd;
+ new_ld->prev = left_d->prev;
+ left_d->prev->next = new_ld;
+ new_ld->next = left_d;
+ left_d->prev = new_ld;
+
+ new_rd->vertex = right_d->vertex;
+ new_rd->pair = new_ld;
+ new_rd->prev = right_d->prev;
+ right_d->prev->next = new_rd;
+ new_rd->next = right_d;
+ right_d->prev = new_rd;
+
+ return new_ld;
+}
+
+/*
+* link the 2 delaunay together
+*/
+static void del_link( delaunay_t *result, delaunay_t *left, delaunay_t *right )
+{
+ point2d_t *u, *v, *ml, *mr;
+ halfedge_t *base;
+
+ assert( left->points == right->points );
+
+ /* save the most right point and the most left point */
+ ml = left->leftmost_he->vertex;
+ mr = right->rightmost_he->vertex;
+
+ base = del_get_lower_tangent(left, right);
+
+ u = base->next->pair->vertex;
+ v = base->pair->prev->pair->vertex;
+
+ while( del_classify_point(base, u) == ON_LEFT ||
+ del_classify_point(base, v) == ON_LEFT )
+ {
+ base = del_valid_link(base);
+ u = base->next->pair->vertex;
+ v = base->pair->prev->pair->vertex;
+ }
+
+ right->rightmost_he = mr->he;
+ left->leftmost_he = ml->he;
+
+ /* TODO: this part is not needed, and can be optimized */
+ while( del_classify_point( right->rightmost_he, right->rightmost_he->prev->pair->vertex ) == ON_RIGHT )
+ right->rightmost_he = right->rightmost_he->prev;
+
+ while( del_classify_point( left->leftmost_he, left->leftmost_he->prev->pair->vertex ) == ON_RIGHT )
+ left->leftmost_he = left->leftmost_he->prev;
+
+ result->leftmost_he = left->leftmost_he;
+ result->rightmost_he = right->rightmost_he;
+ result->points = left->points;
+ result->start_point = left->start_point;
+ result->end_point = right->end_point;
+}
+
+/*
+* divide and conquer delaunay
+*/
+void del_divide_and_conquer( delaunay_t *del, int start, int end )
+{
+ delaunay_t left, right;
+ int i, n;
+
+ n = (end - start + 1);
+
+ if( n > 3 ) {
+ i = (n / 2) + (n & 1);
+ left.points = del->points;
+ right.points = del->points;
+ del_divide_and_conquer( &left, start, start + i - 1 );
+ del_divide_and_conquer( &right, start + i, end );
+ del_link( del, &left, &right );
+ } else {
+ if( n == 3 ) {
+ del_init_tri( del, start );
+ } else {
+ if( n == 2 ) {
+ del_init_seg( del, start );
+ }
+ }
+ }
+}
+
+static void build_halfedge_face( delaunay_t *del, halfedge_t *d )
+{
+ halfedge_t *curr;
+
+ /* test if the halfedge has already a pointing face */
+ if( d->face != NULL )
+ return;
+
+ /* TODO: optimize this */
+ del->faces = (face_t*)realloc(del->faces, (del->num_faces + 1) * sizeof(face_t));
+ assert( NULL != del->faces );
+
+ face_t *f = &(del->faces[del->num_faces]);
+ curr = d;
+ f->he = d;
+ f->num_verts = 0;
+ do {
+ curr->face = f;
+ (f->num_verts)++;
+ curr = curr->pair->prev;
+ } while( curr != d );
+
+ (del->num_faces)++;
+}
+
+/*
+* build the faces for all the halfedge
+*/
+void del_build_faces( delaunay_t *del )
+{
+ unsigned int i;
+ halfedge_t *curr;
+
+ del->num_faces = 0;
+ del->faces = NULL;
+
+ /* build external face first */
+ build_halfedge_face(del, del->rightmost_he->pair);
+
+ for( i = del->start_point; i <= del->end_point; i++ )
+ {
+ curr = del->points[i].he;
+
+ do {
+ build_halfedge_face( del, curr );
+ curr = curr->next;
+ } while( curr != del->points[i].he );
+ }
+}
+
+/*
+*/
+delaunay2d_t* delaunay2d_from(del_point2d_t *points, unsigned int num_points) {
+ delaunay2d_t* res = NULL;
+ delaunay_t del;
+ unsigned int i, j, fbuff_size = 0;
+ unsigned int* faces = NULL;
+
+ /* allocate the points */
+ del.points = (point2d_t*)malloc(num_points * sizeof(point2d_t));
+ assert( NULL != del.points );
+ memset(del.points, 0, num_points * sizeof(point2d_t));
+
+ /* copy the points */
+ for( i = 0; i < num_points; i++ )
+ {
+ del.points[i].idx = i;
+ del.points[i].x = points[i].x;
+ del.points[i].y = points[i].y;
+ }
+
+ qsort(del.points, num_points, sizeof(point2d_t), cmp_points);
+
+ if( num_points >= 3 ) {
+ del_divide_and_conquer( &del, 0, num_points - 1 );
+
+ del_build_faces( &del );
+
+ fbuff_size = 0;
+ for( i = 0; i < del.num_faces; i++ )
+ fbuff_size += del.faces[i].num_verts + 1;
+
+ faces = (unsigned int*)malloc(sizeof(unsigned int) * fbuff_size);
+ assert( NULL != faces );
+
+ j = 0;
+ for( i = 0; i < del.num_faces; i++ )
+ {
+ halfedge_t *curr;
+
+ faces[j] = del.faces[i].num_verts;
+ j++;
+
+ curr = del.faces[i].he;
+ do {
+ faces[j] = curr->vertex->idx;
+ j++;
+ curr = curr->pair->prev;
+ } while( curr != del.faces[i].he );
+ }
+
+ del_free_halfedges( &del );
+
+ free(del.faces);
+ free(del.points);
+ }
+
+ res = (delaunay2d_t*)malloc(sizeof(delaunay2d_t));
+ assert( NULL != res );
+ res->num_points = num_points;
+ res->points = (del_point2d_t*)malloc(sizeof(del_point2d_t) * num_points);
+ assert( NULL != res->points );
+ memcpy(res->points, points, sizeof(del_point2d_t) * num_points);
+ res->num_faces = del.num_faces;
+ res->faces = faces;
+
+ return res;
+}
+
+void delaunay2d_release(delaunay2d_t *del) {
+ free(del->faces);
+ free(del->points);
+ free(del);
+}
+
+
+tri_delaunay2d_t* tri_delaunay2d_from(delaunay2d_t* del) {
+ unsigned int v_offset = del->faces[0] + 1; /* ignore external face */
+ unsigned int dst_offset = 0;
+ unsigned int i;
+
+ tri_delaunay2d_t* tdel = (tri_delaunay2d_t*)malloc(sizeof(tri_delaunay2d_t));
+ assert( NULL != tdel );
+ tdel->num_triangles = 0;
+
+ /* count the number of triangles */
+ if( 1 == del->num_faces ) { /* degenerate case: only external face exists */
+ unsigned int nv = del->faces[0];
+ tdel->num_triangles += nv - 2;
+ } else {
+ for( i = 1; i < del->num_faces; ++i ) {
+ unsigned int nv = del->faces[v_offset];
+ tdel->num_triangles += nv - 2;
+ v_offset += nv + 1;
+ }
+ }
+
+ /* copy points */
+ tdel->num_points = del->num_points;
+ tdel->points = (del_point2d_t*)malloc(sizeof(del_point2d_t) * del->num_points);
+ assert( NULL != tdel->points );
+ memcpy(tdel->points, del->points, sizeof(del_point2d_t) * del->num_points);
+
+ /* build the triangles */
+ tdel->tris = (unsigned int*)malloc(sizeof(unsigned int) * 3 * tdel->num_triangles);
+ assert( NULL != tdel->tris );
+
+ v_offset = del->faces[0] + 1; /* ignore external face */
+
+ if( 1 == del->num_faces ) {
+ /* handle the degenerated case where only the external face exists */
+ unsigned int nv = del->faces[0];
+ unsigned int j = 0;
+ v_offset = 1;
+ for( ; j < nv - 2; ++j ) {
+ tdel->tris[dst_offset] = del->faces[v_offset + j];
+ tdel->tris[dst_offset + 1] = del->faces[(v_offset + j + 1) % nv];
+ tdel->tris[dst_offset + 2] = del->faces[v_offset + j];
+ dst_offset += 3;
+ }
+ } else {
+ for( i = 1; i < del->num_faces; ++i ) {
+ unsigned int nv = del->faces[v_offset];
+ unsigned int j = 0;
+ unsigned int first = del->faces[v_offset + 1];
+
+
+ for( ; j < nv - 2; ++j ) {
+ tdel->tris[dst_offset] = first;
+ tdel->tris[dst_offset + 1] = del->faces[v_offset + j + 2];
+ tdel->tris[dst_offset + 2] = del->faces[v_offset + j + 3];
+ dst_offset += 3;
+ }
+
+ v_offset += nv + 1;
+ }
+ }
+
+ return tdel;
+}
+
+
+void tri_delaunay2d_release(tri_delaunay2d_t* tdel) {
+ free(tdel->tris);
+ free(tdel->points);
+ free(tdel);
+}
+
+#endif
diff --git a/tools/3rd_sproutline.h b/tools/3rd_sproutline.h
new file mode 100644
index 0000000..462cbe8
--- /dev/null
+++ b/tools/3rd_sproutline.h
@@ -0,0 +1,441 @@
+/* sproutline - v0.10 - public domain sprite outline detector - http://github.org/ands/sproutline
+ no warranty implied; use at your own risk
+
+ Do this:
+ #define S2O_IMPLEMENTATION
+ before you include this file in *one* C or C++ file to create the implementation.
+
+ // i.e. it should look like this:
+ #include ...
+ #include ...
+ #include ...
+ #define S2O_IMPLEMENTATION
+ #include "sproutline.h"
+
+ You can #define S2O_MALLOC to avoid using malloc
+
+
+ QUICK NOTES:
+ Primarily of interest to game developers.
+ - Recommended to be used with stb_image.
+ - Detects outlines in sprite images with alpha channels.
+ - Extracts outlines as clockwise paths.
+ - Simplifies outlines based on a distance metric.
+
+ Full documentation under "DOCUMENTATION" below.
+
+
+ Revision 0.10 release notes:
+
+ - Initial release of sproutline.h.
+
+ - Added S2O_MALLOC macro for replacing the memory allocator.
+ Unlike most STB libraries, this macro doesn't support a context parameter,
+ so if you need to pass a context in to the allocator, you'll have to
+ store it in a global or a thread-local variable.
+
+
+ Revision history:
+ 0.10 (2015-10-22) initial version
+
+ ============================ Contributors =========================
+
+ Andreas Mantler (ands)
+
+License:
+ This software is in the public domain. Where that dedication is not
+ recognized, you are granted a perpetual, irrevocable license to copy
+ and modify this file however you want.
+
+*/
+
+#ifndef S2O_INCLUDE_SPROUTLINE_H
+#define S2O_INCLUDE_SPROUTLINE_H
+
+// DOCUMENTATION
+//
+// Limitations:
+// - currently only works with images that have alpha channels
+//
+// Basic usage (with stb_image):
+// int w, h, n, l;
+// unsigned char *rgba = stbi_load(filename, &w, &h, &n, 4);
+// unsigned char *alpha = s2o_rgba_to_alpha(rgba, w, h);
+// unsigned char *thresholded = s2o_alpha_to_thresholded(alpha, w, h, ALPHA_THRESHOLD);
+// unsigned char *outlined = s2o_thresholded_to_outlined(thresholded, w, h);
+// s2o_point *outline = s2o_extract_outline_path(outlined, w, h, &l, 0);
+// while(l)
+// {
+// s2o_distance_based_path_simplification(outline, &l, DISTANCE_THRESHOLD);
+// // ... process outline here ...
+// // ... l = number of points in outline
+// // ... ALPHA_THRESHOLD = 1..255 (the min value to be considered solid)
+// // ... DISTANCE_THRESHOLD = 0.0f..Inf (~0.5f is a suitable value)
+// // ... a greater value results in fewer points in the output
+//
+// outline = s2o_extract_outline_path(outlined, w, h, &l, outline);
+// };
+// free(outline);
+// free(outlined);
+// free(thresholded);
+// free(alpha);
+// free(rgba);
+//
+// s2o_rgba_to_alpha:
+// Expects an 'unsigned char *' to memory of w * h 4-byte pixels in 'RGBA' order.
+// The return value is an 'unsigned char *' to memory of w * h 1-byte pixel alpha components.
+//
+// s2o_alpha_to_thresholded:
+// Expects an 'unsigned char *' to memory of w * h 1-byte pixel alpha components.
+// The return value is an 'unsigned char *' to memory of w * h 1-byte values
+// that are 255 if the corresponding input is >= the specified threshold, otherwise 0.
+//
+// s2o_thresholded_to_outlined:
+// Expects an 'unsigned char *' to memory of w * h 1-byte pixels indicating their solidity {0, nonzero}.
+// The return value is an 'unsigned char *' to memory of w * h 1-byte pixels that indicate if the
+// corresponding input value is part of an outline (= is solid and has a non-solid neighbour).
+//
+// s2o_extract_outline_path:
+// Expects an 'unsigned char *' to memory of w * h 1-byte pixels indicating their outline membership.
+// The return value is an 's2o_point *' to memory of l s2o_point values consisting of a short x and y value.
+// The procedure scans the input data from top to bottom and starts extracting the first outline it finds.
+// The pixels corresponding to the extracted outline are set to 0 in the input, so that a subsequent call to
+// s2o_extract_outline_path extracts a different outline.
+// The length is set to 0 if no outline was found.
+//
+// s2o_distance_based_path_simplification:
+// Expects an 's2o_point *' to memory of l outline points.
+// The procedure throws out points in place that lie on or close to linear sections of the outline.
+// The distanceThreshold parameter specifies the min distance value for points to remain in the outline.
+//
+// ===========================================================================
+//
+// Philosophy
+//
+// This library is designed with the stb philosophy in mind.
+// stb libraries are designed with the following priorities:
+//
+// 1. easy to use
+// 2. easy to maintain
+// 3. good performance
+//
+// Some secondary priorities arise directly from the first two, some of which
+// make more explicit reasons why performance can't be emphasized.
+//
+// - Portable ("ease of use")
+// - Small footprint ("easy to maintain")
+// - No dependencies ("ease of use")
+//
+
+typedef unsigned char s2o_uc;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef S2O_STATIC
+#define S2ODEF static
+#else
+#define S2ODEF extern
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PRIMARY API
+//
+
+S2ODEF s2o_uc * s2o_rgba_to_alpha (const s2o_uc *data, int w, int h);
+S2ODEF s2o_uc * s2o_alpha_to_thresholded (const s2o_uc *data, int w, int h, s2o_uc threshold);
+S2ODEF s2o_uc * s2o_thresholded_to_outlined(const s2o_uc *data, int w, int h);
+
+typedef struct { short x, y; } s2o_point;
+S2ODEF s2o_point * s2o_extract_outline_path(s2o_uc *data, int w, int h, int *point_count, s2o_point *reusable_outline);
+S2ODEF void s2o_distance_based_path_simplification(s2o_point *outline, int *outline_length, float distance_threshold);
+
+#ifdef __cplusplus
+}
+#endif
+
+//
+//
+//// end header file /////////////////////////////////////////////////////
+#endif // S2O_INCLUDE_SPROUTLINE_H
+
+#ifdef S2O_IMPLEMENTATION
+
+#include // sqrtf, abs
+
+#ifndef S2O_MALLOC
+#include // malloc
+#define S2O_MALLOC(sz) malloc(sz)
+#endif
+
+///////////////////////////////////////////////
+//
+// locally used types
+
+typedef int s2o_bool;
+
+// 2d point type helpers
+#define S2O_POINT_ADD(result, a, b) { (result).x = (a).x + (b).x; (result).y = (a).y + (b).y; }
+#define S2O_POINT_SUB(result, a, b) { (result).x = (a).x - (b).x; (result).y = (a).y - (b).y; }
+#define S2O_POINT_IS_INSIDE(a, w, h) ((a).x >= 0 && (a).y >= 0 && (a).x < (w) && (a).y < (h))
+#define S2O_POINT_IS_NEXT_TO(a, b) ((a).x - (b).x <= 1 && (a).x - (b).x >= -1 && (a).y - (b).y <= 1 && (a).y - (b).y >= -1)
+
+// direction type
+typedef int s2o_direction; // 8 cw directions: >, _|, v, |_, <, |", ^, "|
+#define S2O_DIRECTION_OPPOSITE(dir) ((dir + 4) & 7)
+static const s2o_point s2o_direction_to_pixel_offset[] = { {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1} };
+
+// image manipulation functions
+S2ODEF s2o_uc * s2o_rgba_to_alpha(const s2o_uc *data, int w, int h)
+{
+ s2o_uc *result = (s2o_uc*)S2O_MALLOC(w * h);
+ int x, y;
+ for (y = 0; y < h; y++)
+ for (x = 0; x < w; x++)
+ result[y * w + x] = data[(y * w + x) * 4 + 3];
+ return result;
+}
+
+S2ODEF s2o_uc * s2o_alpha_to_thresholded(const s2o_uc *data, int w, int h, s2o_uc threshold)
+{
+ s2o_uc *result = (s2o_uc*)S2O_MALLOC(w * h);
+ int x, y;
+ for (y = 0; y < h; y++)
+ for (x = 0; x < w; x++)
+ result[y * w + x] = data[y * w + x] >= threshold ? 255 : 0;
+ return result;
+}
+
+S2ODEF s2o_uc * s2o_dilate_thresholded(const s2o_uc *data, int w, int h)
+{
+ int x, y, dx, dy, cx, cy;
+ s2o_uc *result = (s2o_uc*)S2O_MALLOC(w * h);
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ result[y * w + x] = 0;
+ for (dy = -1; dy <= 1; dy++)
+ {
+ for (dx = -1; dx <= 1; dx++)
+ {
+ cx = x + dx;
+ cy = y + dy;
+ if (cx >= 0 && cx < w && cy >= 0 && cy < h)
+ {
+ if (data[cy * w + cx])
+ {
+ result[y * w + x] = 255;
+ dy = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+S2ODEF s2o_uc * s2o_thresholded_to_outlined(const s2o_uc *data, int w, int h)
+{
+ s2o_uc *result = (s2o_uc*)S2O_MALLOC(w * h);
+ int x, y;
+ for (x = 0; x < w; x++)
+ {
+ result[x] = data[x];
+ result[(h - 1) * w + x] = data[(h - 1) * w + x];
+ }
+ for (y = 1; y < h - 1; y++)
+ {
+ result[y * w] = data[y * w];
+ for (x = 1; x < w - 1; x++)
+ {
+ if (data[y * w + x] &&
+ (
+ !data[y * w + x - 1] ||
+ !data[y * w + x + 1] ||
+ !data[y * w + x - w] ||
+ !data[y * w + x + w]
+ ))
+ {
+ result[y * w + x] = 255;
+ }
+ else
+ {
+ result[y * w + x] = 0;
+ }
+ }
+ result[y * w + w - 1] = data[y * w + w - 1];
+ }
+ return result;
+}
+
+// outline path procedures
+static s2o_bool s2o_find_first_filled_pixel(const s2o_uc *data, int w, int h, s2o_point *first)
+{
+ int x, y;
+ for (y = 0; y < h; y++)
+ {
+ for (x = 0; x < w; x++)
+ {
+ if (data[y * w + x])
+ {
+ first->x = (short)x;
+ first->y = (short)y;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static s2o_bool s2o_find_next_filled_pixel(const s2o_uc *data, int w, int h, s2o_point current, s2o_direction *dir, s2o_point *next)
+{
+ // turn around 180°, then make a clockwise scan for a filled pixel
+ *dir = S2O_DIRECTION_OPPOSITE(*dir);
+ int i;
+ for (i = 0; i < 8; i++)
+ {
+ S2O_POINT_ADD(*next, current, s2o_direction_to_pixel_offset[*dir]);
+
+ if (S2O_POINT_IS_INSIDE(*next, w, h) && data[next->y * w + next->x])
+ return 1;
+
+ // move to next angle (clockwise)
+ *dir = *dir - 1;
+ if (*dir < 0)
+ *dir = 7;
+ }
+ return 0;
+}
+
+S2ODEF s2o_point * s2o_extract_outline_path(s2o_uc *data, int w, int h, int *point_count, s2o_point *reusable_outline)
+{
+ s2o_point *outline = reusable_outline;
+ if (!outline)
+ outline = (s2o_point*)S2O_MALLOC(w * h * sizeof(s2o_point));
+
+ s2o_point current, next;
+
+restart:
+ if (!s2o_find_first_filled_pixel(data, w, h, ¤t))
+ {
+ *point_count = 0;
+ return outline;
+ }
+
+ int count = 0;
+ s2o_direction dir = 0;
+
+ while(S2O_POINT_IS_INSIDE(current, w, h) && count < (w*h)) //< @r-lyeh: buffer overflow: add count= 0 && count < (w * h); prev--) //< @r-lyeh: buffer overflow: add count 1; l--)
+ {
+ int a, b = l;
+ for (a = 0; a < length; a++)
+ {
+ s2o_point ab;
+ S2O_POINT_SUB(ab, outline[b], outline[a]);
+ float lab = sqrtf((float)(ab.x * ab.x + ab.y * ab.y));
+ float ilab = 1.0f / lab;
+ float abnx = ab.x * ilab, abny = ab.y * ilab;
+
+ if (lab != 0.0f)
+ {
+ s2o_bool found = 1;
+ int i = (a + 1) % length;
+ while (i != b)
+ {
+ s2o_point ai;
+ S2O_POINT_SUB(ai, outline[i], outline[a]);
+ float t = (abnx * ai.x + abny * ai.y) * ilab;
+ float distance = -abny * ai.x + abnx * ai.y;
+ if (t < 0.0f || t > 1.0f || distance > distance_threshold || -distance > distance_threshold)
+ {
+ found = 0;
+ break;
+ }
+
+ if (++i == length)
+ i = 0;
+ }
+
+ if (found)
+ {
+ int i;
+ if (a < b)
+ {
+ for (i = 0; i < length - b; i++)
+ outline[a + i + 1] = outline[b + i];
+ length -= b - a - 1;
+ }
+ else
+ {
+ length = a - b + 1;
+ for (i = 0; i < length; i++)
+ outline[i] = outline[b + i];
+ }
+ if (l >= length)
+ l = length - 1;
+ }
+ }
+
+ if (++b >= length)
+ b = 0;
+ }
+ }
+ *outline_length = length;
+}
+
+#endif // S2O_IMPLEMENTATION
diff --git a/tools/3rd_stb_image_resize.h b/tools/3rd_stb_image_resize.h
new file mode 100644
index 0000000..4ed5b16
--- /dev/null
+++ b/tools/3rd_stb_image_resize.h
@@ -0,0 +1,2634 @@
+/* stb_image_resize - v0.97 - public domain image resizing
+ by Jorge L Rodriguez (@VinoBS) - 2014
+ http://github.com/nothings/stb
+
+ Written with emphasis on usability, portability, and efficiency. (No
+ SIMD or threads, so it be easily outperformed by libs that use those.)
+ Only scaling and translation is supported, no rotations or shears.
+ Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation.
+
+ COMPILING & LINKING
+ In one C/C++ file that #includes this file, do this:
+ #define STB_IMAGE_RESIZE_IMPLEMENTATION
+ before the #include. That will create the implementation in that file.
+
+ QUICKSTART
+ stbir_resize_uint8( input_pixels , in_w , in_h , 0,
+ output_pixels, out_w, out_h, 0, num_channels)
+ stbir_resize_float(...)
+ stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0,
+ output_pixels, out_w, out_h, 0,
+ num_channels , alpha_chan , 0)
+ stbir_resize_uint8_srgb_edgemode(
+ input_pixels , in_w , in_h , 0,
+ output_pixels, out_w, out_h, 0,
+ num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP)
+ // WRAP/REFLECT/ZERO
+
+ FULL API
+ See the "header file" section of the source for API documentation.
+
+ ADDITIONAL DOCUMENTATION
+
+ SRGB & FLOATING POINT REPRESENTATION
+ The sRGB functions presume IEEE floating point. If you do not have
+ IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use
+ a slower implementation.
+
+ MEMORY ALLOCATION
+ The resize functions here perform a single memory allocation using
+ malloc. To control the memory allocation, before the #include that
+ triggers the implementation, do:
+
+ #define STBIR_MALLOC(size,context) ...
+ #define STBIR_FREE(ptr,context) ...
+
+ Each resize function makes exactly one call to malloc/free, so to use
+ temp memory, store the temp memory in the context and return that.
+
+ ASSERT
+ Define STBIR_ASSERT(boolval) to override assert() and not use assert.h
+
+ OPTIMIZATION
+ Define STBIR_SATURATE_INT to compute clamp values in-range using
+ integer operations instead of float operations. This may be faster
+ on some platforms.
+
+ DEFAULT FILTERS
+ For functions which don't provide explicit control over what filters
+ to use, you can change the compile-time defaults with
+
+ #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something
+ #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something
+
+ See stbir_filter in the header-file section for the list of filters.
+
+ NEW FILTERS
+ A number of 1D filter kernels are used. For a list of
+ supported filters see the stbir_filter enum. To add a new filter,
+ write a filter function and add it to stbir__filter_info_table.
+
+ PROGRESS
+ For interactive use with slow resize operations, you can install
+ a progress-report callback:
+
+ #define STBIR_PROGRESS_REPORT(val) some_func(val)
+
+ The parameter val is a float which goes from 0 to 1 as progress is made.
+
+ For example:
+
+ static void my_progress_report(float progress);
+ #define STBIR_PROGRESS_REPORT(val) my_progress_report(val)
+
+ #define STB_IMAGE_RESIZE_IMPLEMENTATION
+ #include "stb_image_resize.h"
+
+ static void my_progress_report(float progress)
+ {
+ printf("Progress: %f%%\n", progress*100);
+ }
+
+ MAX CHANNELS
+ If your image has more than 64 channels, define STBIR_MAX_CHANNELS
+ to the max you'll have.
+
+ ALPHA CHANNEL
+ Most of the resizing functions provide the ability to control how
+ the alpha channel of an image is processed. The important things
+ to know about this:
+
+ 1. The best mathematically-behaved version of alpha to use is
+ called "premultiplied alpha", in which the other color channels
+ have had the alpha value multiplied in. If you use premultiplied
+ alpha, linear filtering (such as image resampling done by this
+ library, or performed in texture units on GPUs) does the "right
+ thing". While premultiplied alpha is standard in the movie CGI
+ industry, it is still uncommon in the videogame/real-time world.
+
+ If you linearly filter non-premultiplied alpha, strange effects
+ occur. (For example, the 50/50 average of 99% transparent bright green
+ and 1% transparent black produces 50% transparent dark green when
+ non-premultiplied, whereas premultiplied it produces 50%
+ transparent near-black. The former introduces green energy
+ that doesn't exist in the source image.)
+
+ 2. Artists should not edit premultiplied-alpha images; artists
+ want non-premultiplied alpha images. Thus, art tools generally output
+ non-premultiplied alpha images.
+
+ 3. You will get best results in most cases by converting images
+ to premultiplied alpha before processing them mathematically.
+
+ 4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the
+ resizer does not do anything special for the alpha channel;
+ it is resampled identically to other channels. This produces
+ the correct results for premultiplied-alpha images, but produces
+ less-than-ideal results for non-premultiplied-alpha images.
+
+ 5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED,
+ then the resizer weights the contribution of input pixels
+ based on their alpha values, or, equivalently, it multiplies
+ the alpha value into the color channels, resamples, then divides
+ by the resultant alpha value. Input pixels which have alpha=0 do
+ not contribute at all to output pixels unless _all_ of the input
+ pixels affecting that output pixel have alpha=0, in which case
+ the result for that pixel is the same as it would be without
+ STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for
+ input images in integer formats. For input images in float format,
+ input pixels with alpha=0 have no effect, and output pixels
+ which have alpha=0 will be 0 in all channels. (For float images,
+ you can manually achieve the same result by adding a tiny epsilon
+ value to the alpha channel of every image, and then subtracting
+ or clamping it at the end.)
+
+ 6. You can suppress the behavior described in #5 and make
+ all-0-alpha pixels have 0 in all channels by #defining
+ STBIR_NO_ALPHA_EPSILON.
+
+ 7. You can separately control whether the alpha channel is
+ interpreted as linear or affected by the colorspace. By default
+ it is linear; you almost never want to apply the colorspace.
+ (For example, graphics hardware does not apply sRGB conversion
+ to the alpha channel.)
+
+ CONTRIBUTORS
+ Jorge L Rodriguez: Implementation
+ Sean Barrett: API design, optimizations
+ Aras Pranckevicius: bugfix
+ Nathan Reed: warning fixes
+
+ REVISIONS
+ 0.97 (2020-02-02) fixed warning
+ 0.96 (2019-03-04) fixed warnings
+ 0.95 (2017-07-23) fixed warnings
+ 0.94 (2017-03-18) fixed warnings
+ 0.93 (2017-03-03) fixed bug with certain combinations of heights
+ 0.92 (2017-01-02) fix integer overflow on large (>2GB) images
+ 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
+ 0.90 (2014-09-17) first released version
+
+ LICENSE
+ See end of file for license information.
+
+ TODO
+ Don't decode all of the image data when only processing a partial tile
+ Don't use full-width decode buffers when only processing a partial tile
+ When processing wide images, break processing into tiles so data fits in L1 cache
+ Installable filters?
+ Resize that respects alpha test coverage
+ (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage:
+ https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp )
+*/
+
+#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H
+#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H
+
+#ifdef _MSC_VER
+typedef unsigned char stbir_uint8;
+typedef unsigned short stbir_uint16;
+typedef unsigned int stbir_uint32;
+#else
+#include
+typedef uint8_t stbir_uint8;
+typedef uint16_t stbir_uint16;
+typedef uint32_t stbir_uint32;
+#endif
+
+#ifndef STBIRDEF
+#ifdef STB_IMAGE_RESIZE_STATIC
+#define STBIRDEF static
+#else
+#ifdef __cplusplus
+#define STBIRDEF extern "C"
+#else
+#define STBIRDEF extern
+#endif
+#endif
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Easy-to-use API:
+//
+// * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4)
+// * input_w is input image width (x-axis), input_h is input image height (y-axis)
+// * stride is the offset between successive rows of image data in memory, in bytes. you can
+// specify 0 to mean packed continuously in memory
+// * alpha channel is treated identically to other channels.
+// * colorspace is linear or sRGB as specified by function name
+// * returned result is 1 for success or 0 in case of an error.
+// #define STBIR_ASSERT() to trigger an assert on parameter validation errors.
+// * Memory required grows approximately linearly with input and output size, but with
+// discontinuities at input_w == output_w and input_h == output_h.
+// * These functions use a "default" resampling filter defined at compile time. To change the filter,
+// you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE
+// and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API.
+
+STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels);
+
+STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels);
+
+
+// The following functions interpret image data as gamma-corrected sRGB.
+// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
+// or otherwise provide the index of the alpha channel. Flags value
+// of 0 will probably do the right thing if you're not sure what
+// the flags mean.
+
+#define STBIR_ALPHA_CHANNEL_NONE -1
+
+// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will
+// use alpha-weighted resampling (effectively premultiplying, resampling,
+// then unpremultiplying).
+#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0)
+// The specified alpha channel should be handled as gamma-corrected value even
+// when doing sRGB operations.
+#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1)
+
+STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags);
+
+
+typedef enum
+{
+ STBIR_EDGE_CLAMP = 1,
+ STBIR_EDGE_REFLECT = 2,
+ STBIR_EDGE_WRAP = 3,
+ STBIR_EDGE_ZERO = 4,
+} stbir_edge;
+
+// This function adds the ability to specify how requests to sample off the edge of the image are handled.
+STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode);
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Medium-complexity API
+//
+// This extends the easy-to-use API as follows:
+//
+// * Alpha-channel can be processed separately
+// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
+// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
+// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)
+// * Filter can be selected explicitly
+// * uint16 image type
+// * sRGB colorspace available for all types
+// * context parameter for passing to STBIR_MALLOC
+
+typedef enum
+{
+ STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses
+ STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
+ STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering
+ STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
+ STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline
+ STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3
+} stbir_filter;
+
+typedef enum
+{
+ STBIR_COLORSPACE_LINEAR,
+ STBIR_COLORSPACE_SRGB,
+
+ STBIR_MAX_COLORSPACES,
+} stbir_colorspace;
+
+// The following functions are all identical except for the type of the image data
+
+STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
+ void *alloc_context);
+
+STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
+ void *alloc_context);
+
+STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
+ void *alloc_context);
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Full-complexity API
+//
+// This extends the medium API as follows:
+//
+// * uint32 image type
+// * not typesafe
+// * separate filter types for each axis
+// * separate edge modes for each axis
+// * can specify scale explicitly for subpixel correctness
+// * can specify image source tile using texture coordinates
+
+typedef enum
+{
+ STBIR_TYPE_UINT8 ,
+ STBIR_TYPE_UINT16,
+ STBIR_TYPE_UINT32,
+ STBIR_TYPE_FLOAT ,
+
+ STBIR_MAX_TYPES
+} stbir_datatype;
+
+STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ stbir_datatype datatype,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
+ stbir_filter filter_horizontal, stbir_filter filter_vertical,
+ stbir_colorspace space, void *alloc_context);
+
+STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ stbir_datatype datatype,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
+ stbir_filter filter_horizontal, stbir_filter filter_vertical,
+ stbir_colorspace space, void *alloc_context,
+ float x_scale, float y_scale,
+ float x_offset, float y_offset);
+
+STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ stbir_datatype datatype,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
+ stbir_filter filter_horizontal, stbir_filter filter_vertical,
+ stbir_colorspace space, void *alloc_context,
+ float s0, float t0, float s1, float t1);
+// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use.
+
+//
+//
+//// end header file /////////////////////////////////////////////////////
+#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H
+
+
+
+
+
+#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION
+
+#ifndef STBIR_ASSERT
+#include
+#define STBIR_ASSERT(x) assert(x)
+#endif
+
+// For memset
+#include
+
+#include
+
+#ifndef STBIR_MALLOC
+#include
+// use comma operator to evaluate c, to avoid "unused parameter" warnings
+#define STBIR_MALLOC(size,c) ((void)(c), malloc(size))
+#define STBIR_FREE(ptr,c) ((void)(c), free(ptr))
+#endif
+
+#ifndef _MSC_VER
+#ifdef __cplusplus
+#define stbir__inline inline
+#else
+#define stbir__inline
+#endif
+#else
+#define stbir__inline __forceinline
+#endif
+
+
+// should produce compiler error if size is wrong
+typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1];
+
+#ifdef _MSC_VER
+#define STBIR__NOTUSED(v) (void)(v)
+#else
+#define STBIR__NOTUSED(v) (void)sizeof(v)
+#endif
+
+#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))
+
+#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE
+#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
+#endif
+
+#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE
+#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
+#endif
+
+#ifndef STBIR_PROGRESS_REPORT
+#define STBIR_PROGRESS_REPORT(float_0_to_1)
+#endif
+
+#ifndef STBIR_MAX_CHANNELS
+#define STBIR_MAX_CHANNELS 64
+#endif
+
+#if STBIR_MAX_CHANNELS > 65536
+#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536."
+// because we store the indices in 16-bit variables
+#endif
+
+// This value is added to alpha just before premultiplication to avoid
+// zeroing out color values. It is equivalent to 2^-80. If you don't want
+// that behavior (it may interfere if you have floating point images with
+// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to
+// disable it.
+#ifndef STBIR_ALPHA_EPSILON
+#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
+#endif
+
+
+
+#ifdef _MSC_VER
+#define STBIR__UNUSED_PARAM(v) (void)(v)
+#else
+#define STBIR__UNUSED_PARAM(v) (void)sizeof(v)
+#endif
+
+// must match stbir_datatype
+static unsigned char stbir__type_size[] = {
+ 1, // STBIR_TYPE_UINT8
+ 2, // STBIR_TYPE_UINT16
+ 4, // STBIR_TYPE_UINT32
+ 4, // STBIR_TYPE_FLOAT
+};
+
+// Kernel function centered at 0
+typedef float (stbir__kernel_fn)(float x, float scale);
+typedef float (stbir__support_fn)(float scale);
+
+typedef struct
+{
+ stbir__kernel_fn* kernel;
+ stbir__support_fn* support;
+} stbir__filter_info;
+
+// When upsampling, the contributors are which source pixels contribute.
+// When downsampling, the contributors are which destination pixels are contributed to.
+typedef struct
+{
+ int n0; // First contributing pixel
+ int n1; // Last contributing pixel
+} stbir__contributors;
+
+typedef struct
+{
+ const void* input_data;
+ int input_w;
+ int input_h;
+ int input_stride_bytes;
+
+ void* output_data;
+ int output_w;
+ int output_h;
+ int output_stride_bytes;
+
+ float s0, t0, s1, t1;
+
+ float horizontal_shift; // Units: output pixels
+ float vertical_shift; // Units: output pixels
+ float horizontal_scale;
+ float vertical_scale;
+
+ int channels;
+ int alpha_channel;
+ stbir_uint32 flags;
+ stbir_datatype type;
+ stbir_filter horizontal_filter;
+ stbir_filter vertical_filter;
+ stbir_edge edge_horizontal;
+ stbir_edge edge_vertical;
+ stbir_colorspace colorspace;
+
+ stbir__contributors* horizontal_contributors;
+ float* horizontal_coefficients;
+
+ stbir__contributors* vertical_contributors;
+ float* vertical_coefficients;
+
+ int decode_buffer_pixels;
+ float* decode_buffer;
+
+ float* horizontal_buffer;
+
+ // cache these because ceil/floor are inexplicably showing up in profile
+ int horizontal_coefficient_width;
+ int vertical_coefficient_width;
+ int horizontal_filter_pixel_width;
+ int vertical_filter_pixel_width;
+ int horizontal_filter_pixel_margin;
+ int vertical_filter_pixel_margin;
+ int horizontal_num_contributors;
+ int vertical_num_contributors;
+
+ int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
+ int ring_buffer_num_entries; // Total number of entries in the ring buffer.
+ int ring_buffer_first_scanline;
+ int ring_buffer_last_scanline;
+ int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer
+ float* ring_buffer;
+
+ float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
+
+ int horizontal_contributors_size;
+ int horizontal_coefficients_size;
+ int vertical_contributors_size;
+ int vertical_coefficients_size;
+ int decode_buffer_size;
+ int horizontal_buffer_size;
+ int ring_buffer_size;
+ int encode_buffer_size;
+} stbir__info;
+
+
+static const float stbir__max_uint8_as_float = 255.0f;
+static const float stbir__max_uint16_as_float = 65535.0f;
+static const double stbir__max_uint32_as_float = 4294967295.0;
+
+
+static stbir__inline int stbir__min(int a, int b)
+{
+ return a < b ? a : b;
+}
+
+static stbir__inline float stbir__saturate(float x)
+{
+ if (x < 0)
+ return 0;
+
+ if (x > 1)
+ return 1;
+
+ return x;
+}
+
+#ifdef STBIR_SATURATE_INT
+static stbir__inline stbir_uint8 stbir__saturate8(int x)
+{
+ if ((unsigned int) x <= 255)
+ return x;
+
+ if (x < 0)
+ return 0;
+
+ return 255;
+}
+
+static stbir__inline stbir_uint16 stbir__saturate16(int x)
+{
+ if ((unsigned int) x <= 65535)
+ return x;
+
+ if (x < 0)
+ return 0;
+
+ return 65535;
+}
+#endif
+
+static float stbir__srgb_uchar_to_linear_float[256] = {
+ 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
+ 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,
+ 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f,
+ 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f,
+ 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f,
+ 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f,
+ 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f,
+ 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,
+ 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f,
+ 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f,
+ 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f,
+ 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f,
+ 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f,
+ 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f,
+ 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,
+ 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f,
+ 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f,
+ 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f,
+ 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f,
+ 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f,
+ 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f,
+ 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,
+ 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f,
+ 0.982251f, 0.991102f, 1.0f
+};
+
+static float stbir__srgb_to_linear(float f)
+{
+ if (f <= 0.04045f)
+ return f / 12.92f;
+ else
+ return (float)pow((f + 0.055f) / 1.055f, 2.4f);
+}
+
+static float stbir__linear_to_srgb(float f)
+{
+ if (f <= 0.0031308f)
+ return f * 12.92f;
+ else
+ return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f;
+}
+
+#ifndef STBIR_NON_IEEE_FLOAT
+// From https://gist.github.com/rygorous/2203834
+
+typedef union
+{
+ stbir_uint32 u;
+ float f;
+} stbir__FP32;
+
+static const stbir_uint32 fp32_to_srgb8_tab4[104] = {
+ 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
+ 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
+ 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
+ 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
+ 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
+ 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
+ 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
+ 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
+ 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
+ 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
+ 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
+ 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
+ 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
+};
+
+static stbir_uint8 stbir__linear_to_srgb_uchar(float in)
+{
+ static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps
+ static const stbir__FP32 minval = { (127-13) << 23 };
+ stbir_uint32 tab,bias,scale,t;
+ stbir__FP32 f;
+
+ // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
+ // The tests are carefully written so that NaNs map to 0, same as in the reference
+ // implementation.
+ if (!(in > minval.f)) // written this way to catch NaNs
+ in = minval.f;
+ if (in > almostone.f)
+ in = almostone.f;
+
+ // Do the table lookup and unpack bias, scale
+ f.f = in;
+ tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];
+ bias = (tab >> 16) << 9;
+ scale = tab & 0xffff;
+
+ // Grab next-highest mantissa bits and perform linear interpolation
+ t = (f.u >> 12) & 0xff;
+ return (unsigned char) ((bias + scale*t) >> 16);
+}
+
+#else
+// sRGB transition values, scaled by 1<<28
+static int stbir__srgb_offset_to_linear_scaled[256] =
+{
+ 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603,
+ 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926,
+ 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148,
+ 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856,
+ 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731,
+ 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369,
+ 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021,
+ 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073,
+ 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389,
+ 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552,
+ 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066,
+ 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490,
+ 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568,
+ 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316,
+ 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096,
+ 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700,
+ 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376,
+ 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912,
+ 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648,
+ 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512,
+ 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072,
+ 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544,
+ 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832,
+ 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528,
+ 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968,
+ 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184,
+ 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992,
+ 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968,
+ 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480,
+ 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656,
+ 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464,
+ 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664,
+};
+
+static stbir_uint8 stbir__linear_to_srgb_uchar(float f)
+{
+ int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp
+ int v = 0;
+ int i;
+
+ // Refine the guess with a short binary search.
+ i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+ i = v + 1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
+
+ return (stbir_uint8) v;
+}
+#endif
+
+static float stbir__filter_trapezoid(float x, float scale)
+{
+ float halfscale = scale / 2;
+ float t = 0.5f + halfscale;
+ STBIR_ASSERT(scale <= 1);
+
+ x = (float)fabs(x);
+
+ if (x >= t)
+ return 0;
+ else
+ {
+ float r = 0.5f - halfscale;
+ if (x <= r)
+ return 1;
+ else
+ return (t - x) / scale;
+ }
+}
+
+static float stbir__support_trapezoid(float scale)
+{
+ STBIR_ASSERT(scale <= 1);
+ return 0.5f + scale / 2;
+}
+
+static float stbir__filter_triangle(float x, float s)
+{
+ STBIR__UNUSED_PARAM(s);
+
+ x = (float)fabs(x);
+
+ if (x <= 1.0f)
+ return 1 - x;
+ else
+ return 0;
+}
+
+static float stbir__filter_cubic(float x, float s)
+{
+ STBIR__UNUSED_PARAM(s);
+
+ x = (float)fabs(x);
+
+ if (x < 1.0f)
+ return (4 + x*x*(3*x - 6))/6;
+ else if (x < 2.0f)
+ return (8 + x*(-12 + x*(6 - x)))/6;
+
+ return (0.0f);
+}
+
+static float stbir__filter_catmullrom(float x, float s)
+{
+ STBIR__UNUSED_PARAM(s);
+
+ x = (float)fabs(x);
+
+ if (x < 1.0f)
+ return 1 - x*x*(2.5f - 1.5f*x);
+ else if (x < 2.0f)
+ return 2 - x*(4 + x*(0.5f*x - 2.5f));
+
+ return (0.0f);
+}
+
+static float stbir__filter_mitchell(float x, float s)
+{
+ STBIR__UNUSED_PARAM(s);
+
+ x = (float)fabs(x);
+
+ if (x < 1.0f)
+ return (16 + x*x*(21 * x - 36))/18;
+ else if (x < 2.0f)
+ return (32 + x*(-60 + x*(36 - 7*x)))/18;
+
+ return (0.0f);
+}
+
+static float stbir__support_zero(float s)
+{
+ STBIR__UNUSED_PARAM(s);
+ return 0;
+}
+
+static float stbir__support_one(float s)
+{
+ STBIR__UNUSED_PARAM(s);
+ return 1;
+}
+
+static float stbir__support_two(float s)
+{
+ STBIR__UNUSED_PARAM(s);
+ return 2;
+}
+
+static stbir__filter_info stbir__filter_info_table[] = {
+ { NULL, stbir__support_zero },
+ { stbir__filter_trapezoid, stbir__support_trapezoid },
+ { stbir__filter_triangle, stbir__support_one },
+ { stbir__filter_cubic, stbir__support_two },
+ { stbir__filter_catmullrom, stbir__support_two },
+ { stbir__filter_mitchell, stbir__support_two },
+};
+
+stbir__inline static int stbir__use_upsampling(float ratio)
+{
+ return ratio > 1;
+}
+
+stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info)
+{
+ return stbir__use_upsampling(stbir_info->horizontal_scale);
+}
+
+stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info)
+{
+ return stbir__use_upsampling(stbir_info->vertical_scale);
+}
+
+// This is the maximum number of input samples that can affect an output sample
+// with the given filter
+static int stbir__get_filter_pixel_width(stbir_filter filter, float scale)
+{
+ STBIR_ASSERT(filter != 0);
+ STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
+
+ if (stbir__use_upsampling(scale))
+ return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2);
+ else
+ return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale);
+}
+
+// This is how much to expand buffers to account for filters seeking outside
+// the image boundaries.
+static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale)
+{
+ return stbir__get_filter_pixel_width(filter, scale) / 2;
+}
+
+static int stbir__get_coefficient_width(stbir_filter filter, float scale)
+{
+ if (stbir__use_upsampling(scale))
+ return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2);
+ else
+ return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2);
+}
+
+static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size)
+{
+ if (stbir__use_upsampling(scale))
+ return output_size;
+ else
+ return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2);
+}
+
+static int stbir__get_total_horizontal_coefficients(stbir__info* info)
+{
+ return info->horizontal_num_contributors
+ * stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale);
+}
+
+static int stbir__get_total_vertical_coefficients(stbir__info* info)
+{
+ return info->vertical_num_contributors
+ * stbir__get_coefficient_width (info->vertical_filter, info->vertical_scale);
+}
+
+static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n)
+{
+ return &contributors[n];
+}
+
+// For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample,
+// if you change it here change it there too.
+static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c)
+{
+ int width = stbir__get_coefficient_width(filter, scale);
+ return &coefficients[width*n + c];
+}
+
+static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max)
+{
+ switch (edge)
+ {
+ case STBIR_EDGE_ZERO:
+ return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later
+
+ case STBIR_EDGE_CLAMP:
+ if (n < 0)
+ return 0;
+
+ if (n >= max)
+ return max - 1;
+
+ return n; // NOTREACHED
+
+ case STBIR_EDGE_REFLECT:
+ {
+ if (n < 0)
+ {
+ if (n < max)
+ return -n;
+ else
+ return max - 1;
+ }
+
+ if (n >= max)
+ {
+ int max2 = max * 2;
+ if (n >= max2)
+ return 0;
+ else
+ return max2 - n - 1;
+ }
+
+ return n; // NOTREACHED
+ }
+
+ case STBIR_EDGE_WRAP:
+ if (n >= 0)
+ return (n % max);
+ else
+ {
+ int m = (-n) % max;
+
+ if (m != 0)
+ m = max - m;
+
+ return (m);
+ }
+ // NOTREACHED
+
+ default:
+ STBIR_ASSERT(!"Unimplemented edge type");
+ return 0;
+ }
+}
+
+stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max)
+{
+ // avoid per-pixel switch
+ if (n >= 0 && n < max)
+ return n;
+ return stbir__edge_wrap_slow(edge, n, max);
+}
+
+// What input pixels contribute to this output pixel?
+static void stbir__calculate_sample_range_upsample(int n, float out_filter_radius, float scale_ratio, float out_shift, int* in_first_pixel, int* in_last_pixel, float* in_center_of_out)
+{
+ float out_pixel_center = (float)n + 0.5f;
+ float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius;
+ float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius;
+
+ float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio;
+ float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio;
+
+ *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio;
+ *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5));
+ *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5));
+}
+
+// What output pixels does this input pixel contribute to?
+static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radius, float scale_ratio, float out_shift, int* out_first_pixel, int* out_last_pixel, float* out_center_of_in)
+{
+ float in_pixel_center = (float)n + 0.5f;
+ float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius;
+ float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius;
+
+ float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift;
+ float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift;
+
+ *out_center_of_in = in_pixel_center * scale_ratio - out_shift;
+ *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5));
+ *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5));
+}
+
+static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group)
+{
+ int i;
+ float total_filter = 0;
+ float filter_scale;
+
+ STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
+
+ contributor->n0 = in_first_pixel;
+ contributor->n1 = in_last_pixel;
+
+ STBIR_ASSERT(contributor->n1 >= contributor->n0);
+
+ for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
+ {
+ float in_pixel_center = (float)(i + in_first_pixel) + 0.5f;
+ coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale);
+
+ // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.)
+ if (i == 0 && !coefficient_group[i])
+ {
+ contributor->n0 = ++in_first_pixel;
+ i--;
+ continue;
+ }
+
+ total_filter += coefficient_group[i];
+ }
+
+ // NOTE(fg): Not actually true in general, nor is there any reason to expect it should be.
+ // It would be true in exact math but is at best approximately true in floating-point math,
+ // and it would not make sense to try and put actual bounds on this here because it depends
+ // on the image aspect ratio which can get pretty extreme.
+ //STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
+
+ STBIR_ASSERT(total_filter > 0.9);
+ STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
+
+ // Make sure the sum of all coefficients is 1.
+ filter_scale = 1 / total_filter;
+
+ for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
+ coefficient_group[i] *= filter_scale;
+
+ for (i = in_last_pixel - in_first_pixel; i >= 0; i--)
+ {
+ if (coefficient_group[i])
+ break;
+
+ // This line has no weight. We can skip it.
+ contributor->n1 = contributor->n0 + i - 1;
+ }
+}
+
+static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group)
+{
+ int i;
+
+ STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
+
+ contributor->n0 = out_first_pixel;
+ contributor->n1 = out_last_pixel;
+
+ STBIR_ASSERT(contributor->n1 >= contributor->n0);
+
+ for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
+ {
+ float out_pixel_center = (float)(i + out_first_pixel) + 0.5f;
+ float x = out_pixel_center - out_center_of_in;
+ coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
+ }
+
+ // NOTE(fg): Not actually true in general, nor is there any reason to expect it should be.
+ // It would be true in exact math but is at best approximately true in floating-point math,
+ // and it would not make sense to try and put actual bounds on this here because it depends
+ // on the image aspect ratio which can get pretty extreme.
+ //STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
+
+ for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
+ {
+ if (coefficient_group[i])
+ break;
+
+ // This line has no weight. We can skip it.
+ contributor->n1 = contributor->n0 + i - 1;
+ }
+}
+
+static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size)
+{
+ int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
+ int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
+ int i, j;
+ int skip;
+
+ for (i = 0; i < output_size; i++)
+ {
+ float scale;
+ float total = 0;
+
+ for (j = 0; j < num_contributors; j++)
+ {
+ if (i >= contributors[j].n0 && i <= contributors[j].n1)
+ {
+ float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0);
+ total += coefficient;
+ }
+ else if (i < contributors[j].n0)
+ break;
+ }
+
+ STBIR_ASSERT(total > 0.9f);
+ STBIR_ASSERT(total < 1.1f);
+
+ scale = 1 / total;
+
+ for (j = 0; j < num_contributors; j++)
+ {
+ if (i >= contributors[j].n0 && i <= contributors[j].n1)
+ *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale;
+ else if (i < contributors[j].n0)
+ break;
+ }
+ }
+
+ // Optimize: Skip zero coefficients and contributions outside of image bounds.
+ // Do this after normalizing because normalization depends on the n0/n1 values.
+ for (j = 0; j < num_contributors; j++)
+ {
+ int range, max, width;
+
+ skip = 0;
+ while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0)
+ skip++;
+
+ contributors[j].n0 += skip;
+
+ while (contributors[j].n0 < 0)
+ {
+ contributors[j].n0++;
+ skip++;
+ }
+
+ range = contributors[j].n1 - contributors[j].n0 + 1;
+ max = stbir__min(num_coefficients, range);
+
+ width = stbir__get_coefficient_width(filter, scale_ratio);
+ for (i = 0; i < max; i++)
+ {
+ if (i + skip >= width)
+ break;
+
+ *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip);
+ }
+
+ continue;
+ }
+
+ // Using min to avoid writing into invalid pixels.
+ for (i = 0; i < num_contributors; i++)
+ contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1);
+}
+
+// Each scan line uses the same kernel values so we should calculate the kernel
+// values once and then we can use them for every scan line.
+static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
+{
+ int n;
+ int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
+
+ if (stbir__use_upsampling(scale_ratio))
+ {
+ float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio;
+
+ // Looping through out pixels
+ for (n = 0; n < total_contributors; n++)
+ {
+ float in_center_of_out; // Center of the current out pixel in the in pixel space
+ int in_first_pixel, in_last_pixel;
+
+ stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
+
+ stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
+ }
+ }
+ else
+ {
+ float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio;
+
+ // Looping through in pixels
+ for (n = 0; n < total_contributors; n++)
+ {
+ float out_center_of_in; // Center of the current out pixel in the in pixel space
+ int out_first_pixel, out_last_pixel;
+ int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio);
+
+ stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
+
+ stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
+ }
+
+ stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size);
+ }
+}
+
+static float* stbir__get_decode_buffer(stbir__info* stbir_info)
+{
+ // The 0 index of the decode buffer starts after the margin. This makes
+ // it okay to use negative indexes on the decode buffer.
+ return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels];
+}
+
+#define STBIR__DECODE(type, colorspace) ((int)(type) * (STBIR_MAX_COLORSPACES) + (int)(colorspace))
+
+static void stbir__decode_scanline(stbir__info* stbir_info, int n)
+{
+ int c;
+ int channels = stbir_info->channels;
+ int alpha_channel = stbir_info->alpha_channel;
+ int type = stbir_info->type;
+ int colorspace = stbir_info->colorspace;
+ int input_w = stbir_info->input_w;
+ size_t input_stride_bytes = stbir_info->input_stride_bytes;
+ float* decode_buffer = stbir__get_decode_buffer(stbir_info);
+ stbir_edge edge_horizontal = stbir_info->edge_horizontal;
+ stbir_edge edge_vertical = stbir_info->edge_vertical;
+ size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
+ const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset;
+ int max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
+ int decode = STBIR__DECODE(type, colorspace);
+
+ int x = -stbir_info->horizontal_filter_pixel_margin;
+
+ // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input,
+ // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO
+ if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h))
+ {
+ for (; x < max_x; x++)
+ for (c = 0; c < channels; c++)
+ decode_buffer[x*channels + c] = 0;
+ return;
+ }
+
+ switch (decode)
+ {
+ case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float;
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]];
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float;
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float;
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float);
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float;
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float);
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float));
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float);
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c];
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
+ for (; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+ int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
+ for (c = 0; c < channels; c++)
+ decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]);
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel];
+ }
+
+ break;
+
+ default:
+ STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
+ break;
+ }
+
+ if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED))
+ {
+ for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++)
+ {
+ int decode_pixel_index = x * channels;
+
+ // If the alpha value is 0 it will clobber the color values. Make sure it's not.
+ float alpha = decode_buffer[decode_pixel_index + alpha_channel];
+#ifndef STBIR_NO_ALPHA_EPSILON
+ if (stbir_info->type != STBIR_TYPE_FLOAT) {
+ alpha += STBIR_ALPHA_EPSILON;
+ decode_buffer[decode_pixel_index + alpha_channel] = alpha;
+ }
+#endif
+ for (c = 0; c < channels; c++)
+ {
+ if (c == alpha_channel)
+ continue;
+
+ decode_buffer[decode_pixel_index + c] *= alpha;
+ }
+ }
+ }
+
+ if (edge_horizontal == STBIR_EDGE_ZERO)
+ {
+ for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++)
+ {
+ for (c = 0; c < channels; c++)
+ decode_buffer[x*channels + c] = 0;
+ }
+ for (x = input_w; x < max_x; x++)
+ {
+ for (c = 0; c < channels; c++)
+ decode_buffer[x*channels + c] = 0;
+ }
+ }
+}
+
+static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length)
+{
+ return &ring_buffer[index * ring_buffer_length];
+}
+
+static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
+{
+ int ring_buffer_index;
+ float* ring_buffer;
+
+ stbir_info->ring_buffer_last_scanline = n;
+
+ if (stbir_info->ring_buffer_begin_index < 0)
+ {
+ ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
+ stbir_info->ring_buffer_first_scanline = n;
+ }
+ else
+ {
+ ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
+ STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
+ }
+
+ ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float));
+ memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
+
+ return ring_buffer;
+}
+
+
+static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer)
+{
+ int x, k;
+ int output_w = stbir_info->output_w;
+ int channels = stbir_info->channels;
+ float* decode_buffer = stbir__get_decode_buffer(stbir_info);
+ stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
+ float* horizontal_coefficients = stbir_info->horizontal_coefficients;
+ int coefficient_width = stbir_info->horizontal_coefficient_width;
+
+ for (x = 0; x < output_w; x++)
+ {
+ int n0 = horizontal_contributors[x].n0;
+ int n1 = horizontal_contributors[x].n1;
+
+ int out_pixel_index = x * channels;
+ int coefficient_group = coefficient_width * x;
+ int coefficient_counter = 0;
+
+ STBIR_ASSERT(n1 >= n0);
+ STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
+ STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
+ STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
+ STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
+
+ switch (channels) {
+ case 1:
+ for (k = n0; k <= n1; k++)
+ {
+ int in_pixel_index = k * 1;
+ float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
+ STBIR_ASSERT(coefficient != 0);
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ }
+ break;
+ case 2:
+ for (k = n0; k <= n1; k++)
+ {
+ int in_pixel_index = k * 2;
+ float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
+ STBIR_ASSERT(coefficient != 0);
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
+ }
+ break;
+ case 3:
+ for (k = n0; k <= n1; k++)
+ {
+ int in_pixel_index = k * 3;
+ float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
+ STBIR_ASSERT(coefficient != 0);
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
+ output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
+ }
+ break;
+ case 4:
+ for (k = n0; k <= n1; k++)
+ {
+ int in_pixel_index = k * 4;
+ float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
+ STBIR_ASSERT(coefficient != 0);
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
+ output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
+ output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
+ }
+ break;
+ default:
+ for (k = n0; k <= n1; k++)
+ {
+ int in_pixel_index = k * channels;
+ float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
+ int c;
+ STBIR_ASSERT(coefficient != 0);
+ for (c = 0; c < channels; c++)
+ output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
+ }
+ break;
+ }
+ }
+}
+
+static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer)
+{
+ int x, k;
+ int input_w = stbir_info->input_w;
+ int channels = stbir_info->channels;
+ float* decode_buffer = stbir__get_decode_buffer(stbir_info);
+ stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
+ float* horizontal_coefficients = stbir_info->horizontal_coefficients;
+ int coefficient_width = stbir_info->horizontal_coefficient_width;
+ int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin;
+ int max_x = input_w + filter_pixel_margin * 2;
+
+ STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info));
+
+ switch (channels) {
+ case 1:
+ for (x = 0; x < max_x; x++)
+ {
+ int n0 = horizontal_contributors[x].n0;
+ int n1 = horizontal_contributors[x].n1;
+
+ int in_x = x - filter_pixel_margin;
+ int in_pixel_index = in_x * 1;
+ int max_n = n1;
+ int coefficient_group = coefficient_width * x;
+
+ for (k = n0; k <= max_n; k++)
+ {
+ int out_pixel_index = k * 1;
+ float coefficient = horizontal_coefficients[coefficient_group + k - n0];
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ }
+ }
+ break;
+
+ case 2:
+ for (x = 0; x < max_x; x++)
+ {
+ int n0 = horizontal_contributors[x].n0;
+ int n1 = horizontal_contributors[x].n1;
+
+ int in_x = x - filter_pixel_margin;
+ int in_pixel_index = in_x * 2;
+ int max_n = n1;
+ int coefficient_group = coefficient_width * x;
+
+ for (k = n0; k <= max_n; k++)
+ {
+ int out_pixel_index = k * 2;
+ float coefficient = horizontal_coefficients[coefficient_group + k - n0];
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
+ }
+ }
+ break;
+
+ case 3:
+ for (x = 0; x < max_x; x++)
+ {
+ int n0 = horizontal_contributors[x].n0;
+ int n1 = horizontal_contributors[x].n1;
+
+ int in_x = x - filter_pixel_margin;
+ int in_pixel_index = in_x * 3;
+ int max_n = n1;
+ int coefficient_group = coefficient_width * x;
+
+ for (k = n0; k <= max_n; k++)
+ {
+ int out_pixel_index = k * 3;
+ float coefficient = horizontal_coefficients[coefficient_group + k - n0];
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
+ output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
+ }
+ }
+ break;
+
+ case 4:
+ for (x = 0; x < max_x; x++)
+ {
+ int n0 = horizontal_contributors[x].n0;
+ int n1 = horizontal_contributors[x].n1;
+
+ int in_x = x - filter_pixel_margin;
+ int in_pixel_index = in_x * 4;
+ int max_n = n1;
+ int coefficient_group = coefficient_width * x;
+
+ for (k = n0; k <= max_n; k++)
+ {
+ int out_pixel_index = k * 4;
+ float coefficient = horizontal_coefficients[coefficient_group + k - n0];
+ output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
+ output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
+ output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
+ output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
+ }
+ }
+ break;
+
+ default:
+ for (x = 0; x < max_x; x++)
+ {
+ int n0 = horizontal_contributors[x].n0;
+ int n1 = horizontal_contributors[x].n1;
+
+ int in_x = x - filter_pixel_margin;
+ int in_pixel_index = in_x * channels;
+ int max_n = n1;
+ int coefficient_group = coefficient_width * x;
+
+ for (k = n0; k <= max_n; k++)
+ {
+ int c;
+ int out_pixel_index = k * channels;
+ float coefficient = horizontal_coefficients[coefficient_group + k - n0];
+ for (c = 0; c < channels; c++)
+ output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
+ }
+ }
+ break;
+ }
+}
+
+static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n)
+{
+ // Decode the nth scanline from the source image into the decode buffer.
+ stbir__decode_scanline(stbir_info, n);
+
+ // Now resample it into the ring buffer.
+ if (stbir__use_width_upsampling(stbir_info))
+ stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
+ else
+ stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
+
+ // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
+}
+
+static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n)
+{
+ // Decode the nth scanline from the source image into the decode buffer.
+ stbir__decode_scanline(stbir_info, n);
+
+ memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float));
+
+ // Now resample it into the horizontal buffer.
+ if (stbir__use_width_upsampling(stbir_info))
+ stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer);
+ else
+ stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer);
+
+ // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers.
+}
+
+// Get the specified scan line from the ring buffer.
+static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length)
+{
+ int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
+ return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
+}
+
+
+static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode)
+{
+ int x;
+ int n;
+ int num_nonalpha;
+ stbir_uint16 nonalpha[STBIR_MAX_CHANNELS];
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
+ {
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ float alpha = encode_buffer[pixel_index + alpha_channel];
+ float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
+
+ // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb
+ for (n = 0; n < channels; n++)
+ if (n != alpha_channel)
+ encode_buffer[pixel_index + n] *= reciprocal_alpha;
+
+ // We added in a small epsilon to prevent the color channel from being deleted with zero alpha.
+ // Because we only add it for integer types, it will automatically be discarded on integer
+ // conversion, so we don't need to subtract it back out (which would be problematic for
+ // numeric precision reasons).
+ }
+ }
+
+ // build a table of all channels that need colorspace correction, so
+ // we don't perform colorspace correction on channels that don't need it.
+ for (x = 0, num_nonalpha = 0; x < channels; ++x)
+ {
+ if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ {
+ nonalpha[num_nonalpha++] = (stbir_uint16)x;
+ }
+ }
+
+ #define STBIR__ROUND_INT(f) ((int) ((f)+0.5))
+ #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5))
+
+ #ifdef STBIR__SATURATE_INT
+ #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float ))
+ #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float))
+ #else
+ #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float )
+ #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float)
+ #endif
+
+ switch (decode)
+ {
+ case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < channels; n++)
+ {
+ int index = pixel_index + n;
+ ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]);
+ }
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < num_nonalpha; n++)
+ {
+ int index = pixel_index + nonalpha[n];
+ ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]);
+ }
+
+ if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]);
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < channels; n++)
+ {
+ int index = pixel_index + n;
+ ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]);
+ }
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < num_nonalpha; n++)
+ {
+ int index = pixel_index + nonalpha[n];
+ ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float);
+ }
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]);
+ }
+
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < channels; n++)
+ {
+ int index = pixel_index + n;
+ ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float);
+ }
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < num_nonalpha; n++)
+ {
+ int index = pixel_index + nonalpha[n];
+ ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float);
+ }
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float);
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < channels; n++)
+ {
+ int index = pixel_index + n;
+ ((float*)output_buffer)[index] = encode_buffer[index];
+ }
+ }
+ break;
+
+ case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
+ for (x=0; x < num_pixels; ++x)
+ {
+ int pixel_index = x*channels;
+
+ for (n = 0; n < num_nonalpha; n++)
+ {
+ int index = pixel_index + nonalpha[n];
+ ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]);
+ }
+
+ if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
+ ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel];
+ }
+ break;
+
+ default:
+ STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
+ break;
+ }
+}
+
+static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n)
+{
+ int x, k;
+ int output_w = stbir_info->output_w;
+ stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
+ float* vertical_coefficients = stbir_info->vertical_coefficients;
+ int channels = stbir_info->channels;
+ int alpha_channel = stbir_info->alpha_channel;
+ int type = stbir_info->type;
+ int colorspace = stbir_info->colorspace;
+ int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
+ void* output_data = stbir_info->output_data;
+ float* encode_buffer = stbir_info->encode_buffer;
+ int decode = STBIR__DECODE(type, colorspace);
+ int coefficient_width = stbir_info->vertical_coefficient_width;
+ int coefficient_counter;
+ int contributor = n;
+
+ float* ring_buffer = stbir_info->ring_buffer;
+ int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
+ int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
+ int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
+
+ int n0,n1, output_row_start;
+ int coefficient_group = coefficient_width * contributor;
+
+ n0 = vertical_contributors[contributor].n0;
+ n1 = vertical_contributors[contributor].n1;
+
+ output_row_start = n * stbir_info->output_stride_bytes;
+
+ STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
+
+ memset(encode_buffer, 0, output_w * sizeof(float) * channels);
+
+ // I tried reblocking this for better cache usage of encode_buffer
+ // (using x_outer, k, x_inner), but it lost speed. -- stb
+
+ coefficient_counter = 0;
+ switch (channels) {
+ case 1:
+ for (k = n0; k <= n1; k++)
+ {
+ int coefficient_index = coefficient_counter++;
+ float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
+ float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
+ for (x = 0; x < output_w; ++x)
+ {
+ int in_pixel_index = x * 1;
+ encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
+ }
+ }
+ break;
+ case 2:
+ for (k = n0; k <= n1; k++)
+ {
+ int coefficient_index = coefficient_counter++;
+ float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
+ float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
+ for (x = 0; x < output_w; ++x)
+ {
+ int in_pixel_index = x * 2;
+ encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
+ encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
+ }
+ }
+ break;
+ case 3:
+ for (k = n0; k <= n1; k++)
+ {
+ int coefficient_index = coefficient_counter++;
+ float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
+ float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
+ for (x = 0; x < output_w; ++x)
+ {
+ int in_pixel_index = x * 3;
+ encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
+ encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
+ encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
+ }
+ }
+ break;
+ case 4:
+ for (k = n0; k <= n1; k++)
+ {
+ int coefficient_index = coefficient_counter++;
+ float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
+ float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
+ for (x = 0; x < output_w; ++x)
+ {
+ int in_pixel_index = x * 4;
+ encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
+ encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
+ encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
+ encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient;
+ }
+ }
+ break;
+ default:
+ for (k = n0; k <= n1; k++)
+ {
+ int coefficient_index = coefficient_counter++;
+ float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
+ float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
+ for (x = 0; x < output_w; ++x)
+ {
+ int in_pixel_index = x * channels;
+ int c;
+ for (c = 0; c < channels; c++)
+ encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient;
+ }
+ }
+ break;
+ }
+ stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
+}
+
+static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n)
+{
+ int x, k;
+ int output_w = stbir_info->output_w;
+ stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
+ float* vertical_coefficients = stbir_info->vertical_coefficients;
+ int channels = stbir_info->channels;
+ int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
+ float* horizontal_buffer = stbir_info->horizontal_buffer;
+ int coefficient_width = stbir_info->vertical_coefficient_width;
+ int contributor = n + stbir_info->vertical_filter_pixel_margin;
+
+ float* ring_buffer = stbir_info->ring_buffer;
+ int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
+ int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
+ int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
+ int n0,n1;
+
+ n0 = vertical_contributors[contributor].n0;
+ n1 = vertical_contributors[contributor].n1;
+
+ STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
+
+ for (k = n0; k <= n1; k++)
+ {
+ int coefficient_index = k - n0;
+ int coefficient_group = coefficient_width * contributor;
+ float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
+
+ float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
+
+ switch (channels) {
+ case 1:
+ for (x = 0; x < output_w; x++)
+ {
+ int in_pixel_index = x * 1;
+ ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
+ }
+ break;
+ case 2:
+ for (x = 0; x < output_w; x++)
+ {
+ int in_pixel_index = x * 2;
+ ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
+ ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
+ }
+ break;
+ case 3:
+ for (x = 0; x < output_w; x++)
+ {
+ int in_pixel_index = x * 3;
+ ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
+ ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
+ ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
+ }
+ break;
+ case 4:
+ for (x = 0; x < output_w; x++)
+ {
+ int in_pixel_index = x * 4;
+ ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
+ ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
+ ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
+ ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient;
+ }
+ break;
+ default:
+ for (x = 0; x < output_w; x++)
+ {
+ int in_pixel_index = x * channels;
+
+ int c;
+ for (c = 0; c < channels; c++)
+ ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient;
+ }
+ break;
+ }
+ }
+}
+
+static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
+{
+ int y;
+ float scale_ratio = stbir_info->vertical_scale;
+ float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio;
+
+ STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
+
+ for (y = 0; y < stbir_info->output_h; y++)
+ {
+ float in_center_of_out = 0; // Center of the current out scanline in the in scanline space
+ int in_first_scanline = 0, in_last_scanline = 0;
+
+ stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
+
+ STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
+
+ if (stbir_info->ring_buffer_begin_index >= 0)
+ {
+ // Get rid of whatever we don't need anymore.
+ while (in_first_scanline > stbir_info->ring_buffer_first_scanline)
+ {
+ if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
+ {
+ // We just popped the last scanline off the ring buffer.
+ // Reset it to the empty state.
+ stbir_info->ring_buffer_begin_index = -1;
+ stbir_info->ring_buffer_first_scanline = 0;
+ stbir_info->ring_buffer_last_scanline = 0;
+ break;
+ }
+ else
+ {
+ stbir_info->ring_buffer_first_scanline++;
+ stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
+ }
+ }
+ }
+
+ // Load in new ones.
+ if (stbir_info->ring_buffer_begin_index < 0)
+ stbir__decode_and_resample_upsample(stbir_info, in_first_scanline);
+
+ while (in_last_scanline > stbir_info->ring_buffer_last_scanline)
+ stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
+
+ // Now all buffers should be ready to write a row of vertical sampling.
+ stbir__resample_vertical_upsample(stbir_info, y);
+
+ STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h);
+ }
+}
+
+static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline)
+{
+ int output_stride_bytes = stbir_info->output_stride_bytes;
+ int channels = stbir_info->channels;
+ int alpha_channel = stbir_info->alpha_channel;
+ int type = stbir_info->type;
+ int colorspace = stbir_info->colorspace;
+ int output_w = stbir_info->output_w;
+ void* output_data = stbir_info->output_data;
+ int decode = STBIR__DECODE(type, colorspace);
+
+ float* ring_buffer = stbir_info->ring_buffer;
+ int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
+
+ if (stbir_info->ring_buffer_begin_index >= 0)
+ {
+ // Get rid of whatever we don't need anymore.
+ while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline)
+ {
+ if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h)
+ {
+ int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes;
+ float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length);
+ stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode);
+ STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h);
+ }
+
+ if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
+ {
+ // We just popped the last scanline off the ring buffer.
+ // Reset it to the empty state.
+ stbir_info->ring_buffer_begin_index = -1;
+ stbir_info->ring_buffer_first_scanline = 0;
+ stbir_info->ring_buffer_last_scanline = 0;
+ break;
+ }
+ else
+ {
+ stbir_info->ring_buffer_first_scanline++;
+ stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
+ }
+ }
+ }
+}
+
+static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
+{
+ int y;
+ float scale_ratio = stbir_info->vertical_scale;
+ int output_h = stbir_info->output_h;
+ float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio;
+ int pixel_margin = stbir_info->vertical_filter_pixel_margin;
+ int max_y = stbir_info->input_h + pixel_margin;
+
+ STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
+
+ for (y = -pixel_margin; y < max_y; y++)
+ {
+ float out_center_of_in; // Center of the current out scanline in the in scanline space
+ int out_first_scanline, out_last_scanline;
+
+ stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
+
+ STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
+
+ if (out_last_scanline < 0 || out_first_scanline >= output_h)
+ continue;
+
+ stbir__empty_ring_buffer(stbir_info, out_first_scanline);
+
+ stbir__decode_and_resample_downsample(stbir_info, y);
+
+ // Load in new ones.
+ if (stbir_info->ring_buffer_begin_index < 0)
+ stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline);
+
+ while (out_last_scanline > stbir_info->ring_buffer_last_scanline)
+ stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
+
+ // Now the horizontal buffer is ready to write to all ring buffer rows.
+ stbir__resample_vertical_downsample(stbir_info, y);
+ }
+
+ stbir__empty_ring_buffer(stbir_info, stbir_info->output_h);
+}
+
+static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels)
+{
+ info->input_w = input_w;
+ info->input_h = input_h;
+ info->output_w = output_w;
+ info->output_h = output_h;
+ info->channels = channels;
+}
+
+static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform)
+{
+ info->s0 = s0;
+ info->t0 = t0;
+ info->s1 = s1;
+ info->t1 = t1;
+
+ if (transform)
+ {
+ info->horizontal_scale = transform[0];
+ info->vertical_scale = transform[1];
+ info->horizontal_shift = transform[2];
+ info->vertical_shift = transform[3];
+ }
+ else
+ {
+ info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0);
+ info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0);
+
+ info->horizontal_shift = s0 * info->output_w / (s1 - s0);
+ info->vertical_shift = t0 * info->output_h / (t1 - t0);
+ }
+}
+
+static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter)
+{
+ if (h_filter == 0)
+ h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
+ if (v_filter == 0)
+ v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
+ info->horizontal_filter = h_filter;
+ info->vertical_filter = v_filter;
+}
+
+static stbir_uint32 stbir__calculate_memory(stbir__info *info)
+{
+ int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
+ int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale);
+
+ info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
+ info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h);
+
+ // One extra entry because floating point precision problems sometimes cause an extra to be necessary.
+ info->ring_buffer_num_entries = filter_height + 1;
+
+ info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors);
+ info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float);
+ info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors);
+ info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float);
+ info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float);
+ info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float);
+ info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float);
+ info->encode_buffer_size = info->output_w * info->channels * sizeof(float);
+
+ STBIR_ASSERT(info->horizontal_filter != 0);
+ STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
+ STBIR_ASSERT(info->vertical_filter != 0);
+ STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
+
+ if (stbir__use_height_upsampling(info))
+ // The horizontal buffer is for when we're downsampling the height and we
+ // can't output the result of sampling the decode buffer directly into the
+ // ring buffers.
+ info->horizontal_buffer_size = 0;
+ else
+ // The encode buffer is to retain precision in the height upsampling method
+ // and isn't used when height downsampling.
+ info->encode_buffer_size = 0;
+
+ return info->horizontal_contributors_size + info->horizontal_coefficients_size
+ + info->vertical_contributors_size + info->vertical_coefficients_size
+ + info->decode_buffer_size + info->horizontal_buffer_size
+ + info->ring_buffer_size + info->encode_buffer_size;
+}
+
+static int stbir__resize_allocated(stbir__info *info,
+ const void* input_data, int input_stride_in_bytes,
+ void* output_data, int output_stride_in_bytes,
+ int alpha_channel, stbir_uint32 flags, stbir_datatype type,
+ stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace,
+ void* tempmem, size_t tempmem_size_in_bytes)
+{
+ size_t memory_required = stbir__calculate_memory(info);
+
+ int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type];
+ int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type];
+
+#ifdef STBIR_DEBUG_OVERWRITE_TEST
+#define OVERWRITE_ARRAY_SIZE 8
+ unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE];
+ unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE];
+ unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE];
+ unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE];
+
+ size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type];
+ memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
+ memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE);
+ memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
+ memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE);
+#endif
+
+ STBIR_ASSERT(info->channels >= 0);
+ STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS);
+
+ if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS)
+ return 0;
+
+ STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
+ STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
+
+ if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
+ return 0;
+ if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
+ return 0;
+
+ if (alpha_channel < 0)
+ flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED;
+
+ if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) {
+ STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels);
+ }
+
+ if (alpha_channel >= info->channels)
+ return 0;
+
+ STBIR_ASSERT(tempmem);
+
+ if (!tempmem)
+ return 0;
+
+ STBIR_ASSERT(tempmem_size_in_bytes >= memory_required);
+
+ if (tempmem_size_in_bytes < memory_required)
+ return 0;
+
+ memset(tempmem, 0, tempmem_size_in_bytes);
+
+ info->input_data = input_data;
+ info->input_stride_bytes = width_stride_input;
+
+ info->output_data = output_data;
+ info->output_stride_bytes = width_stride_output;
+
+ info->alpha_channel = alpha_channel;
+ info->flags = flags;
+ info->type = type;
+ info->edge_horizontal = edge_horizontal;
+ info->edge_vertical = edge_vertical;
+ info->colorspace = colorspace;
+
+ info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale);
+ info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale );
+ info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale);
+ info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale );
+ info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
+ info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale );
+
+ info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float);
+ info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2;
+
+#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size)
+
+ info->horizontal_contributors = (stbir__contributors *) tempmem;
+ info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float);
+ info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors);
+ info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float);
+ info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float);
+
+ if (stbir__use_height_upsampling(info))
+ {
+ info->horizontal_buffer = NULL;
+ info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
+ info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float);
+
+ STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
+ }
+ else
+ {
+ info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
+ info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float);
+ info->encode_buffer = NULL;
+
+ STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
+ }
+
+#undef STBIR__NEXT_MEMPTR
+
+ // This signals that the ring buffer is empty
+ info->ring_buffer_begin_index = -1;
+
+ stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
+ stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
+
+ STBIR_PROGRESS_REPORT(0);
+
+ if (stbir__use_height_upsampling(info))
+ stbir__buffer_loop_upsample(info);
+ else
+ stbir__buffer_loop_downsample(info);
+
+ STBIR_PROGRESS_REPORT(1);
+
+#ifdef STBIR_DEBUG_OVERWRITE_TEST
+ STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
+ STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
+ STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
+ STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
+#endif
+
+ return 1;
+}
+
+
+static int stbir__resize_arbitrary(
+ void *alloc_context,
+ const void* input_data, int input_w, int input_h, int input_stride_in_bytes,
+ void* output_data, int output_w, int output_h, int output_stride_in_bytes,
+ float s0, float t0, float s1, float t1, float *transform,
+ int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type,
+ stbir_filter h_filter, stbir_filter v_filter,
+ stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace)
+{
+ stbir__info info;
+ int result;
+ size_t memory_required;
+ void* extra_memory;
+
+ stbir__setup(&info, input_w, input_h, output_w, output_h, channels);
+ stbir__calculate_transform(&info, s0,t0,s1,t1,transform);
+ stbir__choose_filter(&info, h_filter, v_filter);
+ memory_required = stbir__calculate_memory(&info);
+ extra_memory = STBIR_MALLOC(memory_required, alloc_context);
+
+ if (!extra_memory)
+ return 0;
+
+ result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes,
+ output_data, output_stride_in_bytes,
+ alpha_channel, flags, type,
+ edge_horizontal, edge_vertical,
+ colorspace, extra_memory, memory_required);
+
+ STBIR_FREE(extra_memory, alloc_context);
+
+ return result;
+}
+
+STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels)
+{
+ return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
+ STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
+}
+
+STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels)
+{
+ return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
+ STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
+}
+
+STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags)
+{
+ return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
+ STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB);
+}
+
+STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode)
+{
+ return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
+ edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB);
+}
+
+STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
+ void *alloc_context)
+{
+ return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter,
+ edge_wrap_mode, edge_wrap_mode, space);
+}
+
+STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
+ void *alloc_context)
+{
+ return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter,
+ edge_wrap_mode, edge_wrap_mode, space);
+}
+
+
+STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
+ void *alloc_context)
+{
+ return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter,
+ edge_wrap_mode, edge_wrap_mode, space);
+}
+
+
+STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ stbir_datatype datatype,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
+ stbir_filter filter_horizontal, stbir_filter filter_vertical,
+ stbir_colorspace space, void *alloc_context)
+{
+ return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
+ edge_mode_horizontal, edge_mode_vertical, space);
+}
+
+
+STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ stbir_datatype datatype,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
+ stbir_filter filter_horizontal, stbir_filter filter_vertical,
+ stbir_colorspace space, void *alloc_context,
+ float x_scale, float y_scale,
+ float x_offset, float y_offset)
+{
+ float transform[4];
+ transform[0] = x_scale;
+ transform[1] = y_scale;
+ transform[2] = x_offset;
+ transform[3] = y_offset;
+ return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ 0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
+ edge_mode_horizontal, edge_mode_vertical, space);
+}
+
+STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
+ void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
+ stbir_datatype datatype,
+ int num_channels, int alpha_channel, int flags,
+ stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
+ stbir_filter filter_horizontal, stbir_filter filter_vertical,
+ stbir_colorspace space, void *alloc_context,
+ float s0, float t0, float s1, float t1)
+{
+ return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
+ output_pixels, output_w, output_h, output_stride_in_bytes,
+ s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
+ edge_mode_horizontal, edge_mode_vertical, space);
+}
+
+#endif // STB_IMAGE_RESIZE_IMPLEMENTATION
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2017 Sean Barrett
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+-of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/tools/3rd_stb_rect_pack.h b/tools/3rd_stb_rect_pack.h
new file mode 100644
index 0000000..6a633ce
--- /dev/null
+++ b/tools/3rd_stb_rect_pack.h
@@ -0,0 +1,623 @@
+// stb_rect_pack.h - v1.01 - public domain - rectangle packing
+// Sean Barrett 2014
+//
+// Useful for e.g. packing rectangular textures into an atlas.
+// Does not do rotation.
+//
+// Before #including,
+//
+// #define STB_RECT_PACK_IMPLEMENTATION
+//
+// in the file that you want to have the implementation.
+//
+// Not necessarily the awesomest packing method, but better than
+// the totally naive one in stb_truetype (which is primarily what
+// this is meant to replace).
+//
+// Has only had a few tests run, may have issues.
+//
+// More docs to come.
+//
+// No memory allocations; uses qsort() and assert() from stdlib.
+// Can override those by defining STBRP_SORT and STBRP_ASSERT.
+//
+// This library currently uses the Skyline Bottom-Left algorithm.
+//
+// Please note: better rectangle packers are welcome! Please
+// implement them to the same API, but with a different init
+// function.
+//
+// Credits
+//
+// Library
+// Sean Barrett
+// Minor features
+// Martins Mozeiko
+// github:IntellectualKitty
+//
+// Bugfixes / warning fixes
+// Jeremy Jaussaud
+// Fabian Giesen
+//
+// Version history:
+//
+// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
+// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
+// 0.99 (2019-02-07) warning fixes
+// 0.11 (2017-03-03) return packing success/fail result
+// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
+// 0.09 (2016-08-27) fix compiler warnings
+// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
+// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
+// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
+// 0.05: added STBRP_ASSERT to allow replacing assert
+// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
+// 0.01: initial release
+//
+// LICENSE
+//
+// See end of file for license information.
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// INCLUDE SECTION
+//
+
+#ifndef STB_INCLUDE_STB_RECT_PACK_H
+#define STB_INCLUDE_STB_RECT_PACK_H
+
+#define STB_RECT_PACK_VERSION 1
+
+#ifdef STBRP_STATIC
+#define STBRP_DEF static
+#else
+#define STBRP_DEF extern
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct stbrp_context stbrp_context;
+typedef struct stbrp_node stbrp_node;
+typedef struct stbrp_rect stbrp_rect;
+
+typedef int stbrp_coord;
+
+#define STBRP__MAXVAL 0x7fffffff
+// Mostly for internal use, but this is the maximum supported coordinate value.
+
+STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
+// Assign packed locations to rectangles. The rectangles are of type
+// 'stbrp_rect' defined below, stored in the array 'rects', and there
+// are 'num_rects' many of them.
+//
+// Rectangles which are successfully packed have the 'was_packed' flag
+// set to a non-zero value and 'x' and 'y' store the minimum location
+// on each axis (i.e. bottom-left in cartesian coordinates, top-left
+// if you imagine y increasing downwards). Rectangles which do not fit
+// have the 'was_packed' flag set to 0.
+//
+// You should not try to access the 'rects' array from another thread
+// while this function is running, as the function temporarily reorders
+// the array while it executes.
+//
+// To pack into another rectangle, you need to call stbrp_init_target
+// again. To continue packing into the same rectangle, you can call
+// this function again. Calling this multiple times with multiple rect
+// arrays will probably produce worse packing results than calling it
+// a single time with the full rectangle array, but the option is
+// available.
+//
+// The function returns 1 if all of the rectangles were successfully
+// packed and 0 otherwise.
+
+struct stbrp_rect
+{
+ // reserved for your use:
+ int id;
+
+ // input:
+ stbrp_coord w, h;
+
+ // output:
+ stbrp_coord x, y;
+ int was_packed; // non-zero if valid packing
+
+}; // 16 bytes, nominally
+
+
+STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
+// Initialize a rectangle packer to:
+// pack a rectangle that is 'width' by 'height' in dimensions
+// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
+//
+// You must call this function every time you start packing into a new target.
+//
+// There is no "shutdown" function. The 'nodes' memory must stay valid for
+// the following stbrp_pack_rects() call (or calls), but can be freed after
+// the call (or calls) finish.
+//
+// Note: to guarantee best results, either:
+// 1. make sure 'num_nodes' >= 'width'
+// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
+//
+// If you don't do either of the above things, widths will be quantized to multiples
+// of small integers to guarantee the algorithm doesn't run out of temporary storage.
+//
+// If you do #2, then the non-quantized algorithm will be used, but the algorithm
+// may run out of temporary storage and be unable to pack some rectangles.
+
+STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
+// Optionally call this function after init but before doing any packing to
+// change the handling of the out-of-temp-memory scenario, described above.
+// If you call init again, this will be reset to the default (false).
+
+
+STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
+// Optionally select which packing heuristic the library should use. Different
+// heuristics will produce better/worse results for different data sets.
+// If you call init again, this will be reset to the default.
+
+enum
+{
+ STBRP_HEURISTIC_Skyline_default=0,
+ STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
+ STBRP_HEURISTIC_Skyline_BF_sortHeight
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// the details of the following structures don't matter to you, but they must
+// be visible so you can handle the memory allocations for them
+
+struct stbrp_node
+{
+ stbrp_coord x,y;
+ stbrp_node *next;
+};
+
+struct stbrp_context
+{
+ int width;
+ int height;
+ int align;
+ int init_mode;
+ int heuristic;
+ int num_nodes;
+ stbrp_node *active_head;
+ stbrp_node *free_head;
+ stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// IMPLEMENTATION SECTION
+//
+
+#ifdef STB_RECT_PACK_IMPLEMENTATION
+#ifndef STBRP_SORT
+#include
+#define STBRP_SORT qsort
+#endif
+
+#ifndef STBRP_ASSERT
+#include
+#define STBRP_ASSERT assert
+#endif
+
+#ifdef _MSC_VER
+#define STBRP__NOTUSED(v) (void)(v)
+#define STBRP__CDECL __cdecl
+#else
+#define STBRP__NOTUSED(v) (void)sizeof(v)
+#define STBRP__CDECL
+#endif
+
+enum
+{
+ STBRP__INIT_skyline = 1
+};
+
+STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
+{
+ switch (context->init_mode) {
+ case STBRP__INIT_skyline:
+ STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
+ context->heuristic = heuristic;
+ break;
+ default:
+ STBRP_ASSERT(0);
+ }
+}
+
+STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
+{
+ if (allow_out_of_mem)
+ // if it's ok to run out of memory, then don't bother aligning them;
+ // this gives better packing, but may fail due to OOM (even though
+ // the rectangles easily fit). @TODO a smarter approach would be to only
+ // quantize once we've hit OOM, then we could get rid of this parameter.
+ context->align = 1;
+ else {
+ // if it's not ok to run out of memory, then quantize the widths
+ // so that num_nodes is always enough nodes.
+ //
+ // I.e. num_nodes * align >= width
+ // align >= width / num_nodes
+ // align = ceil(width/num_nodes)
+
+ context->align = (context->width + context->num_nodes-1) / context->num_nodes;
+ }
+}
+
+STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
+{
+ int i;
+
+ for (i=0; i < num_nodes-1; ++i)
+ nodes[i].next = &nodes[i+1];
+ nodes[i].next = NULL;
+ context->init_mode = STBRP__INIT_skyline;
+ context->heuristic = STBRP_HEURISTIC_Skyline_default;
+ context->free_head = &nodes[0];
+ context->active_head = &context->extra[0];
+ context->width = width;
+ context->height = height;
+ context->num_nodes = num_nodes;
+ stbrp_setup_allow_out_of_mem(context, 0);
+
+ // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
+ context->extra[0].x = 0;
+ context->extra[0].y = 0;
+ context->extra[0].next = &context->extra[1];
+ context->extra[1].x = (stbrp_coord) width;
+ context->extra[1].y = (1<<30);
+ context->extra[1].next = NULL;
+}
+
+// find minimum y position if it starts at x1
+static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
+{
+ stbrp_node *node = first;
+ int x1 = x0 + width;
+ int min_y, visited_width, waste_area;
+
+ STBRP__NOTUSED(c);
+
+ STBRP_ASSERT(first->x <= x0);
+
+ #if 0
+ // skip in case we're past the node
+ while (node->next->x <= x0)
+ ++node;
+ #else
+ STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
+ #endif
+
+ STBRP_ASSERT(node->x <= x0);
+
+ min_y = 0;
+ waste_area = 0;
+ visited_width = 0;
+ while (node->x < x1) {
+ if (node->y > min_y) {
+ // raise min_y higher.
+ // we've accounted for all waste up to min_y,
+ // but we'll now add more waste for everything we've visted
+ waste_area += visited_width * (node->y - min_y);
+ min_y = node->y;
+ // the first time through, visited_width might be reduced
+ if (node->x < x0)
+ visited_width += node->next->x - x0;
+ else
+ visited_width += node->next->x - node->x;
+ } else {
+ // add waste area
+ int under_width = node->next->x - node->x;
+ if (under_width + visited_width > width)
+ under_width = width - visited_width;
+ waste_area += under_width * (min_y - node->y);
+ visited_width += under_width;
+ }
+ node = node->next;
+ }
+
+ *pwaste = waste_area;
+ return min_y;
+}
+
+typedef struct
+{
+ int x,y;
+ stbrp_node **prev_link;
+} stbrp__findresult;
+
+static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
+{
+ int best_waste = (1<<30), best_x, best_y = (1 << 30);
+ stbrp__findresult fr;
+ stbrp_node **prev, *node, *tail, **best = NULL;
+
+ // align to multiple of c->align
+ width = (width + c->align - 1);
+ width -= width % c->align;
+ STBRP_ASSERT(width % c->align == 0);
+
+ // if it can't possibly fit, bail immediately
+ if (width > c->width || height > c->height) {
+ fr.prev_link = NULL;
+ fr.x = fr.y = 0;
+ return fr;
+ }
+
+ node = c->active_head;
+ prev = &c->active_head;
+ while (node->x + width <= c->width) {
+ int y,waste;
+ y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
+ if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
+ // bottom left
+ if (y < best_y) {
+ best_y = y;
+ best = prev;
+ }
+ } else {
+ // best-fit
+ if (y + height <= c->height) {
+ // can only use it if it first vertically
+ if (y < best_y || (y == best_y && waste < best_waste)) {
+ best_y = y;
+ best_waste = waste;
+ best = prev;
+ }
+ }
+ }
+ prev = &node->next;
+ node = node->next;
+ }
+
+ best_x = (best == NULL) ? 0 : (*best)->x;
+
+ // if doing best-fit (BF), we also have to try aligning right edge to each node position
+ //
+ // e.g, if fitting
+ //
+ // ____________________
+ // |____________________|
+ //
+ // into
+ //
+ // | |
+ // | ____________|
+ // |____________|
+ //
+ // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
+ //
+ // This makes BF take about 2x the time
+
+ if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
+ tail = c->active_head;
+ node = c->active_head;
+ prev = &c->active_head;
+ // find first node that's admissible
+ while (tail->x < width)
+ tail = tail->next;
+ while (tail) {
+ int xpos = tail->x - width;
+ int y,waste;
+ STBRP_ASSERT(xpos >= 0);
+ // find the left position that matches this
+ while (node->next->x <= xpos) {
+ prev = &node->next;
+ node = node->next;
+ }
+ STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
+ y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
+ if (y + height <= c->height) {
+ if (y <= best_y) {
+ if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
+ best_x = xpos;
+ STBRP_ASSERT(y <= best_y);
+ best_y = y;
+ best_waste = waste;
+ best = prev;
+ }
+ }
+ }
+ tail = tail->next;
+ }
+ }
+
+ fr.prev_link = best;
+ fr.x = best_x;
+ fr.y = best_y;
+ return fr;
+}
+
+static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
+{
+ // find best position according to heuristic
+ stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
+ stbrp_node *node, *cur;
+
+ // bail if:
+ // 1. it failed
+ // 2. the best node doesn't fit (we don't always check this)
+ // 3. we're out of memory
+ if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
+ res.prev_link = NULL;
+ return res;
+ }
+
+ // on success, create new node
+ node = context->free_head;
+ node->x = (stbrp_coord) res.x;
+ node->y = (stbrp_coord) (res.y + height);
+
+ context->free_head = node->next;
+
+ // insert the new node into the right starting point, and
+ // let 'cur' point to the remaining nodes needing to be
+ // stiched back in
+
+ cur = *res.prev_link;
+ if (cur->x < res.x) {
+ // preserve the existing one, so start testing with the next one
+ stbrp_node *next = cur->next;
+ cur->next = node;
+ cur = next;
+ } else {
+ *res.prev_link = node;
+ }
+
+ // from here, traverse cur and free the nodes, until we get to one
+ // that shouldn't be freed
+ while (cur->next && cur->next->x <= res.x + width) {
+ stbrp_node *next = cur->next;
+ // move the current node to the free list
+ cur->next = context->free_head;
+ context->free_head = cur;
+ cur = next;
+ }
+
+ // stitch the list back in
+ node->next = cur;
+
+ if (cur->x < res.x + width)
+ cur->x = (stbrp_coord) (res.x + width);
+
+#ifdef _DEBUG
+ cur = context->active_head;
+ while (cur->x < context->width) {
+ STBRP_ASSERT(cur->x < cur->next->x);
+ cur = cur->next;
+ }
+ STBRP_ASSERT(cur->next == NULL);
+
+ {
+ int count=0;
+ cur = context->active_head;
+ while (cur) {
+ cur = cur->next;
+ ++count;
+ }
+ cur = context->free_head;
+ while (cur) {
+ cur = cur->next;
+ ++count;
+ }
+ STBRP_ASSERT(count == context->num_nodes+2);
+ }
+#endif
+
+ return res;
+}
+
+static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
+{
+ const stbrp_rect *p = (const stbrp_rect *) a;
+ const stbrp_rect *q = (const stbrp_rect *) b;
+ if (p->h > q->h)
+ return -1;
+ if (p->h < q->h)
+ return 1;
+ return (p->w > q->w) ? -1 : (p->w < q->w);
+}
+
+static int STBRP__CDECL rect_original_order(const void *a, const void *b)
+{
+ const stbrp_rect *p = (const stbrp_rect *) a;
+ const stbrp_rect *q = (const stbrp_rect *) b;
+ return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
+}
+
+STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
+{
+ int i, all_rects_packed = 1;
+
+ // we use the 'was_packed' field internally to allow sorting/unsorting
+ for (i=0; i < num_rects; ++i) {
+ rects[i].was_packed = i;
+ }
+
+ // sort according to heuristic
+ STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
+
+ for (i=0; i < num_rects; ++i) {
+ if (rects[i].w == 0 || rects[i].h == 0) {
+ rects[i].x = rects[i].y = 0; // empty rect needs no space
+ } else {
+ stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
+ if (fr.prev_link) {
+ rects[i].x = (stbrp_coord) fr.x;
+ rects[i].y = (stbrp_coord) fr.y;
+ } else {
+ rects[i].x = rects[i].y = STBRP__MAXVAL;
+ }
+ }
+ }
+
+ // unsort
+ STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
+
+ // set was_packed flags and all_rects_packed status
+ for (i=0; i < num_rects; ++i) {
+ rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
+ if (!rects[i].was_packed)
+ all_rects_packed = 0;
+ }
+
+ // return the all_rects_packed status
+ return all_rects_packed;
+}
+#endif
+
+/*
+------------------------------------------------------------------------------
+This software is available under 2 licenses -- choose whichever you prefer.
+------------------------------------------------------------------------------
+ALTERNATIVE A - MIT License
+Copyright (c) 2017 Sean Barrett
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+------------------------------------------------------------------------------
+ALTERNATIVE B - Public Domain (www.unlicense.org)
+This is free and unencumbered software released into the public domain.
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+------------------------------------------------------------------------------
+*/
diff --git a/tools/ark.linux b/tools/ark.linux
new file mode 100644
index 0000000..bed073c
Binary files /dev/null and b/tools/ark.linux differ
diff --git a/tools/ase2ini.c b/tools/ase2ini.c
index c71f2ee..2dc7aa3 100644
--- a/tools/ase2ini.c
+++ b/tools/ase2ini.c
@@ -124,6 +124,11 @@ char* strcatf(char **src_, const char *fmt, ...) {
#define ATLASC_IMPLEMENTATION
#include "3rd_atlasc.h"
+#if defined _WIN32 && defined _MSC_VER
+__declspec(dllexport)
+#elif defined _WIN32 && defined __GNUC__
+__attribute__ ((dllexport))
+#endif
int main(int argc, char* argv[]) {
const char *help =
@@ -213,12 +218,13 @@ int main(int argc, char* argv[]) {
}
for( int i = 0; i < array_count(files); ++i)
- free(files[i]);
+ ATLAS_FREE(files[i], 0);
array_free(files);
return error ? fprintf(stderr, "%s\n", error), -1 : 0;
}
// cl ase2ini.c -I ..\engine\split /DNDEBUG /O2 /Ox /MT
+// cl ase2ini.c -I ..\engine\split /DNDEBUG /O2 /Ox /MT /LD
// tcc ase2ini.c -I ..\engine\split -DNDEBUG
// cc ase2ini.c -I ../engine/split -lm -O3 -oase2ini.linux
diff --git a/tools/ase2ini.linux b/tools/ase2ini.linux
new file mode 100644
index 0000000..68acc9d
Binary files /dev/null and b/tools/ase2ini.linux differ
diff --git a/tools/ass2iqe.c b/tools/ass2iqe.c
index 2942e99..5ca7831 100644
--- a/tools/ass2iqe.c
+++ b/tools/ass2iqe.c
@@ -1,7 +1,7 @@
// License: BSD unless otherwise stated.
// https://github.com/ccxvii/asstools
-char* base64_encode(const void *inbuffer, unsigned inlen);
+#include "3rd_base64.h"
#include
#include
@@ -870,7 +870,6 @@ void export_animlist(FILE *out, const struct aiScene *scene)
fprintf(out, "frame: %s\n", "0-0 Idle");
}
-
/*
* For multi-mesh models, sometimes each mesh has its own inv_bind_matrix set
* for each bone. To export to IQE we must have only one inv_bind_matrix per
@@ -1540,49 +1539,3 @@ flags |= (doflipUV ? aiProcess_FlipUVs : 0);
return 0;
}
-// base64 de/encoder. Based on code by Jon Mayo - November 13, 2003 (PUBLIC DOMAIN).
-// - rlyeh, public domain
-
-#include
-#include
-#include
-#include
-#include
-
-unsigned base64_bounds(unsigned size) {
- return 4 * ((size + 2) / 3);
-}
-
-char* base64_encode(const void *in_, unsigned inlen) {
- unsigned outlen = base64_bounds(inlen);
- char *out_ = calloc(1, outlen);
-
- uint_least32_t v;
- unsigned ii, io, rem;
- char *out = (char *)out_;
- const unsigned char *in = (const unsigned char *)in_;
- const uint8_t base64enc_tab[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-
- for(io = 0, ii = 0, v = 0, rem = 0; ii < inlen; ii ++) {
- unsigned char ch;
- ch = in[ii];
- v = (v << 8) | ch;
- rem += 8;
- while (rem >= 6) {
- rem -= 6;
- if (io >= outlen)
- return (free(out_), 0); /* truncation is failure */
- out[io ++] = base64enc_tab[(v >> rem) & 63];
- }
- }
- if (rem) {
- v <<= (6 - rem);
- if (io >= outlen)
- return (free(out_), 0); /* truncation is failure */
- out[io ++] = base64enc_tab[v & 63];
- }
- if (io < outlen)
- out[io] = 0;
-
- return out_;
-}
diff --git a/tools/cook.c b/tools/cook.c
index c6449e7..ade20fe 100644
--- a/tools/cook.c
+++ b/tools/cook.c
@@ -28,9 +28,11 @@ int main(int argc, const char **argv) {
return 0;
}
-// compiled with:
-// tcc cook.c -I..\engine
-// cl cook.c -I..\engine /openmp /Os /Ox /O2 /Oy /MT /DNDEBUG /GL /GF /Gw /arch:AVX2 /link /OPT:ICF /LTCG
-// cc -ObjC cook.c -I../engine -o cook.osx -framework Cocoa -framework IOKit -framework audiotoolbox -O3
-// cc cook.c -I../engine -o cook.linux -lm -lpthread -ldl -lX11 -O3
-// del cook.o & del cook.obj & del cook.lib & del cook.exp
+/*
+ compiled with:
+ cc -ObjC cook.c -I../engine -o cook.osx -framework Cocoa -framework IOKit -framework audiotoolbox -O3
+ cc cook.c -I../engine -o cook.linux -lm -lpthread -ldl -lX11 -O3
+ tcc cook.c -I..\engine
+ cl cook.c -I..\engine /openmp /Os /Ox /O2 /Oy /MT /DNDEBUG /GL /GF /Gw /arch:AVX2 /link /OPT:ICF /LTCG
+ del cook.o & del cook.obj & del cook.lib & del cook.exp
+*/
\ No newline at end of file
diff --git a/tools/cook.exe b/tools/cook.exe
index 32777aa..dda9c7e 100644
Binary files a/tools/cook.exe and b/tools/cook.exe differ
diff --git a/tools/cook.ini b/tools/cook.ini
index 0208f36..589747c 100644
--- a/tools/cook.ini
+++ b/tools/cook.ini
@@ -25,9 +25,9 @@ ART=../demos/art/,../engine/art/,../tools/editor/art/ ; comma-separated folder(
; also, once a symbol is found, it is replaced by its value always.
; some predefined symbols: INPUT (input filename), OUTPUT (output filename), PRETTY (clean input filename), PROGRESS (cook progress).
-;@windows `echo Cooking PROGRESS% PRETTY...`
-;@linux `echo "Cooking PROGRESS% PRETTY..."`
-;@osx `echo "Cooking PROGRESS% PRETTY..."`
+@windows `echo Cooking PROGRESS% PRETTY...`
+@linux `echo "Cooking PROGRESS% PRETTY..."`
+@osx `echo "Cooking PROGRESS% PRETTY..."`
; ------------------------------------------------------------------------------
; groups below are collection of files that we want to cook, and then package.
diff --git a/tools/cook.linux b/tools/cook.linux
index 14fa12e..b313a9c 100644
Binary files a/tools/cook.linux and b/tools/cook.linux differ
diff --git a/tools/cook.osx b/tools/cook.osx
index 2bece42..adc18e8 100755
Binary files a/tools/cook.osx and b/tools/cook.osx differ
diff --git a/tools/editor/v4k_editor.h b/tools/editor/v4k_editor.h
deleted file mode 100644
index af1a925..0000000
--- a/tools/editor/v4k_editor.h
+++ /dev/null
@@ -1,750 +0,0 @@
-// ## Editor long-term plan
-// - editor = tree of nodes. levels and objects are nodes, and their widgets are also nodes
-// - you can perform actions on nodes, with or without descendants, top-bottom or bottom-top
-// - these operations include load/save, undo/redo, reset, play/render, ddraw, etc
-// - nodes are saved to disk as a filesystem layout: parents are folders, and leafs are files
-// - network replication can be done by external tools by comparing the filesystems and by sending the resulting diff zipped
-//
-// ## Editor roadmap
-// - Gizmos✱, scene tree, property editor✱, load/save✱, undo/redo✱, copy/paste, on/off (vis,tick,ddraw,log), vcs.
-// - Scenenode pass: node singleton display, node console, node labels, node outlines✱.
-// - Render pass: billboards✱, materials, un/lit, cast shadows, wireframe, skybox✱/mie✱, fog/atmosphere
-// - Level pass: volumes, triggers, platforms, level streaming, collide✱, physics
-// - Edit pass: Procedural content, brushes, noise and CSG.
-// - GUI pass: timeline and data tracks, node graphs.
-
-// ## Alt plan
-// editor is a database + window/tile manager + ui toolkit; all network driven.
-// to be precise, editor is a dumb app and ...
-// - does not know a thing about what it stores.
-// - does not know how to render the game graphics.
-// - does not know how to run the game logic.
-//
-// the editor will create a canvas for your game to render.
-// your game will be responsible to tick the logic and render the window inside the editor.
-//
-// that being said, editor...
-// - can store datas hierarchically.
-// - can perform diffs and merges, and version the datas into repositories.
-// - can be instructed to render UI on top of game and window views.
-// - can download new .natvis and plugins quickly.
-// - can dump whole project in a filesystem form (zip).
-
-// - editor reflects database contents up-to-date.
-// - database can be queried and modified via OSC(UDP) commands.
-
-// editor database uses one table, and stores two kind of payload types:
-// - classes: defines typename and dna. class names are prefixed by '@'
-// - instances: defines typename and datas. instance names are as-is, not prefixed.
-//
-// every save contains 5Ws: what, who, when, where, how,
-// every save can be diffed/merged.
-
-// ----------------------------------------------------------------------------
-
-#define EDITOR_VERSION "2023.10"
-
-// ----------------------------------------------------------------------------
-
-typedef struct editor_bind_t {
- const char *command;
- const char *bindings;
- void (*fn)();
-} editor_bind_t;
-
-array(editor_bind_t) editor_binds;
-
-#define EDITOR_BIND(CMD,KEYS,...) void macro(editor_bind_##CMD##_fn_)() { __VA_ARGS__ }; AUTORUN { array_push(editor_binds, ((editor_bind_t){#CMD,KEYS,macro(editor_bind_##CMD##_fn_)}) ); }
-
-// ----------------------------------------------------------------------------
-
-typedef void (*editor_no_property)(void *);
-array(void*) editor_persist_kv;
-array(editor_no_property) editor_no_properties;
-
-#define EDITOR_PROPERTY(property_name,T,defaults) \
-typedef map(void*,T) editor_##property_name##_map_t; \
-editor_##property_name##_map_t *editor_##property_name##_map() { \
- static editor_##property_name##_map_t map = 0; do_once map_init_ptr(map); \
- return ↦ \
-} \
-T editor_##property_name(const void *obj) { \
- return *map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) defaults)); \
-} \
-void editor_set##property_name(const void *obj, T value) { \
- *map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) value)) = ((T) value); \
-} \
-void editor_alt##property_name(const void *obj) { \
- T* found = map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) defaults)); \
- *found = (T)(uintptr_t)!(*found); \
-} \
-void editor_no##property_name(void *obj) { \
- T* found = map_find_or_add(*editor_##property_name##_map(), (void*)obj, ((T) defaults)); \
- map_erase(*editor_##property_name##_map(), (void*)obj); \
-} \
-AUTORUN { array_push(editor_persist_kv, #T); array_push(editor_persist_kv, editor_##property_name##_map()); array_push(editor_no_properties, editor_no##property_name); }
-
-EDITOR_PROPERTY(open, int, 0); // whether object is tree opened in tree editor
-EDITOR_PROPERTY(selected, int, 0); // whether object is displaying a contextual popup or not
-EDITOR_PROPERTY(changed, int, 0); // whether object is displaying a contextual popup or not
-EDITOR_PROPERTY(popup, int, 0); // whether object is displaying a contextual popup or not
-EDITOR_PROPERTY(visible, int, 0);
-EDITOR_PROPERTY(script, int, 0);
-EDITOR_PROPERTY(event, int, 0);
-EDITOR_PROPERTY(iconinstance, char*, 0);
-EDITOR_PROPERTY(iconclass, char*, 0);
-EDITOR_PROPERTY(treeoffsety, int, 0);
-// new prop: breakpoint: request to break on any given node
-// new prop: persist: objects with this property will be saved on disk
-
-void editor_destroy_properties(void *o) {
- for each_array(editor_no_properties,editor_no_property,fn) {
- fn(o);
- }
-}
-
-void editor_load_on_boot(void) {
- puts("@todo: load editor");
-}
-void editor_save_on_quit(void) {
- puts("@todo: save editor");
-}
-AUTORUN {
- editor_load_on_boot();
- (atexit)(editor_save_on_quit);
-}
-
-// ----------------------------------------------------------------------------
-
-typedef int(*subeditor)(int mode);
-
-struct editor_t {
- // time
- unsigned frame;
- double t, dt, slomo;
- // controls
- int transparent;
- int attached;
- int active; // focus? does_grabinput instead?
- int key;
- vec2 mouse; // 2d coord for ray/picking
- bool gamepad; // mask instead? |1|2|4|8
- int hz_high, hz_medium, hz_low;
- int filter;
- bool battery; // battery mode: low fps
- bool unlit;
- bool ddraw;
- // event root nodes
- obj* root;
- obj* on_init;
- obj* on_tick;
- obj* on_draw;
- obj* on_edit;
- obj* on_quit;
- // all of them (hierarchical)
- array(obj*) objs; // @todo:set() world?
- // all of them (flat)
- set(obj*) world;
- //
- array(char*) cmds;
- // subeditors
- array(subeditor) subeditors;
-} editor = {
- .active = 1,
- .gamepad = 1,
- .hz_high = 60, .hz_medium = 18, .hz_low = 5,
-};
-
-enum {
- EDITOR_PANEL,
- EDITOR_WINDOW,
- EDITOR_WINDOW_NK,
- EDITOR_WINDOW_NK_SMALL,
-};
-
-int editor_begin(const char *title, int mode) {
- if( mode == 0 ) return ui_panel(title, PANEL_OPEN);
- if( mode == 1 ) return ui_window(title, 0);
-
- int ww = window_width(), w = ww * 0.66;
- int hh = window_height(), h = hh * 0.66;
-
- struct nk_rect position = { (ww-w)/2,(hh-h)/2, w,h };
- nk_flags win_flags = NK_WINDOW_TITLE | NK_WINDOW_BORDER |
- NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE |
- NK_WINDOW_CLOSABLE | NK_WINDOW_MINIMIZABLE |
- // NK_WINDOW_SCALE_LEFT|NK_WINDOW_SCALE_TOP| //< @fixme: move this logic into nuklear
- // NK_WINDOW_MAXIMIZABLE | NK_WINDOW_PINNABLE |
- 0; // NK_WINDOW_SCROLL_AUTO_HIDE;
-
- if( mode == 3 ) {
- mode = 2, position.x = input(MOUSE_X), position.w = w/3, win_flags =
- NK_WINDOW_TITLE|NK_WINDOW_CLOSABLE|
- NK_WINDOW_SCALABLE|NK_WINDOW_MOVABLE| //< nuklear requires these two to `remember` popup rects
- 0;
- }
-
- if( mode == 2 || mode == 3 )
- if (nk_begin(ui_ctx, title, position, win_flags))
- return 1;
- else
- return nk_end(ui_ctx), 0;
-
- return 0;
-}
-int editor_end(int mode) {
- if( mode == 0 ) return ui_panel_end();
- if( mode == 1 ) return ui_window_end();
- if( mode == 2 ) nk_end(ui_ctx);
- if( mode == 3 ) nk_end(ui_ctx);
- return 0;
-}
-
-#if 0 // deprecate
-bool editor_active() {
- return ui_hover() || ui_active() || gizmo_active() ? editor.active : 0;
-}
-#endif
-
-int editor_filter() {
- if( editor.filter ) {
- if (nk_begin(ui_ctx, "Filter", nk_rect(window_width()-window_width()*0.33,32, window_width()*0.33, 40),
- NK_WINDOW_NO_SCROLLBAR)) {
-
- char *bak = ui_filter; ui_filter = 0;
- ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &bak);
- ui_filter = bak;
-
- if( input(KEY_ESC) || ( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 )) {
- if( ui_filter ) ui_filter[0] = '\0';
- editor.filter = 0;
- }
- }
- nk_end(ui_ctx);
- }
-
- return editor.filter;
-}
-
-static
-int editor_select_(void *o, const char *mask) {
- int matches = 0;
- int off = mask[0] == '!', inv = mask[0] == '~';
- int match = strmatchi(obj_type(o), mask+off+inv) || strmatchi(obj_name(o), mask+off+inv);
- if( match ) {
- editor_setselected(o, inv ? editor_selected(o) ^ 1 : !off);
- ++matches;
- }
- for each_objchild(o, obj*, oo) {
- matches += editor_select_(oo, mask);
- }
- return matches;
-}
-void editor_select(const char *mask) {
- for each_array( editor.objs, obj*, o )
- editor_select_(o, mask);
-}
-void editor_unselect() { // same than editor_select("!**");
- for each_map_ptr(*editor_selected_map(), void*,o, int, k) {
- if( *k ) *k = 0;
- }
-}
-
-void editor_select_aabb(aabb box) {
- int is_inv = input_held(KEY_CTRL);
- int is_add = input_held(KEY_SHIFT);
- if( !is_inv && !is_add ) editor_unselect();
-
- aabb item = {0};
- for each_set_ptr( editor.world, obj*, o ) {
- if( obj_hasmethod(*o,aabb) && obj_aabb(*o, &item) ) {
- if( aabb_test_aabb(item, box) ) {
- if( is_inv )
- editor_altselected(*o);
- else
- editor_setselected(*o, 1);
- }
- }
- }
-}
-
-static obj* active_ = 0;
-static void editor_selectgroup_(obj *o, obj *first, obj *last) {
- // printf("%s (looking for %s in [%s..%s])\n", obj_name(o), active_ ? obj_name(active_) : "", obj_name(first), obj_name(last));
- if( !active_ ) if( o == first || o == last ) active_ = o == first ? last : first;
- if( active_ ) editor_setselected(o, 1);
- if( o == active_ ) active_ = 0;
- for each_objchild(o, obj*, oo) {
- editor_selectgroup_(oo, first, last);
- }
-}
-void editor_selectgroup(obj *first, obj *last) {
- if( last ) {
- if( !first ) first = array_count(editor.objs) ? editor.objs[0] : NULL;
- if( !first ) editor_setselected(last, 1);
- else {
- active_ = 0;
- for each_array(editor.objs,obj*,o) {
- editor_selectgroup_(o, first, last);
- }
- }
- }
-}
-
-static obj *find_any_selected_(obj *o) {
- if( editor_selected(o) ) return o;
- for each_objchild(o,obj*,oo) {
- obj *ooo = find_any_selected_(oo);
- if( ooo )
- return ooo;
- }
- return 0;
-}
-void* editor_first_selected() {
- for each_array(editor.objs,obj*,o) {
- obj *oo = find_any_selected_(o);
- // if( oo ) printf("1st found: %s\n", obj_name(oo));
- if( oo ) return oo;
- }
- return 0;
-}
-
-static obj *find_last_selected_(obj *o) {
- void *last = 0;
- if( editor_selected(o) ) last = o;
- for each_objchild(o,obj*,oo) {
- obj *ooo = find_last_selected_(oo);
- if( ooo )
- last = ooo;
- }
- return last;
-}
-void* editor_last_selected() {
- void *last = 0;
- for each_array(editor.objs,obj*,o) {
- obj *oo = find_last_selected_(o);
- // if( oo ) printf("last found: %s\n", obj_name(oo));
- if( oo ) last = oo;
- }
- return last;
-}
-
-// ----------------------------------------------------------------------------------------
-
-void editor_addtoworld(obj *o) {
- set_find_or_add(editor.world, o);
- for each_objchild(o, obj*, oo) {
- editor_addtoworld(oo);
- }
-}
-
-void editor_watch(const void *o) {
- array_push(editor.objs, (obj*)o);
- obj_push(o); // save state
-
- editor_addtoworld((obj*)o);
-}
-void* editor_spawn(const char *ini) { // deprecate?
- obj *o = obj_make(ini);
- editor_watch(o);
- return o;
-}
-void editor_spawn1() {
- obj *selected = editor_first_selected();
- obj *o = selected ? obj_make(obj_saveini(selected)) : obj_new(obj);
- if( selected ) obj_attach(selected, o), editor_setopen(selected, 1);
- else
- editor_watch(o);
-
- editor_unselect();
- editor_setselected(o, 1);
-}
-
-typedef set(obj*) set_objp_t;
-static
-void editor_glob_recurse(set_objp_t*list, obj *o) {
- set_find_or_add(*list, o);
- for each_objchild(o,obj*,oo) {
- editor_glob_recurse(list, oo);
- }
-}
-void editor_destroy_selected() {
- set_objp_t list = 0;
- set_init_ptr(list);
- for each_map_ptr(*editor_selected_map(), obj*,o, int,selected) {
- if( *selected ) { editor_glob_recurse(&list, *o); }
- }
- for each_set(list, obj*, o) {
- obj_detach(o);
- }
- for each_set(list, obj*, o) {
- // printf("deleting %p %s\n", o, obj_name(o));
- // remove from watched items
- for (int i = 0, end = array_count(editor.objs); i < end; ++i) {
- if (editor.objs[i] == o) {
- editor.objs[i] = 0;
- array_erase_slow(editor.objs, i);
- --end;
- --i;
- }
- }
- // delete from world
- set_erase(editor.world, o);
- // delete properties + obj
- editor_destroy_properties(o);
- obj_free(o);
- }
- set_free(list);
-}
-void editor_inspect(obj *o) {
- ui_section(va("%s (%s)", obj_type(o), obj_name(o)));
-
- if( obj_hasmethod(o, menu) ) {
- obj_menu(o);
- }
-
- for each_objmember(o,TYPE,NAME,PTR) {
- if( !editor_changed(PTR) ) {
- obj_push(o);
- }
- ui_label_icon_highlight = editor_changed(PTR); // @hack: remove ui_label_icon_highlight hack
- char *label = va(ICON_MD_UNDO "%s", NAME);
- int changed = 0;
- /**/ if( !strcmp(TYPE,"float") ) changed = ui_float(label, PTR);
- else if( !strcmp(TYPE,"int") ) changed = ui_int(label, PTR);
- else if( !strcmp(TYPE,"vec2") ) changed = ui_float2(label, PTR);
- else if( !strcmp(TYPE,"vec3") ) changed = ui_float3(label, PTR);
- else if( !strcmp(TYPE,"vec4") ) changed = ui_float4(label, PTR);
- else if( !strcmp(TYPE,"rgb") ) changed = ui_color3(label, PTR);
- else if( !strcmp(TYPE,"rgba") ) changed = ui_color4(label, PTR);
- else if( !strcmp(TYPE,"color") ) changed = ui_color4f(label, PTR);
- else if( !strcmp(TYPE,"color3f") ) changed = ui_color3f(label, PTR);
- else if( !strcmp(TYPE,"color4f") ) changed = ui_color4f(label, PTR);
- else if( !strcmp(TYPE,"char*") ) changed = ui_string(label, PTR);
- else ui_label2(label, va("(%s)", TYPE)); // INFO instead of (TYPE)?
- if( changed ) {
- editor_setchanged(PTR, 1);
- }
- if( ui_label_icon_highlight )
- if( ui_label_icon_clicked_L.x >= 6 && ui_label_icon_clicked_L.x <= 26 ) { // @hack: if clicked on UNDO icon (1st icon)
- editor_setchanged(PTR, 0);
- }
- if( !editor_changed(PTR) ) {
- obj_pop(o);
- }
- }
-}
-
-// ----------------------------------------------------------------------------------------
-// tty
-
-static thread_mutex_t *console_lock;
-static array(char*) editor_jobs;
-int editor_send(const char *cmd) { // return job-id
- int skip = strspn(cmd, " \t\r\n");
- char *buf = STRDUP(cmd + skip);
- strswap(buf, "\r\n", "");
- int jobid;
- do_threadlock(console_lock) {
- array_push(editor_jobs, buf);
- jobid = array_count(editor_jobs) - 1;
- }
- return jobid;
-}
-const char* editor_recv(int jobid, double timeout_ss) {
- char *answer = 0;
-
- while(!answer && timeout_ss >= 0 ) {
- do_threadlock(console_lock) {
- if( editor_jobs[jobid][0] == '\0' )
- answer = editor_jobs[jobid];
- }
- timeout_ss -= 0.1;
- if( timeout_ss > 0 ) sleep_ms(100); // thread_yield()
- }
-
- return answer + 1;
-}
-
-// plain and ctrl keys
-EDITOR_BIND(play, "down(F5)", { window_pause(0); /* if(!editor.slomo) editor.active = 0; */ editor.slomo = 1; } );
-EDITOR_BIND(stop, "down(ESC)", { if(editor.t > 0) { window_pause(1), editor.frame = 0, editor.t = 0, editor.dt = 0, editor.slomo = 0, editor.active = 1; editor_select("**"); editor_destroy_selected(); }} );
-EDITOR_BIND(eject, "down(F1)", { /*window_pause(!editor.active); editor.slomo = !!editor.active;*/ editor.active ^= 1; } );
-EDITOR_BIND(pause, "(held(CTRL) & down(P)) | down(PAUSE)", { window_pause( window_has_pause() ^ 1 ); } );
-EDITOR_BIND(frame, "held(CTRL) & down(LEFT)", { window_pause(1); editor.frame++, editor.t += (editor.dt = 1/60.f); } );
-EDITOR_BIND(slomo, "held(CTRL) & down(RIGHT)", { window_pause(0); editor.slomo = maxf(fmod(editor.slomo * 2, 16), 0.125); } );
-EDITOR_BIND(reload, "held(CTRL) & down(F5)", { window_reload(); } );
-EDITOR_BIND(filter, "held(CTRL) & down(F)", { editor.filter ^= 1; } );
-
-// alt keys
-EDITOR_BIND(quit, "held(ALT) & down(F4)", { record_stop(), exit(0); } );
-EDITOR_BIND(mute, "held(ALT) & down(M)", { audio_volume_master( 1 ^ !!audio_volume_master(-1) ); } );
-EDITOR_BIND(gamepad, "held(ALT) & down(G)", { editor.gamepad ^= 1; } );
-EDITOR_BIND(transparent, "held(ALT) & down(T)", { editor.transparent ^= 1; } );
-EDITOR_BIND(record, "held(ALT) & down(Z)", { if(record_active()) record_stop(), ui_notify(va("Video recorded"), date_string()); else { char *name = file_counter(va("%s.mp4",app_name())); app_beep(), window_record(name); } } );
-EDITOR_BIND(screenshot, "held(ALT) & down(S)", { char *name = file_counter(va("%s.png",app_name())); window_screenshot(name), ui_notify(va("Screenshot: %s", name), date_string()); } );
-EDITOR_BIND(battery, "held(ALT) & down(B)", { editor.battery ^= 1; } );
-EDITOR_BIND(outliner, "held(ALT) & down(O)", { ui_show("Outliner", ui_visible("Outliner") ^ true); } );
-EDITOR_BIND(profiler, "held(ALT) & down(P)", { ui_show("Profiler", profiler_enable(ui_visible("Profiler") ^ true)); } );
-EDITOR_BIND(fullscreen, "(held(ALT)&down(ENTER))|down(F11)",{ record_stop(), window_fullscreen( window_has_fullscreen() ^ 1 ); } ); // close any recording before framebuffer resizing, which would corrupt video stream
-EDITOR_BIND(unlit, "held(ALT) & down(U)", { editor.unlit ^= 1; } );
-EDITOR_BIND(ddraw, "held(ALT) & down(D)", { editor.ddraw ^= 1; } );
-
-void editor_pump() {
- for each_array(editor_binds,editor_bind_t,b) {
- if( input_eval(b.bindings) ) {
- editor_send(b.command);
- }
- }
-
- do_threadlock(console_lock) {
- for each_array_ptr(editor_jobs,char*,cmd) {
- if( (*cmd)[0] ) {
- int found = 0;
- for each_array(editor_binds,editor_bind_t,b) {
- if( !strcmpi(b.command, *cmd)) {
- b.fn();
- found = 1;
- break;
- }
- }
-
- if( !found ) {
- // alert(va("Editor: could not handle `%s` command.", *cmd));
- (*cmd)[0] = '\0'; strcatf(&(*cmd), "\1%s\n", "Err\n"); (*cmd)[0] = '\0';
- }
-
- if( (*cmd)[0] ) {
- (*cmd)[0] = '\0'; strcatf(&(*cmd), "\1%s\n", "Ok\n"); (*cmd)[0] = '\0';
- }
- }
- }
- }
-}
-
-// ----------------------------------------------------------------------------------------
-
-void editor_symbol(int x, int y, const char *sym) {
- #define FONT_SYMBOLS FONT_FACE2
- #define FONT_WHITE FONT_COLOR1
- #define FONT_YELLOW FONT_COLOR2
- #define FONT_ORANGE FONT_COLOR3
- #define FONT_CYAN FONT_COLOR4
- // style: atlas size, unicode ranges and 6 font faces max
- do_once font_face(FONT_SYMBOLS, "MaterialIconsSharp-Regular.otf", 24.f, FONT_EM|FONT_2048);
- // style: 10 colors max
- do_once font_color(FONT_WHITE, WHITE);
- do_once font_color(FONT_YELLOW, YELLOW);
- do_once font_color(FONT_CYAN, CYAN);
- do_once font_color(FONT_ORANGE, ORANGE);
- font_goto(x,y);
- font_print(va(FONT_SYMBOLS FONT_WHITE FONT_H1 "%s", sym));
-}
-
-void editor_frame( void (*game)(unsigned, float, double) ) {
- do_once {
- set_init_ptr(editor.world);
- //set_init_ptr(editor.selection);
- profiler_enable( false );
-
- window_pause( true );
- window_cursor_shape(CURSOR_SW_AUTO);
- editor.hz_high = window_fps_target();
-
- fx_load("editorOutline.fs");
- fx_enable(0, 1);
-
- obj_setname(editor.root = obj_new(obj), "Signals");
- obj_setname(editor.on_init = obj_new(obj), "onInit");
- obj_setname(editor.on_tick = obj_new(obj), "onTick");
- obj_setname(editor.on_draw = obj_new(obj), "onDraw");
- obj_setname(editor.on_edit = obj_new(obj), "onEdit");
- obj_setname(editor.on_quit = obj_new(obj), "onQuit");
-
- obj_attach(editor.root, editor.on_init);
- obj_attach(editor.root, editor.on_tick);
- obj_attach(editor.root, editor.on_draw);
- obj_attach(editor.root, editor.on_edit);
- obj_attach(editor.root, editor.on_quit);
-
- editor_seticoninstance(editor.root, ICON_MDI_SIGNAL_VARIANT);
- editor_seticoninstance(editor.on_init, ICON_MDI_SIGNAL_VARIANT);
- editor_seticoninstance(editor.on_tick, ICON_MDI_SIGNAL_VARIANT);
- editor_seticoninstance(editor.on_draw, ICON_MDI_SIGNAL_VARIANT);
- editor_seticoninstance(editor.on_edit, ICON_MDI_SIGNAL_VARIANT);
- editor_seticoninstance(editor.on_quit, ICON_MDI_SIGNAL_VARIANT);
-
- editor_seticonclass(obj_type(editor.root), ICON_MDI_CUBE_OUTLINE);
- }
-
- // game tick
- game(editor.frame, editor.dt, editor.t);
-
- // timing
- editor.dt = clampf(window_delta(), 0, 1/60.f) * !window_has_pause() * editor.slomo;
- editor.t += editor.dt;
- editor.frame += !window_has_pause();
- editor.frame += !editor.frame;
-
- // process inputs & messages
- editor_pump();
-
- // adaptive framerate
- int app_on_background = !window_has_focus();
- int hz = app_on_background ? editor.hz_low : editor.battery ? editor.hz_medium : editor.hz_high;
- window_fps_lock( hz < 5 ? 5 : hz );
-
- // draw menubar
- static int stats_mode = 1;
- static double last_fps = 0; if(!window_has_pause()) last_fps = window_fps();
- const char *STATS = va("x%4.3f %03d.%03dss %02dF %s",
- editor.slomo, (int)editor.t, (int)(1000 * (editor.t - (int)editor.t)),
- (editor.frame-1) % ((int)window_fps_target() + !(int)window_fps_target()),
- stats_mode == 1 ? va("%5.2f/%dfps", last_fps, (int)window_fps_target()) : stats_mode == 0 ? "0/0 KiB" : xstats());
- const char *ICON_PL4Y = window_has_pause() ? ICON_MDI_PLAY : ICON_MDI_PAUSE;
- const char *ICON_SKIP = window_has_pause() ? ICON_MDI_STEP_FORWARD/*ICON_MDI_SKIP_NEXT*/ : ICON_MDI_FAST_FORWARD;
-
- int is_borderless = !glfwGetWindowAttrib(window, GLFW_DECORATED);
- int ingame = !editor.active;
- static double clicked_titlebar = 0;
- UI_MENU(14+is_borderless, \
- if(ingame) ui_disable(); \
- UI_MENU_ITEM(ICON_MDI_FILE_TREE, editor_send("scene")) \
- if(ingame) ui_enable(); \
- UI_MENU_ITEM(ICON_PL4Y, if(editor.t == 0) editor_send("eject"); editor_send(window_has_pause() ? "play" : "pause")) \
- UI_MENU_ITEM(ICON_SKIP, editor_send(window_has_pause() ? "frame" : "slomo")) \
- UI_MENU_ITEM(ICON_MDI_STOP, editor_send("stop")) \
- UI_MENU_ITEM(ICON_MDI_EJECT, editor_send("eject")) \
- UI_MENU_ITEM(STATS, stats_mode = (++stats_mode) % 3) \
- UI_MENU_ALIGN_RIGHT(32+32+32+32+32+32+34 + 32*is_borderless, clicked_titlebar = time_ms()) \
- if(ingame) ui_disable(); \
- UI_MENU_ITEM(ICON_MD_FOLDER_SPECIAL, editor_send("browser")) \
- UI_MENU_ITEM(ICON_MDI_SCRIPT_TEXT, editor_send("script")) \
- UI_MENU_ITEM(ICON_MDI_CHART_TIMELINE, editor_send("timeline")) \
- UI_MENU_ITEM(ICON_MDI_CONSOLE, editor_send("console")) \
- UI_MENU_ITEM(ICON_MDI_GRAPH, editor_send("nodes")) \
- UI_MENU_ITEM(ICON_MD_SEARCH, editor_send("filter")) \
- UI_MENU_POPUP(ICON_MD_SETTINGS, vec2(0.33,1.00), ui_debug()) \
- if(ingame) ui_enable(); \
- UI_MENU_ITEM(ICON_MD_CLOSE, editor_send("quit")) \
- );
-
- if( is_borderless ) {
- static vec3 drag = {0};
- if( clicked_titlebar ) {
- static double clicks = 0;
- if( input_up(MOUSE_L) ) ++clicks;
- if( input_up(MOUSE_L) && clicks == 2 ) window_visible(false), window_maximize( window_has_maximize() ^ 1 ), window_visible(true);
- if( (time_ms() - clicked_titlebar) > 400 ) clicks = 0, clicked_titlebar = 0;
-
- if( input_down(MOUSE_L) ) drag = vec3(input(MOUSE_X), input(MOUSE_Y), 1);
- }
- if( drag.z *= !input_up(MOUSE_L) ) {
- int wx = 0, wy = 0;
- glfwGetWindowPos(window_handle(), &wx, &wy);
- glfwSetWindowPos(window_handle(), wx + input(MOUSE_X) - drag.x, wy + input(MOUSE_Y) - drag.y);
- }
- }
-
- if( !editor.active ) return;
-
- // draw edit view (gizmos, position markers, etc).
- for each_set_ptr(editor.world,obj*,o) {
- if( obj_hasmethod(*o,edit) ) {
- obj_edit(*o);
- }
- }
-
- // draw silhouettes
- sprite_flush();
- fx_begin();
- for each_map_ptr(*editor_selected_map(),void*,o,int,selected) {
- if( !*selected ) continue;
- if( obj_hasmethod(*o,draw) ) {
- obj_draw(*o);
- }
- if( obj_hasmethod(*o,edit) ) {
- obj_edit(*o);
- }
- }
- sprite_flush();
- fx_end();
-
- // draw box selection
- if( !ui_active() ) { //< check that we're not moving a window
- static vec2 from = {0}, to = {0};
- if( input_down(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y)), from = to;
- if( input(MOUSE_L) ) to = vec2(input(MOUSE_X), input(MOUSE_Y));
- if( len2sq(sub2(from,to)) > 0 ) {
- vec2 a = min2(from, to), b = max2(from, to);
- ddraw_push_2d();
- ddraw_color_push(YELLOW);
- ddraw_line( vec3(a.x,a.y,0),vec3(b.x-1,a.y,0) );
- ddraw_line( vec3(b.x,a.y,0),vec3(b.x,b.y-1,0) );
- ddraw_line( vec3(b.x,b.y,0),vec3(a.x-1,b.y,0) );
- ddraw_line( vec3(a.x,b.y,0),vec3(a.x,a.y-1,0) );
- ddraw_color_pop();
- ddraw_pop_2d();
- }
- if( input_up(MOUSE_L) ) {
- vec2 a = min2(from, to), b = max2(from, to);
- from = to = vec2(0,0);
-
- editor_select_aabb(aabb(vec3(a.x,a.y,0),vec3(b.x,b.y,0)));
- }
- }
-
- // draw mouse aabb
- aabb mouse = { vec3(input(MOUSE_X),input(MOUSE_Y),0), vec3(input(MOUSE_X),input(MOUSE_Y),1)};
- if( 1 ) {
- ddraw_color_push(YELLOW);
- ddraw_push_2d();
- ddraw_aabb(mouse.min, mouse.max);
- ddraw_pop_2d();
- ddraw_color_pop();
- }
-
- // tick mouse aabb selection and contextual tab (RMB)
- aabb box = {0};
- for each_set(editor.world,obj*,o) {
- if( !obj_hasmethod(o, aabb) ) continue;
- if( !obj_aabb(o, &box) ) continue;
-
- // trigger contextual inspector
- if( input_down(MOUSE_R) ) {
- int is_selected = editor_selected(o);
- editor_setpopup(o, is_selected);
- }
-
- // draw contextual inspector
- if( editor_popup(o) ) {
- if( editor_begin(va("%s (%s)", obj_name(o), obj_type(o)),EDITOR_WINDOW_NK_SMALL) ) {
- ui_label2(obj_name(o), obj_type(o));
- editor_inspect(o);
- editor_end(EDITOR_WINDOW_NK_SMALL);
- } else {
- editor_setpopup(o, 0);
- }
- }
- }
-
-
- // draw subeditors
- static int preferred_window_mode = EDITOR_WINDOW;
- static struct nk_color bak, *on = 0; do_once bak = ui_ctx->style.window.fixed_background.data.color; // ui_ctx->style.window.fixed_background.data.color = !!(on = (on ? NULL : &bak)) ? AS_NKCOLOR(0) : bak; };
- if( editor.transparent ) ui_ctx->style.window.fixed_background.data.color = AS_NKCOLOR(0);
- for each_array(editor.subeditors, subeditor, fn) {
- fn(preferred_window_mode);
- }
- ui_ctx->style.window.fixed_background.data.color = bak;
-
- // draw ui filter (note: render at end-of-frame, so it's hopefully on-top)
- editor_filter();
-}
-
-#include "v4k_editor1_scene.h"
-#include "v4k_editor2_browser.h"
-#include "v4k_editor3_timeline.h"
-#include "v4k_editor4_console.h"
-#include "v4k_editor5_nodes.h"
-#include "v4k_editor6_script.h"
diff --git a/tools/editor/v4k_sprite.c b/tools/editor/v4k_sprite.c
deleted file mode 100644
index a0a7e10..0000000
--- a/tools/editor/v4k_sprite.c
+++ /dev/null
@@ -1,455 +0,0 @@
-#include "engine/v4k.c"
-
-// texture_t texture_createclip(unsigned cx,unsigned cy,unsigned cw,unsigned ch, unsigned tw,unsigned th,unsigned tn,void *pixels, unsigned flags) {
-// return texture_create(tw,th,tn,pixels,flags);
-// static array(unsigned) clip = 0;
-// array_resize(clip, cw*ch*4);
-// for( unsigned y = 0; y < ch; ++y )
-// memcpy((char *)clip + (0+(0+y)*cw)*tn, (char*)pixels + (cx+(cy+y)*tw)*tn, cw*tn);
-// return texture_create(cw,ch,tn,clip,flags);
-// }
-
-#define array_reserve_(arr,x) (array_count(arr) > (x) ? (arr) : array_resize(arr, 1+(x)))
-
-#define ui_array(label,type,ptr) do { \
- int changed = 0; \
- if( ui_collapse(label, va(#type "%p",ptr)) ) { \
- char label_ex[8]; \
- for( int idx = 0, iend = array_count(*(ptr)); idx < iend; ++idx ) { \
- type* it = *(ptr) + idx; \
- snprintf(label_ex, sizeof(label_ex), "[%d]", idx); \
- changed |= ui_##type(label_ex, it); \
- } \
- ui_collapse_end(); \
- } \
-} while(0)
-
-int ui_vec2i(const char *label, vec2i *v) { return ui_unsigned2(label, (unsigned*)v); }
-int ui_vec3i(const char *label, vec3i *v) { return ui_unsigned3(label, (unsigned*)v); }
-int ui_vec2(const char *label, vec2 *v) { return ui_float2(label, (float*)v); }
-int ui_vec3(const char *label, vec3 *v) { return ui_float3(label, (float*)v); }
-int ui_vec4(const char *label, vec4 *v) { return ui_float4(label, (float*)v); }
-
-char *trimspace(char *str) {
- for( char *s = str; *s; ++s )
- if(*s <= 32) memmove(s, s+1, strlen(s));
- return str;
-}
-
-char *file_parent(const char *f) { // folder/folder/abc
- char *p = file_path(f); // folder/folder/
- char *last = strrchr(p, '/'); // ^
- if( !last ) return p; // return parent if no sep
- *last = '\0'; // folder/folder
- last = strrchr(p, '/'); // ^
- return last ? last + 1 : p; // return parent if no sep
-}
-
-int ui_obj(const char *fmt, obj *o) {
- int changed = 0, item = 1;
- for each_objmember(o, TYPE,NAME,PTR) {
- char *label = va(fmt, NAME);
- /**/ if(!strcmp(TYPE,"float")) { if(ui_float(label, PTR)) changed = item; }
- else if(!strcmp(TYPE,"int")) { if(ui_int(label, PTR)) changed = item; }
- else if(!strcmp(TYPE,"unsigned")) { if(ui_unsigned(label, PTR)) changed = item; }
- else if(!strcmp(TYPE,"vec2")) { if(ui_float2(label, PTR)) changed = item; }
- else if(!strcmp(TYPE,"vec3")) { if(ui_float3(label, PTR)) changed = item; }
- else if(!strcmp(TYPE,"vec4")) { if(ui_float4(label, PTR)) changed = item; }
- else if(!strcmp(TYPE,"rgb")) { if(ui_color3(label, PTR)) changed = item; }
- else if(!strcmp(TYPE,"rgba")) { if(ui_color4(label, PTR)) changed = item; }
- else if(!strcmp(TYPE,"color")) { if(ui_color4f(label, PTR)) changed = item; }
- else if(!strcmp(TYPE,"color3f")) { if(ui_color3f(label, PTR)) changed = item; }
- else if(!strcmp(TYPE,"color4f")) { if(ui_color4f(label, PTR)) changed = item; }
- else if(!strcmp(TYPE,"char*")) { if(ui_string(label, PTR)) changed = item; }
- else ui_label2(label, va("(%s)", TYPE)); // INFO instead of (TYPE)?
- ++item;
- }
- return changed;
-}
-
-
-TODO("serialize array(types)")
-TODO("serialize map(char*,types)")
-TODO("serialize map(int,types)")
-TODO("sprite: solid platforms, one-way platforms")
-TODO("sprite: shake left-right, up-down")
-TODO("sprite: coyote time")
-TODO("sprite: jump buffering before grounded")
-TODO("sprite: double jump, wall sliding, wall climbing")
-TODO("sprite: hitbox for enemies -> wall detection")
-
-#define OBJTYPEDEF2(...) OBJTYPEDEF(__VA_ARGS__); AUTORUN
-
-typedef unsigned quark_t;
-
-typedef struct atlas_frame_t {
- unsigned delay;
- vec4 sheet;
- vec2 anchor; // @todo
- array(vec3i) indices;
- array(vec2) coords;
- array(vec2) uvs;
-} atlas_frame_t;
-
-typedef struct atlas_anim_t {
- quark_t name;
- array(unsigned) frames;
-} atlas_anim_t;
-
-typedef struct atlas_t {
- texture_t tex;
-
- array(atlas_frame_t) frames;
- array(atlas_anim_t) anims;
-
- quarks_db db;
-} atlas_t;
-
-int ui_atlas_frame(atlas_frame_t *f) {
- ui_unsigned("delay", &f->delay);
- ui_vec4("sheet", &f->sheet);
- ui_array("indices", vec3i, &f->indices);
- ui_array("coords", vec2, &f->coords);
- ui_array("uvs", vec2, &f->uvs);
- return 0;
-}
-
-int ui_atlas(atlas_t *a) {
- int changed = 0;
- ui_texture(NULL, a->tex);
- for( int i = 0; i < array_count(a->anims); ++i ) {
- if( ui_collapse(quark_string(&a->db, a->anims[i].name), va("%p%d", a, a->anims[i].name) ) ) {
- changed = i+1;
- for( int j = 0; j < array_count(a->anims[i].frames); ++j ) {
- if( ui_collapse(va("[%d]",j), va("%p%d.%d", a, a->anims[i].name,j) ) ) {
- ui_unsigned("Frame", &a->anims[i].frames[j]);
- ui_atlas_frame(a->frames + a->anims[i].frames[j]);
- ui_collapse_end();
- }
- }
- ui_collapse_end();
- }
- }
- return changed;
-}
-
-void atlas_destroy(atlas_t *a) {
- if( a ) {
- texture_destroy(&a->tex);
- memset(a, 0, sizeof(atlas_t));
- }
-}
-atlas_t atlas_create(const char *inifile, unsigned flags) {
- atlas_t a = {0};
- int padding = 0, border = 0;
-
- ini_t kv = ini(inifile);
- for each_map(kv, char*,k, char*,v ) {
- unsigned index = atoi(k);
- /**/ if( strend(k, ".name") ) {
- array_reserve_(a.anims, index);
-
- a.anims[index].name = quark_intern(&a.db, v);
- }
- else if( strend(k, ".frames") ) {
- array_reserve_(a.anims, index);
-
- array(char*) pairs = strsplit(v, ",");
- for( int i = 0, end = array_count(pairs); i < end; i += 2 ) {
- unsigned frame = atoi(pairs[i]);
- unsigned delay = atoi(pairs[i+1]);
-
- array_reserve_(a.frames, frame);
- a.frames[frame].delay = delay;
-
- array_push(a.anims[index].frames, frame);
- }
- }
- else if( strend(k, ".sheet") ) {
- array_reserve_(a.frames, index);
-
- vec4 sheet = atof4(v); //x,y,x2+2,y2+2 -> x,y,w,h (for 2,2 padding)
- a.frames[index].sheet = vec4(sheet.x,sheet.y,sheet.z-sheet.x,sheet.w-sheet.y);
- }
- else if( strend(k, ".indices") ) {
- array_reserve_(a.frames, index);
-
- const char *text = v;
- array(char*) tuples = strsplit(text, ",");
- for( int i = 0, end = array_count(tuples); i < end; i += 3 ) {
- unsigned p1 = atoi(tuples[i]);
- unsigned p2 = atoi(tuples[i+1]);
- unsigned p3 = atoi(tuples[i+2]);
- array_push(a.frames[index].indices, vec3i(p1,p2,p3));
- }
- }
- else if( strend(k, ".coords") ) {
- array_reserve_(a.frames, index);
-
- const char *text = v;
- array(char*) pairs = strsplit(text, ",");
- for( int i = 0, end = array_count(pairs); i < end; i += 2 ) {
- unsigned x = atoi(pairs[i]);
- unsigned y = atoi(pairs[i+1]);
- array_push(a.frames[index].coords, vec2(x,y));
- }
- }
- else if( strend(k, ".uvs") ) {
- array_reserve_(a.frames, index);
-
- const char *text = v;
- array(char*) pairs = strsplit(text, ",");
- for( int i = 0, end = array_count(pairs); i < end; i += 2 ) {
- unsigned u = atoi(pairs[i]);
- unsigned v = atoi(pairs[i+1]);
- array_push(a.frames[index].uvs, vec2(u,v));
- }
- }
- else if( strend(k, "padding") ) {
- padding = atoi(v);
- }
- else if( strend(k, "border") ) {
- border = atoi(v);
- }
- else if( strend(k, "file") ) {
- a.tex = texture(v, 0);
- }
- else if( strend(k, "bitmap") ) {
- const char *text = v;
- array(char) bin = base64_decode(text, strlen(text));
- a.tex = texture_from_mem(bin, array_count(bin), 0);
- array_free(bin);
- }
-#if 0
- else if( strend(k, ".frame") ) {
- array_reserve_(a.frames, index);
- puts(k), puts(v);
- }
-#endif
- }
-
- // post-process: normalize uvs and coords into [0..1] ranges
- for each_array_ptr(a.frames, atlas_frame_t, f) {
- for each_array_ptr(f->uvs, vec2, uv) {
- uv->x /= a.tex.w;
- uv->y /= a.tex.h;
- }
- for each_array_ptr(f->coords, vec2, xy) {
- xy->x /= a.tex.w;
- xy->y /= a.tex.h;
- }
- // @todo: adjust padding/border
- }
-#if 0
- // post-process: specify an anchor for each anim based on 1st frame dims
- for each_array_ptr(a.anims, atlas_anim_t, anim) {
- atlas_frame_t *first = a.frames + *anim->frames;
- for( int i = 0; i < array_count(anim->frames); i += 2) {
- atlas_frame_t *ff = a.frames + anim->frames[ i ];
- ff->anchor.x = (ff->sheet.z - first->sheet.z) / 2;
- ff->anchor.y = (ff->sheet.w - first->sheet.w) / 2;
- }
- }
-#endif
-
- return a;
-}
-
-typedef struct sprite2 { OBJ
- vec4 gamepad; // up,down,left,right
- vec2 fire; // a,b
-
- vec3 pos;
- float tilt;
- unsigned tint;
- unsigned frame;
- unsigned timer, timer_ms;
- unsigned flip_, flipped;
- unsigned play;
- bool paused;
- // array(unsigned) play_queue; or unsigned play_next;
- atlas_t *a; // shared
- atlas_t own; // owned
-} sprite2;
-
-void sprite2_setanim(sprite2 *s, unsigned name) {
- if( s->play != name ) {
- s->play = name;
- s->frame = 0;
-
- atlas_frame_t *f = &s->a->frames[ s->a->anims[s->play].frames[s->frame] ];
-
- s->timer_ms = f->delay;
- s->timer = s->timer_ms;
- }
-}
-
-void sprite2_ctor(sprite2 *s) {
- s->tint = WHITE;
- s->timer_ms = 100;
- s->flipped = 1;
-}
-void sprite2_dtor(sprite2 *s) {
- memset(s, 0, sizeof(*s));
-}
-void sprite2_tick(sprite2 *s) {
- int move = input(s->gamepad.array[3]) - input(s->gamepad.array[2]); // RIGHT - LEFT
- int dt = 16; // window_delta() * 1000;
-
- unsigned over = (s->timer - dt) > s->timer;
- if(!s->paused)
- s->timer -= dt;
- if( over ) {
-
- int len = array_count(s->a->anims[s->play].frames);
- unsigned next = (s->frame + 1) % (len + !len);
- unsigned eoa = next < s->frame;
- s->frame = next;
-
- atlas_frame_t *f = &s->a->frames[ s->a->anims[s->play].frames[s->frame] ];
- s->timer_ms = f->delay;
- s->timer += s->timer_ms;
- }
-
- if( s->play == 0 && move ) sprite2_setanim(s, 1);
- if( s->play == 1 ) { //<
- float speed = 1.0f;
- if(move) s->pos.x += speed * move, s->flip_ = move < 0, sprite2_setanim(s, 1);
- else sprite2_setanim(s, 0);
- }
-}
-void sprite2_draw(sprite2 *s) {
- atlas_frame_t *f = &s->a->frames[ s->a->anims[s->play].frames[s->frame] ];
-
-#if 1
- // @todo {
- unsigned sample = s->a->anims[s->play].frames[s->frame];
- sample = 0;
- f->anchor.x = (-s->a->frames[sample].sheet.z + f->sheet.z) / 2;
- f->anchor.y = (+s->a->frames[sample].sheet.w - f->sheet.w) / 2;
- // }
-#endif
-
- // rect(x,y,w,h) is [0..1] normalized, z-index, pos(x,y,scale), rotation (degrees), color (rgba)
- vec4 rect = { f->sheet.x / s->a->tex.w, f->sheet.y / s->a->tex.h, f->sheet.z / s->a->tex.w, f->sheet.w / s->a->tex.h };
- sprite_rect(s->a->tex, rect, s->pos.y, vec4(s->pos.x+f->anchor.x,s->pos.y+f->anchor.y,s->flip_ ^ s->flipped?1:-1,1), s->tilt, s->tint);
-}
-void sprite2_edit(sprite2 *s) {
- const char *id = vac("%p", s);
- if( s && ui_collapse(id, id) ) {
- ui_obj("%s", (obj*)s);
-
- ui_bool("paused", &s->paused);
- ui_label(va("frame anim [%d]", s->a->anims[s->play].frames[s->frame]));
-
- int k = s->play;
- if( ui_int("anim", &k) ) {
- sprite2_setanim(s, k);
- }
-
- int selected = ui_atlas(s->a);
- if( selected ) sprite2_setanim(s, selected - 1);
-
- ui_collapse_end();
- }
-}
-
-OBJTYPEDEF(sprite2,10);
-AUTORUN {
- STRUCT(sprite2, vec4, gamepad);
- STRUCT(sprite2, vec2, fire);
- STRUCT(sprite2, vec3, pos);
- STRUCT(sprite2, float, tilt);
- STRUCT(sprite2, rgba, tint);
- STRUCT(sprite2, unsigned, frame);
- STRUCT(sprite2, unsigned, timer);
- STRUCT(sprite2, unsigned, timer_ms);
- STRUCT(sprite2, unsigned, flipped);
- STRUCT(sprite2, unsigned, play);
- EXTEND(sprite2, ctor,edit,draw,tick);
-}
-
-sprite2* sprite2_new(const char *ase, int bindings[6]) {
- sprite2 *s = obj_new(sprite2, {bindings[0],bindings[1],bindings[2],bindings[3]}, {bindings[4],bindings[5]});
- s->own = atlas_create(ase, 0);
- s->a = &s->own;
- return s;
-}
-void sprite2_del(sprite2 *s) {
- if( s ) {
- if( s->a == &s->own ) atlas_destroy(&s->own);
- obj_free(s);
- memset(s, 0, sizeof(sprite2));
- }
-}
-
-
-
-void game(unsigned frame) {
- static camera_t cam;
- static sprite2 *s1 = 0;
- static sprite2 *s2 = 0;
- static sprite2 *s3 = 0;
- static sprite2 *s4 = 0;
- if( !frame ) {
- // camera center(x,y) zoom(z)
- cam = camera();
- cam.position = vec3(window_width()/2,window_height()/2,8);
- camera_enable(&cam);
-
- sprite2_del(s1);
- sprite2_del(s2);
- sprite2_del(s3);
- sprite2_del(s4);
-
- s1 = sprite2_new("Captain Clown Nose.ase", (int[6]){KEY_UP,KEY_DOWN,KEY_LEFT,KEY_RIGHT,KEY_A,KEY_S});
- s2 = sprite2_new("Crew-Crabby.ase", (int[6]){KEY_I,KEY_K,KEY_J,KEY_L} );
- s3 = sprite2_new("Props-Shooter Traps.ase", (int[6]){0} );
- s4 = sprite2_new("Crew-Fierce Tooth.ase", (int[6]){0,0,KEY_N,KEY_M} );
-
- // pos and z-order
- s1->pos = vec3(window_width()/2, window_height()/2, 2);
- s2->pos = vec3(window_width()/2, window_height()/2, 1);
- s3->pos = vec3(window_width()/2, window_height()/2, 1);
- s4->pos = vec3(window_width()/2, window_height()/2, 1);
-
- s4->flipped ^= 1;
- }
-
- // camera panning (x,y) & zooming (z)
- if( !ui_hover() && !ui_active() ) {
- if( input(MOUSE_L) ) cam.position.x -= input_diff(MOUSE_X);
- if( input(MOUSE_L) ) cam.position.y -= input_diff(MOUSE_Y);
- cam.position.z += input_diff(MOUSE_W) * 0.1; // cam.p.z += 0.001f; for tests
- }
-
- obj_tick(s1);
- obj_draw(s1);
-
- obj_tick(s2);
- obj_draw(s2);
-
- obj_tick(s3);
- obj_draw(s3);
-
- obj_tick(s4);
- obj_draw(s4);
-
- if( ui_panel("Sprites", PANEL_OPEN)) {
- obj_edit(s1);
- obj_edit(s2);
- obj_edit(s3);
- obj_edit(s4);
- ui_panel_end();
- }
-}
-
-int main() {
- unsigned frame = 0;
-
- for( window_create(0.75, 0); window_swap(); ) {
- if( input_down(KEY_Z) && input(KEY_ALT) ) window_record(file_counter(va("%s.mp4",app_name())));
- if( input_down(KEY_F5) ) frame = 0;
- game( frame++ );
- }
-}
\ No newline at end of file
diff --git a/tools/join.py b/tools/join.py
index 1bb6413..d97c740 100644
--- a/tools/join.py
+++ b/tools/join.py
@@ -35,7 +35,7 @@ def process_command(name, value):
file_path = os.path.join(input_path, value)
print("Appending file: " + value)
with open(file_path, "r") as file:
- res = "#line 1 \"engine/split/" + value + "\"\n"
+ res = "#line 1 \"" + value + "\"\n"
res += file.read()
res += "#line 0"
return res
diff --git a/tools/editor/labs.osc/MAKE.bat b/tools/labs/MAKE.bat
similarity index 63%
rename from tools/editor/labs.osc/MAKE.bat
rename to tools/labs/MAKE.bat
index 6689d74..429b545 100644
--- a/tools/editor/labs.osc/MAKE.bat
+++ b/tools/labs/MAKE.bat
@@ -16,12 +16,12 @@
exit /b
)
-if not exist "*.zip" ..\..\..\tools\cook --cook-ini=..\..\cook.ini
+if not exist "*.zip" ..\..\tools\cook --cook-ini=..\..\cook.ini
taskkill /im "oscedit.exe" > nul 2> nul
-call ..\..\..\tools\tcc oscgame.c -I ..\..\..\engine\joint -DFWK_IMPLEMENTATION -DCOOK_ON_DEMAND %*
-call ..\..\..\tools\tcc oscsend.c -I ..\..\..\engine\joint -DFWK_IMPLEMENTATION -DCOOK_ON_DEMAND %*
-call ..\..\..\tools\tcc oscedit.c -I ..\..\..\engine\joint -DFWK_IMPLEMENTATION -DCOOK_ON_DEMAND %* && start oscedit.exe
+call ..\..\tools\tcc oscgame.c -I ..\..\engine\joint -DFWK_IMPLEMENTATION -DCOOK_ON_DEMAND %*
+call ..\..\tools\tcc oscsend.c -I ..\..\engine\joint -DFWK_IMPLEMENTATION -DCOOK_ON_DEMAND %*
+call ..\..\tools\tcc oscedit.c -I ..\..\engine\joint -DFWK_IMPLEMENTATION -DCOOK_ON_DEMAND %* && start oscedit.exe
timeout 3
diff --git a/tools/labs/cmder.c b/tools/labs/cmder.c
new file mode 100644
index 0000000..0392836
--- /dev/null
+++ b/tools/labs/cmder.c
@@ -0,0 +1,42 @@
+#include
+#include
+#include
+
+void _tmain( int argc, TCHAR *argv[] )
+{
+ if( argc < 2 )
+ {
+ printf("Usage: %s [cmdline]\n", argv[0]);
+ return;
+ }
+
+ PROCESS_INFORMATION pi = {0};
+ STARTUPINFO si = {0}; si.cb = sizeof(si);
+
+ char cmdline[32767], *ptr = cmdline;
+ for( int i = 1; i < argc; ++i ) ptr += sprintf(ptr, " %s", argv[i]);
+
+ // Start the child process.
+ if( !CreateProcess( NULL, // No module name (use command line)
+ cmdline+1, // Command line
+ NULL, // Process handle not inheritable
+ NULL, // Thread handle not inheritable
+ FALSE, // Set handle inheritance to FALSE
+ 0, // No creation flags
+ NULL, // Use parent's environment block
+ NULL, // Use parent's starting directory
+ &si, // Pointer to STARTUPINFO structure
+ &pi ) // Pointer to PROCESS_INFORMATION structure
+ )
+ {
+ printf( "CreateProcess failed (%d).\n", GetLastError() );
+ return;
+ }
+
+ // Wait until child process exits.
+ WaitForSingleObject( pi.hProcess, INFINITE );
+
+ // Close process and thread handles.
+ CloseHandle( pi.hProcess );
+ CloseHandle( pi.hThread );
+}
diff --git a/tools/labs/dll.c b/tools/labs/dll.c
new file mode 100644
index 0000000..244e9ea
--- /dev/null
+++ b/tools/labs/dll.c
@@ -0,0 +1,16 @@
+#include "engine/fwk.c"
+
+int main() {
+ int (*dll_main)(int argc, char **argv);
+ dll_main = dll("tools/ase2ini.exe","main"); // crashes
+ printf("%p\n", dll_main);
+ dll_main = dll("tools/ase2ini.dll","main");
+ printf("%p\n", dll_main);
+
+ benchmark {
+ for( int i = 0; i < 10000; ++i ) {
+ char *args[] = { "ase2ini.exe", "demos/art/sprites/Treasure Hunters/Captain Clown Nose.ase", 0 };
+ dll_main(countof(args)-1, args);
+ }
+ }
+}
diff --git a/tools/editor/labs.vm/ecs.c b/tools/labs/ecs.c
similarity index 100%
rename from tools/editor/labs.vm/ecs.c
rename to tools/labs/ecs.c
diff --git a/tools/editor/editor.h b/tools/labs/editor.h
similarity index 99%
rename from tools/editor/editor.h
rename to tools/labs/editor.h
index f72c99b..d136b84 100644
--- a/tools/editor/editor.h
+++ b/tools/labs/editor.h
@@ -1,4 +1,5 @@
-#if 0
+#if 1
+#elif 0
#define ICON_EVENT ICON_MDI_CALENDAR
//#define ICON_CIRCLE ICON_MDI_CIRCLE_OUTLINE
diff --git a/tools/editor/labs.vm/fwk_diff.md b/tools/labs/fwk_diff.md
similarity index 100%
rename from tools/editor/labs.vm/fwk_diff.md
rename to tools/labs/fwk_diff.md
diff --git a/tools/editor/labs.vm/fwk_obj.c b/tools/labs/fwk_obj.c
similarity index 100%
rename from tools/editor/labs.vm/fwk_obj.c
rename to tools/labs/fwk_obj.c
diff --git a/tools/editor/labs.vm/hybrid-p2p.md b/tools/labs/hybrid-p2p.md
similarity index 100%
rename from tools/editor/labs.vm/hybrid-p2p.md
rename to tools/labs/hybrid-p2p.md
diff --git a/tools/editor/labs.meta/meta_dna.c b/tools/labs/meta_dna.c
similarity index 100%
rename from tools/editor/labs.meta/meta_dna.c
rename to tools/labs/meta_dna.c
diff --git a/tools/editor/labs.meta/meta_info.c b/tools/labs/meta_info.c
similarity index 99%
rename from tools/editor/labs.meta/meta_info.c
rename to tools/labs/meta_info.c
index 3adfb98..32d1b22 100644
--- a/tools/editor/labs.meta/meta_info.c
+++ b/tools/labs/meta_info.c
@@ -1,6 +1,6 @@
//#define META_DEMO
-#include "v4k.h"
+#include "fwk.h"
#include
#include
diff --git a/tools/editor/labs.meta/meta_tool.c b/tools/labs/meta_tool.c
similarity index 97%
rename from tools/editor/labs.meta/meta_tool.c
rename to tools/labs/meta_tool.c
index 723dd2c..a381339 100644
--- a/tools/editor/labs.meta/meta_tool.c
+++ b/tools/labs/meta_tool.c
@@ -1,5 +1,5 @@
-#define V4K_C
-#include "v4k.h"
+#define FWK_C
+#include "fwk.h"
bool parse_struct(const char *line) {
return strstr(line, "s""truct ");
diff --git a/tools/labs/mt.c b/tools/labs/mt.c
new file mode 100644
index 0000000..e463d96
--- /dev/null
+++ b/tools/labs/mt.c
@@ -0,0 +1,137 @@
+https://devblogs.microsoft.com/oldnewthing/20200306-00/?p=103538
+
+#include "engine/fwk.c"
+
+char *trimspace(char *str) {
+ for( char *s = str; *s; ++s )
+ if(*s <= 32) memmove(s, s+1, strlen(s));
+ return str;
+}
+char *trimleads(char *str) {
+ int cnt = 0;
+ while( str[cnt] && str[cnt] <= 32 ) ++cnt;
+ if( cnt ) memmove(str, str+cnt, strlen(str) - cnt);
+ return str;
+}
+char *trimends(char *str) {
+ int len = strlen(str);
+ while( len && str[len-1] <= 32 ) str[--len] = 0;
+ return str;
+}
+
+int exec_popen(void* cmd) {
+ int rc;
+ for( FILE *fp = popen( cmd, "r" ); fp; rc = pclose(fp), fp = 0)
+ {}
+ return 0;
+}
+
+int exec_system(void* cmd) {
+ int rc = system(cmd);
+ return 0;
+}
+
+int exec_win( const char *cmd ) {
+ bool ok = WinExec(va("cmd /c \"%s\"", cmd), SW_HIDE) > 31; // this is async
+ return 0;
+}
+
+int exec_win2( const char *cmd ) {
+ bool ok = WinExec(va("start \"\" /wait \"%s\"", cmd), SW_HIDE) > 31;
+ return 0;
+}
+
+int exec_process(void *cmd) {
+ char output[4096] = {0};
+ // sscanf((const char *)cmd, "%[^|>\r\n]", output); // exclude pipes
+ const char *pipe = strchr(cmd, '>');
+ if( !pipe )
+ snprintf(output, 4096, "cmd /c \"%s\"", (const char *)cmd);
+ else
+ snprintf(output, 4096, "cmd /c \"%.*s\"", (int)(pipe - (const char*)cmd), (char*)cmd);
+ trimleads(output);
+ trimends(output);
+
+ STARTUPINFOA si = {0}; si.cb = sizeof(si);
+ PROCESS_INFORMATION pi = {0};
+
+ HANDLE m_hChildStd_OUT_Rd = NULL;
+ HANDLE m_hChildStd_OUT_Wr = NULL;
+ // Create a pipe for the child process's STDOUT.
+ SECURITY_ATTRIBUTES saAttr = {0};
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saAttr.bInheritHandle = TRUE;
+ saAttr.lpSecurityDescriptor = NULL;
+ if (!CreatePipe(&m_hChildStd_OUT_Rd, &m_hChildStd_OUT_Wr, &saAttr, 0))
+ return (int)GetLastError();
+ // Ensure the read handle to the pipe for STDOUT is not inherited.
+ if (!SetHandleInformation(m_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
+ return (int)GetLastError();
+
+ si.hStdError = m_hChildStd_OUT_Wr;
+ si.hStdOutput = m_hChildStd_OUT_Wr;
+ si.dwFlags |= STARTF_USESTDHANDLES;
+
+ if( !CreateProcessA(NULL, output,
+ NULL, NULL, // dont inherit
+ TRUE, // inherit handles
+ 0 /*CREATE_DEFAULT_ERROR_MODE|CREATE_NO_WINDOW*/, // 0|HIGH_PRIORITY_CLASS
+ NULL, // "", // NULL would inherit env
+ NULL, // current dir
+ &si, &pi) ) {
+ return (int) GetLastError();
+ }
+
+ DWORD dwExitCode = WaitForSingleObject(pi.hProcess, INFINITE);
+
+ if( pipe )
+ {
+ FILE* pipe_fp = fopen(trimspace(pipe + 1), "wb");
+ if (pipe_fp)
+ {
+ enum { BUFSIZE = 1024 };
+ DWORD dwRead;
+ CHAR chBuf[BUFSIZE];
+ BOOL bSuccess = FALSE;
+
+ for (;;)
+ {
+ bSuccess = ReadFile(m_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
+ if (!bSuccess || dwRead == 0) continue;
+
+ // Log chBuf
+ fwrite(chBuf, dwRead, 1, pipe_fp);
+
+ if (!bSuccess) break;
+ }
+
+ fclose(pipe_fp);
+ }
+ }
+
+ CloseHandle(m_hChildStd_OUT_Rd);
+ CloseHandle(m_hChildStd_OUT_Wr);
+
+ return 0;
+}
+
+// https://github.com/hasherezade/exe_to_dll
+// rundll32.exe test_case1.dll,Start
+
+int main(int argc, char **argv) {
+ void* thd[64] = {0};
+
+#define TEST(fn) do { \
+ printf("%11s ", #fn); remove("nul0"); \
+ benchmark { \
+ for( int i = 0; i < 64; ++i ) thd[i] = thread( fn, va("dir > nul%d",i)); \
+ for( int i = 0; i < 64; ++i ) thread_destroy( thd[i] ); \
+ } \
+ if(!file_size("nul0")) puts("**Error!**"); } while(0)
+
+ TEST( exec_process );
+ TEST( exec_popen );
+ TEST( exec_system );
+ TEST( exec_win2 );
+ TEST( exec_win );
+}
diff --git a/tools/editor/labs.vm/netproto.md b/tools/labs/netproto.md
similarity index 100%
rename from tools/editor/labs.vm/netproto.md
rename to tools/labs/netproto.md
diff --git a/tools/editor/objtests.h b/tools/labs/objtests.h
similarity index 100%
rename from tools/editor/objtests.h
rename to tools/labs/objtests.h
diff --git a/tools/editor/labs.osc/oscedit.c b/tools/labs/oscedit.c
similarity index 97%
rename from tools/editor/labs.osc/oscedit.c
rename to tools/labs/oscedit.c
index a5c65a4..774d222 100644
--- a/tools/editor/labs.osc/oscedit.c
+++ b/tools/labs/oscedit.c
@@ -1,4 +1,4 @@
-#include "v4k.h"
+#include "fwk.h"
#include "oscedit.h"
// demo
diff --git a/tools/editor/labs.osc/oscedit.h b/tools/labs/oscedit.h
similarity index 100%
rename from tools/editor/labs.osc/oscedit.h
rename to tools/labs/oscedit.h
diff --git a/tools/editor/labs.osc/oscgame.c b/tools/labs/oscgame.c
similarity index 98%
rename from tools/editor/labs.osc/oscgame.c
rename to tools/labs/oscgame.c
index e7d5064..a8698ac 100644
--- a/tools/editor/labs.osc/oscgame.c
+++ b/tools/labs/oscgame.c
@@ -1,4 +1,4 @@
-#include "v4k.h"
+#include "fwk.h"
#include "oscedit.h"
// game
diff --git a/tools/editor/labs.osc/osclab1.c b/tools/labs/osclab1.c
similarity index 99%
rename from tools/editor/labs.osc/osclab1.c
rename to tools/labs/osclab1.c
index c8f5627..d4b76fb 100644
--- a/tools/editor/labs.osc/osclab1.c
+++ b/tools/labs/osclab1.c
@@ -1,4 +1,4 @@
-#include "v4k.h"
+#include "fwk.h"
#define OSCPACK_C
#define OSCRECV_C
diff --git a/tools/editor/labs.osc/osclab2.c b/tools/labs/osclab2.c
similarity index 99%
rename from tools/editor/labs.osc/osclab2.c
rename to tools/labs/osclab2.c
index d449e0d..bc0d5e3 100644
--- a/tools/editor/labs.osc/osclab2.c
+++ b/tools/labs/osclab2.c
@@ -1,7 +1,7 @@
// networked gui demo
// - rlyeh, public domain
-#include "v4k.h"
+#include "fwk.h"
#define OSCPACK_C
#define OSCRECV_C
diff --git a/tools/editor/labs.osc/oscpack.h b/tools/labs/oscpack.h
similarity index 100%
rename from tools/editor/labs.osc/oscpack.h
rename to tools/labs/oscpack.h
diff --git a/tools/editor/labs.osc/oscrecv.h b/tools/labs/oscrecv.h
similarity index 100%
rename from tools/editor/labs.osc/oscrecv.h
rename to tools/labs/oscrecv.h
diff --git a/tools/editor/labs.osc/oscsend.c b/tools/labs/oscsend.c
similarity index 99%
rename from tools/editor/labs.osc/oscsend.c
rename to tools/labs/oscsend.c
index 242cd83..ede9bf6 100644
--- a/tools/editor/labs.osc/oscsend.c
+++ b/tools/labs/oscsend.c
@@ -1,4 +1,4 @@
-#include "v4k.h"
+#include "fwk.h"
#include "oscsend.h"
#include "oscedit.h"
int main(int argc, char **argv) {
diff --git a/tools/editor/labs.osc/oscsend.h b/tools/labs/oscsend.h
similarity index 100%
rename from tools/editor/labs.osc/oscsend.h
rename to tools/labs/oscsend.h
diff --git a/tools/editor/stdio2.c b/tools/labs/stdio2.c
similarity index 99%
rename from tools/editor/stdio2.c
rename to tools/labs/stdio2.c
index e6817de..40ac157 100644
--- a/tools/editor/stdio2.c
+++ b/tools/labs/stdio2.c
@@ -6,8 +6,8 @@
#include
#if 1
-#define V4K_IMPLEMENTATION
-#include "/prj/v4k/engine/joint/v4k.h"
+#define FWK_IMPLEMENTATION
+#include "/prj/fwk/engine/joint/fwk.h"
#define vl tempvl
#define test2 test2_
#else
diff --git a/tools/luajit_make_bindings.lua b/tools/luajit_make_bindings.lua
index 45d63b3..f581626 100644
--- a/tools/luajit_make_bindings.lua
+++ b/tools/luajit_make_bindings.lua
@@ -18,16 +18,16 @@ function trim_multilines(str)
return output
end
-io.input("./engine/v4k.h")
-local v4k_h = io.read("*all")
-v4k_h = v4k_h:gsub("#line", "//#line")
-v4k_h = v4k_h:gsub("#include", "//#include")
+io.input("./engine/fwk.h")
+local fwk_h = io.read("*all")
+fwk_h = fwk_h:gsub("#line", "//#line")
+fwk_h = fwk_h:gsub("#include", "//#include")
print('--autogenerated luajit bindings. do not edit.') -- .. os.date("%Y/%m/%d"))
print('local ffi = require("ffi")')
print('ffi.cdef([[')
-local result = lcpp.compile(glue .. v4k_h)
+local result = lcpp.compile(glue .. fwk_h)
print( trim_multilines(result) )
print(']])')
@@ -68,11 +68,11 @@ function _M.mat44()
return m
end
-local v4k = ffi.load("v4k")
+local fwk = ffi.load("fwk")
return setmetatable( _M, {
__index = function( table, key )
- return v4k[ key ]
+ return fwk[ key ]
end
} )
]])
diff --git a/tools/editor/windows.ini b/tools/windows.ini
similarity index 100%
rename from tools/editor/windows.ini
rename to tools/windows.ini