diff options
| author | Ray <[email protected]> | 2023-08-26 23:30:44 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-08-26 23:30:44 +0200 |
| commit | 7aeaa9f58543bc8cce5e7307d6ea14197a34987f (patch) | |
| tree | 29286add23b5e6df2cac2a7e574f0676e062807a | |
| parent | dd19af08372036ccfc92050ef4347fc2b1469b2a (diff) | |
| parent | bffc2bb159d04507e83f75676b7859096b5e5b65 (diff) | |
| download | raylib.com-7aeaa9f58543bc8cce5e7307d6ea14197a34987f.tar.gz raylib.com-7aeaa9f58543bc8cce5e7307d6ea14197a34987f.zip | |
Merge pull request #57 from RokasPuzonas/feature-add-function-search
Add searching by used functions in examples page
| -rw-r--r-- | common/examples.css | 5 | ||||
| -rw-r--r-- | common/examples.js | 356 | ||||
| -rw-r--r-- | examples.html | 8 | ||||
| -rw-r--r-- | examples/function_usages.json | 1 | ||||
| -rw-r--r-- | tools/cheatsheet-generator/README.md | 3 | ||||
| -rw-r--r-- | tools/example-indexer/.gitignore | 1 | ||||
| -rw-r--r-- | tools/example-indexer/Makefile | 20 | ||||
| -rw-r--r-- | tools/example-indexer/README.md | 14 | ||||
| -rw-r--r-- | tools/example-indexer/main.c | 304 | ||||
| -rw-r--r-- | tools/example-indexer/raylib_parser.c | 502 | ||||
| -rw-r--r-- | tools/example-indexer/stb_c_lexer.h | 940 |
11 files changed, 2008 insertions, 146 deletions
diff --git a/common/examples.css b/common/examples.css index 4c97c29..65ba8ad 100644 --- a/common/examples.css +++ b/common/examples.css @@ -3,6 +3,9 @@ #difficulty_level { position: absolute; bottom: 18px; left: 12px; font-size: 24px; } #filter_menu { width:820px; height:80px; margin-left:15px; } +#filter_function_label { margin-top: 2rem; } +#filter_function { display: block; height: 1rem; margin-left:15px; margin-bottom: 2rem; } +#matches_counter { display: inline; margin-bottom: 2rem; } .legendButton { float:left; margin-right:8px; margin-bottom:20px; width:84px; height:78px; text-align:right; line-height:130px; cursor: pointer; transition: 0.125s; } #core { background-color:#e1e1e1; color:#5c5a5a; border:5px solid #898888; } @@ -66,4 +69,4 @@ #container .fphysics a:hover { border: 10px solid #d3b157; } #container .fphysics a:hover img { margin: -10px; opacity: 0.3; } -#container .extext { position:absolute; top:140px; width:320px; text-align: center; display: none; }
\ No newline at end of file +#container .extext { position:absolute; top:140px; width:320px; text-align: center; display: none; } diff --git a/common/examples.js b/common/examples.js index 45c921c..992c46e 100644 --- a/common/examples.js +++ b/common/examples.js @@ -3,161 +3,229 @@ $(document).ready(function() { // Init fancybox $('.fancybox').fancybox(); + function exampleEntry(difficulty, module, base) { + return {difficulty, module, base, name: module + '_' + base } + } + + function findExampleByName(examples, targetName) { + for (var example of examples) { + if (example.name == targetName) { + return example + } + } + } + + function findExampleIndexByName(examples, targetName) { + return examples.findIndex(example => example.name == targetName) + } + + function applyByFunctionFilter(functionName) { + var filterText = functionName.toLowerCase() + if (filterText === "") { + $('#container').mixItUp('filter', exampleDivs); + $('#matches_counter').hide(); + return + } + $('#matches_counter').show(); + + const filteredExamples = [] + for (var functionName in functionUsages) { + if (!functionName.toLowerCase().includes(filterText)) continue; + + for (var usage of functionUsages[functionName]) { + const exampleIndex = findExampleIndexByName(exampleData, usage) + if (!filteredExamples.includes(exampleIndex)) { + filteredExamples.push(exampleIndex) + } + } + } + + const filteredDivs = filteredExamples.map(index => exampleDivs[index]); + $('#container').mixItUp('filter', filteredDivs); + $('#matches_counter').text(`Found ${filteredExamples.length} examples`); + } + var exampleData = [ - '⭐️☆☆☆#core_basic_window', - '⭐️☆☆☆#core_input_keys', - '⭐️☆☆☆#core_input_mouse', - '⭐️☆☆☆#core_input_mouse_wheel', - '⭐️☆☆☆#core_input_gamepad', - '⭐️☆☆☆#core_input_multitouch', - '⭐️⭐️☆☆#core_input_gestures', - '⭐️⭐️☆☆#core_2d_camera', - '⭐️⭐️☆☆#core_2d_camera_mouse_zoom', - '⭐️⭐️⭐️☆#core_2d_camera_platformer', - '⭐️☆☆☆#core_3d_camera_mode', - '⭐️☆☆☆#core_3d_camera_free', - '⭐️⭐️☆☆#core_3d_camera_first_person', - '⭐️⭐️☆☆#core_3d_picking', - '⭐️⭐️☆☆#core_world_screen', - '⭐️⭐️⭐️☆#core_custom_logging', - '⭐️⭐️⭐️☆#core_window_flags', - '⭐️⭐️☆☆#core_window_letterbox', - '⭐️☆☆☆#core_window_should_close', - '⭐️⭐️☆☆#core_drop_files', - '⭐️☆☆☆#core_random_values', - '⭐️⭐️☆☆#core_storage_values', - '⭐️⭐️⭐️☆#core_vr_simulator', - '⭐️⭐️⭐️☆#core_loading_thread', - '⭐️☆☆☆#core_scissor_test', - '⭐️☆☆☆#core_basic_screen_manager', - '⭐️⭐️⭐️⭐️#core_custom_frame_control', - '⭐️⭐️⭐️☆#core_smooth_pixelperfect', - '⭐️⭐️⭐️⭐️#core_split_screen', - '⭐️☆☆☆#shapes_basic_shapes', - '⭐️☆☆☆#shapes_bouncing_ball', - '⭐️⭐️☆☆#shapes_colors_palette', - '⭐️☆☆☆#shapes_logo_raylib', - '⭐️⭐️☆☆#shapes_logo_raylib_anim', - '⭐️⭐️☆☆#shapes_rectangle_scaling', - '⭐️☆☆☆#shapes_lines_bezier', - '⭐️⭐️☆☆#shapes_collision_area', - '⭐️⭐️☆☆#shapes_following_eyes', - '⭐️⭐️☆☆#shapes_easings_ball_anim', - '⭐️⭐️☆☆#shapes_easings_box_anim', - '⭐️⭐️⭐️☆#shapes_easings_rectangle_array', - '⭐️⭐️⭐️☆#shapes_draw_ring', - '⭐️⭐️⭐️☆#shapes_draw_circle_sector', - '⭐️⭐️⭐️☆#shapes_draw_rectangle_rounded', - '⭐️⭐️⭐️⭐️#shapes_top_down_lights', - '⭐️☆☆☆#textures_logo_raylib', - '⭐️⭐️⭐️☆#textures_srcrec_dstrec', - '⭐️⭐️☆☆#textures_image_drawing', - '⭐️⭐️☆☆#textures_image_generation', - '⭐️☆☆☆#textures_image_loading', - '⭐️⭐️⭐️☆#textures_image_processing', - '⭐️⭐️☆☆#textures_image_text', - '⭐️☆☆☆#textures_to_image', - '⭐️⭐️⭐️☆#textures_raw_data', - '⭐️☆☆☆#textures_particles_blending', - '⭐️⭐️⭐️☆#textures_npatch_drawing', - '⭐️☆☆☆#textures_background_scrolling', - '⭐️⭐️☆☆#textures_sprite_anim', - '⭐️⭐️☆☆#textures_sprite_button', - '⭐️⭐️☆☆#textures_sprite_explosion', - '⭐️⭐️⭐️☆#textures_bunnymark', - '⭐️⭐️⭐️☆#textures_mouse_painting', - '⭐️☆☆☆#textures_blend_modes', - '⭐️⭐️⭐️☆#textures_draw_tiled', - '⭐️☆☆☆#textures_polygon', - '⭐️⭐️⭐️☆#textures_fog_of_war', - '⭐️⭐️⭐️☆#textures_gif_player', - '⭐️⭐️⭐️☆#textures_textured_curve', - '⭐️☆☆☆#text_raylib_fonts', - '⭐️☆☆☆#text_font_spritefont', - '⭐️⭐️☆☆#text_font_filters', - '⭐️☆☆☆#text_font_loading', - '⭐️⭐️⭐️☆#text_font_sdf', - '⭐️☆☆☆#text_format_text', - '⭐️⭐️☆☆#text_input_box', - '⭐️⭐️☆☆#text_writing_anim', - '⭐️⭐️⭐️⭐️#text_rectangle_bounds', - '⭐️⭐️⭐️⭐️#text_unicode', - '⭐️⭐️⭐️⭐️#text_draw_3d', - '⭐️⭐️⭐️☆#text_codepoints_loading', - '⭐️⭐️☆☆#models_animation', - '⭐️⭐️⭐️☆#models_billboard', - '⭐️☆☆☆#models_box_collisions', - '⭐️⭐️☆☆#models_cubicmap', - '⭐️⭐️☆☆#models_first_person_maze', - '⭐️☆☆☆#models_geometric_shapes', - '⭐️⭐️☆☆#models_mesh_generation', - '⭐️⭐️⭐️☆#models_mesh_picking', - '⭐️☆☆☆#models_loading', - '⭐️☆☆☆#models_loading_gltf', - '⭐️☆☆☆#models_loading_vox', - '⭐️⭐️☆☆#models_loading_m3d', - '⭐️☆☆☆#models_orthographic_projection', - '⭐️⭐️⭐️⭐️#models_rlgl_solar_system', - '⭐️⭐️☆☆#models_yaw_pitch_roll', - '⭐️⭐️⭐️☆#models_waving_cubes', - '⭐️☆☆☆#models_heightmap', - '⭐️⭐️☆☆#models_skybox', - '⭐️⭐️☆☆#models_draw_cube_texture', - '⭐️⭐️⭐️⭐️#shaders_basic_lighting', - '⭐️⭐️☆☆#shaders_model_shader', - '⭐️⭐️☆☆#shaders_shapes_textures', - '⭐️⭐️☆☆#shaders_custom_uniform', - '⭐️⭐️⭐️☆#shaders_postprocessing', - '⭐️⭐️⭐️☆#shaders_palette_switch', - '⭐️⭐️⭐️⭐️#shaders_raymarching', - '⭐️⭐️☆☆#shaders_texture_drawing', - '⭐️⭐️⭐️☆#shaders_texture_outline', - '⭐️⭐️☆☆#shaders_texture_waves', - '⭐️⭐️⭐️☆#shaders_julia_set', - '⭐️⭐️⭐️☆#shaders_eratosthenes', - '⭐️⭐️⭐️☆#shaders_fog', - '⭐️⭐️☆☆#shaders_simple_mask', - '⭐️⭐️⭐️☆#shaders_hot_reloading', - '⭐️⭐️⭐️⭐️#shaders_mesh_instancing', - '⭐️⭐️☆☆#shaders_multi_sample2d', - '⭐️⭐️☆☆#shaders_spotlight', - '⭐️⭐️☆☆#shaders_write_depth', - '⭐️⭐️⭐️⭐️#shaders_hybrid_render', - '⭐️☆☆☆#audio_module_playing', - '⭐️☆☆☆#audio_music_stream', - '⭐️⭐️⭐️☆#audio_raw_stream', - '⭐️☆☆☆#audio_sound_loading', - '⭐️⭐️⭐️⭐️#audio_stream_effects', - '⭐️⭐️⭐️⭐️#audio_mixed_processor']; - - for (var i = 0; i < exampleData.length; i++) - { - var difficulty = exampleData[i].substring(0, exampleData[i].indexOf('#')); - var exampleName = exampleData[i].substring(exampleData[i].indexOf('#') + 1); - var exampleBase = exampleName.slice(exampleName.indexOf('_') + 1); - var exampleDesc = exampleBase.replace('_', ' '); - var filterType = exampleName.substring(0, exampleName.indexOf("_")); - - $('#container').append( - '<div class="mix f' + filterType + '">' + - '<a class="fancybox fancybox.iframe" href="examples/' + filterType + '/' + 'loader.html?name=' + exampleName + '" title="' + exampleDesc + '">' + - '<img width="400" height="225" src="https://raw.githubusercontent.com/raysan5/raylib/master/examples/' + filterType + '/' + exampleName + '.png"><div class="extext"><p>' + exampleDesc + '</p></div></a>' + - '<div id="difficulty_level">' + difficulty + '</div>' + - '</div>'); + exampleEntry('⭐️☆☆☆' , 'core' , 'basic_window'), + exampleEntry('⭐️☆☆☆' , 'core' , 'input_keys'), + exampleEntry('⭐️☆☆☆' , 'core' , 'input_mouse'), + exampleEntry('⭐️☆☆☆' , 'core' , 'input_mouse_wheel'), + exampleEntry('⭐️☆☆☆' , 'core' , 'input_gamepad'), + exampleEntry('⭐️☆☆☆' , 'core' , 'input_multitouch'), + exampleEntry('⭐️⭐️☆☆' , 'core' , 'input_gestures'), + exampleEntry('⭐️⭐️☆☆' , 'core' , '2d_camera'), + exampleEntry('⭐️⭐️☆☆' , 'core' , '2d_camera_mouse_zoom'), + exampleEntry('⭐️⭐️⭐️☆' , 'core' , '2d_camera_platformer'), + exampleEntry('⭐️☆☆☆' , 'core' , '3d_camera_mode'), + exampleEntry('⭐️☆☆☆' , 'core' , '3d_camera_free'), + exampleEntry('⭐️⭐️☆☆' , 'core' , '3d_camera_first_person'), + exampleEntry('⭐️⭐️☆☆' , 'core' , '3d_picking'), + exampleEntry('⭐️⭐️☆☆' , 'core' , 'world_screen'), + exampleEntry('⭐️⭐️⭐️☆' , 'core' , 'custom_logging'), + exampleEntry('⭐️⭐️⭐️☆' , 'core' , 'window_flags'), + exampleEntry('⭐️⭐️☆☆' , 'core' , 'window_letterbox'), + exampleEntry('⭐️☆☆☆' , 'core' , 'window_should_close'), + exampleEntry('⭐️⭐️☆☆' , 'core' , 'drop_files'), + exampleEntry('⭐️☆☆☆' , 'core' , 'random_values'), + exampleEntry('⭐️⭐️☆☆' , 'core' , 'storage_values'), + exampleEntry('⭐️⭐️⭐️☆' , 'core' , 'vr_simulator'), + exampleEntry('⭐️⭐️⭐️☆' , 'core' , 'loading_thread'), + exampleEntry('⭐️☆☆☆' , 'core' , 'scissor_test'), + exampleEntry('⭐️☆☆☆' , 'core' , 'basic_screen_manager'), + exampleEntry('⭐️⭐️⭐️⭐️', 'core' , 'custom_frame_control'), + exampleEntry('⭐️⭐️⭐️☆' , 'core' , 'smooth_pixelperfect'), + exampleEntry('⭐️⭐️⭐️⭐️', 'core' , 'split_screen'), + exampleEntry('⭐️☆☆☆' , 'shapes' , 'basic_shapes'), + exampleEntry('⭐️☆☆☆' , 'shapes' , 'bouncing_ball'), + exampleEntry('⭐️⭐️☆☆' , 'shapes' , 'colors_palette'), + exampleEntry('⭐️☆☆☆' , 'shapes' , 'logo_raylib'), + exampleEntry('⭐️⭐️☆☆' , 'shapes' , 'logo_raylib_anim'), + exampleEntry('⭐️⭐️☆☆' , 'shapes' , 'rectangle_scaling'), + exampleEntry('⭐️☆☆☆' , 'shapes' , 'lines_bezier'), + exampleEntry('⭐️⭐️☆☆' , 'shapes' , 'collision_area'), + exampleEntry('⭐️⭐️☆☆' , 'shapes' , 'following_eyes'), + exampleEntry('⭐️⭐️☆☆' , 'shapes' , 'easings_ball_anim'), + exampleEntry('⭐️⭐️☆☆' , 'shapes' , 'easings_box_anim'), + exampleEntry('⭐️⭐️⭐️☆' , 'shapes' , 'easings_rectangle_array'), + exampleEntry('⭐️⭐️⭐️☆' , 'shapes' , 'draw_ring'), + exampleEntry('⭐️⭐️⭐️☆' , 'shapes' , 'draw_circle_sector'), + exampleEntry('⭐️⭐️⭐️☆' , 'shapes' , 'draw_rectangle_rounded'), + exampleEntry('⭐️⭐️⭐️⭐️', 'shapes' , 'top_down_lights'), + exampleEntry('⭐️☆☆☆' , 'textures', 'logo_raylib'), + exampleEntry('⭐️⭐️⭐️☆' , 'textures', 'srcrec_dstrec'), + exampleEntry('⭐️⭐️☆☆' , 'textures', 'image_drawing'), + exampleEntry('⭐️⭐️☆☆' , 'textures', 'image_generation'), + exampleEntry('⭐️☆☆☆' , 'textures', 'image_loading'), + exampleEntry('⭐️⭐️⭐️☆' , 'textures', 'image_processing'), + exampleEntry('⭐️⭐️☆☆' , 'textures', 'image_text'), + exampleEntry('⭐️☆☆☆' , 'textures', 'to_image'), + exampleEntry('⭐️⭐️⭐️☆' , 'textures', 'raw_data'), + exampleEntry('⭐️☆☆☆' , 'textures', 'particles_blending'), + exampleEntry('⭐️⭐️⭐️☆' , 'textures', 'npatch_drawing'), + exampleEntry('⭐️☆☆☆' , 'textures', 'background_scrolling'), + exampleEntry('⭐️⭐️☆☆' , 'textures', 'sprite_anim'), + exampleEntry('⭐️⭐️☆☆' , 'textures', 'sprite_button'), + exampleEntry('⭐️⭐️☆☆' , 'textures', 'sprite_explosion'), + exampleEntry('⭐️⭐️⭐️☆' , 'textures', 'bunnymark'), + exampleEntry('⭐️⭐️⭐️☆' , 'textures', 'mouse_painting'), + exampleEntry('⭐️☆☆☆' , 'textures', 'blend_modes'), + exampleEntry('⭐️⭐️⭐️☆' , 'textures', 'draw_tiled'), + exampleEntry('⭐️☆☆☆' , 'textures', 'polygon'), + exampleEntry('⭐️⭐️⭐️☆' , 'textures', 'fog_of_war'), + exampleEntry('⭐️⭐️⭐️☆' , 'textures', 'gif_player'), + exampleEntry('⭐️⭐️⭐️☆' , 'textures', 'textured_curve'), + exampleEntry('⭐️☆☆☆' , 'text' , 'raylib_fonts'), + exampleEntry('⭐️☆☆☆' , 'text' , 'font_spritefont'), + exampleEntry('⭐️⭐️☆☆' , 'text' , 'font_filters'), + exampleEntry('⭐️☆☆☆' , 'text' , 'font_loading'), + exampleEntry('⭐️⭐️⭐️☆' , 'text' , 'font_sdf'), + exampleEntry('⭐️☆☆☆' , 'text' , 'format_text'), + exampleEntry('⭐️⭐️☆☆' , 'text' , 'input_box'), + exampleEntry('⭐️⭐️☆☆' , 'text' , 'writing_anim'), + exampleEntry('⭐️⭐️⭐️⭐️', 'text' , 'rectangle_bounds'), + exampleEntry('⭐️⭐️⭐️⭐️', 'text' , 'unicode'), + exampleEntry('⭐️⭐️⭐️⭐️', 'text' , 'draw_3d'), + exampleEntry('⭐️⭐️⭐️☆' , 'text' , 'codepoints_loading'), + exampleEntry('⭐️⭐️☆☆' , 'models' , 'animation'), + exampleEntry('⭐️⭐️⭐️☆' , 'models' , 'billboard'), + exampleEntry('⭐️☆☆☆' , 'models' , 'box_collisions'), + exampleEntry('⭐️⭐️☆☆' , 'models' , 'cubicmap'), + exampleEntry('⭐️⭐️☆☆' , 'models' , 'first_person_maze'), + exampleEntry('⭐️☆☆☆' , 'models' , 'geometric_shapes'), + exampleEntry('⭐️⭐️☆☆' , 'models' , 'mesh_generation'), + exampleEntry('⭐️⭐️⭐️☆' , 'models' , 'mesh_picking'), + exampleEntry('⭐️☆☆☆' , 'models' , 'loading'), + exampleEntry('⭐️☆☆☆' , 'models' , 'loading_gltf'), + exampleEntry('⭐️☆☆☆' , 'models' , 'loading_vox'), + exampleEntry('⭐️⭐️☆☆' , 'models' , 'loading_m3d'), + exampleEntry('⭐️☆☆☆' , 'models' , 'orthographic_projection'), + exampleEntry('⭐️⭐️⭐️⭐️', 'models' , 'rlgl_solar_system'), + exampleEntry('⭐️⭐️☆☆' , 'models' , 'yaw_pitch_roll'), + exampleEntry('⭐️⭐️⭐️☆' , 'models' , 'waving_cubes'), + exampleEntry('⭐️☆☆☆' , 'models' , 'heightmap'), + exampleEntry('⭐️⭐️☆☆' , 'models' , 'skybox'), + exampleEntry('⭐️⭐️☆☆' , 'models' , 'draw_cube_texture'), + exampleEntry('⭐️⭐️⭐️⭐️', 'shaders' , 'basic_lighting'), + exampleEntry('⭐️⭐️☆☆' , 'shaders' , 'model_shader'), + exampleEntry('⭐️⭐️☆☆' , 'shaders' , 'shapes_textures'), + exampleEntry('⭐️⭐️☆☆' , 'shaders' , 'custom_uniform'), + exampleEntry('⭐️⭐️⭐️☆' , 'shaders' , 'postprocessing'), + exampleEntry('⭐️⭐️⭐️☆' , 'shaders' , 'palette_switch'), + exampleEntry('⭐️⭐️⭐️⭐️', 'shaders' , 'raymarching'), + exampleEntry('⭐️⭐️☆☆' , 'shaders' , 'texture_drawing'), + exampleEntry('⭐️⭐️⭐️☆' , 'shaders' , 'texture_outline'), + exampleEntry('⭐️⭐️☆☆' , 'shaders' , 'texture_waves'), + exampleEntry('⭐️⭐️⭐️☆' , 'shaders' , 'julia_set'), + exampleEntry('⭐️⭐️⭐️☆' , 'shaders' , 'eratosthenes'), + exampleEntry('⭐️⭐️⭐️☆' , 'shaders' , 'fog'), + exampleEntry('⭐️⭐️☆☆' , 'shaders' , 'simple_mask'), + exampleEntry('⭐️⭐️⭐️☆' , 'shaders' , 'hot_reloading'), + exampleEntry('⭐️⭐️⭐️⭐️', 'shaders' , 'mesh_instancing'), + exampleEntry('⭐️⭐️☆☆' , 'shaders' , 'multi_sample2d'), + exampleEntry('⭐️⭐️☆☆' , 'shaders' , 'spotlight'), + exampleEntry('⭐️⭐️☆☆' , 'shaders' , 'write_depth'), + exampleEntry('⭐️⭐️⭐️⭐️', 'shaders' , 'hybrid_render'), + exampleEntry('⭐️☆☆☆' , 'audio' , 'module_playing'), + exampleEntry('⭐️☆☆☆' , 'audio' , 'music_stream'), + exampleEntry('⭐️⭐️⭐️☆' , 'audio' , 'raw_stream'), + exampleEntry('⭐️☆☆☆' , 'audio' , 'sound_loading'), + exampleEntry('⭐️⭐️⭐️⭐️', 'audio' , 'stream_effects'), + exampleEntry('⭐️⭐️⭐️⭐️', 'audio' , 'mixed_processor')]; + + var exampleDivs = [] + for (var i = 0; i < exampleData.length; i++) { + var difficulty = exampleData[i].difficulty + var module = exampleData[i].module; + var name = exampleData[i].name; + var description = exampleData[i].base.replaceAll('_', ' '); + var previewImageURL = `https://raw.githubusercontent.com/raysan5/raylib/master/examples/${module}/${name}.png` + var exampleLoaderURL = `examples/${module}/loader.html?name=${name}`; + + const exampleDiv = $( + `<div class="mix f${module}">` + + `<a class="fancybox fancybox.iframe" href="${exampleLoaderURL}" title="${description}">` + + `<img width="400" height="225" src="${previewImageURL}"><div class="extext"><p>${description}</p></div></a>` + + `<div id="difficulty_level">${difficulty}</div>` + + '</div>')[0]; + + exampleDivs.push(exampleDiv); + + $('#container').append(exampleDiv); $('#container a .extext').hide(); } + const filterFunctionInput = $('#filter_function input'); + + var functionUsages = {} + $.getJSON('examples/function_usages.json', function(functionUsagesData) { + // Filter out function usages of examples, which don't have a page + for (var functionName in functionUsagesData) { + functionUsages[functionName] = functionUsagesData[functionName].filter(usage => findExampleByName(exampleData, usage)) + } + + // While the JSON file was loaded, user could have entered text. + // So apply filter, if it not empty + if (filterFunctionInput !== '') { + applyByFunctionFilter(filterFunctionInput.val()) + } + + // From now listen for input update events + filterFunctionInput.on("input", function(event) { + applyByFunctionFilter(event.target.value) + }); + }) + // Instantiate MixItUp: $('#container').mixItUp(); - $("#container a").hover( - function(){ $(this).find(".extext").show(); }, - function(){ $(this).find(".extext").hide(); }); + $('#container a').hover( + function(){ $(this).find('.extext').show(); }, + function(){ $(this).find('.extext').hide(); }); /* $("#container a img").hover( function() { $(this).stop().animate({ opacity:0.6 }, 200, "easeOutQuad" ); }, function() { $(this).stop().animate({ opacity:0 }, 200, "easeOutQuad" ); } ) */ -});
\ No newline at end of file +}); diff --git a/examples.html b/examples.html index 633d8aa..7dbfc92 100644 --- a/examples.html +++ b/examples.html @@ -80,6 +80,12 @@ <div class="filter legendButton" id="audio" data-filter=".faudio">audio</div> </div> + <p id="filter_function_label">Or filter by used functions in the example:</p> + <div id="filter_function"> + <input></input> + <p id="matches_counter"></p> + </div> + <!-- Items container, filled when loading --> <div id="container"></div> @@ -111,4 +117,4 @@ <!-- Add own script code --> <script src="common/examples.js"></script> </body> -</html>
\ No newline at end of file +</html> diff --git a/examples/function_usages.json b/examples/function_usages.json new file mode 100644 index 0000000..4c7afb3 --- /dev/null +++ b/examples/function_usages.json @@ -0,0 +1 @@ +{"rlMatrixMode":["rlgl_standalone"],"rlPushMatrix":["rlgl_standalone","models_rlgl_solar_system","core_2d_camera_mouse_zoom","text_draw_3d"],"rlPopMatrix":["rlgl_standalone","models_rlgl_solar_system","core_2d_camera_mouse_zoom","text_draw_3d"],"rlLoadIdentity":["rlgl_standalone"],"rlTranslatef":["rlgl_standalone","models_rlgl_solar_system","core_2d_camera_mouse_zoom","text_draw_3d"],"rlRotatef":["models_rlgl_solar_system","core_2d_camera_mouse_zoom","text_draw_3d"],"rlScalef":["models_rlgl_solar_system"],"rlMultMatrixf":[],"rlFrustum":[],"rlOrtho":["rlgl_standalone"],"rlViewport":["rlgl_standalone","models_skybox"],"rlBegin":["rlgl_standalone","textures_textured_curve","textures_polygon","models_draw_cube_texture","models_rlgl_solar_system","text_draw_3d"],"rlEnd":["rlgl_standalone","textures_textured_curve","textures_polygon","models_draw_cube_texture","models_rlgl_solar_system","text_draw_3d"],"rlVertex2i":[],"rlVertex2f":["rlgl_standalone","textures_textured_curve","textures_polygon"],"rlVertex3f":["rlgl_standalone","models_draw_cube_texture","models_rlgl_solar_system","text_draw_3d"],"rlTexCoord2f":["textures_textured_curve","textures_polygon","models_draw_cube_texture","text_draw_3d"],"rlNormal3f":["textures_textured_curve","models_draw_cube_texture","text_draw_3d"],"rlColor4ub":["rlgl_standalone","textures_textured_curve","textures_polygon","models_draw_cube_texture","models_rlgl_solar_system","text_draw_3d"],"rlColor3f":["rlgl_standalone"],"rlColor4f":[],"rlEnableVertexArray":["shaders_lightmap"],"rlDisableVertexArray":["shaders_lightmap"],"rlEnableVertexBuffer":[],"rlDisableVertexBuffer":[],"rlEnableVertexBufferElement":[],"rlDisableVertexBufferElement":[],"rlEnableVertexAttribute":["shaders_lightmap"],"rlDisableVertexAttribute":[],"rlEnableStatePointer":[],"rlDisableStatePointer":[],"rlActiveTextureSlot":["models_skybox"],"rlEnableTexture":["models_skybox"],"rlDisableTexture":["models_skybox"],"rlEnableTextureCubemap":[],"rlDisableTextureCubemap":[],"rlTextureParameters":[],"rlCubemapParameters":[],"rlEnableShader":["rlgl_compute_shader","models_skybox"],"rlDisableShader":["rlgl_compute_shader","models_skybox"],"rlEnableFramebuffer":["shaders_write_depth","shaders_hybrid_render","models_skybox"],"rlDisableFramebuffer":["shaders_write_depth","shaders_hybrid_render","models_skybox"],"rlActiveDrawBuffers":[],"rlEnableColorBlend":[],"rlDisableColorBlend":[],"rlEnableDepthTest":["shaders_hybrid_render","rlgl_standalone"],"rlDisableDepthTest":[],"rlEnableDepthMask":["models_skybox"],"rlDisableDepthMask":["models_skybox"],"rlEnableBackfaceCulling":["models_skybox"],"rlDisableBackfaceCulling":["models_skybox"],"rlSetCullFace":[],"rlEnableScissorTest":[],"rlDisableScissorTest":[],"rlScissor":[],"rlEnableWireMode":[],"rlDisableWireMode":[],"rlSetLineWidth":[],"rlGetLineWidth":[],"rlEnableSmoothLines":[],"rlDisableSmoothLines":[],"rlEnableStereoRender":[],"rlDisableStereoRender":[],"rlIsStereoRenderEnabled":[],"rlClearColor":["rlgl_standalone"],"rlClearScreenBuffers":["rlgl_standalone","models_skybox"],"rlCheckErrors":[],"rlSetBlendMode":["shapes_top_down_lights"],"rlSetBlendFactors":["shapes_top_down_lights"],"rlSetBlendFactorsSeparate":[],"rlglInit":["rlgl_standalone"],"rlglClose":["rlgl_standalone"],"rlLoadExtensions":["rlgl_standalone"],"rlGetVersion":[],"rlSetFramebufferWidth":[],"rlGetFramebufferWidth":["models_skybox"],"rlSetFramebufferHeight":[],"rlGetFramebufferHeight":["models_skybox"],"rlGetTextureIdDefault":[],"rlGetShaderIdDefault":["shaders_hot_reloading"],"rlGetShaderLocsDefault":[],"rlLoadRenderBatch":[],"rlUnloadRenderBatch":[],"rlDrawRenderBatch":[],"rlSetRenderBatchActive":[],"rlDrawRenderBatchActive":["rlgl_standalone","raylib_opengl_interop","shapes_top_down_lights"],"rlCheckRenderBatchLimit":["models_rlgl_solar_system","text_draw_3d"],"rlSetTexture":["textures_textured_curve","textures_polygon","models_draw_cube_texture","text_draw_3d"],"rlLoadVertexArray":[],"rlLoadVertexBuffer":["shaders_lightmap"],"rlLoadVertexBufferElement":[],"rlUpdateVertexBuffer":[],"rlUpdateVertexBufferElements":[],"rlUnloadVertexArray":[],"rlUnloadVertexBuffer":[],"rlSetVertexAttribute":["shaders_lightmap"],"rlSetVertexAttributeDivisor":[],"rlSetVertexAttributeDefault":[],"rlDrawVertexArray":[],"rlDrawVertexArrayElements":[],"rlDrawVertexArrayInstanced":[],"rlDrawVertexArrayElementsInstanced":[],"rlLoadTexture":["shaders_write_depth","shaders_hybrid_render"],"rlLoadTextureDepth":["shaders_write_depth","shaders_hybrid_render","models_skybox"],"rlLoadTextureCubemap":["models_skybox"],"rlUpdateTexture":[],"rlGetGlTextureFormats":[],"rlGetPixelFormatName":[],"rlUnloadTexture":["shaders_write_depth","shaders_hybrid_render"],"rlGenTextureMipmaps":[],"rlReadTexturePixels":[],"rlReadScreenPixels":[],"rlLoadFramebuffer":["shaders_write_depth","shaders_hybrid_render","models_skybox"],"rlFramebufferAttach":["shaders_write_depth","shaders_hybrid_render","models_skybox"],"rlFramebufferComplete":["shaders_write_depth","shaders_hybrid_render","models_skybox"],"rlUnloadFramebuffer":["shaders_write_depth","shaders_hybrid_render","models_skybox"],"rlLoadShaderCode":[],"rlCompileShader":["rlgl_compute_shader"],"rlLoadShaderProgram":[],"rlUnloadShaderProgram":["rlgl_compute_shader"],"rlGetLocationUniform":[],"rlGetLocationAttrib":[],"rlSetUniform":[],"rlSetUniformMatrix":["models_skybox"],"rlSetUniformSampler":[],"rlSetShader":[],"rlLoadComputeShaderProgram":["rlgl_compute_shader"],"rlComputeShaderDispatch":["rlgl_compute_shader"],"rlLoadShaderBuffer":["rlgl_compute_shader"],"rlUnloadShaderBuffer":["rlgl_compute_shader"],"rlUpdateShaderBuffer":["rlgl_compute_shader"],"rlBindShaderBuffer":["rlgl_compute_shader"],"rlReadShaderBuffer":[],"rlCopyShaderBuffer":[],"rlGetShaderBufferSize":[],"rlBindImageTexture":[],"rlGetMatrixModelview":["raylib_opengl_interop"],"rlGetMatrixProjection":["raylib_opengl_interop"],"rlGetMatrixTransform":[],"rlGetMatrixProjectionStereo":[],"rlGetMatrixViewOffsetStereo":[],"rlSetMatrixProjection":["rlgl_standalone"],"rlSetMatrixModelview":["rlgl_standalone"],"rlSetMatrixProjectionStereo":[],"rlSetMatrixViewOffsetStereo":[],"rlLoadDrawCube":["models_skybox"],"rlLoadDrawQuad":[],"GetCameraForward":[],"GetCameraUp":[],"GetCameraRight":[],"CameraMoveForward":[],"CameraMoveUp":[],"CameraMoveRight":[],"CameraMoveToTarget":[],"CameraYaw":["core_3d_camera_first_person"],"CameraPitch":["core_3d_camera_first_person"],"CameraRoll":[],"GetCameraViewMatrix":[],"GetCameraProjectionMatrix":[],"InitWindow":["shaders_lightmap","shaders_write_depth","shaders_eratosthenes","shaders_spotlight","shaders_mesh_instancing","shaders_texture_outline","shaders_model_shader","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_hybrid_render","shaders_simple_mask","shaders_texture_drawing","shaders_texture_waves","shaders_shapes_textures","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","shaders_basic_lighting","shaders_fog","raymath_vector_angle","rlgl_compute_shader","easings_testbed","raylib_opengl_interop","embedded_files_loading","textures_image_generation","textures_particles_blending","textures_raw_data","textures_sprite_button","textures_textured_curve","textures_srcrec_dstrec","textures_image_text","textures_blend_modes","textures_image_loading","textures_sprite_explosion","textures_polygon","textures_fog_of_war","textures_mouse_painting","textures_bunnymark","textures_image_drawing","textures_gif_player","textures_sprite_anim","textures_image_rotate","textures_draw_tiled","textures_background_scrolling","textures_to_image","textures_image_processing","textures_npatch_drawing","textures_logo_raylib","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_loading_gltf","models_mesh_generation","models_loading_vox","models_waving_cubes","models_first_person_maze","models_heightmap","models_draw_cube_texture","models_rlgl_solar_system","models_skybox","models_yaw_pitch_roll","models_orthographic_projection","models_billboard","models_box_collisions","models_geometric_shapes","models_loading_m3d","core_smooth_pixelperfect","core_scissor_test","core_input_mouse","core_storage_values","core_window_letterbox","core_2d_camera","core_basic_window","core_input_mouse_wheel","core_basic_window_web","core_vr_simulator","core_loading_thread","core_basic_screen_manager","core_custom_frame_control","core_split_screen","core_input_gestures","core_custom_logging","core_3d_camera_free","core_window_should_close","core_2d_camera_platformer","core_random_values","core_world_screen","core_drop_files","core_input_gestures_web","core_input_multitouch","core_input_gamepad","core_window_flags","core_3d_picking","core_input_keys","core_2d_camera_mouse_zoom","core_3d_camera_first_person","core_3d_camera_mode","audio_module_playing","audio_sound_loading","audio_music_stream","audio_raw_stream","audio_sound_multi","audio_mixed_processor","audio_stream_effects","text_draw_3d","text_writing_anim","text_codepoints_loading","text_font_filters","text_format_text","text_raylib_fonts","text_rectangle_bounds","text_font_spritefont","text_input_box","text_font_sdf","text_unicode","text_font_loading","shapes_bouncing_ball","shapes_draw_rectangle_rounded","shapes_basic_shapes","shapes_rectangle_scaling","shapes_collision_area","shapes_logo_raylib_anim","shapes_colors_palette","shapes_following_eyes","shapes_draw_ring","shapes_easings_ball_anim","shapes_logo_raylib","shapes_easings_rectangle_array","shapes_easings_box_anim","shapes_top_down_lights","shapes_draw_circle_sector","shapes_lines_bezier"],"WindowShouldClose":["shaders_lightmap","shaders_write_depth","shaders_eratosthenes","shaders_spotlight","shaders_mesh_instancing","shaders_texture_outline","shaders_model_shader","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_hybrid_render","shaders_simple_mask","shaders_texture_drawing","shaders_texture_waves","shaders_shapes_textures","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","shaders_basic_lighting","shaders_fog","raymath_vector_angle","rlgl_compute_shader","easings_testbed","raylib_opengl_interop","embedded_files_loading","textures_image_generation","textures_particles_blending","textures_raw_data","textures_sprite_button","textures_textured_curve","textures_srcrec_dstrec","textures_image_text","textures_blend_modes","textures_image_loading","textures_sprite_explosion","textures_polygon","textures_fog_of_war","textures_mouse_painting","textures_bunnymark","textures_image_drawing","textures_gif_player","textures_sprite_anim","textures_image_rotate","textures_draw_tiled","textures_background_scrolling","textures_to_image","textures_image_processing","textures_npatch_drawing","textures_logo_raylib","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_loading_gltf","models_mesh_generation","models_loading_vox","models_waving_cubes","models_first_person_maze","models_heightmap","models_draw_cube_texture","models_rlgl_solar_system","models_skybox","models_yaw_pitch_roll","models_orthographic_projection","models_billboard","models_box_collisions","models_geometric_shapes","models_loading_m3d","core_smooth_pixelperfect","core_scissor_test","core_input_mouse","core_storage_values","core_window_letterbox","core_2d_camera","core_basic_window","core_input_mouse_wheel","core_basic_window_web","core_vr_simulator","core_loading_thread","core_basic_screen_manager","core_custom_frame_control","core_split_screen","core_input_gestures","core_custom_logging","core_3d_camera_free","core_window_should_close","core_2d_camera_platformer","core_random_values","core_world_screen","core_drop_files","core_input_gestures_web","core_input_multitouch","core_input_gamepad","core_window_flags","core_3d_picking","core_input_keys","core_2d_camera_mouse_zoom","core_3d_camera_first_person","core_3d_camera_mode","audio_module_playing","audio_sound_loading","audio_music_stream","audio_raw_stream","audio_sound_multi","audio_mixed_processor","audio_stream_effects","text_draw_3d","text_writing_anim","text_codepoints_loading","text_font_filters","text_format_text","text_raylib_fonts","text_rectangle_bounds","text_font_spritefont","text_input_box","text_font_sdf","text_unicode","text_font_loading","shapes_bouncing_ball","shapes_draw_rectangle_rounded","shapes_basic_shapes","shapes_rectangle_scaling","shapes_collision_area","shapes_logo_raylib_anim","shapes_colors_palette","shapes_following_eyes","shapes_draw_ring","shapes_easings_ball_anim","shapes_logo_raylib","shapes_easings_rectangle_array","shapes_easings_box_anim","shapes_top_down_lights","shapes_draw_circle_sector","shapes_lines_bezier"],"CloseWindow":["shaders_lightmap","shaders_write_depth","shaders_eratosthenes","shaders_spotlight","shaders_mesh_instancing","shaders_texture_outline","shaders_model_shader","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_hybrid_render","shaders_simple_mask","shaders_texture_drawing","shaders_texture_waves","shaders_shapes_textures","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","shaders_basic_lighting","shaders_fog","raymath_vector_angle","rlgl_compute_shader","easings_testbed","raylib_opengl_interop","embedded_files_loading","textures_image_generation","textures_particles_blending","textures_raw_data","textures_sprite_button","textures_textured_curve","textures_srcrec_dstrec","textures_image_text","textures_blend_modes","textures_image_loading","textures_sprite_explosion","textures_polygon","textures_fog_of_war","textures_mouse_painting","textures_bunnymark","textures_image_drawing","textures_gif_player","textures_sprite_anim","textures_image_rotate","textures_draw_tiled","textures_background_scrolling","textures_to_image","textures_image_processing","textures_npatch_drawing","textures_logo_raylib","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_loading_gltf","models_mesh_generation","models_loading_vox","models_waving_cubes","models_first_person_maze","models_heightmap","models_draw_cube_texture","models_rlgl_solar_system","models_skybox","models_yaw_pitch_roll","models_orthographic_projection","models_billboard","models_box_collisions","models_geometric_shapes","models_loading_m3d","core_smooth_pixelperfect","core_scissor_test","core_input_mouse","core_storage_values","core_window_letterbox","core_2d_camera","core_basic_window","core_input_mouse_wheel","core_basic_window_web","core_vr_simulator","core_loading_thread","core_basic_screen_manager","core_custom_frame_control","core_split_screen","core_input_gestures","core_custom_logging","core_3d_camera_free","core_window_should_close","core_2d_camera_platformer","core_random_values","core_world_screen","core_drop_files","core_input_gestures_web","core_input_multitouch","core_input_gamepad","core_window_flags","core_3d_picking","core_input_keys","core_2d_camera_mouse_zoom","core_3d_camera_first_person","core_3d_camera_mode","audio_module_playing","audio_sound_loading","audio_music_stream","audio_raw_stream","audio_sound_multi","audio_mixed_processor","audio_stream_effects","text_draw_3d","text_writing_anim","text_codepoints_loading","text_font_filters","text_format_text","text_raylib_fonts","text_rectangle_bounds","text_font_spritefont","text_input_box","text_font_sdf","text_unicode","text_font_loading","shapes_bouncing_ball","shapes_draw_rectangle_rounded","shapes_basic_shapes","shapes_rectangle_scaling","shapes_collision_area","shapes_logo_raylib_anim","shapes_colors_palette","shapes_following_eyes","shapes_draw_ring","shapes_easings_ball_anim","shapes_logo_raylib","shapes_easings_rectangle_array","shapes_easings_box_anim","shapes_top_down_lights","shapes_draw_circle_sector","shapes_lines_bezier"],"IsWindowReady":[],"IsWindowFullscreen":[],"IsWindowHidden":[],"IsWindowMinimized":[],"IsWindowMaximized":[],"IsWindowFocused":[],"IsWindowResized":["shaders_raymarching"],"IsWindowState":["core_window_flags"],"SetWindowState":["core_window_flags"],"ClearWindowState":["core_window_flags"],"ToggleFullscreen":["core_window_flags"],"ToggleBorderlessWindowed":[],"MaximizeWindow":["core_window_flags"],"MinimizeWindow":["core_window_flags"],"RestoreWindow":["core_window_flags"],"SetWindowIcon":[],"SetWindowIcons":[],"SetWindowTitle":[],"SetWindowPosition":[],"SetWindowMonitor":[],"SetWindowMinSize":["core_window_letterbox"],"SetWindowSize":[],"SetWindowOpacity":[],"SetWindowFocused":[],"GetWindowHandle":[],"GetScreenWidth":["shaders_eratosthenes","shaders_spotlight","shaders_texture_outline","shaders_raymarching","shaders_palette_switch","shaders_texture_waves","shaders_julia_set","rlgl_compute_shader","textures_polygon","textures_mouse_painting","textures_bunnymark","textures_gif_player","textures_draw_tiled","models_loading","models_first_person_maze","models_loading_m3d","core_smooth_pixelperfect","core_scissor_test","core_window_letterbox","core_vr_simulator","core_custom_frame_control","core_window_flags","audio_raw_stream","text_codepoints_loading","text_font_sdf","shapes_bouncing_ball","shapes_draw_rectangle_rounded","shapes_rectangle_scaling","shapes_collision_area","shapes_logo_raylib_anim","shapes_colors_palette","shapes_following_eyes","shapes_draw_ring","shapes_easings_box_anim","shapes_top_down_lights","shapes_draw_circle_sector"],"GetScreenHeight":["shaders_eratosthenes","shaders_spotlight","shaders_multi_sample2d","shaders_raymarching","shaders_texture_waves","shaders_julia_set","easings_testbed","textures_polygon","textures_mouse_painting","textures_bunnymark","textures_draw_tiled","models_loading","models_loading_gltf","models_skybox","models_orthographic_projection","models_loading_m3d","core_scissor_test","core_window_letterbox","core_vr_simulator","core_custom_frame_control","core_window_flags","text_codepoints_loading","text_font_sdf","text_font_loading","shapes_bouncing_ball","shapes_draw_rectangle_rounded","shapes_rectangle_scaling","shapes_collision_area","shapes_logo_raylib_anim","shapes_colors_palette","shapes_following_eyes","shapes_draw_ring","shapes_easings_box_anim","shapes_top_down_lights","shapes_draw_circle_sector"],"GetRenderWidth":["shaders_lightmap"],"GetRenderHeight":[],"GetMonitorCount":[],"GetCurrentMonitor":[],"GetMonitorPosition":[],"GetMonitorWidth":[],"GetMonitorHeight":[],"GetMonitorPhysicalWidth":[],"GetMonitorPhysicalHeight":[],"GetMonitorRefreshRate":[],"GetWindowPosition":[],"GetWindowScaleDPI":[],"GetMonitorName":[],"SetClipboardText":[],"GetClipboardText":[],"EnableEventWaiting":[],"DisableEventWaiting":[],"SwapScreenBuffer":["core_custom_frame_control"],"PollInputEvents":["core_custom_frame_control"],"WaitTime":["core_custom_frame_control"],"ShowCursor":[],"HideCursor":["shaders_spotlight"],"IsCursorHidden":["models_mesh_picking","core_3d_picking"],"EnableCursor":["models_mesh_picking","core_3d_picking"],"DisableCursor":["shaders_model_shader","shaders_raymarching","shaders_simple_mask","models_loading","models_animation","models_mesh_picking","models_loading_gltf","models_first_person_maze","models_skybox","models_loading_m3d","core_vr_simulator","core_3d_camera_free","core_world_screen","core_3d_picking","core_3d_camera_first_person","text_draw_3d"],"IsCursorOnScreen":[],"ClearBackground":["shaders_lightmap","shaders_write_depth","shaders_eratosthenes","shaders_spotlight","shaders_mesh_instancing","shaders_texture_outline","shaders_model_shader","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_hybrid_render","shaders_simple_mask","shaders_texture_drawing","shaders_texture_waves","shaders_shapes_textures","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","shaders_basic_lighting","shaders_fog","raymath_vector_angle","rlgl_compute_shader","easings_testbed","raylib_opengl_interop","embedded_files_loading","textures_image_generation","textures_particles_blending","textures_raw_data","textures_sprite_button","textures_textured_curve","textures_srcrec_dstrec","textures_image_text","textures_blend_modes","textures_image_loading","textures_sprite_explosion","textures_polygon","textures_fog_of_war","textures_mouse_painting","textures_bunnymark","textures_image_drawing","textures_gif_player","textures_sprite_anim","textures_image_rotate","textures_draw_tiled","textures_background_scrolling","textures_to_image","textures_image_processing","textures_npatch_drawing","textures_logo_raylib","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_loading_gltf","models_mesh_generation","models_loading_vox","models_waving_cubes","models_first_person_maze","models_heightmap","models_draw_cube_texture","models_rlgl_solar_system","models_skybox","models_yaw_pitch_roll","models_orthographic_projection","models_billboard","models_box_collisions","models_geometric_shapes","models_loading_m3d","core_smooth_pixelperfect","core_scissor_test","core_input_mouse","core_storage_values","core_window_letterbox","core_2d_camera","core_basic_window","core_input_mouse_wheel","core_basic_window_web","core_vr_simulator","core_loading_thread","core_basic_screen_manager","core_custom_frame_control","core_split_screen","core_input_gestures","core_custom_logging","core_3d_camera_free","core_window_should_close","core_2d_camera_platformer","core_random_values","core_world_screen","core_drop_files","core_input_gestures_web","core_input_multitouch","core_input_gamepad","core_window_flags","core_3d_picking","core_input_keys","core_2d_camera_mouse_zoom","core_3d_camera_first_person","core_3d_camera_mode","audio_module_playing","audio_sound_loading","audio_music_stream","audio_raw_stream","audio_sound_multi","audio_mixed_processor","audio_stream_effects","text_draw_3d","text_writing_anim","text_codepoints_loading","text_font_filters","text_format_text","text_raylib_fonts","text_rectangle_bounds","text_font_spritefont","text_input_box","text_font_sdf","text_unicode","text_font_loading","shapes_bouncing_ball","shapes_draw_rectangle_rounded","shapes_basic_shapes","shapes_rectangle_scaling","shapes_collision_area","shapes_logo_raylib_anim","shapes_colors_palette","shapes_following_eyes","shapes_draw_ring","shapes_easings_ball_anim","shapes_logo_raylib","shapes_easings_rectangle_array","shapes_easings_box_anim","shapes_top_down_lights","shapes_draw_circle_sector","shapes_lines_bezier"],"BeginDrawing":["shaders_lightmap","shaders_write_depth","shaders_eratosthenes","shaders_spotlight","shaders_mesh_instancing","shaders_texture_outline","shaders_model_shader","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_hybrid_render","shaders_simple_mask","shaders_texture_drawing","shaders_texture_waves","shaders_shapes_textures","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","shaders_basic_lighting","shaders_fog","raymath_vector_angle","rlgl_compute_shader","easings_testbed","raylib_opengl_interop","embedded_files_loading","textures_image_generation","textures_particles_blending","textures_raw_data","textures_sprite_button","textures_textured_curve","textures_srcrec_dstrec","textures_image_text","textures_blend_modes","textures_image_loading","textures_sprite_explosion","textures_polygon","textures_fog_of_war","textures_mouse_painting","textures_bunnymark","textures_image_drawing","textures_gif_player","textures_sprite_anim","textures_image_rotate","textures_draw_tiled","textures_background_scrolling","textures_to_image","textures_image_processing","textures_npatch_drawing","textures_logo_raylib","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_loading_gltf","models_mesh_generation","models_loading_vox","models_waving_cubes","models_first_person_maze","models_heightmap","models_draw_cube_texture","models_rlgl_solar_system","models_skybox","models_yaw_pitch_roll","models_orthographic_projection","models_billboard","models_box_collisions","models_geometric_shapes","models_loading_m3d","core_smooth_pixelperfect","core_scissor_test","core_input_mouse","core_storage_values","core_window_letterbox","core_2d_camera","core_basic_window","core_input_mouse_wheel","core_basic_window_web","core_vr_simulator","core_loading_thread","core_basic_screen_manager","core_custom_frame_control","core_split_screen","core_input_gestures","core_custom_logging","core_3d_camera_free","core_window_should_close","core_2d_camera_platformer","core_random_values","core_world_screen","core_drop_files","core_input_gestures_web","core_input_multitouch","core_input_gamepad","core_window_flags","core_3d_picking","core_input_keys","core_2d_camera_mouse_zoom","core_3d_camera_first_person","core_3d_camera_mode","audio_module_playing","audio_sound_loading","audio_music_stream","audio_raw_stream","audio_sound_multi","audio_mixed_processor","audio_stream_effects","text_draw_3d","text_writing_anim","text_codepoints_loading","text_font_filters","text_format_text","text_raylib_fonts","text_rectangle_bounds","text_font_spritefont","text_input_box","text_font_sdf","text_unicode","text_font_loading","shapes_bouncing_ball","shapes_draw_rectangle_rounded","shapes_basic_shapes","shapes_rectangle_scaling","shapes_collision_area","shapes_logo_raylib_anim","shapes_colors_palette","shapes_following_eyes","shapes_draw_ring","shapes_easings_ball_anim","shapes_logo_raylib","shapes_easings_rectangle_array","shapes_easings_box_anim","shapes_top_down_lights","shapes_draw_circle_sector","shapes_lines_bezier"],"EndDrawing":["shaders_lightmap","shaders_write_depth","shaders_eratosthenes","shaders_spotlight","shaders_mesh_instancing","shaders_texture_outline","shaders_model_shader","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_hybrid_render","shaders_simple_mask","shaders_texture_drawing","shaders_texture_waves","shaders_shapes_textures","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","shaders_basic_lighting","shaders_fog","raymath_vector_angle","rlgl_compute_shader","easings_testbed","raylib_opengl_interop","embedded_files_loading","textures_image_generation","textures_particles_blending","textures_raw_data","textures_sprite_button","textures_textured_curve","textures_srcrec_dstrec","textures_image_text","textures_blend_modes","textures_image_loading","textures_sprite_explosion","textures_polygon","textures_fog_of_war","textures_mouse_painting","textures_bunnymark","textures_image_drawing","textures_gif_player","textures_sprite_anim","textures_image_rotate","textures_draw_tiled","textures_background_scrolling","textures_to_image","textures_image_processing","textures_npatch_drawing","textures_logo_raylib","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_loading_gltf","models_mesh_generation","models_loading_vox","models_waving_cubes","models_first_person_maze","models_heightmap","models_draw_cube_texture","models_rlgl_solar_system","models_skybox","models_yaw_pitch_roll","models_orthographic_projection","models_billboard","models_box_collisions","models_geometric_shapes","models_loading_m3d","core_smooth_pixelperfect","core_scissor_test","core_input_mouse","core_storage_values","core_window_letterbox","core_2d_camera","core_basic_window","core_input_mouse_wheel","core_basic_window_web","core_vr_simulator","core_loading_thread","core_basic_screen_manager","core_custom_frame_control","core_split_screen","core_input_gestures","core_custom_logging","core_3d_camera_free","core_window_should_close","core_2d_camera_platformer","core_random_values","core_world_screen","core_drop_files","core_input_gestures_web","core_input_multitouch","core_input_gamepad","core_window_flags","core_3d_picking","core_input_keys","core_2d_camera_mouse_zoom","core_3d_camera_first_person","core_3d_camera_mode","audio_module_playing","audio_sound_loading","audio_music_stream","audio_raw_stream","audio_sound_multi","audio_mixed_processor","audio_stream_effects","text_draw_3d","text_writing_anim","text_codepoints_loading","text_font_filters","text_format_text","text_raylib_fonts","text_rectangle_bounds","text_font_spritefont","text_input_box","text_font_sdf","text_unicode","text_font_loading","shapes_bouncing_ball","shapes_draw_rectangle_rounded","shapes_basic_shapes","shapes_rectangle_scaling","shapes_collision_area","shapes_logo_raylib_anim","shapes_colors_palette","shapes_following_eyes","shapes_draw_ring","shapes_easings_ball_anim","shapes_logo_raylib","shapes_easings_rectangle_array","shapes_easings_box_anim","shapes_top_down_lights","shapes_draw_circle_sector","shapes_lines_bezier"],"BeginMode2D":["core_smooth_pixelperfect","core_2d_camera","core_2d_camera_platformer","core_2d_camera_mouse_zoom"],"EndMode2D":["core_smooth_pixelperfect","core_2d_camera","core_2d_camera_platformer","core_2d_camera_mouse_zoom"],"BeginMode3D":["shaders_lightmap","shaders_write_depth","shaders_mesh_instancing","shaders_model_shader","shaders_hybrid_render","shaders_simple_mask","shaders_custom_uniform","shaders_postprocessing","shaders_basic_lighting","shaders_fog","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_loading_gltf","models_mesh_generation","models_loading_vox","models_waving_cubes","models_first_person_maze","models_heightmap","models_draw_cube_texture","models_rlgl_solar_system","models_skybox","models_yaw_pitch_roll","models_orthographic_projection","models_billboard","models_box_collisions","models_geometric_shapes","models_loading_m3d","core_vr_simulator","core_split_screen","core_3d_camera_free","core_world_screen","core_3d_picking","core_3d_camera_first_person","core_3d_camera_mode","text_draw_3d"],"EndMode3D":["shaders_lightmap","shaders_write_depth","shaders_mesh_instancing","shaders_model_shader","shaders_hybrid_render","shaders_simple_mask","shaders_custom_uniform","shaders_postprocessing","shaders_basic_lighting","shaders_fog","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_loading_gltf","models_mesh_generation","models_loading_vox","models_waving_cubes","models_first_person_maze","models_heightmap","models_draw_cube_texture","models_rlgl_solar_system","models_skybox","models_yaw_pitch_roll","models_orthographic_projection","models_billboard","models_box_collisions","models_geometric_shapes","models_loading_m3d","core_vr_simulator","core_split_screen","core_3d_camera_free","core_world_screen","core_3d_picking","core_3d_camera_first_person","core_3d_camera_mode","text_draw_3d"],"BeginTextureMode":["shaders_lightmap","shaders_write_depth","shaders_eratosthenes","shaders_hybrid_render","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","textures_fog_of_war","textures_mouse_painting","core_smooth_pixelperfect","core_window_letterbox","core_vr_simulator","core_split_screen","shapes_top_down_lights"],"EndTextureMode":["shaders_lightmap","shaders_write_depth","shaders_eratosthenes","shaders_hybrid_render","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","textures_fog_of_war","textures_mouse_painting","core_smooth_pixelperfect","core_window_letterbox","core_vr_simulator","core_split_screen","shapes_top_down_lights"],"BeginShaderMode":["shaders_write_depth","shaders_eratosthenes","shaders_spotlight","shaders_texture_outline","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_hybrid_render","shaders_texture_drawing","shaders_texture_waves","shaders_shapes_textures","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","rlgl_compute_shader","core_vr_simulator","text_draw_3d","text_font_sdf"],"EndShaderMode":["shaders_write_depth","shaders_eratosthenes","shaders_spotlight","shaders_texture_outline","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_hybrid_render","shaders_texture_drawing","shaders_texture_waves","shaders_shapes_textures","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","rlgl_compute_shader","core_vr_simulator","text_draw_3d","text_font_sdf"],"BeginBlendMode":["shaders_lightmap","textures_particles_blending","textures_blend_modes"],"EndBlendMode":["textures_particles_blending","textures_blend_modes"],"BeginScissorMode":["core_scissor_test"],"EndScissorMode":["core_scissor_test"],"BeginVrStereoMode":["core_vr_simulator"],"EndVrStereoMode":["core_vr_simulator"],"LoadVrStereoConfig":["core_vr_simulator"],"UnloadVrStereoConfig":["core_vr_simulator"],"LoadShader":["shaders_lightmap","shaders_write_depth","shaders_eratosthenes","shaders_spotlight","shaders_mesh_instancing","shaders_texture_outline","shaders_model_shader","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_hybrid_render","shaders_simple_mask","shaders_texture_drawing","shaders_texture_waves","shaders_shapes_textures","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","shaders_basic_lighting","shaders_fog","rlgl_compute_shader","raylib_opengl_interop","models_skybox","core_vr_simulator","text_draw_3d","text_font_sdf"],"LoadShaderFromMemory":[],"IsShaderReady":[],"GetShaderLocation":["shaders_spotlight","shaders_mesh_instancing","shaders_texture_outline","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_hybrid_render","shaders_simple_mask","shaders_texture_drawing","shaders_texture_waves","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_basic_lighting","shaders_fog","rlgl_compute_shader","raylib_opengl_interop","models_skybox","core_vr_simulator"],"GetShaderLocationAttrib":["shaders_mesh_instancing"],"SetShaderValue":["shaders_spotlight","shaders_mesh_instancing","shaders_texture_outline","shaders_multi_sample2d","shaders_raymarching","shaders_hybrid_render","shaders_simple_mask","shaders_texture_drawing","shaders_texture_waves","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_basic_lighting","shaders_fog","rlgl_compute_shader","models_skybox","core_vr_simulator"],"SetShaderValueV":["shaders_palette_switch"],"SetShaderValueMatrix":[],"SetShaderValueTexture":["shaders_multi_sample2d"],"UnloadShader":["shaders_lightmap","shaders_write_depth","shaders_eratosthenes","shaders_spotlight","shaders_texture_outline","shaders_model_shader","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_hybrid_render","shaders_simple_mask","shaders_texture_drawing","shaders_texture_waves","shaders_shapes_textures","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","shaders_basic_lighting","shaders_fog","rlgl_compute_shader","raylib_opengl_interop","models_skybox","core_vr_simulator","text_font_sdf"],"GetMouseRay":["models_loading","models_mesh_picking","core_3d_picking","text_draw_3d"],"GetCameraMatrix":[],"GetCameraMatrix2D":[],"GetWorldToScreen":["core_world_screen"],"GetScreenToWorld2D":["core_2d_camera_platformer","core_2d_camera_mouse_zoom"],"GetWorldToScreenEx":[],"GetWorldToScreen2D":["core_2d_camera_platformer"],"SetTargetFPS":["shaders_lightmap","shaders_write_depth","shaders_eratosthenes","shaders_spotlight","shaders_mesh_instancing","shaders_texture_outline","shaders_model_shader","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_hybrid_render","shaders_simple_mask","shaders_texture_drawing","shaders_texture_waves","shaders_shapes_textures","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","shaders_basic_lighting","shaders_fog","raymath_vector_angle","easings_testbed","raylib_opengl_interop","embedded_files_loading","textures_image_generation","textures_particles_blending","textures_sprite_button","textures_textured_curve","textures_srcrec_dstrec","textures_image_text","textures_image_loading","textures_sprite_explosion","textures_polygon","textures_fog_of_war","textures_mouse_painting","textures_bunnymark","textures_image_drawing","textures_gif_player","textures_sprite_anim","textures_draw_tiled","textures_background_scrolling","textures_image_processing","textures_npatch_drawing","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_loading_gltf","models_mesh_generation","models_loading_vox","models_waving_cubes","models_first_person_maze","models_heightmap","models_draw_cube_texture","models_rlgl_solar_system","models_skybox","models_yaw_pitch_roll","models_orthographic_projection","models_billboard","models_box_collisions","models_geometric_shapes","models_loading_m3d","core_smooth_pixelperfect","core_scissor_test","core_input_mouse","core_storage_values","core_window_letterbox","core_2d_camera","core_basic_window","core_input_mouse_wheel","core_basic_window_web","core_vr_simulator","core_loading_thread","core_basic_screen_manager","core_split_screen","core_input_gestures","core_custom_logging","core_3d_camera_free","core_window_should_close","core_2d_camera_platformer","core_random_values","core_world_screen","core_drop_files","core_input_gestures_web","core_input_multitouch","core_input_gamepad","core_3d_picking","core_input_keys","core_2d_camera_mouse_zoom","core_3d_camera_first_person","core_3d_camera_mode","audio_module_playing","audio_sound_loading","audio_music_stream","audio_raw_stream","audio_sound_multi","audio_mixed_processor","audio_stream_effects","text_draw_3d","text_writing_anim","text_codepoints_loading","text_font_filters","text_format_text","text_raylib_fonts","text_rectangle_bounds","text_font_spritefont","text_input_box","text_font_sdf","text_unicode","text_font_loading","shapes_bouncing_ball","shapes_draw_rectangle_rounded","shapes_basic_shapes","shapes_rectangle_scaling","shapes_collision_area","shapes_logo_raylib_anim","shapes_colors_palette","shapes_following_eyes","shapes_draw_ring","shapes_easings_ball_anim","shapes_logo_raylib","shapes_easings_rectangle_array","shapes_easings_box_anim","shapes_top_down_lights","shapes_draw_circle_sector","shapes_lines_bezier"],"GetFPS":["textures_draw_tiled"],"GetFrameTime":["shaders_raymarching","shaders_texture_waves","shaders_hot_reloading","shaders_julia_set","core_smooth_pixelperfect","core_split_screen","core_2d_camera_platformer","text_draw_3d","text_format_text"],"GetTime":["shaders_texture_drawing","raylib_opengl_interop","models_loading_vox","models_waving_cubes","core_smooth_pixelperfect","core_custom_frame_control"],"GetRandomValue":["shaders_spotlight","shaders_mesh_instancing","raylib_opengl_interop","textures_particles_blending","textures_fog_of_war","textures_bunnymark","core_storage_values","core_window_letterbox","core_2d_camera","core_random_values","core_3d_camera_first_person","audio_module_playing","text_draw_3d","text_unicode","shapes_top_down_lights"],"SetRandomSeed":[],"TakeScreenshot":[],"SetConfigFlags":["shaders_lightmap","shaders_model_shader","shaders_raymarching","shaders_custom_uniform","shaders_postprocessing","shaders_basic_lighting","shaders_fog","textures_textured_curve","textures_draw_tiled","core_window_letterbox","core_input_gamepad","audio_module_playing","text_draw_3d","text_unicode","shapes_lines_bezier"],"TraceLog":["models_loading_vox","models_skybox","core_storage_values","core_loading_thread"],"SetTraceLogLevel":[],"MemAlloc":["models_mesh_generation"],"MemRealloc":[],"MemFree":[],"OpenURL":[],"SetTraceLogCallback":["core_custom_logging"],"SetLoadFileDataCallback":[],"SetSaveFileDataCallback":[],"SetLoadFileTextCallback":[],"SetSaveFileTextCallback":[],"LoadFileData":["core_storage_values","text_font_sdf"],"UnloadFileData":["core_storage_values","text_font_sdf"],"SaveFileData":["core_storage_values"],"ExportDataAsCode":[],"LoadFileText":["rlgl_compute_shader"],"UnloadFileText":["rlgl_compute_shader"],"SaveFileText":[],"FileExists":[],"DirectoryExists":[],"IsFileExtension":["models_loading","models_skybox","text_draw_3d","text_font_filters"],"GetFileLength":[],"GetFileExtension":[],"GetFileName":["models_loading_vox","models_skybox"],"GetFileNameWithoutExt":[],"GetDirectoryPath":[],"GetPrevDirectoryPath":[],"GetWorkingDirectory":[],"GetApplicationDirectory":[],"ChangeDirectory":[],"IsPathFile":[],"LoadDirectoryFiles":[],"LoadDirectoryFilesEx":[],"UnloadDirectoryFiles":[],"IsFileDropped":["models_loading","models_skybox","core_drop_files","text_draw_3d","text_font_filters"],"LoadDroppedFiles":["models_loading","models_skybox","core_drop_files","text_draw_3d","text_font_filters"],"UnloadDroppedFiles":["models_loading","models_skybox","core_drop_files","text_draw_3d","text_font_filters"],"GetFileModTime":["shaders_hot_reloading"],"CompressData":[],"DecompressData":[],"EncodeDataBase64":[],"DecodeDataBase64":[],"IsKeyPressed":["shaders_palette_switch","shaders_hot_reloading","shaders_julia_set","shaders_postprocessing","shaders_basic_lighting","raymath_vector_angle","easings_testbed","embedded_files_loading","textures_image_generation","textures_particles_blending","textures_textured_curve","textures_blend_modes","textures_mouse_painting","textures_gif_player","textures_sprite_anim","textures_image_rotate","textures_draw_tiled","textures_image_processing","models_loading_gltf","models_mesh_generation","models_loading_vox","models_orthographic_projection","models_loading_m3d","core_scissor_test","core_storage_values","core_window_letterbox","core_2d_camera","core_loading_thread","core_basic_screen_manager","core_custom_frame_control","core_window_should_close","core_2d_camera_platformer","core_input_gamepad","core_window_flags","core_3d_camera_first_person","audio_module_playing","audio_sound_loading","audio_music_stream","audio_sound_multi","audio_mixed_processor","audio_stream_effects","text_draw_3d","text_writing_anim","text_codepoints_loading","text_font_filters","text_rectangle_bounds","text_input_box","text_unicode","shapes_bouncing_ball","shapes_collision_area","shapes_logo_raylib_anim","shapes_easings_ball_anim","shapes_easings_rectangle_array","shapes_easings_box_anim","shapes_top_down_lights"],"IsKeyPressedRepeat":[],"IsKeyDown":["shaders_multi_sample2d","shaders_fog","easings_testbed","textures_image_text","textures_fog_of_war","models_animation","models_yaw_pitch_roll","models_box_collisions","models_loading_m3d","core_2d_camera","core_split_screen","core_3d_camera_free","core_2d_camera_platformer","core_input_keys","audio_module_playing","text_draw_3d","text_writing_anim","text_font_filters","text_font_sdf","text_font_loading","shapes_colors_palette"],"IsKeyReleased":[],"IsKeyUp":[],"SetExitKey":["core_window_should_close"],"GetKeyPressed":["text_input_box"],"GetCharPressed":["text_draw_3d","text_input_box"],"IsGamepadAvailable":["core_input_gamepad"],"GetGamepadName":["core_input_gamepad"],"IsGamepadButtonPressed":[],"IsGamepadButtonDown":["core_input_gamepad"],"IsGamepadButtonReleased":[],"IsGamepadButtonUp":[],"GetGamepadButtonPressed":["core_input_gamepad"],"GetGamepadAxisCount":["core_input_gamepad"],"GetGamepadAxisMovement":["core_input_gamepad"],"SetGamepadMappings":[],"IsMouseButtonPressed":["shaders_hot_reloading","textures_image_generation","textures_sprite_explosion","textures_mouse_painting","textures_image_rotate","textures_draw_tiled","models_loading","models_mesh_picking","models_mesh_generation","models_loading_vox","core_input_mouse","core_3d_picking","text_draw_3d","text_unicode","shapes_rectangle_scaling","shapes_top_down_lights"],"IsMouseButtonDown":["shaders_julia_set","rlgl_compute_shader","textures_sprite_button","textures_textured_curve","textures_mouse_painting","textures_bunnymark","core_2d_camera_mouse_zoom","audio_raw_stream","text_rectangle_bounds","shapes_top_down_lights","shapes_lines_bezier"],"IsMouseButtonReleased":["textures_sprite_button","textures_mouse_painting","textures_image_processing","core_input_gestures_web","text_rectangle_bounds","shapes_rectangle_scaling"],"IsMouseButtonUp":[],"GetMouseX":["rlgl_compute_shader","textures_mouse_painting","core_scissor_test","shapes_collision_area"],"GetMouseY":["rlgl_compute_shader","textures_mouse_painting","core_scissor_test","shapes_collision_area"],"GetMousePosition":["shaders_spotlight","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","raymath_vector_angle","textures_particles_blending","textures_sprite_button","textures_textured_curve","textures_sprite_explosion","textures_mouse_painting","textures_bunnymark","textures_draw_tiled","textures_image_processing","textures_npatch_drawing","models_loading","models_mesh_picking","core_input_mouse","core_window_letterbox","core_input_gestures_web","core_window_flags","core_3d_picking","core_2d_camera_mouse_zoom","audio_raw_stream","text_draw_3d","text_rectangle_bounds","text_input_box","text_unicode","shapes_rectangle_scaling","shapes_colors_palette","shapes_following_eyes","shapes_top_down_lights","shapes_lines_bezier"],"GetMouseDelta":["textures_textured_curve","core_2d_camera_mouse_zoom"],"SetMousePosition":[],"SetMouseOffset":[],"SetMouseScale":[],"GetMouseWheelMove":["shaders_texture_outline","rlgl_compute_shader","textures_mouse_painting","core_2d_camera","core_input_mouse_wheel","core_2d_camera_platformer","core_2d_camera_mouse_zoom","text_font_filters","text_font_sdf"],"GetMouseWheelMoveV":[],"SetMouseCursor":["text_input_box"],"GetTouchX":[],"GetTouchY":[],"GetTouchPosition":["core_input_gestures","core_input_gestures_web","core_input_multitouch"],"GetTouchPointId":[],"GetTouchPointCount":["core_input_gestures_web","core_input_multitouch"],"SetGesturesEnabled":[],"IsGestureDetected":["core_basic_screen_manager"],"GetGestureDetected":["textures_mouse_painting","core_input_gestures","core_input_gestures_web"],"GetGestureHoldDuration":[],"GetGestureDragVector":[],"GetGestureDragAngle":["core_input_gestures_web"],"GetGesturePinchVector":[],"GetGesturePinchAngle":["core_input_gestures_web"],"UpdateCamera":["shaders_lightmap","shaders_write_depth","shaders_mesh_instancing","shaders_model_shader","shaders_raymarching","shaders_hybrid_render","shaders_simple_mask","shaders_custom_uniform","shaders_postprocessing","shaders_basic_lighting","shaders_fog","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_loading_gltf","models_mesh_generation","models_loading_vox","models_first_person_maze","models_heightmap","models_rlgl_solar_system","models_skybox","models_billboard","models_loading_m3d","core_vr_simulator","core_3d_camera_free","core_world_screen","core_3d_picking","core_3d_camera_first_person","text_draw_3d"],"UpdateCameraPro":[],"SetShapesTexture":[],"DrawPixel":[],"DrawPixelV":["audio_raw_stream"],"DrawLine":["raymath_vector_angle","textures_srcrec_dstrec","textures_mouse_painting","core_2d_camera","audio_mixed_processor","text_raylib_fonts","shapes_draw_rectangle_rounded","shapes_basic_shapes","shapes_draw_ring","shapes_draw_circle_sector"],"DrawLineV":["textures_textured_curve"],"DrawLineEx":["raymath_vector_angle","core_input_gestures_web"],"DrawLineBezier":["shapes_lines_bezier"],"DrawLineBezierQuad":[],"DrawLineBezierCubic":["textures_textured_curve"],"DrawLineBSpline":[],"DrawLineCatmullRom":[],"DrawLineStrip":[],"DrawCircle":["shaders_shapes_textures","textures_mouse_painting","core_custom_frame_control","core_input_gestures_web","core_input_gamepad","core_2d_camera_mouse_zoom","shapes_basic_shapes","shapes_easings_ball_anim","shapes_top_down_lights"],"DrawCircleSector":["raymath_vector_angle","shapes_draw_circle_sector"],"DrawCircleSectorLines":["shapes_draw_ring","shapes_draw_circle_sector"],"DrawCircleGradient":["shaders_shapes_textures","shapes_basic_shapes","shapes_top_down_lights"],"DrawCircleV":["easings_testbed","textures_textured_curve","core_input_mouse","core_input_gestures","core_input_gestures_web","core_input_multitouch","core_window_flags","core_input_keys","audio_module_playing","shapes_bouncing_ball","shapes_following_eyes"],"DrawCircleLines":["shaders_shapes_textures","textures_mouse_painting","shapes_basic_shapes"],"DrawEllipse":[],"DrawEllipseLines":[],"DrawRing":["core_input_gestures_web","shapes_draw_ring"],"DrawRingLines":["shapes_draw_ring"],"DrawRectangle":["shaders_eratosthenes","shaders_spotlight","shaders_raymarching","shaders_palette_switch","shaders_simple_mask","shaders_shapes_textures","shaders_hot_reloading","shaders_julia_set","shaders_postprocessing","raylib_opengl_interop","textures_image_generation","textures_fog_of_war","textures_mouse_painting","textures_bunnymark","textures_gif_player","textures_sprite_anim","textures_draw_tiled","models_mesh_generation","models_loading_vox","models_first_person_maze","models_yaw_pitch_roll","core_scissor_test","core_window_letterbox","core_2d_camera","core_input_mouse_wheel","core_loading_thread","core_basic_screen_manager","core_custom_frame_control","core_input_gestures","core_3d_camera_free","core_window_should_close","core_drop_files","core_input_gestures_web","core_input_gamepad","core_3d_camera_first_person","audio_module_playing","audio_music_stream","audio_mixed_processor","audio_stream_effects","text_codepoints_loading","text_font_filters","text_rectangle_bounds","shapes_draw_rectangle_rounded","shapes_basic_shapes","shapes_collision_area","shapes_logo_raylib_anim","shapes_colors_palette","shapes_draw_ring","shapes_easings_ball_anim","shapes_logo_raylib","shapes_draw_circle_sector"],"DrawRectangleV":["rlgl_standalone","textures_fog_of_war"],"DrawRectangleRec":["shaders_hybrid_render","textures_mouse_painting","textures_draw_tiled","textures_image_processing","core_2d_camera","core_input_gestures","core_2d_camera_platformer","core_input_gestures_web","text_rectangle_bounds","text_input_box","text_unicode","shapes_draw_rectangle_rounded","shapes_rectangle_scaling","shapes_collision_area","shapes_colors_palette","shapes_top_down_lights"],"DrawRectanglePro":["core_smooth_pixelperfect","shapes_easings_rectangle_array","shapes_easings_box_anim"],"DrawRectangleGradientV":[],"DrawRectangleGradientH":["shaders_shapes_textures","shapes_basic_shapes"],"DrawRectangleGradientEx":[],"DrawRectangleLines":["shaders_shapes_textures","rlgl_compute_shader","textures_image_generation","textures_fog_of_war","textures_mouse_painting","textures_image_drawing","textures_gif_player","textures_sprite_anim","textures_image_processing","textures_npatch_drawing","models_cubicmap","models_mesh_generation","models_loading_vox","models_first_person_maze","models_heightmap","models_yaw_pitch_roll","core_2d_camera","core_loading_thread","core_input_gestures","core_3d_camera_free","core_3d_camera_first_person","audio_module_playing","audio_music_stream","audio_mixed_processor","audio_stream_effects","text_codepoints_loading","text_input_box","shapes_basic_shapes","shapes_top_down_lights"],"DrawRectangleLinesEx":["textures_mouse_painting","textures_draw_tiled","core_scissor_test","core_window_flags","text_rectangle_bounds","shapes_rectangle_scaling","shapes_colors_palette"],"DrawRectangleRounded":["shapes_draw_rectangle_rounded"],"DrawRectangleRoundedLines":["shapes_draw_rectangle_rounded"],"DrawTriangle":["shaders_shapes_textures","core_input_gestures_web","core_input_gamepad","text_unicode","shapes_basic_shapes","shapes_rectangle_scaling"],"DrawTriangleLines":["shaders_shapes_textures","shapes_basic_shapes"],"DrawTriangleFan":["shapes_top_down_lights"],"DrawTriangleStrip":[],"DrawPoly":["shaders_shapes_textures","shapes_basic_shapes"],"DrawPolyLines":["shapes_basic_shapes"],"DrawPolyLinesEx":["shapes_basic_shapes"],"CheckCollisionRecs":["shapes_collision_area","shapes_top_down_lights"],"CheckCollisionCircles":[],"CheckCollisionCircleRec":["models_first_person_maze"],"CheckCollisionPointRec":["textures_sprite_button","textures_mouse_painting","textures_draw_tiled","textures_image_processing","core_input_gestures","core_input_gestures_web","text_rectangle_bounds","text_input_box","text_unicode","shapes_rectangle_scaling","shapes_colors_palette","shapes_top_down_lights"],"CheckCollisionPointCircle":["textures_textured_curve","shapes_following_eyes"],"CheckCollisionPointTriangle":[],"CheckCollisionPointPoly":[],"CheckCollisionLines":[],"CheckCollisionPointLine":[],"GetCollisionRec":["shapes_collision_area"],"LoadImage":["textures_image_text","textures_blend_modes","textures_image_loading","textures_image_drawing","textures_image_rotate","textures_to_image","textures_image_processing","models_cubicmap","models_first_person_maze","models_heightmap","models_skybox"],"LoadImageRaw":["textures_raw_data"],"LoadImageAnim":["textures_gif_player"],"LoadImageFromMemory":[],"LoadImageFromTexture":["textures_mouse_painting","textures_to_image"],"LoadImageFromScreen":[],"IsImageReady":[],"UnloadImage":["shaders_multi_sample2d","shaders_texture_drawing","rlgl_compute_shader","textures_image_generation","textures_raw_data","textures_image_text","textures_blend_modes","textures_image_loading","textures_mouse_painting","textures_image_drawing","textures_gif_player","textures_to_image","textures_image_processing","models_cubicmap","models_mesh_generation","models_first_person_maze","models_heightmap","models_skybox","text_font_sdf","shapes_top_down_lights"],"ExportImage":["textures_mouse_painting"],"ExportImageToMemory":[],"ExportImageAsCode":[],"GenImageColor":["shaders_multi_sample2d","shaders_texture_drawing","rlgl_compute_shader"],"GenImageGradientLinear":["textures_image_generation"],"GenImageGradientRadial":["textures_image_generation"],"GenImageGradientSquare":["textures_image_generation"],"GenImageChecked":["textures_image_generation","models_mesh_generation","shapes_top_down_lights"],"GenImageWhiteNoise":["textures_image_generation"],"GenImagePerlinNoise":["textures_image_generation"],"GenImageCellular":["textures_image_generation"],"GenImageText":[],"ImageCopy":["textures_image_processing"],"ImageFromImage":[],"ImageText":[],"ImageTextEx":[],"ImageFormat":["textures_image_processing"],"ImageToPOT":[],"ImageCrop":["textures_image_drawing"],"ImageAlphaCrop":[],"ImageAlphaClear":[],"ImageAlphaMask":[],"ImageAlphaPremultiply":[],"ImageBlurGaussian":["textures_image_processing"],"ImageResize":["textures_image_drawing"],"ImageResizeNN":[],"ImageResizeCanvas":[],"ImageMipmaps":[],"ImageDither":[],"ImageFlipVertical":["textures_mouse_painting","textures_image_processing"],"ImageFlipHorizontal":["textures_image_drawing","textures_image_processing"],"ImageRotate":["textures_image_rotate"],"ImageRotateCW":[],"ImageRotateCCW":[],"ImageColorTint":["textures_image_processing"],"ImageColorInvert":["textures_image_processing"],"ImageColorGrayscale":["textures_image_processing"],"ImageColorContrast":["textures_image_processing"],"ImageColorBrightness":["textures_image_processing"],"ImageColorReplace":[],"LoadImageColors":["textures_image_processing","models_first_person_maze"],"LoadImagePalette":[],"UnloadImageColors":["textures_image_processing","models_first_person_maze"],"UnloadImagePalette":[],"GetImageAlphaBorder":[],"GetImageColor":[],"ImageClearBackground":[],"ImageDrawPixel":["textures_image_drawing"],"ImageDrawPixelV":[],"ImageDrawLine":[],"ImageDrawLineV":[],"ImageDrawCircle":[],"ImageDrawCircleV":[],"ImageDrawCircleLines":["textures_image_drawing"],"ImageDrawCircleLinesV":[],"ImageDrawRectangle":["textures_image_drawing"],"ImageDrawRectangleV":[],"ImageDrawRectangleRec":[],"ImageDrawRectangleLines":[],"ImageDraw":["textures_image_drawing"],"ImageDrawText":[],"ImageDrawTextEx":["textures_image_text","textures_image_drawing"],"LoadTexture":["shaders_lightmap","shaders_spotlight","shaders_texture_outline","shaders_model_shader","shaders_simple_mask","shaders_texture_waves","shaders_shapes_textures","shaders_custom_uniform","shaders_postprocessing","shaders_fog","textures_particles_blending","textures_sprite_button","textures_textured_curve","textures_srcrec_dstrec","textures_sprite_explosion","textures_polygon","textures_bunnymark","textures_sprite_anim","textures_draw_tiled","textures_background_scrolling","textures_npatch_drawing","textures_logo_raylib","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_first_person_maze","models_draw_cube_texture","models_skybox","models_yaw_pitch_roll","models_billboard","core_input_gamepad"],"LoadTextureFromImage":["shaders_multi_sample2d","shaders_texture_drawing","rlgl_compute_shader","embedded_files_loading","textures_image_generation","textures_raw_data","textures_image_text","textures_blend_modes","textures_image_loading","textures_image_drawing","textures_gif_player","textures_image_rotate","textures_to_image","textures_image_processing","models_cubicmap","models_mesh_generation","models_first_person_maze","models_heightmap","text_font_sdf","shapes_top_down_lights"],"LoadTextureCubemap":["models_skybox"],"LoadRenderTexture":["shaders_lightmap","shaders_eratosthenes","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","textures_fog_of_war","textures_mouse_painting","core_smooth_pixelperfect","core_window_letterbox","core_vr_simulator","core_split_screen","shapes_top_down_lights"],"IsTextureReady":[],"UnloadTexture":["shaders_spotlight","shaders_texture_outline","shaders_model_shader","shaders_multi_sample2d","shaders_simple_mask","shaders_texture_waves","shaders_shapes_textures","shaders_custom_uniform","shaders_postprocessing","shaders_fog","rlgl_compute_shader","embedded_files_loading","textures_image_generation","textures_particles_blending","textures_raw_data","textures_sprite_button","textures_textured_curve","textures_srcrec_dstrec","textures_image_text","textures_blend_modes","textures_image_loading","textures_sprite_explosion","textures_polygon","textures_bunnymark","textures_image_drawing","textures_gif_player","textures_sprite_anim","textures_image_rotate","textures_draw_tiled","textures_background_scrolling","textures_to_image","textures_image_processing","textures_npatch_drawing","textures_logo_raylib","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_mesh_generation","models_first_person_maze","models_heightmap","models_draw_cube_texture","models_skybox","models_billboard","core_input_gamepad","shapes_top_down_lights"],"IsRenderTextureReady":[],"UnloadRenderTexture":["shaders_eratosthenes","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","textures_fog_of_war","textures_mouse_painting","core_smooth_pixelperfect","core_window_letterbox","core_vr_simulator","core_split_screen","shapes_top_down_lights"],"UpdateTexture":["textures_gif_player","textures_image_processing"],"UpdateTextureRec":[],"GenTextureMipmaps":["shaders_lightmap","text_font_filters"],"SetTextureFilter":["shaders_lightmap","textures_textured_curve","textures_fog_of_war","textures_draw_tiled","core_window_letterbox","text_codepoints_loading","text_font_filters","text_font_sdf"],"SetTextureWrap":[],"DrawTexture":["shaders_spotlight","shaders_texture_outline","shaders_multi_sample2d","shaders_texture_drawing","shaders_texture_waves","shaders_shapes_textures","rlgl_compute_shader","embedded_files_loading","textures_image_generation","textures_raw_data","textures_image_text","textures_blend_modes","textures_image_loading","textures_bunnymark","textures_image_drawing","textures_gif_player","textures_sprite_anim","textures_image_rotate","textures_draw_tiled","textures_to_image","textures_image_processing","textures_npatch_drawing","textures_logo_raylib","models_heightmap","core_input_gamepad","text_codepoints_loading","text_font_sdf"],"DrawTextureV":["textures_image_text"],"DrawTextureEx":["shaders_julia_set","textures_background_scrolling","models_cubicmap","models_first_person_maze"],"DrawTextureRec":["shaders_write_depth","shaders_eratosthenes","shaders_hybrid_render","shaders_custom_uniform","shaders_postprocessing","textures_sprite_button","textures_sprite_explosion","textures_mouse_painting","textures_sprite_anim","core_split_screen","shapes_top_down_lights"],"DrawTexturePro":["shaders_lightmap","textures_particles_blending","textures_srcrec_dstrec","textures_fog_of_war","textures_draw_tiled","core_smooth_pixelperfect","core_window_letterbox","core_vr_simulator"],"DrawTextureNPatch":["textures_npatch_drawing"],"Fade":["shaders_postprocessing","raymath_vector_angle","textures_image_generation","textures_particles_blending","textures_raw_data","textures_fog_of_war","textures_mouse_painting","models_mesh_generation","models_loading_vox","models_rlgl_solar_system","models_yaw_pitch_roll","core_2d_camera","core_input_gestures","core_3d_camera_free","core_drop_files","core_input_gestures_web","core_3d_camera_first_person","audio_module_playing","text_rectangle_bounds","text_unicode","shapes_draw_rectangle_rounded","shapes_rectangle_scaling","shapes_logo_raylib_anim","shapes_colors_palette","shapes_draw_ring","shapes_easings_ball_anim","shapes_easings_box_anim","shapes_draw_circle_sector"],"ColorToInt":[],"ColorNormalize":["raylib_opengl_interop"],"ColorFromNormalized":[],"ColorToHSV":[],"ColorFromHSV":["models_waving_cubes","text_draw_3d","text_unicode"],"ColorTint":[],"ColorBrightness":[],"ColorContrast":[],"ColorAlpha":["shaders_basic_lighting","textures_draw_tiled","shapes_top_down_lights"],"ColorAlphaBlend":[],"GetColor":["textures_background_scrolling"],"GetPixelColor":[],"SetPixelColor":[],"GetPixelDataSize":[],"GetFontDefault":["text_draw_3d","text_rectangle_bounds","text_unicode"],"LoadFont":["textures_image_drawing","text_draw_3d","text_raylib_fonts","text_font_spritefont","text_unicode","text_font_loading"],"LoadFontEx":["textures_image_text","text_draw_3d","text_codepoints_loading","text_font_filters","text_font_loading"],"LoadFontFromImage":[],"LoadFontFromMemory":[],"IsFontReady":[],"LoadFontData":["text_font_sdf"],"GenImageFontAtlas":["text_font_sdf"],"UnloadFontData":[],"UnloadFont":["textures_image_text","textures_image_drawing","text_draw_3d","text_codepoints_loading","text_font_filters","text_raylib_fonts","text_font_spritefont","text_font_sdf","text_unicode","text_font_loading"],"ExportFontAsCode":[],"DrawFPS":["shaders_lightmap","shaders_write_depth","shaders_spotlight","shaders_mesh_instancing","shaders_texture_outline","shaders_model_shader","shaders_palette_switch","shaders_hybrid_render","shaders_simple_mask","shaders_custom_uniform","shaders_postprocessing","shaders_basic_lighting","rlgl_compute_shader","raylib_opengl_interop","textures_bunnymark","models_loading","models_mesh_picking","models_cubicmap","models_waving_cubes","models_first_person_maze","models_heightmap","models_draw_cube_texture","models_rlgl_solar_system","models_skybox","models_orthographic_projection","models_billboard","models_box_collisions","models_geometric_shapes","core_smooth_pixelperfect","core_vr_simulator","core_window_flags","core_3d_picking","core_3d_camera_mode","text_draw_3d","shapes_bouncing_ball","shapes_draw_rectangle_rounded","shapes_collision_area","shapes_following_eyes","shapes_draw_ring","shapes_top_down_lights","shapes_draw_circle_sector"],"DrawText":["shaders_lightmap","shaders_spotlight","shaders_texture_outline","shaders_model_shader","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_simple_mask","shaders_texture_drawing","shaders_shapes_textures","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","shaders_basic_lighting","shaders_fog","raymath_vector_angle","rlgl_compute_shader","easings_testbed","raylib_opengl_interop","embedded_files_loading","textures_image_generation","textures_particles_blending","textures_raw_data","textures_textured_curve","textures_srcrec_dstrec","textures_image_text","textures_blend_modes","textures_image_loading","textures_polygon","textures_fog_of_war","textures_mouse_painting","textures_bunnymark","textures_image_drawing","textures_gif_player","textures_sprite_anim","textures_draw_tiled","textures_background_scrolling","textures_to_image","textures_image_processing","textures_npatch_drawing","textures_logo_raylib","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_loading_gltf","models_mesh_generation","models_loading_vox","models_rlgl_solar_system","models_skybox","models_yaw_pitch_roll","models_orthographic_projection","models_box_collisions","models_loading_m3d","core_smooth_pixelperfect","core_scissor_test","core_input_mouse","core_storage_values","core_window_letterbox","core_2d_camera","core_basic_window","core_input_mouse_wheel","core_basic_window_web","core_loading_thread","core_basic_screen_manager","core_custom_frame_control","core_split_screen","core_input_gestures","core_custom_logging","core_3d_camera_free","core_window_should_close","core_2d_camera_platformer","core_random_values","core_world_screen","core_drop_files","core_input_gestures_web","core_input_multitouch","core_input_gamepad","core_window_flags","core_3d_picking","core_input_keys","core_2d_camera_mouse_zoom","core_3d_camera_first_person","core_3d_camera_mode","audio_sound_loading","audio_music_stream","audio_raw_stream","audio_sound_multi","audio_mixed_processor","audio_stream_effects","text_draw_3d","text_writing_anim","text_codepoints_loading","text_font_filters","text_format_text","text_raylib_fonts","text_rectangle_bounds","text_input_box","text_font_sdf","text_unicode","text_font_loading","shapes_bouncing_ball","shapes_draw_rectangle_rounded","shapes_basic_shapes","shapes_rectangle_scaling","shapes_collision_area","shapes_logo_raylib_anim","shapes_colors_palette","shapes_draw_ring","shapes_easings_ball_anim","shapes_logo_raylib","shapes_easings_rectangle_array","shapes_easings_box_anim","shapes_top_down_lights","shapes_draw_circle_sector","shapes_lines_bezier"],"DrawTextEx":["textures_image_text","text_codepoints_loading","text_font_filters","text_raylib_fonts","text_font_spritefont","text_font_sdf","text_unicode","text_font_loading"],"DrawTextPro":[],"DrawTextCodepoint":["text_rectangle_bounds","text_unicode"],"DrawTextCodepoints":[],"SetTextLineSpacing":[],"MeasureText":["shaders_simple_mask","textures_image_processing","core_world_screen","core_3d_picking","text_draw_3d","text_input_box","shapes_collision_area","shapes_colors_palette"],"MeasureTextEx":["text_font_filters","text_raylib_fonts","text_font_spritefont","text_font_sdf","text_unicode"],"GetGlyphIndex":["text_draw_3d","text_rectangle_bounds","text_unicode"],"GetGlyphInfo":[],"GetGlyphAtlasRec":[],"LoadUTF8":[],"UnloadUTF8":[],"LoadCodepoints":["text_codepoints_loading"],"UnloadCodepoints":["text_codepoints_loading"],"GetCodepointCount":["text_unicode"],"GetCodepoint":["text_draw_3d","text_rectangle_bounds","text_unicode"],"GetCodepointNext":["text_codepoints_loading"],"GetCodepointPrevious":["text_codepoints_loading"],"CodepointToUTF8":[],"TextCopy":["models_skybox","core_input_gestures","core_drop_files","core_input_gestures_web"],"TextIsEqual":["models_mesh_picking","core_input_gamepad","text_unicode"],"TextLength":["text_draw_3d","text_rectangle_bounds","text_unicode"],"TextFormat":["shaders_lightmap","shaders_write_depth","shaders_eratosthenes","shaders_spotlight","shaders_mesh_instancing","shaders_texture_outline","shaders_model_shader","shaders_multi_sample2d","shaders_raymarching","shaders_palette_switch","shaders_hybrid_render","shaders_simple_mask","shaders_texture_drawing","shaders_texture_waves","shaders_shapes_textures","shaders_hot_reloading","shaders_custom_uniform","shaders_julia_set","shaders_postprocessing","shaders_basic_lighting","shaders_fog","raymath_vector_angle","easings_testbed","raylib_opengl_interop","textures_textured_curve","textures_fog_of_war","textures_bunnymark","textures_gif_player","textures_sprite_anim","textures_draw_tiled","models_mesh_picking","models_loading_gltf","models_loading_vox","models_skybox","core_smooth_pixelperfect","core_storage_values","core_window_letterbox","core_input_mouse_wheel","core_vr_simulator","core_custom_frame_control","core_random_values","core_world_screen","core_input_gestures_web","core_input_multitouch","core_input_gamepad","core_window_flags","core_3d_camera_first_person","audio_raw_stream","audio_mixed_processor","audio_stream_effects","text_draw_3d","text_codepoints_loading","text_font_filters","text_format_text","text_input_box","text_font_sdf","text_unicode","shapes_draw_rectangle_rounded","shapes_collision_area","shapes_draw_ring","shapes_draw_circle_sector"],"TextSubtext":["core_input_gestures_web","text_writing_anim","shapes_logo_raylib_anim"],"TextReplace":[],"TextInsert":[],"TextJoin":[],"TextSplit":[],"TextAppend":[],"TextFindIndex":["core_input_gestures_web"],"TextToUpper":[],"TextToLower":[],"TextToPascal":[],"TextToInteger":[],"DrawLine3D":["models_mesh_picking","models_loading_m3d"],"DrawPoint3D":[],"DrawCircle3D":["models_rlgl_solar_system"],"DrawTriangle3D":[],"DrawTriangleStrip3D":[],"DrawCube":["rlgl_standalone","models_animation","models_mesh_picking","models_waving_cubes","models_orthographic_projection","models_box_collisions","models_geometric_shapes","models_loading_m3d","core_vr_simulator","core_split_screen","core_3d_camera_free","core_world_screen","core_3d_picking","core_3d_camera_first_person","core_3d_camera_mode"],"DrawCubeV":["shaders_write_depth","shaders_hybrid_render","models_box_collisions","text_draw_3d"],"DrawCubeWires":["rlgl_standalone","models_mesh_picking","models_orthographic_projection","models_box_collisions","models_geometric_shapes","core_vr_simulator","core_3d_camera_free","core_world_screen","core_3d_picking","core_3d_camera_first_person","core_3d_camera_mode","text_draw_3d"],"DrawCubeWiresV":["shaders_write_depth","shaders_hybrid_render","text_draw_3d"],"DrawSphere":["models_orthographic_projection","models_box_collisions","models_geometric_shapes"],"DrawSphereEx":["shaders_basic_lighting"],"DrawSphereWires":["shaders_basic_lighting","models_mesh_picking","models_orthographic_projection","models_box_collisions","models_geometric_shapes"],"DrawCylinder":["models_orthographic_projection","models_geometric_shapes"],"DrawCylinderEx":[],"DrawCylinderWires":["models_orthographic_projection","models_geometric_shapes"],"DrawCylinderWiresEx":[],"DrawCapsule":["models_geometric_shapes"],"DrawCapsuleWires":["models_geometric_shapes"],"DrawPlane":["core_split_screen","core_3d_camera_first_person"],"DrawRay":["models_mesh_picking","core_3d_picking"],"DrawGrid":["shaders_write_depth","shaders_model_shader","shaders_hybrid_render","shaders_simple_mask","shaders_custom_uniform","shaders_postprocessing","shaders_basic_lighting","rlgl_standalone","models_loading","models_animation","models_mesh_picking","models_loading_gltf","models_mesh_generation","models_loading_vox","models_waving_cubes","models_heightmap","models_draw_cube_texture","models_rlgl_solar_system","models_skybox","models_yaw_pitch_roll","models_orthographic_projection","models_billboard","models_box_collisions","models_geometric_shapes","models_loading_m3d","core_vr_simulator","core_3d_camera_free","core_world_screen","core_3d_picking","core_2d_camera_mouse_zoom","core_3d_camera_mode","text_draw_3d"],"LoadModel":["shaders_model_shader","shaders_custom_uniform","shaders_postprocessing","models_loading","models_animation","models_mesh_picking","models_loading_gltf","models_loading_vox","models_yaw_pitch_roll","models_loading_m3d"],"LoadModelFromMesh":["shaders_simple_mask","shaders_basic_lighting","shaders_fog","models_cubicmap","models_mesh_generation","models_first_person_maze","models_heightmap","models_skybox"],"IsModelReady":[],"UnloadModel":["shaders_model_shader","shaders_simple_mask","shaders_custom_uniform","shaders_postprocessing","shaders_basic_lighting","shaders_fog","models_loading","models_animation","models_mesh_picking","models_cubicmap","models_loading_gltf","models_mesh_generation","models_loading_vox","models_first_person_maze","models_heightmap","models_skybox","models_yaw_pitch_roll","models_loading_m3d"],"GetModelBoundingBox":["models_loading_vox"],"DrawModel":["shaders_model_shader","shaders_simple_mask","shaders_custom_uniform","shaders_postprocessing","shaders_basic_lighting","shaders_fog","models_loading","models_mesh_picking","models_cubicmap","models_loading_gltf","models_mesh_generation","models_loading_vox","models_first_person_maze","models_heightmap","models_skybox","models_yaw_pitch_roll","models_loading_m3d"],"DrawModelEx":["shaders_simple_mask","models_animation"],"DrawModelWires":[],"DrawModelWiresEx":[],"DrawBoundingBox":["models_loading","models_mesh_picking"],"DrawBillboard":["models_billboard"],"DrawBillboardRec":[],"DrawBillboardPro":["models_billboard"],"UploadMesh":["models_mesh_generation"],"UpdateMeshBuffer":[],"UnloadMesh":["shaders_lightmap"],"DrawMesh":["shaders_lightmap","shaders_mesh_instancing"],"DrawMeshInstanced":["shaders_mesh_instancing"],"ExportMesh":[],"GetMeshBoundingBox":["models_loading","models_mesh_picking"],"GenMeshTangents":[],"GenMeshPoly":["models_mesh_generation"],"GenMeshPlane":["shaders_lightmap","shaders_basic_lighting","models_mesh_generation"],"GenMeshCube":["shaders_mesh_instancing","shaders_simple_mask","shaders_basic_lighting","shaders_fog","models_mesh_generation","models_skybox"],"GenMeshSphere":["shaders_simple_mask","shaders_fog","models_mesh_generation"],"GenMeshHemiSphere":["models_mesh_generation"],"GenMeshCylinder":["models_mesh_generation"],"GenMeshCone":[],"GenMeshTorus":["shaders_simple_mask","shaders_fog","models_mesh_generation"],"GenMeshKnot":["models_mesh_generation"],"GenMeshHeightmap":["models_heightmap"],"GenMeshCubicmap":["models_cubicmap","models_first_person_maze"],"LoadMaterials":[],"LoadMaterialDefault":["shaders_lightmap","shaders_mesh_instancing"],"IsMaterialReady":[],"UnloadMaterial":[],"SetMaterialTexture":["models_animation"],"SetModelMeshMaterial":[],"LoadModelAnimations":["models_animation","models_loading_gltf","models_loading_m3d"],"UpdateModelAnimation":["models_animation","models_loading_gltf","models_loading_m3d"],"UnloadModelAnimation":[],"UnloadModelAnimations":["models_animation","models_loading_m3d"],"IsModelAnimationValid":[],"CheckCollisionSpheres":[],"CheckCollisionBoxes":["models_box_collisions"],"CheckCollisionBoxSphere":["models_box_collisions"],"GetRayCollisionSphere":["models_mesh_picking"],"GetRayCollisionBox":["models_loading","models_mesh_picking","core_3d_picking","text_draw_3d"],"GetRayCollisionMesh":["models_mesh_picking"],"GetRayCollisionTriangle":["models_mesh_picking"],"GetRayCollisionQuad":["models_mesh_picking"],"InitAudioDevice":["embedded_files_loading","textures_sprite_button","textures_sprite_explosion","audio_module_playing","audio_sound_loading","audio_music_stream","audio_raw_stream","audio_sound_multi","audio_mixed_processor","audio_stream_effects"],"CloseAudioDevice":["embedded_files_loading","textures_sprite_button","textures_sprite_explosion","audio_module_playing","audio_sound_loading","audio_music_stream","audio_raw_stream","audio_sound_multi","audio_mixed_processor","audio_stream_effects"],"IsAudioDeviceReady":[],"SetMasterVolume":[],"LoadWave":[],"LoadWaveFromMemory":[],"IsWaveReady":[],"LoadSound":["textures_sprite_button","textures_sprite_explosion","audio_sound_loading","audio_sound_multi","audio_mixed_processor"],"LoadSoundFromWave":["embedded_files_loading"],"LoadSoundAlias":["audio_sound_multi"],"IsSoundReady":[],"UpdateSound":[],"UnloadWave":[],"UnloadSound":["embedded_files_loading","textures_sprite_button","textures_sprite_explosion","audio_sound_loading","audio_sound_multi"],"UnloadSoundAlias":["audio_sound_multi"],"ExportWave":[],"ExportWaveAsCode":[],"PlaySound":["embedded_files_loading","textures_sprite_button","textures_sprite_explosion","audio_sound_loading","audio_sound_multi","audio_mixed_processor"],"StopSound":[],"PauseSound":[],"ResumeSound":[],"IsSoundPlaying":[],"SetSoundVolume":[],"SetSoundPitch":[],"SetSoundPan":[],"WaveCopy":[],"WaveCrop":[],"WaveFormat":[],"LoadWaveSamples":[],"UnloadWaveSamples":[],"LoadMusicStream":["audio_module_playing","audio_music_stream","audio_mixed_processor","audio_stream_effects"],"LoadMusicStreamFromMemory":[],"IsMusicReady":[],"UnloadMusicStream":["audio_module_playing","audio_music_stream","audio_mixed_processor","audio_stream_effects"],"PlayMusicStream":["audio_module_playing","audio_music_stream","audio_mixed_processor","audio_stream_effects"],"IsMusicStreamPlaying":[],"UpdateMusicStream":["audio_module_playing","audio_music_stream","audio_mixed_processor","audio_stream_effects"],"StopMusicStream":["audio_module_playing","audio_music_stream","audio_stream_effects"],"PauseMusicStream":["audio_module_playing","audio_music_stream","audio_stream_effects"],"ResumeMusicStream":["audio_module_playing","audio_music_stream","audio_stream_effects"],"SeekMusicStream":[],"SetMusicVolume":[],"SetMusicPitch":["audio_module_playing"],"SetMusicPan":[],"GetMusicTimeLength":["audio_module_playing","audio_music_stream","audio_stream_effects"],"GetMusicTimePlayed":["audio_module_playing","audio_music_stream","audio_stream_effects"],"LoadAudioStream":["audio_raw_stream"],"IsAudioStreamReady":[],"UnloadAudioStream":["audio_raw_stream"],"UpdateAudioStream":[],"IsAudioStreamProcessed":[],"PlayAudioStream":["audio_raw_stream"],"PauseAudioStream":[],"ResumeAudioStream":[],"IsAudioStreamPlaying":[],"StopAudioStream":[],"SetAudioStreamVolume":[],"SetAudioStreamPitch":[],"SetAudioStreamPan":["audio_raw_stream"],"SetAudioStreamBufferSizeDefault":["audio_raw_stream"],"SetAudioStreamCallback":["audio_raw_stream"],"AttachAudioStreamProcessor":["audio_stream_effects"],"DetachAudioStreamProcessor":["audio_stream_effects"],"AttachAudioMixedProcessor":["audio_mixed_processor"],"DetachAudioMixedProcessor":["audio_mixed_processor"]}
\ No newline at end of file diff --git a/tools/cheatsheet-generator/README.md b/tools/cheatsheet-generator/README.md new file mode 100644 index 0000000..37eef3a --- /dev/null +++ b/tools/cheatsheet-generator/README.md @@ -0,0 +1,3 @@ +# Cheatsheet generator + +// TODO: Move cheatsheet generator here and update it so it works diff --git a/tools/example-indexer/.gitignore b/tools/example-indexer/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/tools/example-indexer/.gitignore @@ -0,0 +1 @@ +build diff --git a/tools/example-indexer/Makefile b/tools/example-indexer/Makefile new file mode 100644 index 0000000..0dce0c2 --- /dev/null +++ b/tools/example-indexer/Makefile @@ -0,0 +1,20 @@ +BUILD_DIR := build + +.DEFAULT_GOAL := all +.PHONY := raylib_example_indexer all clean + +example_indexer: main.c + mkdir -p $(BUILD_DIR) + gcc main.c -o $(BUILD_DIR)/example_indexer -DSTB_C_LEXER_IMPLEMENTATION + +$(BUILD_DIR)/raylib: + mkdir -p $(BUILD_DIR) + git clone [email protected]:raysan5/raylib.git $(BUILD_DIR)/raylib + +run: example_indexer + ./$(BUILD_DIR)/example_indexer $(BUILD_DIR)/raylib/src $(BUILD_DIR)/raylib/examples $(BUILD_DIR)/output.json + +all: $(BUILD_DIR)/raylib example_indexer run + +clean: + rm -rf $(BUILD_DIR) diff --git a/tools/example-indexer/README.md b/tools/example-indexer/README.md new file mode 100644 index 0000000..d740cd2 --- /dev/null +++ b/tools/example-indexer/README.md @@ -0,0 +1,14 @@ +# Raylib example indexer + +Go through all raylib examples and extract places were API functions were used. + +```shell +make all +``` + +Or + +```shell +make example_indexer +./build/example_indexer <raylib-src-dir> <examples-dir> <output-file> +``` diff --git a/tools/example-indexer/main.c b/tools/example-indexer/main.c new file mode 100644 index 0000000..f912c80 --- /dev/null +++ b/tools/example-indexer/main.c @@ -0,0 +1,304 @@ +#include <stdio.h> +#include <limits.h> +#include <stdlib.h> +#include <stdbool.h> +#include <sys/param.h> +#include <dirent.h> +#include <string.h> +#include <assert.h> + +#include "stb_c_lexer.h" +#include "raylib_parser.c" + +#define MAX_FUNCS_TO_PARSE 1024 // Maximum number of functions to parse +#define MAX_FUNCS_PER_EXAMPLE 1024 // Maximum number of usages per function per file + +typedef struct { + char filename[256]; + // TODO: Track where function usage was found and display it? +} FunctionUsage; + +typedef struct { + int from, to; // [from, to) - from inclusive, to exclusive +} LineRange; + +static bool StartsWith(char *text, int textSize, char *prefix, int prefixSize) +{ + return textSize >= prefixSize && !strncmp(text, prefix, prefixSize); +} + +static bool EndsSith(char *text, int textSize, char *suffix, int suffixSize) +{ + return textSize >= suffixSize && !strncmp(text+textSize-suffixSize, suffix, suffixSize); +} + +static bool GetNextLine(LineRange *line, char *text, int textSize, int from) +{ + for (int i = from; i < textSize; i++) { + if (text[i] == '\n') { + line->from = from; + line->to = i; + return true; + } + } + return false; +} + +static int GetFunctionFromIdentifier(char *id, FunctionInfo *functions, int functionCount) +{ + int idSize = strlen(id); + + for (int i = 0; i < functionCount; i++) { + FunctionInfo *function = &functions[i]; + if (idSize > sizeof(function->name)) continue; + if (!strcmp(id, function->name)) { + return i; + } + } + return -1; +} + +static bool ParseFunctionUsagesFromFile(char *directory, char *filePath, FunctionUsage *usages[], int *usageCounts, FunctionInfo *functions, int functionCount) +{ + char fullPath[PATH_MAX] = { 0 }; + snprintf(fullPath, sizeof(fullPath), "%s/%s", directory, filePath); + + int fileSize = 0; + char *exampleCode = LoadFileText(fullPath, &fileSize); + if (exampleCode == NULL) { + return false; + } + + stb_lexer lexer; + char stringStore[512]; + stb_c_lexer_init(&lexer, exampleCode, exampleCode+fileSize, stringStore, sizeof(stringStore)); + + while (stb_c_lexer_get_token(&lexer)) { + if (lexer.token != CLEX_id) continue; + + int functionIndex = GetFunctionFromIdentifier(lexer.string, functions, functionCount); + if (functionIndex != -1) { + int *usageCount = &usageCounts[functionIndex]; + assert(*usageCount < MAX_FUNCS_PER_EXAMPLE); + FunctionUsage *usage = &usages[functionIndex][*usageCount]; + strncpy(usage->filename, filePath, strlen(filePath)); + (*usageCount)++; + } + } + + free(exampleCode); + + return true; +} + +static void ParseFunctionsUsagesFromFolder(char *cwd, char *dir, FunctionUsage *usages[], int *usageCounts, FunctionInfo *functions, int functionCount) +{ + char dirPath[PATH_MAX]; + snprintf(dirPath, sizeof(dirPath), "%s/%s", cwd, dir); + DIR *dirp = opendir(dirPath); + if (dirp == NULL) { + fprintf(stderr, "Failed to open directory '%s'\n", dirPath); + return; + } + + struct dirent *entry; + while ((entry = readdir(dirp)) != NULL) { + if (entry->d_type != DT_REG) continue; + + char *extension = strrchr(entry->d_name, '.'); + if (!strcmp(extension, ".c")) { + char filePath[PATH_MAX]; + snprintf(filePath, sizeof(filePath), "%s/%s", dir, entry->d_name); + ParseFunctionUsagesFromFile(cwd, filePath, usages, usageCounts, functions, functionCount); + } + } + + closedir(dirp); +} + +// Checks if the line is in the format "#if defined(*_IMPLEMENTATION)" +static bool IsLineImplementationIfdef(char *line, int line_size) { + char *prefix = "#if defined("; + char *suffix = "_IMPLEMENTATION)"; + return StartsWith(line, line_size, prefix, strlen(prefix)) && + EndsSith(line, line_size, suffix, strlen(suffix)); +} + +static int ParseFunctionsDefinitionsFromHeader(char *path, FunctionInfo *functions, int maxFunctions) +{ + int fileSize; + char *contents = LoadFileText(path, &fileSize); + + int count = 0; + + int nextLineFrom = 0; + LineRange curr = { 0 }; + while (GetNextLine(&curr, contents, fileSize, nextLineFrom)) { + int lineSize = curr.to - curr.from; + char line[512] = { 0 }; + strncpy(line, &contents[curr.from], lineSize); // `raylib_parser.c` expects lines to be null-terminated + if (IsLineImplementationIfdef(line, lineSize)) break; + + if (IsLineAPIFunction(line, lineSize)) { + ParseAPIFunctionInfo(line, lineSize, &functions[count]); + count++; + if (count == maxFunctions) break; + } + + nextLineFrom = curr.to+1; + } + + free(contents); + + return count; +} + +static int ParseFunctionsDefinitionsFromFolder(char *dir, FunctionInfo *functions, int maxFunctions) +{ + DIR *dirp = opendir(dir); + if (dirp == NULL) { + fprintf(stderr, "Failed to open directory '%s'\n", dir); + return -1; + } + + int count = 0; + struct dirent *entry; + while ((entry = readdir(dirp)) != NULL) { + if (entry->d_type != DT_REG) continue; + + char *fileExtension = strrchr(entry->d_name, '.'); + if (fileExtension == NULL) continue; + if (strcmp(fileExtension, ".h")) continue; + + char path[256]; + snprintf(path, sizeof(path), "%s/%s", dir, entry->d_name); + count += ParseFunctionsDefinitionsFromHeader(path, functions + count, maxFunctions - count); + } + closedir(dirp); + + return count; +} + +static int GetUniqueFilenames(FunctionUsage *usages, int usageCount, char *uniqueFilenames[]) +{ + int count = 0; + + for (int i = 0; i < usageCount; i++) { + FunctionUsage *usage = &usages[i]; + + bool found = false; + for (int j = 0; j < count; j++) { + if (!strcmp(uniqueFilenames[j], usage->filename)) { + found = true; + break; + } + } + + if (!found) { + uniqueFilenames[count] = strdup(usage->filename); + count++; + } + } + + return count; +} + +static int OutputFunctionUsagesJSON(char *output, FunctionInfo *functions, int functionCount, FunctionUsage **usages, int *usageCounts) +{ + FILE *outputFile = fopen(output, "w"); + if (outputFile == NULL) { + fprintf(stderr, "Failed to open file '%s\n'", output); + return -1; + } + + fwrite("{", sizeof(char), 1, outputFile); + for (int functionIndex = 0; functionIndex < functionCount; functionIndex++) { + FunctionInfo *info = &functions[functionIndex]; + + fwrite("\"", sizeof(char), 1, outputFile); + fwrite(info->name, sizeof(char), strlen(info->name), outputFile); + fwrite("\":[", sizeof(char), 3, outputFile); + + int usageCount = usageCounts[functionIndex]; + if (usageCount > 0) { + char *uniqueFilenames[usageCount]; + int uniqueCount = GetUniqueFilenames(usages[functionIndex], usageCount, uniqueFilenames); + + for (int i = 0; i < uniqueCount; i++) { + char *filename = uniqueFilenames[i]; + char *example_name = strchr(filename, '/')+1; + int example_name_size = strchr(filename, '.') - example_name; + + fwrite("\"", sizeof(char), 1, outputFile); + fwrite(example_name, sizeof(char), example_name_size, outputFile); + fwrite("\"", sizeof(char), 1, outputFile); + if (i < uniqueCount-1) { + fwrite(",", sizeof(char), 1, outputFile); + } + } + + for (int i = 0; i < uniqueCount; i++) { + free(uniqueFilenames[i]); + } + } + + fwrite("]", sizeof(char), 1, outputFile); + if (functionIndex < functionCount-1) { + fwrite(",", sizeof(char), 1, outputFile); + } + } + + fwrite("}", sizeof(char), 1, outputFile); + fclose(outputFile); + + return 0; +} + +int main(int argc, char **argv) +{ + if (argc != 4) { + printf("Usage: %s <raylib-src-dir> <examples-dir> <output-file>\n", argv[0]); + return -1; + } + + char *raylibSrc = argv[1]; + char *raylibExamplesPath = argv[2]; + char *outputPath = argv[3]; + + FunctionInfo functions[MAX_FUNCS_TO_PARSE]; + int functionCount = ParseFunctionsDefinitionsFromFolder(raylibSrc, functions, MAX_FUNCS_TO_PARSE); + if (functionCount < 0) { + return -1; + } + + FunctionUsage *usages[MAX_FUNCS_TO_PARSE] = { 0 }; + for (int i = 0; i < functionCount; i++) { + usages[i] = malloc(MAX_FUNCS_PER_EXAMPLE * sizeof(FunctionUsage)); + } + int usageCounts[MAX_FUNCS_TO_PARSE] = { 0 }; + + { // Collect function usages from examples + DIR *dirp = opendir(raylibExamplesPath); + if (dirp == NULL) { + fprintf(stderr, "Failed to open directory '%s'\n", raylibExamplesPath); + return -1; + } + struct dirent *entry; + while ((entry = readdir(dirp)) != NULL) { + if (entry->d_type != DT_DIR) continue; + if (entry->d_name[0] == '.') continue; + + ParseFunctionsUsagesFromFolder(raylibExamplesPath, entry->d_name, usages, usageCounts, functions, functionCount); + } + closedir(dirp); + } + + // Output function usages + OutputFunctionUsagesJSON(outputPath, functions, functionCount, usages, usageCounts); + + for (int i = 0; i < functionCount; i++) { + free(usages[i]); + } + + return 0; +} diff --git a/tools/example-indexer/raylib_parser.c b/tools/example-indexer/raylib_parser.c new file mode 100644 index 0000000..d4b4568 --- /dev/null +++ b/tools/example-indexer/raylib_parser.c @@ -0,0 +1,502 @@ +/********************************************************************************************** + + raylib API parser + + This parser scans raylib.h to get API information about defines, structs, aliases, enums, callbacks and functions. + All data is divided into pieces, usually as strings. The following types are used for data: + + - struct DefineInfo + - struct StructInfo + - struct AliasInfo + - struct EnumInfo + - struct FunctionInfo + + CONSTRAINTS: + + This parser is specifically designed to work with raylib.h, so, it has some constraints: + + - Functions are expected as a single line with the following structure: + + <retType> <name>(<paramType[0]> <paramName[0]>, <paramType[1]> <paramName[1]>); <desc> + + Be careful with functions broken into several lines, it breaks the process! + + - Structures are expected as several lines with the following form: + + <desc> + typedef struct <name> { + <fieldType[0]> <fieldName[0]>; <fieldDesc[0]> + <fieldType[1]> <fieldName[1]>; <fieldDesc[1]> + <fieldType[2]> <fieldName[2]>; <fieldDesc[2]> + } <name>; + + - Enums are expected as several lines with the following form: + + <desc> + typedef enum { + <valueName[0]> = <valueInteger[0]>, <valueDesc[0]> + <valueName[1]>, + <valueName[2]>, <valueDesc[2]> + <valueName[3]> <valueDesc[3]> + } <name>; + + NOTE: Multiple options are supported for enums: + - If value is not provided, (<valueInteger[i -1]> + 1) is assigned + - Value description can be provided or not + + OTHER NOTES: + + - This parser could work with other C header files if mentioned constraints are followed. + - This parser does not require <string.h> library, all data is parsed directly from char buffers. + - This is a modified/stripped down version of the original parser + Done so to make it usable as a library, and not a CLI tool. + This does not implement a function for every type to parse + + LICENSE: zlib/libpng + + raylib-parser is licensed under an unmodified zlib/libpng license, which is an OSI-certified, + BSD-like license that allows static linking with closed source software: + + Copyright (c) 2021-2023 Ramon Santamaria (@raysan5) + +**********************************************************************************************/ + + +#define _CRT_SECURE_NO_WARNINGS + +#include <stdlib.h> // Required for: malloc(), calloc(), realloc(), free(), atoi(), strtol() +#include <stdio.h> // Required for: printf(), fopen(), fseek(), ftell(), fread(), fclose() +#include <stdbool.h> // Required for: bool +#include <ctype.h> // Required for: isdigit() + +#define MAX_LINE_LENGTH 512 // Maximum length of one line (including comments) + +#define MAX_STRUCT_FIELDS 64 // Maximum number of struct fields +#define MAX_ENUM_VALUES 512 // Maximum number of enum values +#define MAX_FUNCTION_PARAMETERS 12 // Maximum number of function parameters + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- + +// Type of parsed define +typedef enum { + UNKNOWN = 0, + MACRO, + GUARD, + INT, + INT_MATH, + LONG, + LONG_MATH, + FLOAT, + FLOAT_MATH, + DOUBLE, + DOUBLE_MATH, + CHAR, + STRING, + COLOR +} DefineType; + +// Define info data +typedef struct DefineInfo { + char name[64]; // Define name + int type; // Define type + char value[256]; // Define value + char desc[128]; // Define description + bool isHex; // Define is hex number (for types INT, LONG) +} DefineInfo; + +// Struct info data +typedef struct StructInfo { + char name[64]; // Struct name + char desc[128]; // Struct type description + int fieldCount; // Number of fields in the struct + char fieldType[MAX_STRUCT_FIELDS][64]; // Field type + char fieldName[MAX_STRUCT_FIELDS][64]; // Field name + char fieldDesc[MAX_STRUCT_FIELDS][128]; // Field description +} StructInfo; + +// Alias info data +typedef struct AliasInfo { + char type[64]; // Alias type + char name[64]; // Alias name + char desc[128]; // Alias description +} AliasInfo; + +// Enum info data +typedef struct EnumInfo { + char name[64]; // Enum name + char desc[128]; // Enum description + int valueCount; // Number of values in enumerator + char valueName[MAX_ENUM_VALUES][64]; // Value name definition + int valueInteger[MAX_ENUM_VALUES]; // Value integer + char valueDesc[MAX_ENUM_VALUES][128]; // Value description +} EnumInfo; + +// Function info data +typedef struct FunctionInfo { + char name[64]; // Function name + char desc[128]; // Function description (comment at the end) + char retType[32]; // Return value type + int paramCount; // Number of function parameters + char paramType[MAX_FUNCTION_PARAMETERS][32]; // Parameters type + char paramName[MAX_FUNCTION_PARAMETERS][32]; // Parameters name + char paramDesc[MAX_FUNCTION_PARAMETERS][128]; // Parameters description +} FunctionInfo; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- + +#ifndef RAYLIB_API_DEFINE + #define RAYLIB_API_DEFINE "RLAPI" +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- + +static bool IsLineAPIFunction(char *line, int lineSize); +static void ParseAPIFunctionInfo(char *linePtr, int lineSize, FunctionInfo *functionInfo); + +static char *LoadFileText(const char *fileName, int *length); +static char **GetTextLines(const char *buffer, int length, int *linesCount); +static void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name); +static void GetDescription(const char *source, char *description); +static void MoveArraySize(char *name, char *type); // Move array size from name to type +static unsigned int TextLength(const char *text); // Get text length in bytes, check for \0 character +static bool IsTextEqual(const char *text1, const char *text2, unsigned int count); +static int TextFindIndex(const char *text, const char *find); // Find first text occurrence within a string +static void MemoryCopy(void *dest, const void *src, unsigned int count); +static char *EscapeBackslashes(char *text); // Replace '\' by "\\" when exporting to JSON and XML +static const char *StrDefineType(DefineType type); // Get string of define type + +//---------------------------------------------------------------------------------- +// Additional functions for use as a library +//---------------------------------------------------------------------------------- + +static bool IsLineAPIFunction(char *line, int lineSize) +{ + int apiDefineSize = TextLength(RAYLIB_API_DEFINE); + + // Read function line (starting with `define`, i.e. for raylib.h "RLAPI") + return lineSize >= apiDefineSize && IsTextEqual(line, RAYLIB_API_DEFINE, apiDefineSize); +} + +// Assumes that `func_info` is zero initialized +static void ParseAPIFunctionInfo(char *linePtr, int lineSize, FunctionInfo *functionInfo) +{ + int funcParamsStart = 0; + int funcEnd = 0; + + // Get return type and function name from func line + for (int c = 0; c < lineSize; c++) + { + if (linePtr[c] == '(') // Starts function parameters + { + funcParamsStart = c + 1; + + // At this point we have function return type and function name + char funcRetTypeName[128] = { 0 }; + int dc = TextLength(RAYLIB_API_DEFINE) + 1; + int funcRetTypeNameLen = c - dc; // Substract `define` ("RLAPI " for raylib.h) + MemoryCopy(funcRetTypeName, &linePtr[dc], funcRetTypeNameLen); + + GetDataTypeAndName(funcRetTypeName, funcRetTypeNameLen, functionInfo->retType, functionInfo->name); + break; + } + } + + // Get parameters from func line + for (int c = funcParamsStart; c < lineSize; c++) + { + int paramIndex = functionInfo->paramCount; + + if (linePtr[c] == ',') // Starts function parameters + { + // Get parameter type + name, extract info + char funcParamTypeName[128] = { 0 }; + int funcParamTypeNameLen = c - funcParamsStart; + MemoryCopy(funcParamTypeName, &linePtr[funcParamsStart], funcParamTypeNameLen); + + GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, functionInfo->paramType[paramIndex], functionInfo->paramName[paramIndex]); + + funcParamsStart = c + 1; + if (linePtr[c + 1] == ' ') funcParamsStart += 1; + functionInfo->paramCount++; // Move to next parameter + } + else if (linePtr[c] == ')') + { + funcEnd = c + 2; + + // Check if previous word is void + if ((linePtr[c - 4] == 'v') && (linePtr[c - 3] == 'o') && (linePtr[c - 2] == 'i') && (linePtr[c - 1] == 'd')) break; + + // Get parameter type + name, extract info + char funcParamTypeName[128] = { 0 }; + int funcParamTypeNameLen = c - funcParamsStart; + MemoryCopy(funcParamTypeName, &linePtr[funcParamsStart], funcParamTypeNameLen); + + GetDataTypeAndName(funcParamTypeName, funcParamTypeNameLen, functionInfo->paramType[paramIndex], functionInfo->paramName[paramIndex]); + + functionInfo->paramCount++; // Move to next parameter + break; + } + } + + // Get function description + GetDescription(&linePtr[funcEnd], functionInfo->desc); + + // Move array sizes from name to type + for (int j = 0; j < functionInfo->paramCount; j++) + { + MoveArraySize(functionInfo->paramName[j], functionInfo->paramType[j]); + } +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- + +// Load text data from file, returns a '\0' terminated string +// NOTE: text chars array should be freed manually +static char *LoadFileText(const char *fileName, int *length) +{ + char *text = NULL; + + if (fileName != NULL) + { + FILE *file = fopen(fileName, "rt"); + + if (file != NULL) + { + // WARNING: When reading a file as 'text' file, + // text mode causes carriage return-linefeed translation... + // ...but using fseek() should return correct byte-offset + fseek(file, 0, SEEK_END); + int size = ftell(file); + fseek(file, 0, SEEK_SET); + + if (size > 0) + { + text = (char *)calloc((size + 1), sizeof(char)); + unsigned int count = (unsigned int)fread(text, sizeof(char), size, file); + + // WARNING: \r\n is converted to \n on reading, so, + // read bytes count gets reduced by the number of lines + if (count < (unsigned int)size) + { + text = realloc(text, count + 1); + *length = count; + } + else *length = size; + + // Zero-terminate the string + text[count] = '\0'; + } + + fclose(file); + } + } + + return text; +} + +// Get all lines from a text buffer (expecting lines ending with '\n') +static char **GetTextLines(const char *buffer, int length, int *linesCount) +{ + // Get the number of lines in the text + int count = 0; + for (int i = 0; i < length; i++) if (buffer[i] == '\n') count++; + + printf("Number of text lines in buffer: %i\n", count); + + // Allocate as many pointers as lines + char **lines = (char **)malloc(count*sizeof(char **)); + + char *bufferPtr = (char *)buffer; + + for (int i = 0; (i < count) || (bufferPtr[0] != '\0'); i++) + { + lines[i] = (char *)calloc(MAX_LINE_LENGTH, sizeof(char)); + + // Remove line leading spaces + // Find last index of space/tab character + int index = 0; + while ((bufferPtr[index] == ' ') || (bufferPtr[index] == '\t')) index++; + + int j = 0; + while (bufferPtr[index + j] != '\n') + { + lines[i][j] = bufferPtr[index + j]; + j++; + } + + bufferPtr += (index + j + 1); + } + + *linesCount = count; + return lines; +} + +// Get data type and name from a string containing both +// NOTE: Useful to parse function parameters and struct fields +static void GetDataTypeAndName(const char *typeName, int typeNameLen, char *type, char *name) +{ + for (int k = typeNameLen; k > 0; k--) + { + if ((typeName[k] == ' ') && (typeName[k - 1] != ',')) + { + // Function name starts at this point (and ret type finishes at this point) + MemoryCopy(type, typeName, k); + MemoryCopy(name, typeName + k + 1, typeNameLen - k - 1); + break; + } + else if (typeName[k] == '*') + { + MemoryCopy(type, typeName, k + 1); + MemoryCopy(name, typeName + k + 1, typeNameLen - k - 1); + break; + } + else if ((typeName[k] == '.') && (typeNameLen == 3)) // Handle varargs ...); + { + MemoryCopy(type, "...", 3); + MemoryCopy(name, "args", 4); + break; + } + } +} + +// Get comment from a line, do nothing if no comment in line +static void GetDescription(const char *line, char *description) +{ + int c = 0; + int descStart = -1; + int lastSlash = -2; + bool isValid = false; + while (line[c] != '\0') + { + if (isValid && (descStart == -1) && (line[c] != ' ')) descStart = c; + else if (line[c] == '/') + { + if (lastSlash == c - 1) isValid = true; + lastSlash = c; + } + c++; + } + if (descStart != -1) MemoryCopy(description, &line[descStart], c - descStart); +} + +// Move array size from name to type +static void MoveArraySize(char *name, char *type) +{ + int nameLength = TextLength(name); + if (name[nameLength - 1] == ']') + { + for (int k = nameLength; k > 0; k--) + { + if (name[k] == '[') + { + int sizeLength = nameLength - k; + MemoryCopy(&type[TextLength(type)], &name[k], sizeLength); + name[k] = '\0'; + } + } + } +} + +// Get text length in bytes, check for \0 character +static unsigned int TextLength(const char *text) +{ + unsigned int length = 0; + + if (text != NULL) while (*text++) length++; + + return length; +} + +// Compare two text strings, requires number of characters to compare +static bool IsTextEqual(const char *text1, const char *text2, unsigned int count) +{ + bool result = true; + + for (unsigned int i = 0; i < count; i++) + { + if (text1[i] != text2[i]) + { + result = false; + break; + } + } + + return result; +} + +// Find first text occurrence within a string +int TextFindIndex(const char *text, const char *find) +{ + int textLen = TextLength(text); + int findLen = TextLength(find); + + for (int i = 0; i <= textLen - findLen; i++) + { + if (IsTextEqual(&text[i], find, findLen)) return i; + } + + return -1; +} + +// Custom memcpy() to avoid <string.h> +static void MemoryCopy(void *dest, const void *src, unsigned int count) +{ + char *srcPtr = (char *)src; + char *destPtr = (char *)dest; + + for (unsigned int i = 0; i < count; i++) destPtr[i] = srcPtr[i]; +} + +// Escape backslashes in a string, writing the escaped string into a static buffer +static char *EscapeBackslashes(char *text) +{ + static char buffer[256] = { 0 }; + + int count = 0; + + for (int i = 0; (text[i] != '\0') && (i < 255); i++, count++) + { + buffer[count] = text[i]; + + if (text[i] == '\\') + { + buffer[count + 1] = '\\'; + count++; + } + } + + buffer[count] = '\0'; + + return buffer; +} + +// Get string of define type +static const char *StrDefineType(DefineType type) +{ + switch (type) + { + case UNKNOWN: return "UNKNOWN"; + case GUARD: return "GUARD"; + case MACRO: return "MACRO"; + case INT: return "INT"; + case INT_MATH: return "INT_MATH"; + case LONG: return "LONG"; + case LONG_MATH: return "LONG_MATH"; + case FLOAT: return "FLOAT"; + case FLOAT_MATH: return "FLOAT_MATH"; + case DOUBLE: return "DOUBLE"; + case DOUBLE_MATH: return "DOUBLE_MATH"; + case CHAR: return "CHAR"; + case STRING: return "STRING"; + case COLOR: return "COLOR"; + } + return ""; +} diff --git a/tools/example-indexer/stb_c_lexer.h b/tools/example-indexer/stb_c_lexer.h new file mode 100644 index 0000000..bf89dca --- /dev/null +++ b/tools/example-indexer/stb_c_lexer.h @@ -0,0 +1,940 @@ +// stb_c_lexer.h - v0.12 - public domain Sean Barrett 2013 +// lexer for making little C-like languages with recursive-descent parsers +// +// This file provides both the interface and the implementation. +// To instantiate the implementation, +// #define STB_C_LEXER_IMPLEMENTATION +// in *ONE* source file, before #including this file. +// +// The default configuration is fairly close to a C lexer, although +// suffixes on integer constants are not handled (you can override this). +// +// History: +// 0.12 fix compilation bug for NUL support; better support separate inclusion +// 0.11 fix clang static analysis warning +// 0.10 fix warnings +// 0.09 hex floats, no-stdlib fixes +// 0.08 fix bad pointer comparison +// 0.07 fix mishandling of hexadecimal constants parsed by strtol +// 0.06 fix missing next character after ending quote mark (Andreas Fredriksson) +// 0.05 refixed get_location because github version had lost the fix +// 0.04 fix octal parsing bug +// 0.03 added STB_C_LEX_DISCARD_PREPROCESSOR option +// refactor API to simplify (only one struct instead of two) +// change literal enum names to have 'lit' at the end +// 0.02 first public release +// +// Status: +// - haven't tested compiling as C++ +// - haven't tested the float parsing path +// - haven't tested the non-default-config paths (e.g. non-stdlib) +// - only tested default-config paths by eyeballing output of self-parse +// +// - haven't implemented multiline strings +// - haven't implemented octal/hex character constants +// - haven't implemented support for unicode CLEX_char +// - need to expand error reporting so you don't just get "CLEX_parse_error" +// +// Contributors: +// Arpad Goretity (bugfix) +// Alan Hickman (hex floats) +// +// LICENSE +// +// See end of file for license information. + +#ifdef STB_C_LEXER_IMPLEMENTATION +#ifndef STB_C_LEXER_DEFINITIONS +// to change the default parsing rules, copy the following lines +// into your C/C++ file *before* including this, and then replace +// the Y's with N's for the ones you don't want. This needs to be +// set to the same values for every place in your program where +// stb_c_lexer.h is included. +// --BEGIN-- + +#if defined(Y) || defined(N) +#error "Can only use stb_c_lexer in contexts where the preprocessor symbols 'Y' and 'N' are not defined" +#endif + +#define STB_C_LEX_C_DECIMAL_INTS Y // "0|[1-9][0-9]*" CLEX_intlit +#define STB_C_LEX_C_HEX_INTS Y // "0x[0-9a-fA-F]+" CLEX_intlit +#define STB_C_LEX_C_OCTAL_INTS Y // "[0-7]+" CLEX_intlit +#define STB_C_LEX_C_DECIMAL_FLOATS Y // "[0-9]*(.[0-9]*([eE][-+]?[0-9]+)?) CLEX_floatlit +#define STB_C_LEX_C99_HEX_FLOATS N // "0x{hex}+(.{hex}*)?[pP][-+]?{hex}+ CLEX_floatlit +#define STB_C_LEX_C_IDENTIFIERS Y // "[_a-zA-Z][_a-zA-Z0-9]*" CLEX_id +#define STB_C_LEX_C_DQ_STRINGS Y // double-quote-delimited strings with escapes CLEX_dqstring +#define STB_C_LEX_C_SQ_STRINGS N // single-quote-delimited strings with escapes CLEX_ssstring +#define STB_C_LEX_C_CHARS Y // single-quote-delimited character with escape CLEX_charlits +#define STB_C_LEX_C_COMMENTS Y // "/* comment */" +#define STB_C_LEX_CPP_COMMENTS Y // "// comment to end of line\n" +#define STB_C_LEX_C_COMPARISONS Y // "==" CLEX_eq "!=" CLEX_noteq "<=" CLEX_lesseq ">=" CLEX_greatereq +#define STB_C_LEX_C_LOGICAL Y // "&&" CLEX_andand "||" CLEX_oror +#define STB_C_LEX_C_SHIFTS Y // "<<" CLEX_shl ">>" CLEX_shr +#define STB_C_LEX_C_INCREMENTS Y // "++" CLEX_plusplus "--" CLEX_minusminus +#define STB_C_LEX_C_ARROW Y // "->" CLEX_arrow +#define STB_C_LEX_EQUAL_ARROW N // "=>" CLEX_eqarrow +#define STB_C_LEX_C_BITWISEEQ Y // "&=" CLEX_andeq "|=" CLEX_oreq "^=" CLEX_xoreq +#define STB_C_LEX_C_ARITHEQ Y // "+=" CLEX_pluseq "-=" CLEX_minuseq + // "*=" CLEX_muleq "/=" CLEX_diveq "%=" CLEX_modeq + // if both STB_C_LEX_SHIFTS & STB_C_LEX_ARITHEQ: + // "<<=" CLEX_shleq ">>=" CLEX_shreq + +#define STB_C_LEX_PARSE_SUFFIXES N // letters after numbers are parsed as part of those numbers, and must be in suffix list below +#define STB_C_LEX_DECIMAL_SUFFIXES "" // decimal integer suffixes e.g. "uUlL" -- these are returned as-is in string storage +#define STB_C_LEX_HEX_SUFFIXES "" // e.g. "uUlL" +#define STB_C_LEX_OCTAL_SUFFIXES "" // e.g. "uUlL" +#define STB_C_LEX_FLOAT_SUFFIXES "" // + +#define STB_C_LEX_0_IS_EOF N // if Y, ends parsing at '\0'; if N, returns '\0' as token +#define STB_C_LEX_INTEGERS_AS_DOUBLES N // parses integers as doubles so they can be larger than 'int', but only if STB_C_LEX_STDLIB==N +#define STB_C_LEX_MULTILINE_DSTRINGS N // allow newlines in double-quoted strings +#define STB_C_LEX_MULTILINE_SSTRINGS N // allow newlines in single-quoted strings +#define STB_C_LEX_USE_STDLIB Y // use strtod,strtol for parsing #s; otherwise inaccurate hack +#define STB_C_LEX_DOLLAR_IDENTIFIER Y // allow $ as an identifier character +#define STB_C_LEX_FLOAT_NO_DECIMAL Y // allow floats that have no decimal point if they have an exponent + +#define STB_C_LEX_DEFINE_ALL_TOKEN_NAMES N // if Y, all CLEX_ token names are defined, even if never returned + // leaving it as N should help you catch config bugs + +#define STB_C_LEX_DISCARD_PREPROCESSOR Y // discard C-preprocessor directives (e.g. after prepocess + // still have #line, #pragma, etc) + +//#define STB_C_LEX_ISWHITE(str) ... // return length in bytes of whitespace characters if first char is whitespace + +#define STB_C_LEXER_DEFINITIONS // This line prevents the header file from replacing your definitions +// --END-- +#endif +#endif + +#ifndef INCLUDE_STB_C_LEXER_H +#define INCLUDE_STB_C_LEXER_H + +typedef struct +{ + // lexer variables + char *input_stream; + char *eof; + char *parse_point; + char *string_storage; + int string_storage_len; + + // lexer parse location for error messages + char *where_firstchar; + char *where_lastchar; + + // lexer token variables + long token; + double real_number; + long int_number; + char *string; + int string_len; +} stb_lexer; + +typedef struct +{ + int line_number; + int line_offset; +} stb_lex_location; + +#ifdef __cplusplus +extern "C" { +#endif + +extern void stb_c_lexer_init(stb_lexer *lexer, const char *input_stream, const char *input_stream_end, char *string_store, int store_length); +// this function initialize the 'lexer' structure +// Input: +// - input_stream points to the file to parse, loaded into memory +// - input_stream_end points to the end of the file, or NULL if you use 0-for-EOF +// - string_store is storage the lexer can use for storing parsed strings and identifiers +// - store_length is the length of that storage + +extern int stb_c_lexer_get_token(stb_lexer *lexer); +// this function returns non-zero if a token is parsed, or 0 if at EOF +// Output: +// - lexer->token is the token ID, which is unicode code point for a single-char token, < 0 for a multichar or eof or error +// - lexer->real_number is a double constant value for CLEX_floatlit, or CLEX_intlit if STB_C_LEX_INTEGERS_AS_DOUBLES +// - lexer->int_number is an integer constant for CLEX_intlit if !STB_C_LEX_INTEGERS_AS_DOUBLES, or character for CLEX_charlit +// - lexer->string is a 0-terminated string for CLEX_dqstring or CLEX_sqstring or CLEX_identifier +// - lexer->string_len is the byte length of lexer->string + +extern void stb_c_lexer_get_location(const stb_lexer *lexer, const char *where, stb_lex_location *loc); +// this inefficient function returns the line number and character offset of a +// given location in the file as returned by stb_lex_token. Because it's inefficient, +// you should only call it for errors, not for every token. +// For error messages of invalid tokens, you typically want the location of the start +// of the token (which caused the token to be invalid). For bugs involving legit +// tokens, you can report the first or the range. +// Output: +// - loc->line_number is the line number in the file, counting from 1, of the location +// - loc->line_offset is the char-offset in the line, counting from 0, of the location + + +#ifdef __cplusplus +} +#endif + +enum +{ + CLEX_eof = 256, + CLEX_parse_error, + CLEX_intlit , + CLEX_floatlit , + CLEX_id , + CLEX_dqstring , + CLEX_sqstring , + CLEX_charlit , + CLEX_eq , + CLEX_noteq , + CLEX_lesseq , + CLEX_greatereq , + CLEX_andand , + CLEX_oror , + CLEX_shl , + CLEX_shr , + CLEX_plusplus , + CLEX_minusminus , + CLEX_pluseq , + CLEX_minuseq , + CLEX_muleq , + CLEX_diveq , + CLEX_modeq , + CLEX_andeq , + CLEX_oreq , + CLEX_xoreq , + CLEX_arrow , + CLEX_eqarrow , + CLEX_shleq, CLEX_shreq, + + CLEX_first_unused_token + +}; +#endif // INCLUDE_STB_C_LEXER_H + +#ifdef STB_C_LEXER_IMPLEMENTATION + +// Hacky definitions so we can easily #if on them +#define Y(x) 1 +#define N(x) 0 + +#if STB_C_LEX_INTEGERS_AS_DOUBLES(x) +typedef double stb__clex_int; +#define intfield real_number +#define STB__clex_int_as_double +#else +typedef long stb__clex_int; +#define intfield int_number +#endif + +// Convert these config options to simple conditional #defines so we can more +// easily test them once we've change the meaning of Y/N + +#if STB_C_LEX_PARSE_SUFFIXES(x) +#define STB__clex_parse_suffixes +#endif + +#if STB_C_LEX_C99_HEX_FLOATS(x) +#define STB__clex_hex_floats +#endif + +#if STB_C_LEX_C_HEX_INTS(x) +#define STB__clex_hex_ints +#endif + +#if STB_C_LEX_C_DECIMAL_INTS(x) +#define STB__clex_decimal_ints +#endif + +#if STB_C_LEX_C_OCTAL_INTS(x) +#define STB__clex_octal_ints +#endif + +#if STB_C_LEX_C_DECIMAL_FLOATS(x) +#define STB__clex_decimal_floats +#endif + +#if STB_C_LEX_DISCARD_PREPROCESSOR(x) +#define STB__clex_discard_preprocessor +#endif + +#if STB_C_LEX_USE_STDLIB(x) && (!defined(STB__clex_hex_floats) || __STDC_VERSION__ >= 199901L) +#define STB__CLEX_use_stdlib +#include <stdlib.h> +#endif + +// Now for the rest of the file we'll use the basic definition where +// where Y expands to its contents and N expands to nothing +#undef Y +#define Y(a) a +#undef N +#define N(a) + +// API function +void stb_c_lexer_init(stb_lexer *lexer, const char *input_stream, const char *input_stream_end, char *string_store, int store_length) +{ + lexer->input_stream = (char *) input_stream; + lexer->eof = (char *) input_stream_end; + lexer->parse_point = (char *) input_stream; + lexer->string_storage = string_store; + lexer->string_storage_len = store_length; +} + +// API function +void stb_c_lexer_get_location(const stb_lexer *lexer, const char *where, stb_lex_location *loc) +{ + char *p = lexer->input_stream; + int line_number = 1; + int char_offset = 0; + while (*p && p < where) { + if (*p == '\n' || *p == '\r') { + p += (p[0]+p[1] == '\r'+'\n' ? 2 : 1); // skip newline + line_number += 1; + char_offset = 0; + } else { + ++p; + ++char_offset; + } + } + loc->line_number = line_number; + loc->line_offset = char_offset; +} + +// main helper function for returning a parsed token +static int stb__clex_token(stb_lexer *lexer, int token, char *start, char *end) +{ + lexer->token = token; + lexer->where_firstchar = start; + lexer->where_lastchar = end; + lexer->parse_point = end+1; + return 1; +} + +// helper function for returning eof +static int stb__clex_eof(stb_lexer *lexer) +{ + lexer->token = CLEX_eof; + return 0; +} + +static int stb__clex_iswhite(int x) +{ + return x == ' ' || x == '\t' || x == '\r' || x == '\n' || x == '\f'; +} + +static const char *stb__strchr(const char *str, int ch) +{ + for (; *str; ++str) + if (*str == ch) + return str; + return 0; +} + +// parse suffixes at the end of a number +static int stb__clex_parse_suffixes(stb_lexer *lexer, long tokenid, char *start, char *cur, const char *suffixes) +{ + #ifdef STB__clex_parse_suffixes + lexer->string = lexer->string_storage; + lexer->string_len = 0; + + while ((*cur >= 'a' && *cur <= 'z') || (*cur >= 'A' && *cur <= 'Z')) { + if (stb__strchr(suffixes, *cur) == 0) + return stb__clex_token(lexer, CLEX_parse_error, start, cur); + if (lexer->string_len+1 >= lexer->string_storage_len) + return stb__clex_token(lexer, CLEX_parse_error, start, cur); + lexer->string[lexer->string_len++] = *cur++; + } + #else + suffixes = suffixes; // attempt to suppress warnings + #endif + return stb__clex_token(lexer, tokenid, start, cur-1); +} + +#ifndef STB__CLEX_use_stdlib +static double stb__clex_pow(double base, unsigned int exponent) +{ + double value=1; + for ( ; exponent; exponent >>= 1) { + if (exponent & 1) + value *= base; + base *= base; + } + return value; +} + +static double stb__clex_parse_float(char *p, char **q) +{ + char *s = p; + double value=0; + int base=10; + int exponent=0; + +#ifdef STB__clex_hex_floats + if (*p == '0') { + if (p[1] == 'x' || p[1] == 'X') { + base=16; + p += 2; + } + } +#endif + + for (;;) { + if (*p >= '0' && *p <= '9') + value = value*base + (*p++ - '0'); +#ifdef STB__clex_hex_floats + else if (base == 16 && *p >= 'a' && *p <= 'f') + value = value*base + 10 + (*p++ - 'a'); + else if (base == 16 && *p >= 'A' && *p <= 'F') + value = value*base + 10 + (*p++ - 'A'); +#endif + else + break; + } + + if (*p == '.') { + double pow, addend = 0; + ++p; + for (pow=1; ; pow*=base) { + if (*p >= '0' && *p <= '9') + addend = addend*base + (*p++ - '0'); +#ifdef STB__clex_hex_floats + else if (base == 16 && *p >= 'a' && *p <= 'f') + addend = addend*base + 10 + (*p++ - 'a'); + else if (base == 16 && *p >= 'A' && *p <= 'F') + addend = addend*base + 10 + (*p++ - 'A'); +#endif + else + break; + } + value += addend / pow; + } +#ifdef STB__clex_hex_floats + if (base == 16) { + // exponent required for hex float literal + if (*p != 'p' && *p != 'P') { + *q = s; + return 0; + } + exponent = 1; + } else +#endif + exponent = (*p == 'e' || *p == 'E'); + + if (exponent) { + int sign = p[1] == '-'; + unsigned int exponent=0; + double power=1; + ++p; + if (*p == '-' || *p == '+') + ++p; + while (*p >= '0' && *p <= '9') + exponent = exponent*10 + (*p++ - '0'); + +#ifdef STB__clex_hex_floats + if (base == 16) + power = stb__clex_pow(2, exponent); + else +#endif + power = stb__clex_pow(10, exponent); + if (sign) + value /= power; + else + value *= power; + } + *q = p; + return value; +} +#endif + +static int stb__clex_parse_char(char *p, char **q) +{ + if (*p == '\\') { + *q = p+2; // tentatively guess we'll parse two characters + switch(p[1]) { + case '\\': return '\\'; + case '\'': return '\''; + case '"': return '"'; + case 't': return '\t'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case '0': return '\0'; // @TODO ocatal constants + case 'x': case 'X': return -1; // @TODO hex constants + case 'u': return -1; // @TODO unicode constants + } + } + *q = p+1; + return (unsigned char) *p; +} + +static int stb__clex_parse_string(stb_lexer *lexer, char *p, int type) +{ + char *start = p; + char delim = *p++; // grab the " or ' for later matching + char *out = lexer->string_storage; + char *outend = lexer->string_storage + lexer->string_storage_len; + while (*p != delim) { + int n; + if (*p == '\\') { + char *q; + n = stb__clex_parse_char(p, &q); + if (n < 0) + return stb__clex_token(lexer, CLEX_parse_error, start, q); + p = q; + } else { + // @OPTIMIZE: could speed this up by looping-while-not-backslash + n = (unsigned char) *p++; + } + if (out+1 > outend) + return stb__clex_token(lexer, CLEX_parse_error, start, p); + // @TODO expand unicode escapes to UTF8 + *out++ = (char) n; + } + *out = 0; + lexer->string = lexer->string_storage; + lexer->string_len = (int) (out - lexer->string_storage); + return stb__clex_token(lexer, type, start, p); +} + +int stb_c_lexer_get_token(stb_lexer *lexer) +{ + char *p = lexer->parse_point; + + // skip whitespace and comments + for (;;) { + #ifdef STB_C_LEX_ISWHITE + while (p != lexer->stream_end) { + int n; + n = STB_C_LEX_ISWHITE(p); + if (n == 0) break; + if (lexer->eof && lexer->eof - lexer->parse_point < n) + return stb__clex_token(tok, CLEX_parse_error, p,lexer->eof-1); + p += n; + } + #else + while (p != lexer->eof && stb__clex_iswhite(*p)) + ++p; + #endif + + STB_C_LEX_CPP_COMMENTS( + if (p != lexer->eof && p[0] == '/' && p[1] == '/') { + while (p != lexer->eof && *p != '\r' && *p != '\n') + ++p; + continue; + } + ) + + STB_C_LEX_C_COMMENTS( + if (p != lexer->eof && p[0] == '/' && p[1] == '*') { + char *start = p; + p += 2; + while (p != lexer->eof && (p[0] != '*' || p[1] != '/')) + ++p; + if (p == lexer->eof) + return stb__clex_token(lexer, CLEX_parse_error, start, p-1); + p += 2; + continue; + } + ) + + #ifdef STB__clex_discard_preprocessor + // @TODO this discards everything after a '#', regardless + // of where in the line the # is, rather than requiring it + // be at the start. (because this parser doesn't otherwise + // check for line breaks!) + if (p != lexer->eof && p[0] == '#') { + while (p != lexer->eof && *p != '\r' && *p != '\n') + ++p; + continue; + } + #endif + + break; + } + + if (p == lexer->eof) + return stb__clex_eof(lexer); + + switch (*p) { + default: + if ( (*p >= 'a' && *p <= 'z') + || (*p >= 'A' && *p <= 'Z') + || *p == '_' || (unsigned char) *p >= 128 // >= 128 is UTF8 char + STB_C_LEX_DOLLAR_IDENTIFIER( || *p == '$' ) ) + { + int n = 0; + lexer->string = lexer->string_storage; + lexer->string_len = n; + do { + if (n+1 >= lexer->string_storage_len) + return stb__clex_token(lexer, CLEX_parse_error, p, p+n); + lexer->string[n] = p[n]; + ++n; + } while ( + (p[n] >= 'a' && p[n] <= 'z') + || (p[n] >= 'A' && p[n] <= 'Z') + || (p[n] >= '0' && p[n] <= '9') // allow digits in middle of identifier + || p[n] == '_' || (unsigned char) p[n] >= 128 + STB_C_LEX_DOLLAR_IDENTIFIER( || p[n] == '$' ) + ); + lexer->string[n] = 0; + return stb__clex_token(lexer, CLEX_id, p, p+n-1); + } + + // check for EOF + STB_C_LEX_0_IS_EOF( + if (*p == 0) + return stb__clex_eof(lexer); + ) + + single_char: + // not an identifier, return the character as itself + return stb__clex_token(lexer, *p, p, p); + + case '+': + if (p+1 != lexer->eof) { + STB_C_LEX_C_INCREMENTS(if (p[1] == '+') return stb__clex_token(lexer, CLEX_plusplus, p,p+1);) + STB_C_LEX_C_ARITHEQ( if (p[1] == '=') return stb__clex_token(lexer, CLEX_pluseq , p,p+1);) + } + goto single_char; + case '-': + if (p+1 != lexer->eof) { + STB_C_LEX_C_INCREMENTS(if (p[1] == '-') return stb__clex_token(lexer, CLEX_minusminus, p,p+1);) + STB_C_LEX_C_ARITHEQ( if (p[1] == '=') return stb__clex_token(lexer, CLEX_minuseq , p,p+1);) + STB_C_LEX_C_ARROW( if (p[1] == '>') return stb__clex_token(lexer, CLEX_arrow , p,p+1);) + } + goto single_char; + case '&': + if (p+1 != lexer->eof) { + STB_C_LEX_C_LOGICAL( if (p[1] == '&') return stb__clex_token(lexer, CLEX_andand, p,p+1);) + STB_C_LEX_C_BITWISEEQ(if (p[1] == '=') return stb__clex_token(lexer, CLEX_andeq , p,p+1);) + } + goto single_char; + case '|': + if (p+1 != lexer->eof) { + STB_C_LEX_C_LOGICAL( if (p[1] == '|') return stb__clex_token(lexer, CLEX_oror, p,p+1);) + STB_C_LEX_C_BITWISEEQ(if (p[1] == '=') return stb__clex_token(lexer, CLEX_oreq, p,p+1);) + } + goto single_char; + case '=': + if (p+1 != lexer->eof) { + STB_C_LEX_C_COMPARISONS(if (p[1] == '=') return stb__clex_token(lexer, CLEX_eq, p,p+1);) + STB_C_LEX_EQUAL_ARROW( if (p[1] == '>') return stb__clex_token(lexer, CLEX_eqarrow, p,p+1);) + } + goto single_char; + case '!': + STB_C_LEX_C_COMPARISONS(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_noteq, p,p+1);) + goto single_char; + case '^': + STB_C_LEX_C_BITWISEEQ(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_xoreq, p,p+1)); + goto single_char; + case '%': + STB_C_LEX_C_ARITHEQ(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_modeq, p,p+1)); + goto single_char; + case '*': + STB_C_LEX_C_ARITHEQ(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_muleq, p,p+1)); + goto single_char; + case '/': + STB_C_LEX_C_ARITHEQ(if (p+1 != lexer->eof && p[1] == '=') return stb__clex_token(lexer, CLEX_diveq, p,p+1)); + goto single_char; + case '<': + if (p+1 != lexer->eof) { + STB_C_LEX_C_COMPARISONS(if (p[1] == '=') return stb__clex_token(lexer, CLEX_lesseq, p,p+1);) + STB_C_LEX_C_SHIFTS( if (p[1] == '<') { + STB_C_LEX_C_ARITHEQ(if (p+2 != lexer->eof && p[2] == '=') + return stb__clex_token(lexer, CLEX_shleq, p,p+2);) + return stb__clex_token(lexer, CLEX_shl, p,p+1); + } + ) + } + goto single_char; + case '>': + if (p+1 != lexer->eof) { + STB_C_LEX_C_COMPARISONS(if (p[1] == '=') return stb__clex_token(lexer, CLEX_greatereq, p,p+1);) + STB_C_LEX_C_SHIFTS( if (p[1] == '>') { + STB_C_LEX_C_ARITHEQ(if (p+2 != lexer->eof && p[2] == '=') + return stb__clex_token(lexer, CLEX_shreq, p,p+2);) + return stb__clex_token(lexer, CLEX_shr, p,p+1); + } + ) + } + goto single_char; + + case '"': + STB_C_LEX_C_DQ_STRINGS(return stb__clex_parse_string(lexer, p, CLEX_dqstring);) + goto single_char; + case '\'': + STB_C_LEX_C_SQ_STRINGS(return stb__clex_parse_string(lexer, p, CLEX_sqstring);) + STB_C_LEX_C_CHARS( + { + char *start = p; + lexer->int_number = stb__clex_parse_char(p+1, &p); + if (lexer->int_number < 0) + return stb__clex_token(lexer, CLEX_parse_error, start,start); + if (p == lexer->eof || *p != '\'') + return stb__clex_token(lexer, CLEX_parse_error, start,p); + return stb__clex_token(lexer, CLEX_charlit, start, p+1); + }) + goto single_char; + + case '0': + #if defined(STB__clex_hex_ints) || defined(STB__clex_hex_floats) + if (p+1 != lexer->eof) { + if (p[1] == 'x' || p[1] == 'X') { + char *q; + + #ifdef STB__clex_hex_floats + for (q=p+2; + q != lexer->eof && ((*q >= '0' && *q <= '9') || (*q >= 'a' && *q <= 'f') || (*q >= 'A' && *q <= 'F')); + ++q); + if (q != lexer->eof) { + if (*q == '.' STB_C_LEX_FLOAT_NO_DECIMAL(|| *q == 'p' || *q == 'P')) { + #ifdef STB__CLEX_use_stdlib + lexer->real_number = strtod((char *) p, (char**) &q); + #else + lexer->real_number = stb__clex_parse_float(p, &q); + #endif + + if (p == q) + return stb__clex_token(lexer, CLEX_parse_error, p,q); + return stb__clex_parse_suffixes(lexer, CLEX_floatlit, p,q, STB_C_LEX_FLOAT_SUFFIXES); + + } + } + #endif // STB__CLEX_hex_floats + + #ifdef STB__clex_hex_ints + #ifdef STB__CLEX_use_stdlib + lexer->int_number = strtol((char *) p, (char **) &q, 16); + #else + { + stb__clex_int n=0; + for (q=p+2; q != lexer->eof; ++q) { + if (*q >= '0' && *q <= '9') + n = n*16 + (*q - '0'); + else if (*q >= 'a' && *q <= 'f') + n = n*16 + (*q - 'a') + 10; + else if (*q >= 'A' && *q <= 'F') + n = n*16 + (*q - 'A') + 10; + else + break; + } + lexer->int_number = n; + } + #endif + if (q == p+2) + return stb__clex_token(lexer, CLEX_parse_error, p-2,p-1); + return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_HEX_SUFFIXES); + #endif + } + } + #endif // defined(STB__clex_hex_ints) || defined(STB__clex_hex_floats) + // can't test for octal because we might parse '0.0' as float or as '0' '.' '0', + // so have to do float first + + /* FALL THROUGH */ + case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': + + #ifdef STB__clex_decimal_floats + { + char *q = p; + while (q != lexer->eof && (*q >= '0' && *q <= '9')) + ++q; + if (q != lexer->eof) { + if (*q == '.' STB_C_LEX_FLOAT_NO_DECIMAL(|| *q == 'e' || *q == 'E')) { + #ifdef STB__CLEX_use_stdlib + lexer->real_number = strtod((char *) p, (char**) &q); + #else + lexer->real_number = stb__clex_parse_float(p, &q); + #endif + + return stb__clex_parse_suffixes(lexer, CLEX_floatlit, p,q, STB_C_LEX_FLOAT_SUFFIXES); + + } + } + } + #endif // STB__clex_decimal_floats + + #ifdef STB__clex_octal_ints + if (p[0] == '0') { + char *q = p; + #ifdef STB__CLEX_use_stdlib + lexer->int_number = strtol((char *) p, (char **) &q, 8); + #else + stb__clex_int n=0; + while (q != lexer->eof) { + if (*q >= '0' && *q <= '7') + n = n*8 + (*q - '0'); + else + break; + ++q; + } + if (q != lexer->eof && (*q == '8' || *q=='9')) + return stb__clex_token(lexer, CLEX_parse_error, p, q); + lexer->int_number = n; + #endif + return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_OCTAL_SUFFIXES); + } + #endif // STB__clex_octal_ints + + #ifdef STB__clex_decimal_ints + { + char *q = p; + #ifdef STB__CLEX_use_stdlib + lexer->int_number = strtol((char *) p, (char **) &q, 10); + #else + stb__clex_int n=0; + while (q != lexer->eof) { + if (*q >= '0' && *q <= '9') + n = n*10 + (*q - '0'); + else + break; + ++q; + } + lexer->int_number = n; + #endif + return stb__clex_parse_suffixes(lexer, CLEX_intlit, p,q, STB_C_LEX_OCTAL_SUFFIXES); + } + #endif // STB__clex_decimal_ints + goto single_char; + } +} +#endif // STB_C_LEXER_IMPLEMENTATION + +#ifdef STB_C_LEXER_SELF_TEST +#define _CRT_SECURE_NO_WARNINGS +#include <stdio.h> +#include <stdlib.h> + +static void print_token(stb_lexer *lexer) +{ + switch (lexer->token) { + case CLEX_id : printf("_%s", lexer->string); break; + case CLEX_eq : printf("=="); break; + case CLEX_noteq : printf("!="); break; + case CLEX_lesseq : printf("<="); break; + case CLEX_greatereq : printf(">="); break; + case CLEX_andand : printf("&&"); break; + case CLEX_oror : printf("||"); break; + case CLEX_shl : printf("<<"); break; + case CLEX_shr : printf(">>"); break; + case CLEX_plusplus : printf("++"); break; + case CLEX_minusminus: printf("--"); break; + case CLEX_arrow : printf("->"); break; + case CLEX_andeq : printf("&="); break; + case CLEX_oreq : printf("|="); break; + case CLEX_xoreq : printf("^="); break; + case CLEX_pluseq : printf("+="); break; + case CLEX_minuseq : printf("-="); break; + case CLEX_muleq : printf("*="); break; + case CLEX_diveq : printf("/="); break; + case CLEX_modeq : printf("%%="); break; + case CLEX_shleq : printf("<<="); break; + case CLEX_shreq : printf(">>="); break; + case CLEX_eqarrow : printf("=>"); break; + case CLEX_dqstring : printf("\"%s\"", lexer->string); break; + case CLEX_sqstring : printf("'\"%s\"'", lexer->string); break; + case CLEX_charlit : printf("'%s'", lexer->string); break; + #if defined(STB__clex_int_as_double) && !defined(STB__CLEX_use_stdlib) + case CLEX_intlit : printf("#%g", lexer->real_number); break; + #else + case CLEX_intlit : printf("#%ld", lexer->int_number); break; + #endif + case CLEX_floatlit : printf("%g", lexer->real_number); break; + default: + if (lexer->token >= 0 && lexer->token < 256) + printf("%c", (int) lexer->token); + else { + printf("<<<UNKNOWN TOKEN %ld >>>\n", lexer->token); + } + break; + } +} + +/* Force a test +of parsing +multiline comments */ + +/*/ comment /*/ +/**/ extern /**/ + +void dummy(void) +{ + double some_floats[] = { + 1.0501, -10.4e12, 5E+10, +#if 0 // not supported in C++ or C-pre-99, so don't try to compile it, but let our parser test it + 0x1.0p+24, 0xff.FP-8, 0x1p-23, +#endif + 4. + }; + (void) sizeof(some_floats); + (void) some_floats[1]; + + printf("test %d",1); // https://github.com/nothings/stb/issues/13 +} + +int main(int argc, char **argv) +{ + FILE *f = fopen("stb_c_lexer.h","rb"); + char *text = (char *) malloc(1 << 20); + int len = f ? (int) fread(text, 1, 1<<20, f) : -1; + stb_lexer lex; + if (len < 0) { + fprintf(stderr, "Error opening file\n"); + free(text); + fclose(f); + return 1; + } + fclose(f); + + stb_c_lexer_init(&lex, text, text+len, (char *) malloc(0x10000), 0x10000); + while (stb_c_lexer_get_token(&lex)) { + if (lex.token == CLEX_parse_error) { + printf("\n<<<PARSE ERROR>>>\n"); + break; + } + print_token(&lex); + printf(" "); + } + return 0; +} +#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. +------------------------------------------------------------------------------ +*/ |
