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