From 6499bcd2a213028577f9543f50e84563a6695141 Mon Sep 17 00:00:00 2001 From: martinfouilleul Date: Fri, 16 Jun 2023 19:48:33 +0200 Subject: [PATCH] [win32] fixing include directives to avoid having to pass all include dirs to compiler --- src/graphics.h | 656 ++++++++++---------- src/milepost.h | 24 +- src/mp_app.h | 8 +- src/platform/platform_clock.h | 68 +- src/platform/platform_log.h | 116 ++-- src/ui.h | 1098 ++++++++++++++++----------------- 6 files changed, 985 insertions(+), 985 deletions(-) diff --git a/src/graphics.h b/src/graphics.h index 9a70019..7f97a95 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -1,328 +1,328 @@ -/************************************************************//** -* -* @file: graphics.h -* @author: Martin Fouilleul -* @date: 23/01/2023 -* @revision: -* -*****************************************************************/ -#ifndef __GRAPHICS_H_ -#define __GRAPHICS_H_ - -#include"typedefs.h" -#include"platform.h" -#include"mp_app.h" - -//------------------------------------------------------------------------------------------ -//NOTE(martin): backends selection -//------------------------------------------------------------------------------------------ - -typedef enum { - MG_NONE, - MG_METAL, - MG_GL, - MG_GLES, - MG_CANVAS, - MG_HOST } mg_surface_api; - -//NOTE: these macros are used to select which backend to include when building milepost -// they can be overridden by passing them to the compiler command line -#if PLATFORM_MACOS - #ifndef MG_COMPILE_METAL - #define MG_COMPILE_METAL 1 - #endif - - #ifndef MG_COMPILE_GLES - #define MG_COMPILE_GLES 1 - #endif - - #ifndef MG_COMPILE_CANVAS - #if !MG_COMPILE_METAL - #error "Canvas surface requires a Metal backend on macOS. Make sure you define MG_COMPILE_METAL to 1." - #endif - #define MG_COMPILE_CANVAS 1 - #endif - - #define MG_COMPILE_GL 0 - -#elif PLATFORM_WINDOWS - #ifndef MG_COMPILE_GL - #define MG_COMPILE_GL 1 - #endif - - #ifndef MG_COMPILE_GLES - #define MG_COMPILE_GLES 1 - #endif - - #ifndef MG_COMPILE_CANVAS - #if !MG_COMPILE_GL - #error "Canvas surface requires an OpenGL backend on Windows. Make sure you define MG_COMPILE_GL to 1." - #endif - #define MG_COMPILE_CANVAS 1 - #endif - -#elif PLATFORM_LINUX - #ifndef MG_COMPILE_GL - #define MG_COMPILE_GL 1 - #endif - - #ifndef MG_COMPILE_CANVAS - #if !MG_COMPILE_GL - #error "Canvas surface requires an OpenGL backend on Linux. Make sure you define MG_COMPILE_GL to 1." - #endif - #define MG_COMPILE_CANVAS 1 - #endif -#endif - -//NOTE: these macros are used to select backend-specific APIs to include when using milepost -#ifdef MG_EXPOSE_SURFACE_METAL - #include"mtl_surface.h" -#endif - -#ifdef MG_EXPOSE_SURFACE_WGL - #include"wgl_surface.h" -#endif - -//TODO: expose nsgl surface when supported, expose egl surface, etc... - -//TODO: add MG_INCLUDE_OPENGL/GLES/etc, once we know how we make different gl versions co-exist - -MP_API bool mg_is_surface_api_available(mg_surface_api api); - -//------------------------------------------------------------------------------------------ -//NOTE(martin): graphics surface -//------------------------------------------------------------------------------------------ -typedef struct mg_surface { u64 h; } mg_surface; - -MP_API mg_surface mg_surface_nil(void); -MP_API bool mg_surface_is_nil(mg_surface surface); - -MP_API mg_surface mg_surface_create_for_window(mp_window window, mg_surface_api api); -MP_API void mg_surface_destroy(mg_surface surface); -MP_API void mg_surface_prepare(mg_surface surface); -MP_API void mg_surface_present(mg_surface surface); -MP_API void mg_surface_swap_interval(mg_surface surface, int swap); -MP_API vec2 mg_surface_contents_scaling(mg_surface surface); -MP_API mp_rect mg_surface_get_frame(mg_surface surface); -MP_API void mg_surface_set_frame(mg_surface surface, mp_rect frame); -MP_API bool mg_surface_get_hidden(mg_surface surface); -MP_API void mg_surface_set_hidden(mg_surface surface, bool hidden); - -//NOTE(martin): surface sharing -typedef u64 mg_surface_id; - -MP_API mg_surface mg_surface_create_remote(u32 width, u32 height, mg_surface_api api); -MP_API mg_surface mg_surface_create_host(mp_window window); -MP_API mg_surface_id mg_surface_remote_id(mg_surface surface); -MP_API void mg_surface_host_connect(mg_surface surface, mg_surface_id remoteId); - -//------------------------------------------------------------------------------------------ -//NOTE(martin): graphics canvas structs -//------------------------------------------------------------------------------------------ -typedef struct mg_canvas { u64 h; } mg_canvas; -typedef struct mg_font { u64 h; } mg_font; -typedef struct mg_image { u64 h; } mg_image; - -typedef struct mg_mat2x3 -{ - f32 m[6]; -} mg_mat2x3; - -typedef struct mg_color -{ - union - { - struct - { - f32 r; - f32 g; - f32 b; - f32 a; - }; - f32 c[4]; - }; -} mg_color; - -typedef enum {MG_JOINT_MITER = 0, - MG_JOINT_BEVEL, - MG_JOINT_NONE } mg_joint_type; - -typedef enum {MG_CAP_NONE = 0, - MG_CAP_SQUARE } mg_cap_type; - -typedef struct mg_font_extents -{ - f32 ascent; // the extent above the baseline (by convention a positive value extends above the baseline) - f32 descent; // the extent below the baseline (by convention, positive value extends below the baseline) - f32 leading; // spacing between one row's descent and the next row's ascent - f32 xHeight; // height of the lower case letter 'x' - f32 capHeight; // height of the upper case letter 'M' - f32 width; // maximum width of the font - -} mg_font_extents; - -typedef struct mg_text_extents -{ - f32 xBearing; - f32 yBearing; - f32 width; - f32 height; - f32 xAdvance; - f32 yAdvance; - -} mg_text_extents; - -//------------------------------------------------------------------------------------------ -//NOTE(martin): graphics canvas -//------------------------------------------------------------------------------------------ -MP_API mg_canvas mg_canvas_nil(void); -MP_API bool mg_canvas_is_nil(mg_canvas canvas); - -MP_API mg_canvas mg_canvas_create(void); -MP_API void mg_canvas_destroy(mg_canvas canvas); -mg_canvas mg_canvas_set_current(mg_canvas canvas); -MP_API void mg_render(mg_surface surface, mg_canvas canvas); - -//------------------------------------------------------------------------------------------ -//NOTE(martin): fonts -//------------------------------------------------------------------------------------------ -MP_API mg_font mg_font_nil(void); -MP_API mg_font mg_font_create_from_memory(u32 size, byte* buffer, u32 rangeCount, unicode_range* ranges); -MP_API void mg_font_destroy(mg_font font); - -//NOTE(martin): the following int valued functions return -1 if font is invalid or codepoint is not present in font// -//TODO(martin): add enum error codes - -MP_API mg_font_extents mg_font_get_extents(mg_font font); -MP_API mg_font_extents mg_font_get_scaled_extents(mg_font font, f32 emSize); -MP_API f32 mg_font_get_scale_for_em_pixels(mg_font font, f32 emSize); - -//NOTE(martin): if you need to process more than one codepoint, first convert your codepoints to glyph indices, then use the -// glyph index versions of the functions, which can take an array of glyph indices. - -MP_API str32 mg_font_get_glyph_indices(mg_font font, str32 codePoints, str32 backing); -MP_API str32 mg_font_push_glyph_indices(mg_font font, mem_arena* arena, str32 codePoints); -MP_API u32 mg_font_get_glyph_index(mg_font font, utf32 codePoint); - -MP_API int mg_font_get_codepoint_extents(mg_font font, utf32 codePoint, mg_text_extents* outExtents); - -MP_API int mg_font_get_glyph_extents(mg_font font, str32 glyphIndices, mg_text_extents* outExtents); - -MP_API mp_rect mg_text_bounding_box_utf32(mg_font font, f32 fontSize, str32 text); -MP_API mp_rect mg_text_bounding_box(mg_font font, f32 fontSize, str8 text); - -//------------------------------------------------------------------------------------------ -//NOTE(martin): images -//------------------------------------------------------------------------------------------ -MP_API mg_image mg_image_nil(void); -MP_API bool mg_image_is_nil(mg_image a); - -MP_API mg_image mg_image_create(mg_surface surface, u32 width, u32 height); -MP_API mg_image mg_image_create_from_rgba8(mg_surface surface, u32 width, u32 height, u8* pixels); -MP_API mg_image mg_image_create_from_data(mg_surface surface, str8 data, bool flip); -MP_API mg_image mg_image_create_from_file(mg_surface surface, str8 path, bool flip); - -MP_API void mg_image_destroy(mg_image image); - -MP_API void mg_image_upload_region_rgba8(mg_image image, mp_rect region, u8* pixels); -MP_API vec2 mg_image_size(mg_image image); - -//------------------------------------------------------------------------------------------ -//NOTE(martin): atlasing -//------------------------------------------------------------------------------------------ - -//NOTE: rectangle allocator -typedef struct mg_rect_atlas mg_rect_atlas; - -mg_rect_atlas* mg_rect_atlas_create(mem_arena* arena, i32 width, i32 height); -mp_rect mg_rect_atlas_alloc(mg_rect_atlas* atlas, i32 width, i32 height); -void mg_rect_atlas_recycle(mg_rect_atlas* atlas, mp_rect rect); - -//NOTE: image atlas helpers -typedef struct mg_image_region -{ - mg_image image; - mp_rect rect; -} mg_image_region; - -mg_image_region mg_image_atlas_alloc_from_rgba8(mg_rect_atlas* atlas, mg_image backingImage, u32 width, u32 height, u8* pixels); -mg_image_region mg_image_atlas_alloc_from_data(mg_rect_atlas* atlas, mg_image backingImage, str8 data, bool flip); -mg_image_region mg_image_atlas_alloc_from_file(mg_rect_atlas* atlas, mg_image backingImage, str8 path, bool flip); -void mg_image_atlas_recycle(mg_rect_atlas* atlas, mg_image_region imageRgn); - -//------------------------------------------------------------------------------------------ -//NOTE(martin): transform, viewport and clipping -//------------------------------------------------------------------------------------------ -MP_API void mg_viewport(mp_rect viewPort); - -MP_API void mg_matrix_push(mg_mat2x3 matrix); -MP_API void mg_matrix_pop(void); - -MP_API void mg_clip_push(f32 x, f32 y, f32 w, f32 h); -MP_API void mg_clip_pop(void); - -//------------------------------------------------------------------------------------------ -//NOTE(martin): graphics attributes setting/getting -//------------------------------------------------------------------------------------------ -MP_API void mg_set_color(mg_color color); -MP_API void mg_set_color_rgba(f32 r, f32 g, f32 b, f32 a); -MP_API void mg_set_width(f32 width); -MP_API void mg_set_tolerance(f32 tolerance); -MP_API void mg_set_joint(mg_joint_type joint); -MP_API void mg_set_max_joint_excursion(f32 maxJointExcursion); -MP_API void mg_set_cap(mg_cap_type cap); -MP_API void mg_set_font(mg_font font); -MP_API void mg_set_font_size(f32 size); -MP_API void mg_set_text_flip(bool flip); -MP_API void mg_set_image(mg_image image); -MP_API void mg_set_image_source_region(mp_rect region); - -MP_API mg_color mg_get_color(void); -MP_API f32 mg_get_width(void); -MP_API f32 mg_get_tolerance(void); -MP_API mg_joint_type mg_get_joint(void); -MP_API f32 mg_get_max_joint_excursion(void); -MP_API mg_cap_type mg_get_cap(void); -MP_API mg_font mg_get_font(void); -MP_API f32 mg_get_font_size(void); -MP_API bool mg_get_text_flip(void); - -//------------------------------------------------------------------------------------------ -//NOTE(martin): path construction -//------------------------------------------------------------------------------------------ -MP_API vec2 mg_get_position(void); -MP_API void mg_move_to(f32 x, f32 y); -MP_API void mg_line_to(f32 x, f32 y); -MP_API void mg_quadratic_to(f32 x1, f32 y1, f32 x2, f32 y2); -MP_API void mg_cubic_to(f32 x1, f32 y1, f32 x2, f32 y2, f32 x3, f32 y3); -MP_API void mg_close_path(void); - -MP_API mp_rect mg_glyph_outlines(str32 glyphIndices); -MP_API void mg_codepoints_outlines(str32 string); -MP_API void mg_text_outlines(str8 string); - -//------------------------------------------------------------------------------------------ -//NOTE(martin): clear/fill/stroke -//------------------------------------------------------------------------------------------ -MP_API void mg_clear(void); -MP_API void mg_fill(void); -MP_API void mg_stroke(void); - -//------------------------------------------------------------------------------------------ -//NOTE(martin): 'fast' shapes primitives -//------------------------------------------------------------------------------------------ -MP_API void mg_rectangle_fill(f32 x, f32 y, f32 w, f32 h); -MP_API void mg_rectangle_stroke(f32 x, f32 y, f32 w, f32 h); -MP_API void mg_rounded_rectangle_fill(f32 x, f32 y, f32 w, f32 h, f32 r); -MP_API void mg_rounded_rectangle_stroke(f32 x, f32 y, f32 w, f32 h, f32 r); -MP_API void mg_ellipse_fill(f32 x, f32 y, f32 rx, f32 ry); -MP_API void mg_ellipse_stroke(f32 x, f32 y, f32 rx, f32 ry); -MP_API void mg_circle_fill(f32 x, f32 y, f32 r); -MP_API void mg_circle_stroke(f32 x, f32 y, f32 r); -MP_API void mg_arc(f32 x, f32 y, f32 r, f32 arcAngle, f32 startAngle); - -//NOTE: image helpers -MP_API void mg_image_draw(mg_image image, mp_rect rect); -MP_API void mg_image_draw_region(mg_image image, mp_rect srcRegion, mp_rect dstRegion); - -#endif //__GRAPHICS_H_ +/************************************************************//** +* +* @file: graphics.h +* @author: Martin Fouilleul +* @date: 23/01/2023 +* @revision: +* +*****************************************************************/ +#ifndef __GRAPHICS_H_ +#define __GRAPHICS_H_ + +#include"util/typedefs.h" +#include"platform/platform.h" +#include"mp_app.h" + +//------------------------------------------------------------------------------------------ +//NOTE(martin): backends selection +//------------------------------------------------------------------------------------------ + +typedef enum { + MG_NONE, + MG_METAL, + MG_GL, + MG_GLES, + MG_CANVAS, + MG_HOST } mg_surface_api; + +//NOTE: these macros are used to select which backend to include when building milepost +// they can be overridden by passing them to the compiler command line +#if PLATFORM_MACOS + #ifndef MG_COMPILE_METAL + #define MG_COMPILE_METAL 1 + #endif + + #ifndef MG_COMPILE_GLES + #define MG_COMPILE_GLES 1 + #endif + + #ifndef MG_COMPILE_CANVAS + #if !MG_COMPILE_METAL + #error "Canvas surface requires a Metal backend on macOS. Make sure you define MG_COMPILE_METAL to 1." + #endif + #define MG_COMPILE_CANVAS 1 + #endif + + #define MG_COMPILE_GL 0 + +#elif PLATFORM_WINDOWS + #ifndef MG_COMPILE_GL + #define MG_COMPILE_GL 1 + #endif + + #ifndef MG_COMPILE_GLES + #define MG_COMPILE_GLES 1 + #endif + + #ifndef MG_COMPILE_CANVAS + #if !MG_COMPILE_GL + #error "Canvas surface requires an OpenGL backend on Windows. Make sure you define MG_COMPILE_GL to 1." + #endif + #define MG_COMPILE_CANVAS 1 + #endif + +#elif PLATFORM_LINUX + #ifndef MG_COMPILE_GL + #define MG_COMPILE_GL 1 + #endif + + #ifndef MG_COMPILE_CANVAS + #if !MG_COMPILE_GL + #error "Canvas surface requires an OpenGL backend on Linux. Make sure you define MG_COMPILE_GL to 1." + #endif + #define MG_COMPILE_CANVAS 1 + #endif +#endif + +//NOTE: these macros are used to select backend-specific APIs to include when using milepost +#ifdef MG_EXPOSE_SURFACE_METAL + #include"mtl_surface.h" +#endif + +#ifdef MG_EXPOSE_SURFACE_WGL + #include"wgl_surface.h" +#endif + +//TODO: expose nsgl surface when supported, expose egl surface, etc... + +//TODO: add MG_INCLUDE_OPENGL/GLES/etc, once we know how we make different gl versions co-exist + +MP_API bool mg_is_surface_api_available(mg_surface_api api); + +//------------------------------------------------------------------------------------------ +//NOTE(martin): graphics surface +//------------------------------------------------------------------------------------------ +typedef struct mg_surface { u64 h; } mg_surface; + +MP_API mg_surface mg_surface_nil(void); +MP_API bool mg_surface_is_nil(mg_surface surface); + +MP_API mg_surface mg_surface_create_for_window(mp_window window, mg_surface_api api); +MP_API void mg_surface_destroy(mg_surface surface); +MP_API void mg_surface_prepare(mg_surface surface); +MP_API void mg_surface_present(mg_surface surface); +MP_API void mg_surface_swap_interval(mg_surface surface, int swap); +MP_API vec2 mg_surface_contents_scaling(mg_surface surface); +MP_API mp_rect mg_surface_get_frame(mg_surface surface); +MP_API void mg_surface_set_frame(mg_surface surface, mp_rect frame); +MP_API bool mg_surface_get_hidden(mg_surface surface); +MP_API void mg_surface_set_hidden(mg_surface surface, bool hidden); + +//NOTE(martin): surface sharing +typedef u64 mg_surface_id; + +MP_API mg_surface mg_surface_create_remote(u32 width, u32 height, mg_surface_api api); +MP_API mg_surface mg_surface_create_host(mp_window window); +MP_API mg_surface_id mg_surface_remote_id(mg_surface surface); +MP_API void mg_surface_host_connect(mg_surface surface, mg_surface_id remoteId); + +//------------------------------------------------------------------------------------------ +//NOTE(martin): graphics canvas structs +//------------------------------------------------------------------------------------------ +typedef struct mg_canvas { u64 h; } mg_canvas; +typedef struct mg_font { u64 h; } mg_font; +typedef struct mg_image { u64 h; } mg_image; + +typedef struct mg_mat2x3 +{ + f32 m[6]; +} mg_mat2x3; + +typedef struct mg_color +{ + union + { + struct + { + f32 r; + f32 g; + f32 b; + f32 a; + }; + f32 c[4]; + }; +} mg_color; + +typedef enum {MG_JOINT_MITER = 0, + MG_JOINT_BEVEL, + MG_JOINT_NONE } mg_joint_type; + +typedef enum {MG_CAP_NONE = 0, + MG_CAP_SQUARE } mg_cap_type; + +typedef struct mg_font_extents +{ + f32 ascent; // the extent above the baseline (by convention a positive value extends above the baseline) + f32 descent; // the extent below the baseline (by convention, positive value extends below the baseline) + f32 leading; // spacing between one row's descent and the next row's ascent + f32 xHeight; // height of the lower case letter 'x' + f32 capHeight; // height of the upper case letter 'M' + f32 width; // maximum width of the font + +} mg_font_extents; + +typedef struct mg_text_extents +{ + f32 xBearing; + f32 yBearing; + f32 width; + f32 height; + f32 xAdvance; + f32 yAdvance; + +} mg_text_extents; + +//------------------------------------------------------------------------------------------ +//NOTE(martin): graphics canvas +//------------------------------------------------------------------------------------------ +MP_API mg_canvas mg_canvas_nil(void); +MP_API bool mg_canvas_is_nil(mg_canvas canvas); + +MP_API mg_canvas mg_canvas_create(void); +MP_API void mg_canvas_destroy(mg_canvas canvas); +mg_canvas mg_canvas_set_current(mg_canvas canvas); +MP_API void mg_render(mg_surface surface, mg_canvas canvas); + +//------------------------------------------------------------------------------------------ +//NOTE(martin): fonts +//------------------------------------------------------------------------------------------ +MP_API mg_font mg_font_nil(void); +MP_API mg_font mg_font_create_from_memory(u32 size, byte* buffer, u32 rangeCount, unicode_range* ranges); +MP_API void mg_font_destroy(mg_font font); + +//NOTE(martin): the following int valued functions return -1 if font is invalid or codepoint is not present in font// +//TODO(martin): add enum error codes + +MP_API mg_font_extents mg_font_get_extents(mg_font font); +MP_API mg_font_extents mg_font_get_scaled_extents(mg_font font, f32 emSize); +MP_API f32 mg_font_get_scale_for_em_pixels(mg_font font, f32 emSize); + +//NOTE(martin): if you need to process more than one codepoint, first convert your codepoints to glyph indices, then use the +// glyph index versions of the functions, which can take an array of glyph indices. + +MP_API str32 mg_font_get_glyph_indices(mg_font font, str32 codePoints, str32 backing); +MP_API str32 mg_font_push_glyph_indices(mg_font font, mem_arena* arena, str32 codePoints); +MP_API u32 mg_font_get_glyph_index(mg_font font, utf32 codePoint); + +MP_API int mg_font_get_codepoint_extents(mg_font font, utf32 codePoint, mg_text_extents* outExtents); + +MP_API int mg_font_get_glyph_extents(mg_font font, str32 glyphIndices, mg_text_extents* outExtents); + +MP_API mp_rect mg_text_bounding_box_utf32(mg_font font, f32 fontSize, str32 text); +MP_API mp_rect mg_text_bounding_box(mg_font font, f32 fontSize, str8 text); + +//------------------------------------------------------------------------------------------ +//NOTE(martin): images +//------------------------------------------------------------------------------------------ +MP_API mg_image mg_image_nil(void); +MP_API bool mg_image_is_nil(mg_image a); + +MP_API mg_image mg_image_create(mg_surface surface, u32 width, u32 height); +MP_API mg_image mg_image_create_from_rgba8(mg_surface surface, u32 width, u32 height, u8* pixels); +MP_API mg_image mg_image_create_from_data(mg_surface surface, str8 data, bool flip); +MP_API mg_image mg_image_create_from_file(mg_surface surface, str8 path, bool flip); + +MP_API void mg_image_destroy(mg_image image); + +MP_API void mg_image_upload_region_rgba8(mg_image image, mp_rect region, u8* pixels); +MP_API vec2 mg_image_size(mg_image image); + +//------------------------------------------------------------------------------------------ +//NOTE(martin): atlasing +//------------------------------------------------------------------------------------------ + +//NOTE: rectangle allocator +typedef struct mg_rect_atlas mg_rect_atlas; + +mg_rect_atlas* mg_rect_atlas_create(mem_arena* arena, i32 width, i32 height); +mp_rect mg_rect_atlas_alloc(mg_rect_atlas* atlas, i32 width, i32 height); +void mg_rect_atlas_recycle(mg_rect_atlas* atlas, mp_rect rect); + +//NOTE: image atlas helpers +typedef struct mg_image_region +{ + mg_image image; + mp_rect rect; +} mg_image_region; + +mg_image_region mg_image_atlas_alloc_from_rgba8(mg_rect_atlas* atlas, mg_image backingImage, u32 width, u32 height, u8* pixels); +mg_image_region mg_image_atlas_alloc_from_data(mg_rect_atlas* atlas, mg_image backingImage, str8 data, bool flip); +mg_image_region mg_image_atlas_alloc_from_file(mg_rect_atlas* atlas, mg_image backingImage, str8 path, bool flip); +void mg_image_atlas_recycle(mg_rect_atlas* atlas, mg_image_region imageRgn); + +//------------------------------------------------------------------------------------------ +//NOTE(martin): transform, viewport and clipping +//------------------------------------------------------------------------------------------ +MP_API void mg_viewport(mp_rect viewPort); + +MP_API void mg_matrix_push(mg_mat2x3 matrix); +MP_API void mg_matrix_pop(void); + +MP_API void mg_clip_push(f32 x, f32 y, f32 w, f32 h); +MP_API void mg_clip_pop(void); + +//------------------------------------------------------------------------------------------ +//NOTE(martin): graphics attributes setting/getting +//------------------------------------------------------------------------------------------ +MP_API void mg_set_color(mg_color color); +MP_API void mg_set_color_rgba(f32 r, f32 g, f32 b, f32 a); +MP_API void mg_set_width(f32 width); +MP_API void mg_set_tolerance(f32 tolerance); +MP_API void mg_set_joint(mg_joint_type joint); +MP_API void mg_set_max_joint_excursion(f32 maxJointExcursion); +MP_API void mg_set_cap(mg_cap_type cap); +MP_API void mg_set_font(mg_font font); +MP_API void mg_set_font_size(f32 size); +MP_API void mg_set_text_flip(bool flip); +MP_API void mg_set_image(mg_image image); +MP_API void mg_set_image_source_region(mp_rect region); + +MP_API mg_color mg_get_color(void); +MP_API f32 mg_get_width(void); +MP_API f32 mg_get_tolerance(void); +MP_API mg_joint_type mg_get_joint(void); +MP_API f32 mg_get_max_joint_excursion(void); +MP_API mg_cap_type mg_get_cap(void); +MP_API mg_font mg_get_font(void); +MP_API f32 mg_get_font_size(void); +MP_API bool mg_get_text_flip(void); + +//------------------------------------------------------------------------------------------ +//NOTE(martin): path construction +//------------------------------------------------------------------------------------------ +MP_API vec2 mg_get_position(void); +MP_API void mg_move_to(f32 x, f32 y); +MP_API void mg_line_to(f32 x, f32 y); +MP_API void mg_quadratic_to(f32 x1, f32 y1, f32 x2, f32 y2); +MP_API void mg_cubic_to(f32 x1, f32 y1, f32 x2, f32 y2, f32 x3, f32 y3); +MP_API void mg_close_path(void); + +MP_API mp_rect mg_glyph_outlines(str32 glyphIndices); +MP_API void mg_codepoints_outlines(str32 string); +MP_API void mg_text_outlines(str8 string); + +//------------------------------------------------------------------------------------------ +//NOTE(martin): clear/fill/stroke +//------------------------------------------------------------------------------------------ +MP_API void mg_clear(void); +MP_API void mg_fill(void); +MP_API void mg_stroke(void); + +//------------------------------------------------------------------------------------------ +//NOTE(martin): 'fast' shapes primitives +//------------------------------------------------------------------------------------------ +MP_API void mg_rectangle_fill(f32 x, f32 y, f32 w, f32 h); +MP_API void mg_rectangle_stroke(f32 x, f32 y, f32 w, f32 h); +MP_API void mg_rounded_rectangle_fill(f32 x, f32 y, f32 w, f32 h, f32 r); +MP_API void mg_rounded_rectangle_stroke(f32 x, f32 y, f32 w, f32 h, f32 r); +MP_API void mg_ellipse_fill(f32 x, f32 y, f32 rx, f32 ry); +MP_API void mg_ellipse_stroke(f32 x, f32 y, f32 rx, f32 ry); +MP_API void mg_circle_fill(f32 x, f32 y, f32 r); +MP_API void mg_circle_stroke(f32 x, f32 y, f32 r); +MP_API void mg_arc(f32 x, f32 y, f32 r, f32 arcAngle, f32 startAngle); + +//NOTE: image helpers +MP_API void mg_image_draw(mg_image image, mp_rect rect); +MP_API void mg_image_draw_region(mg_image image, mp_rect srcRegion, mp_rect dstRegion); + +#endif //__GRAPHICS_H_ diff --git a/src/milepost.h b/src/milepost.h index 82ad415..5cfa699 100644 --- a/src/milepost.h +++ b/src/milepost.h @@ -12,22 +12,22 @@ //---------------------------------------------------------------- // utility layer //---------------------------------------------------------------- -#include"platform.h" -#include"typedefs.h" -#include"macro_helpers.h" -#include"platform_log.h" -#include"lists.h" -#include"memory.h" -#include"strings.h" -#include"utf8.h" -#include"hash.h" +#include"platform/platform.h" +#include"util/typedefs.h" +#include"util/macro_helpers.h" +#include"platform/platform_log.h" +#include"util/lists.h" +#include"util/memory.h" +#include"util/strings.h" +#include"util/utf8.h" +#include"util/hash.h" //---------------------------------------------------------------- // platform layer //---------------------------------------------------------------- -#include"platform_clock.h" -#include"platform_path.h" -#include"platform_io.h" +#include"platform/platform_clock.h" +#include"platform/platform_path.h" +#include"platform/platform_io.h" /* #include"platform_rng.h" #include"platform_socket.h" diff --git a/src/mp_app.h b/src/mp_app.h index b9c6a22..e2cd6b1 100644 --- a/src/mp_app.h +++ b/src/mp_app.h @@ -9,10 +9,10 @@ #ifndef __PLATFORM_APP_H_ #define __PLATFORM_APP_H_ -#include"typedefs.h" -#include"utf8.h" -#include"lists.h" -#include"memory.h" +#include"util/typedefs.h" +#include"util/utf8.h" +#include"util/lists.h" +#include"util/memory.h" #ifdef __cplusplus extern "C" { diff --git a/src/platform/platform_clock.h b/src/platform/platform_clock.h index 8c3b1cd..023b885 100644 --- a/src/platform/platform_clock.h +++ b/src/platform/platform_clock.h @@ -1,34 +1,34 @@ -/************************************************************//** -* -* @file: platform_clock.h -* @author: Martin Fouilleul -* @date: 07/03/2019 -* @revision: -* -*****************************************************************/ -#ifndef __PLATFORM_CLOCK_H_ -#define __PLATFORM_CLOCK_H_ - -#include"typedefs.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -typedef enum { - MP_CLOCK_MONOTONIC, // clock that increment monotonically - MP_CLOCK_UPTIME, // clock that increment monotonically during uptime - MP_CLOCK_DATE // clock that is driven by the platform time -} mp_clock_kind; - -MP_API void mp_clock_init(); // initialize the clock subsystem -MP_API u64 mp_get_timestamp(mp_clock_kind clock); -MP_API f64 mp_get_time(mp_clock_kind clock); -MP_API void mp_sleep_nanoseconds(u64 nanoseconds); // sleep for a given number of nanoseconds - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - - -#endif //__PLATFORM_CLOCK_H_ +/************************************************************//** +* +* @file: platform_clock.h +* @author: Martin Fouilleul +* @date: 07/03/2019 +* @revision: +* +*****************************************************************/ +#ifndef __PLATFORM_CLOCK_H_ +#define __PLATFORM_CLOCK_H_ + +#include"util/typedefs.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +typedef enum { + MP_CLOCK_MONOTONIC, // clock that increment monotonically + MP_CLOCK_UPTIME, // clock that increment monotonically during uptime + MP_CLOCK_DATE // clock that is driven by the platform time +} mp_clock_kind; + +MP_API void mp_clock_init(); // initialize the clock subsystem +MP_API u64 mp_get_timestamp(mp_clock_kind clock); +MP_API f64 mp_get_time(mp_clock_kind clock); +MP_API void mp_sleep_nanoseconds(u64 nanoseconds); // sleep for a given number of nanoseconds + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + + +#endif //__PLATFORM_CLOCK_H_ diff --git a/src/platform/platform_log.h b/src/platform/platform_log.h index f33951e..6c9ec5a 100644 --- a/src/platform/platform_log.h +++ b/src/platform/platform_log.h @@ -1,58 +1,58 @@ -/************************************************************//** -* -* @file: platform_log.h -* @author: Martin Fouilleul -* @date: 18/04/2023 -* -*****************************************************************/ -#ifndef __PLATFORM_LOG_H_ -#define __PLATFORM_LOG_H_ - -#include"platform.h" -#include"strings.h" - -typedef enum { LOG_LEVEL_ERROR, - LOG_LEVEL_WARNING, - LOG_LEVEL_INFO, - LOG_LEVEL_COUNT } log_level; - -typedef struct log_output log_output; - -extern log_output* LOG_DEFAULT_OUTPUT; - -MP_API void log_set_level(log_level level); -MP_API void log_set_output(log_output* output); -MP_API void log_push(log_level level, - str8 function, - str8 file, - int line, - const char* fmt, - ...); - -#define log_generic(level, msg, ...) log_push(level, STR8(__FUNCTION__), STR8(__FILE__), __LINE__, msg, ##__VA_ARGS__) - -#define log_error(msg, ...) log_generic(LOG_LEVEL_ERROR, msg, ##__VA_ARGS__) - -#ifndef LOG_COMPILE_WARNING - #define LOG_COMPILE_WARNING 1 -#endif - -#ifndef LOG_COMPILE_INFO - #define LOG_COMPILE_INFO 1 -#endif - -#if LOG_COMPILE_WARNING || LOG_COMPILE_INFO - #define log_warning(msg, ...) log_generic(LOG_LEVEL_WARNING, msg, ##__VA_ARGS__) - - #if LOG_COMPILE_INFO - #define log_info(msg, ...) log_generic(LOG_LEVEL_INFO, msg, ##__VA_ARGS__ ) - #else - #define log_info(msg, ...) - #endif -#else - #define log_warning(msg, ...) - #define log_info(msg, ...) -#endif - - -#endif //__PLATFORM_LOG_H_ +/************************************************************//** +* +* @file: platform_log.h +* @author: Martin Fouilleul +* @date: 18/04/2023 +* +*****************************************************************/ +#ifndef __PLATFORM_LOG_H_ +#define __PLATFORM_LOG_H_ + +#include"platform.h" +#include"util/strings.h" + +typedef enum { LOG_LEVEL_ERROR, + LOG_LEVEL_WARNING, + LOG_LEVEL_INFO, + LOG_LEVEL_COUNT } log_level; + +typedef struct log_output log_output; + +extern log_output* LOG_DEFAULT_OUTPUT; + +MP_API void log_set_level(log_level level); +MP_API void log_set_output(log_output* output); +MP_API void log_push(log_level level, + str8 function, + str8 file, + int line, + const char* fmt, + ...); + +#define log_generic(level, msg, ...) log_push(level, STR8(__FUNCTION__), STR8(__FILE__), __LINE__, msg, ##__VA_ARGS__) + +#define log_error(msg, ...) log_generic(LOG_LEVEL_ERROR, msg, ##__VA_ARGS__) + +#ifndef LOG_COMPILE_WARNING + #define LOG_COMPILE_WARNING 1 +#endif + +#ifndef LOG_COMPILE_INFO + #define LOG_COMPILE_INFO 1 +#endif + +#if LOG_COMPILE_WARNING || LOG_COMPILE_INFO + #define log_warning(msg, ...) log_generic(LOG_LEVEL_WARNING, msg, ##__VA_ARGS__) + + #if LOG_COMPILE_INFO + #define log_info(msg, ...) log_generic(LOG_LEVEL_INFO, msg, ##__VA_ARGS__ ) + #else + #define log_info(msg, ...) + #endif +#else + #define log_warning(msg, ...) + #define log_info(msg, ...) +#endif + + +#endif //__PLATFORM_LOG_H_ diff --git a/src/ui.h b/src/ui.h index 5913c3e..4c4a843 100644 --- a/src/ui.h +++ b/src/ui.h @@ -1,549 +1,549 @@ -/************************************************************//** -* -* @file: ui.h -* @author: Martin Fouilleul -* @date: 08/08/2022 -* @revision: -* -*****************************************************************/ -#ifndef __UI_H_ -#define __UI_H_ - -#include"typedefs.h" -#include"lists.h" -#include"input_state.h" -#include"graphics.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct ui_key -{ - u64 hash; -} ui_key; - -typedef enum -{ - UI_AXIS_X, - UI_AXIS_Y, - UI_AXIS_COUNT -} ui_axis; - -typedef enum -{ - UI_ALIGN_START, - UI_ALIGN_END, - UI_ALIGN_CENTER, -} ui_align; - -typedef union ui_layout_align -{ - struct - { - ui_align x; - ui_align y; - }; - ui_align c[UI_AXIS_COUNT]; -} ui_layout_align; - -typedef struct ui_layout -{ - ui_axis axis; - f32 spacing; - union - { - struct - { - f32 x; - f32 y; - }; - f32 c[UI_AXIS_COUNT]; - } margin; - ui_layout_align align; - -} ui_layout; - -typedef enum ui_size_kind -{ - UI_SIZE_TEXT, - UI_SIZE_PIXELS, - UI_SIZE_CHILDREN, - UI_SIZE_PARENT, - UI_SIZE_PARENT_MINUS_PIXELS, - -} ui_size_kind; - -typedef struct ui_size -{ - ui_size_kind kind; - f32 value; - f32 relax; -} ui_size; - -typedef union ui_box_size -{ - struct - { - ui_size width; - ui_size height; - }; - ui_size c[UI_AXIS_COUNT]; -} ui_box_size; - -typedef union ui_box_floating -{ - struct - { - bool x; - bool y; - }; - bool c[UI_AXIS_COUNT]; -} ui_box_floating; - -//NOTE: flags for axis-dependent properties (e.g. UI_STYLE_FLOAT_X/Y) need to be consecutive bits -// in order to play well with axis agnostic functions -typedef u64 ui_style_mask; -enum -{ - UI_STYLE_NONE = 0, - UI_STYLE_SIZE_WIDTH = 1<<1, - UI_STYLE_SIZE_HEIGHT = 1<<2, - UI_STYLE_LAYOUT_AXIS = 1<<3, - UI_STYLE_LAYOUT_ALIGN_X = 1<<4, - UI_STYLE_LAYOUT_ALIGN_Y = 1<<5, - UI_STYLE_LAYOUT_SPACING = 1<<6, - UI_STYLE_LAYOUT_MARGIN_X = 1<<7, - UI_STYLE_LAYOUT_MARGIN_Y = 1<<8, - UI_STYLE_FLOAT_X = 1<<9, - UI_STYLE_FLOAT_Y = 1<<10, - UI_STYLE_COLOR = 1<<11, - UI_STYLE_BG_COLOR = 1<<12, - UI_STYLE_BORDER_COLOR = 1<<13, - UI_STYLE_BORDER_SIZE = 1<<14, - UI_STYLE_ROUNDNESS = 1<<15, - UI_STYLE_FONT = 1<<16, - UI_STYLE_FONT_SIZE = 1<<17, - UI_STYLE_ANIMATION_TIME = 1<<18, - UI_STYLE_ANIMATION_MASK = 1<<19, - - //masks - UI_STYLE_SIZE = UI_STYLE_SIZE_WIDTH - | UI_STYLE_SIZE_HEIGHT, - - UI_STYLE_LAYOUT_MARGINS = UI_STYLE_LAYOUT_MARGIN_X - | UI_STYLE_LAYOUT_MARGIN_Y, - - UI_STYLE_LAYOUT = UI_STYLE_LAYOUT_AXIS - | UI_STYLE_LAYOUT_ALIGN_X - | UI_STYLE_LAYOUT_ALIGN_Y - | UI_STYLE_LAYOUT_SPACING - | UI_STYLE_LAYOUT_MARGIN_X - | UI_STYLE_LAYOUT_MARGIN_Y, - - UI_STYLE_FLOAT = UI_STYLE_FLOAT_X - | UI_STYLE_FLOAT_Y, - - UI_STYLE_MASK_INHERITED = UI_STYLE_COLOR - | UI_STYLE_FONT - | UI_STYLE_FONT_SIZE - | UI_STYLE_ANIMATION_TIME - | UI_STYLE_ANIMATION_MASK, -}; - -typedef struct ui_style -{ - ui_box_size size; - ui_layout layout; - ui_box_floating floating; - vec2 floatTarget; - mg_color color; - mg_color bgColor; - mg_color borderColor; - mg_font font; - f32 fontSize; - f32 borderSize; - f32 roundness; - f32 animationTime; - ui_style_mask animationMask; -} ui_style; - -typedef struct ui_tag { u64 hash; } ui_tag; - -typedef enum -{ - UI_SEL_ANY, - UI_SEL_OWNER, - UI_SEL_TEXT, - UI_SEL_TAG, - UI_SEL_STATUS, - UI_SEL_KEY, - //... -} ui_selector_kind; - -typedef u8 ui_status; -enum -{ - UI_NONE = 0, - UI_HOVER = 1<<1, - UI_ACTIVE = 1<<2, - UI_DRAGGING = 1<<3, -}; - -typedef enum -{ - UI_SEL_DESCENDANT = 0, - UI_SEL_AND = 1, - //... -} ui_selector_op; - -typedef struct ui_selector -{ - list_elt listElt; - ui_selector_kind kind; - ui_selector_op op; - union - { - str8 text; - ui_key key; - ui_tag tag; - ui_status status; - //... - }; -} ui_selector; - -typedef struct ui_pattern { list_info l; } ui_pattern; - -typedef struct ui_box ui_box; - -typedef struct ui_style_rule -{ - list_elt boxElt; - list_elt buildElt; - list_elt tmpElt; - - ui_box* owner; - ui_pattern pattern; - ui_style_mask mask; - ui_style* style; -} ui_style_rule; - -typedef struct ui_sig -{ - ui_box* box; - - vec2 mouse; - vec2 delta; - vec2 wheel; - - bool pressed; - bool released; - bool clicked; - bool doubleClicked; - bool rightPressed; - - bool dragging; - bool hovering; - -} ui_sig; - -typedef void(*ui_box_draw_proc)(ui_box* box, void* data); - -typedef enum -{ - UI_FLAG_CLICKABLE = (1<<0), - UI_FLAG_SCROLL_WHEEL_X = (1<<1), - UI_FLAG_SCROLL_WHEEL_Y = (1<<2), - UI_FLAG_BLOCK_MOUSE = (1<<3), - UI_FLAG_HOT_ANIMATION = (1<<4), - UI_FLAG_ACTIVE_ANIMATION = (1<<5), - //WARN: these two following flags need to be kept as consecutive bits to - // play well with axis-agnostic functions - UI_FLAG_ALLOW_OVERFLOW_X = (1<<6), - UI_FLAG_ALLOW_OVERFLOW_Y = (1<<7), - UI_FLAG_CLIP = (1<<8), - UI_FLAG_DRAW_BACKGROUND = (1<<9), - UI_FLAG_DRAW_FOREGROUND = (1<<10), - UI_FLAG_DRAW_BORDER = (1<<11), - UI_FLAG_DRAW_TEXT = (1<<12), - UI_FLAG_DRAW_PROC = (1<<13), - - UI_FLAG_OVERLAY = (1<<14), -} ui_flags; - -struct ui_box -{ - // hierarchy - list_elt listElt; - list_info children; - ui_box* parent; - - list_elt overlayElt; - - // keying and caching - list_elt bucketElt; - ui_key key; - u64 frameCounter; - - // builder-provided info - ui_flags flags; - str8 string; - list_info tags; - - ui_box_draw_proc drawProc; - void* drawData; - - // styling - list_info beforeRules; - list_info afterRules; - - //ui_style_tag tag; - ui_style* targetStyle; - ui_style style; - u32 z; - - vec2 floatPos; - f32 childrenSum[2]; - f32 spacing[2]; - mp_rect rect; - - // signals - ui_sig* sig; - - // stateful behaviour - bool fresh; - bool closed; - bool parentClosed; - bool dragging; - bool hot; - bool active; - vec2 scroll; - - // animation data - f32 hotTransition; - f32 activeTransition; -}; - -//----------------------------------------------------------------------------- -// context -//----------------------------------------------------------------------------- - -enum { UI_MAX_INPUT_CHAR_PER_FRAME = 64 }; - -typedef struct ui_input_text -{ - u8 count; - utf32 codePoints[UI_MAX_INPUT_CHAR_PER_FRAME]; - -} ui_input_text; - -typedef struct ui_stack_elt ui_stack_elt; -struct ui_stack_elt -{ - ui_stack_elt* parent; - union - { - ui_box* box; - ui_size size; - mp_rect clip; - }; -}; - -typedef struct ui_tag_elt -{ - list_elt listElt; - ui_tag tag; -} ui_tag_elt; - -enum { UI_BOX_MAP_BUCKET_COUNT = 1024 }; - -typedef struct ui_context -{ - bool init; - - mp_input_state input; - - u64 frameCounter; - f64 frameTime; - f64 lastFrameDuration; - - mem_arena frameArena; - mem_pool boxPool; - list_info boxMap[UI_BOX_MAP_BUCKET_COUNT]; - - ui_box* root; - ui_box* overlay; - list_info overlayList; - ui_stack_elt* boxStack; - ui_stack_elt* clipStack; - - list_info nextBoxBeforeRules; - list_info nextBoxAfterRules; - list_info nextBoxTags; - - u32 z; - ui_box* hovered; - - ui_box* focus; - i32 editCursor; - i32 editMark; - i32 editFirstDisplayedChar; - f64 editCursorBlinkStart; - -} ui_context; - -//------------------------------------------------------------------------------------- -// UI context initialization and frame cycle -//------------------------------------------------------------------------------------- -MP_API void ui_init(ui_context* context); -MP_API ui_context* ui_get_context(void); -MP_API void ui_set_context(ui_context* context); - -MP_API void ui_process_event(mp_event* event); -MP_API void ui_begin_frame(vec2 size, ui_style* defaultStyle, ui_style_mask mask); -MP_API void ui_end_frame(void); -MP_API void ui_draw(void); - -#define ui_frame(size, style, mask) defer_loop(ui_begin_frame((size), (style), (mask)), ui_end_frame()) - -//------------------------------------------------------------------------------------- -// Box keys -//------------------------------------------------------------------------------------- -MP_API ui_key ui_key_make_str8(str8 string); -MP_API ui_key ui_key_make_path(str8_list path); - -MP_API ui_box* ui_box_lookup_key(ui_key key); -MP_API ui_box* ui_box_lookup_str8(str8 string); - -// C-string helper -#define ui_key_make(s) ui_key_make_str8(STR8(s)) -#define ui_box_lookup(s) ui_box_lookup_str8(STR8(s)) - -//------------------------------------------------------------------------------------- -// Box hierarchy building -//------------------------------------------------------------------------------------- -MP_API ui_box* ui_box_make_str8(str8 string, ui_flags flags); -MP_API ui_box* ui_box_begin_str8(str8 string, ui_flags flags); - -MP_API ui_box* ui_box_end(void); -#define ui_container(name, flags) defer_loop(ui_box_begin(name, flags), ui_box_end()) -#define ui_container_str8(name, flags) defer_loop(ui_box_begin_str8(name, flags), ui_box_end()) - -MP_API void ui_box_push(ui_box* box); -MP_API void ui_box_pop(void); -MP_API ui_box* ui_box_top(void); - -MP_API void ui_box_set_draw_proc(ui_box* box, ui_box_draw_proc proc, void* data); - -// C-string helpers -#define ui_box_lookup(s) ui_box_lookup_str8(STR8(s)) -#define ui_box_make(s, flags) ui_box_make_str8(STR8(s), flags) -#define ui_box_begin(s, flags) ui_box_begin_str8(STR8(s), flags) - -//------------------------------------------------------------------------------------- -// Box status and signals -//------------------------------------------------------------------------------------- -MP_API bool ui_box_closed(ui_box* box); -MP_API void ui_box_set_closed(ui_box* box, bool closed); - -MP_API bool ui_box_active(ui_box* box); -MP_API void ui_box_activate(ui_box* box); -MP_API void ui_box_deactivate(ui_box* box); - -MP_API bool ui_box_hot(ui_box* box); -MP_API void ui_box_set_hot(ui_box* box, bool hot); - -MP_API ui_sig ui_box_sig(ui_box* box); - -//------------------------------------------------------------------------------------- -// Tagging -//------------------------------------------------------------------------------------- -MP_API ui_tag ui_tag_make_str8(str8 string); -MP_API void ui_tag_box_str8(ui_box* box, str8 string); -MP_API void ui_tag_next_str8(str8 string); - -// C-string helpers -#define ui_tag_make(s) ui_tag_make_str8(STR8(s)) -#define ui_tag_box(b, s) ui_tag_box_str8(b, STR8(s)) -#define ui_tag_next(s) ui_tag_next_str8(STR8(s)) - -//------------------------------------------------------------------------------------- -// Styling -//------------------------------------------------------------------------------------- -//NOTE: styling API -//WARN: You can use a pattern in multiple rules, but be aware that a pattern is references an underlying list of selectors, -// hence pushing to a pattern also modifies rules in which the pattern was previously used! -MP_API void ui_apply_style_with_mask(ui_style* dst, ui_style* src, ui_style_mask mask); - -MP_API void ui_pattern_push(mem_arena* arena, ui_pattern* pattern, ui_selector selector); -MP_API ui_pattern ui_pattern_all(void); -MP_API ui_pattern ui_pattern_owner(void); - -MP_API void ui_style_next(ui_style* style, ui_style_mask mask); -MP_API void ui_style_match_before(ui_pattern pattern, ui_style* style, ui_style_mask mask); -MP_API void ui_style_match_after(ui_pattern pattern, ui_style* style, ui_style_mask mask); - -//------------------------------------------------------------------------- -// Basic widget helpers -//------------------------------------------------------------------------- -enum { - UI_STYLE_TAG_USER_MAX = 1<<16, - UI_STYLE_TAG_LABEL, - UI_STYLE_TAG_BUTTON, - UI_STYLE_TAG_SCROLLBAR, - UI_STYLE_TAG_PANEL, - UI_STYLE_TAG_TOOLTIP, - UI_STYLE_TAG_MENU -}; - -MP_API ui_sig ui_label(const char* label); -MP_API ui_sig ui_label_str8(str8 label); - -MP_API ui_sig ui_button(const char* label); -MP_API ui_sig ui_checkbox(const char* name, bool* checked); -MP_API ui_box* ui_slider(const char* label, f32 thumbRatio, f32* scrollValue); - -MP_API void ui_panel_begin(const char* name, ui_flags flags); -MP_API void ui_panel_end(void); -#define ui_panel(s, f) defer_loop(ui_panel_begin(s, f), ui_panel_end()) - -MP_API ui_sig ui_tooltip_begin(const char* name); -MP_API void ui_tooltip_end(void); -#define ui_tooltip(name) defer_loop(ui_tooltip_begin(name), ui_tooltip_end()) - -MP_API void ui_menu_bar_begin(const char* label); -MP_API void ui_menu_bar_end(void); -#define ui_menu_bar(name) defer_loop(ui_menu_bar_begin(name), ui_menu_bar_end()) - -MP_API void ui_menu_begin(const char* label); -MP_API void ui_menu_end(void); -#define ui_menu(name) defer_loop(ui_menu_begin(name), ui_menu_end()) - -MP_API ui_sig ui_menu_button(const char* name); - -typedef struct ui_text_box_result -{ - bool changed; - bool accepted; - str8 text; - -}ui_text_box_result; - -MP_API ui_text_box_result ui_text_box(const char* name, mem_arena* arena, str8 text); - - -typedef struct ui_select_popup_info -{ - bool changed; - int selectedIndex; - int optionCount; - str8* options; -} ui_select_popup_info; - -MP_API ui_select_popup_info ui_select_popup(const char* name, ui_select_popup_info* info); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif //__UI_H_ +/************************************************************//** +* +* @file: ui.h +* @author: Martin Fouilleul +* @date: 08/08/2022 +* @revision: +* +*****************************************************************/ +#ifndef __UI_H_ +#define __UI_H_ + +#include"util/typedefs.h" +#include"util/lists.h" +#include"input_state.h" +#include"graphics.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ui_key +{ + u64 hash; +} ui_key; + +typedef enum +{ + UI_AXIS_X, + UI_AXIS_Y, + UI_AXIS_COUNT +} ui_axis; + +typedef enum +{ + UI_ALIGN_START, + UI_ALIGN_END, + UI_ALIGN_CENTER, +} ui_align; + +typedef union ui_layout_align +{ + struct + { + ui_align x; + ui_align y; + }; + ui_align c[UI_AXIS_COUNT]; +} ui_layout_align; + +typedef struct ui_layout +{ + ui_axis axis; + f32 spacing; + union + { + struct + { + f32 x; + f32 y; + }; + f32 c[UI_AXIS_COUNT]; + } margin; + ui_layout_align align; + +} ui_layout; + +typedef enum ui_size_kind +{ + UI_SIZE_TEXT, + UI_SIZE_PIXELS, + UI_SIZE_CHILDREN, + UI_SIZE_PARENT, + UI_SIZE_PARENT_MINUS_PIXELS, + +} ui_size_kind; + +typedef struct ui_size +{ + ui_size_kind kind; + f32 value; + f32 relax; +} ui_size; + +typedef union ui_box_size +{ + struct + { + ui_size width; + ui_size height; + }; + ui_size c[UI_AXIS_COUNT]; +} ui_box_size; + +typedef union ui_box_floating +{ + struct + { + bool x; + bool y; + }; + bool c[UI_AXIS_COUNT]; +} ui_box_floating; + +//NOTE: flags for axis-dependent properties (e.g. UI_STYLE_FLOAT_X/Y) need to be consecutive bits +// in order to play well with axis agnostic functions +typedef u64 ui_style_mask; +enum +{ + UI_STYLE_NONE = 0, + UI_STYLE_SIZE_WIDTH = 1<<1, + UI_STYLE_SIZE_HEIGHT = 1<<2, + UI_STYLE_LAYOUT_AXIS = 1<<3, + UI_STYLE_LAYOUT_ALIGN_X = 1<<4, + UI_STYLE_LAYOUT_ALIGN_Y = 1<<5, + UI_STYLE_LAYOUT_SPACING = 1<<6, + UI_STYLE_LAYOUT_MARGIN_X = 1<<7, + UI_STYLE_LAYOUT_MARGIN_Y = 1<<8, + UI_STYLE_FLOAT_X = 1<<9, + UI_STYLE_FLOAT_Y = 1<<10, + UI_STYLE_COLOR = 1<<11, + UI_STYLE_BG_COLOR = 1<<12, + UI_STYLE_BORDER_COLOR = 1<<13, + UI_STYLE_BORDER_SIZE = 1<<14, + UI_STYLE_ROUNDNESS = 1<<15, + UI_STYLE_FONT = 1<<16, + UI_STYLE_FONT_SIZE = 1<<17, + UI_STYLE_ANIMATION_TIME = 1<<18, + UI_STYLE_ANIMATION_MASK = 1<<19, + + //masks + UI_STYLE_SIZE = UI_STYLE_SIZE_WIDTH + | UI_STYLE_SIZE_HEIGHT, + + UI_STYLE_LAYOUT_MARGINS = UI_STYLE_LAYOUT_MARGIN_X + | UI_STYLE_LAYOUT_MARGIN_Y, + + UI_STYLE_LAYOUT = UI_STYLE_LAYOUT_AXIS + | UI_STYLE_LAYOUT_ALIGN_X + | UI_STYLE_LAYOUT_ALIGN_Y + | UI_STYLE_LAYOUT_SPACING + | UI_STYLE_LAYOUT_MARGIN_X + | UI_STYLE_LAYOUT_MARGIN_Y, + + UI_STYLE_FLOAT = UI_STYLE_FLOAT_X + | UI_STYLE_FLOAT_Y, + + UI_STYLE_MASK_INHERITED = UI_STYLE_COLOR + | UI_STYLE_FONT + | UI_STYLE_FONT_SIZE + | UI_STYLE_ANIMATION_TIME + | UI_STYLE_ANIMATION_MASK, +}; + +typedef struct ui_style +{ + ui_box_size size; + ui_layout layout; + ui_box_floating floating; + vec2 floatTarget; + mg_color color; + mg_color bgColor; + mg_color borderColor; + mg_font font; + f32 fontSize; + f32 borderSize; + f32 roundness; + f32 animationTime; + ui_style_mask animationMask; +} ui_style; + +typedef struct ui_tag { u64 hash; } ui_tag; + +typedef enum +{ + UI_SEL_ANY, + UI_SEL_OWNER, + UI_SEL_TEXT, + UI_SEL_TAG, + UI_SEL_STATUS, + UI_SEL_KEY, + //... +} ui_selector_kind; + +typedef u8 ui_status; +enum +{ + UI_NONE = 0, + UI_HOVER = 1<<1, + UI_ACTIVE = 1<<2, + UI_DRAGGING = 1<<3, +}; + +typedef enum +{ + UI_SEL_DESCENDANT = 0, + UI_SEL_AND = 1, + //... +} ui_selector_op; + +typedef struct ui_selector +{ + list_elt listElt; + ui_selector_kind kind; + ui_selector_op op; + union + { + str8 text; + ui_key key; + ui_tag tag; + ui_status status; + //... + }; +} ui_selector; + +typedef struct ui_pattern { list_info l; } ui_pattern; + +typedef struct ui_box ui_box; + +typedef struct ui_style_rule +{ + list_elt boxElt; + list_elt buildElt; + list_elt tmpElt; + + ui_box* owner; + ui_pattern pattern; + ui_style_mask mask; + ui_style* style; +} ui_style_rule; + +typedef struct ui_sig +{ + ui_box* box; + + vec2 mouse; + vec2 delta; + vec2 wheel; + + bool pressed; + bool released; + bool clicked; + bool doubleClicked; + bool rightPressed; + + bool dragging; + bool hovering; + +} ui_sig; + +typedef void(*ui_box_draw_proc)(ui_box* box, void* data); + +typedef enum +{ + UI_FLAG_CLICKABLE = (1<<0), + UI_FLAG_SCROLL_WHEEL_X = (1<<1), + UI_FLAG_SCROLL_WHEEL_Y = (1<<2), + UI_FLAG_BLOCK_MOUSE = (1<<3), + UI_FLAG_HOT_ANIMATION = (1<<4), + UI_FLAG_ACTIVE_ANIMATION = (1<<5), + //WARN: these two following flags need to be kept as consecutive bits to + // play well with axis-agnostic functions + UI_FLAG_ALLOW_OVERFLOW_X = (1<<6), + UI_FLAG_ALLOW_OVERFLOW_Y = (1<<7), + UI_FLAG_CLIP = (1<<8), + UI_FLAG_DRAW_BACKGROUND = (1<<9), + UI_FLAG_DRAW_FOREGROUND = (1<<10), + UI_FLAG_DRAW_BORDER = (1<<11), + UI_FLAG_DRAW_TEXT = (1<<12), + UI_FLAG_DRAW_PROC = (1<<13), + + UI_FLAG_OVERLAY = (1<<14), +} ui_flags; + +struct ui_box +{ + // hierarchy + list_elt listElt; + list_info children; + ui_box* parent; + + list_elt overlayElt; + + // keying and caching + list_elt bucketElt; + ui_key key; + u64 frameCounter; + + // builder-provided info + ui_flags flags; + str8 string; + list_info tags; + + ui_box_draw_proc drawProc; + void* drawData; + + // styling + list_info beforeRules; + list_info afterRules; + + //ui_style_tag tag; + ui_style* targetStyle; + ui_style style; + u32 z; + + vec2 floatPos; + f32 childrenSum[2]; + f32 spacing[2]; + mp_rect rect; + + // signals + ui_sig* sig; + + // stateful behaviour + bool fresh; + bool closed; + bool parentClosed; + bool dragging; + bool hot; + bool active; + vec2 scroll; + + // animation data + f32 hotTransition; + f32 activeTransition; +}; + +//----------------------------------------------------------------------------- +// context +//----------------------------------------------------------------------------- + +enum { UI_MAX_INPUT_CHAR_PER_FRAME = 64 }; + +typedef struct ui_input_text +{ + u8 count; + utf32 codePoints[UI_MAX_INPUT_CHAR_PER_FRAME]; + +} ui_input_text; + +typedef struct ui_stack_elt ui_stack_elt; +struct ui_stack_elt +{ + ui_stack_elt* parent; + union + { + ui_box* box; + ui_size size; + mp_rect clip; + }; +}; + +typedef struct ui_tag_elt +{ + list_elt listElt; + ui_tag tag; +} ui_tag_elt; + +enum { UI_BOX_MAP_BUCKET_COUNT = 1024 }; + +typedef struct ui_context +{ + bool init; + + mp_input_state input; + + u64 frameCounter; + f64 frameTime; + f64 lastFrameDuration; + + mem_arena frameArena; + mem_pool boxPool; + list_info boxMap[UI_BOX_MAP_BUCKET_COUNT]; + + ui_box* root; + ui_box* overlay; + list_info overlayList; + ui_stack_elt* boxStack; + ui_stack_elt* clipStack; + + list_info nextBoxBeforeRules; + list_info nextBoxAfterRules; + list_info nextBoxTags; + + u32 z; + ui_box* hovered; + + ui_box* focus; + i32 editCursor; + i32 editMark; + i32 editFirstDisplayedChar; + f64 editCursorBlinkStart; + +} ui_context; + +//------------------------------------------------------------------------------------- +// UI context initialization and frame cycle +//------------------------------------------------------------------------------------- +MP_API void ui_init(ui_context* context); +MP_API ui_context* ui_get_context(void); +MP_API void ui_set_context(ui_context* context); + +MP_API void ui_process_event(mp_event* event); +MP_API void ui_begin_frame(vec2 size, ui_style* defaultStyle, ui_style_mask mask); +MP_API void ui_end_frame(void); +MP_API void ui_draw(void); + +#define ui_frame(size, style, mask) defer_loop(ui_begin_frame((size), (style), (mask)), ui_end_frame()) + +//------------------------------------------------------------------------------------- +// Box keys +//------------------------------------------------------------------------------------- +MP_API ui_key ui_key_make_str8(str8 string); +MP_API ui_key ui_key_make_path(str8_list path); + +MP_API ui_box* ui_box_lookup_key(ui_key key); +MP_API ui_box* ui_box_lookup_str8(str8 string); + +// C-string helper +#define ui_key_make(s) ui_key_make_str8(STR8(s)) +#define ui_box_lookup(s) ui_box_lookup_str8(STR8(s)) + +//------------------------------------------------------------------------------------- +// Box hierarchy building +//------------------------------------------------------------------------------------- +MP_API ui_box* ui_box_make_str8(str8 string, ui_flags flags); +MP_API ui_box* ui_box_begin_str8(str8 string, ui_flags flags); + +MP_API ui_box* ui_box_end(void); +#define ui_container(name, flags) defer_loop(ui_box_begin(name, flags), ui_box_end()) +#define ui_container_str8(name, flags) defer_loop(ui_box_begin_str8(name, flags), ui_box_end()) + +MP_API void ui_box_push(ui_box* box); +MP_API void ui_box_pop(void); +MP_API ui_box* ui_box_top(void); + +MP_API void ui_box_set_draw_proc(ui_box* box, ui_box_draw_proc proc, void* data); + +// C-string helpers +#define ui_box_lookup(s) ui_box_lookup_str8(STR8(s)) +#define ui_box_make(s, flags) ui_box_make_str8(STR8(s), flags) +#define ui_box_begin(s, flags) ui_box_begin_str8(STR8(s), flags) + +//------------------------------------------------------------------------------------- +// Box status and signals +//------------------------------------------------------------------------------------- +MP_API bool ui_box_closed(ui_box* box); +MP_API void ui_box_set_closed(ui_box* box, bool closed); + +MP_API bool ui_box_active(ui_box* box); +MP_API void ui_box_activate(ui_box* box); +MP_API void ui_box_deactivate(ui_box* box); + +MP_API bool ui_box_hot(ui_box* box); +MP_API void ui_box_set_hot(ui_box* box, bool hot); + +MP_API ui_sig ui_box_sig(ui_box* box); + +//------------------------------------------------------------------------------------- +// Tagging +//------------------------------------------------------------------------------------- +MP_API ui_tag ui_tag_make_str8(str8 string); +MP_API void ui_tag_box_str8(ui_box* box, str8 string); +MP_API void ui_tag_next_str8(str8 string); + +// C-string helpers +#define ui_tag_make(s) ui_tag_make_str8(STR8(s)) +#define ui_tag_box(b, s) ui_tag_box_str8(b, STR8(s)) +#define ui_tag_next(s) ui_tag_next_str8(STR8(s)) + +//------------------------------------------------------------------------------------- +// Styling +//------------------------------------------------------------------------------------- +//NOTE: styling API +//WARN: You can use a pattern in multiple rules, but be aware that a pattern is references an underlying list of selectors, +// hence pushing to a pattern also modifies rules in which the pattern was previously used! +MP_API void ui_apply_style_with_mask(ui_style* dst, ui_style* src, ui_style_mask mask); + +MP_API void ui_pattern_push(mem_arena* arena, ui_pattern* pattern, ui_selector selector); +MP_API ui_pattern ui_pattern_all(void); +MP_API ui_pattern ui_pattern_owner(void); + +MP_API void ui_style_next(ui_style* style, ui_style_mask mask); +MP_API void ui_style_match_before(ui_pattern pattern, ui_style* style, ui_style_mask mask); +MP_API void ui_style_match_after(ui_pattern pattern, ui_style* style, ui_style_mask mask); + +//------------------------------------------------------------------------- +// Basic widget helpers +//------------------------------------------------------------------------- +enum { + UI_STYLE_TAG_USER_MAX = 1<<16, + UI_STYLE_TAG_LABEL, + UI_STYLE_TAG_BUTTON, + UI_STYLE_TAG_SCROLLBAR, + UI_STYLE_TAG_PANEL, + UI_STYLE_TAG_TOOLTIP, + UI_STYLE_TAG_MENU +}; + +MP_API ui_sig ui_label(const char* label); +MP_API ui_sig ui_label_str8(str8 label); + +MP_API ui_sig ui_button(const char* label); +MP_API ui_sig ui_checkbox(const char* name, bool* checked); +MP_API ui_box* ui_slider(const char* label, f32 thumbRatio, f32* scrollValue); + +MP_API void ui_panel_begin(const char* name, ui_flags flags); +MP_API void ui_panel_end(void); +#define ui_panel(s, f) defer_loop(ui_panel_begin(s, f), ui_panel_end()) + +MP_API ui_sig ui_tooltip_begin(const char* name); +MP_API void ui_tooltip_end(void); +#define ui_tooltip(name) defer_loop(ui_tooltip_begin(name), ui_tooltip_end()) + +MP_API void ui_menu_bar_begin(const char* label); +MP_API void ui_menu_bar_end(void); +#define ui_menu_bar(name) defer_loop(ui_menu_bar_begin(name), ui_menu_bar_end()) + +MP_API void ui_menu_begin(const char* label); +MP_API void ui_menu_end(void); +#define ui_menu(name) defer_loop(ui_menu_begin(name), ui_menu_end()) + +MP_API ui_sig ui_menu_button(const char* name); + +typedef struct ui_text_box_result +{ + bool changed; + bool accepted; + str8 text; + +}ui_text_box_result; + +MP_API ui_text_box_result ui_text_box(const char* name, mem_arena* arena, str8 text); + + +typedef struct ui_select_popup_info +{ + bool changed; + int selectedIndex; + int optionCount; + str8* options; +} ui_select_popup_info; + +MP_API ui_select_popup_info ui_select_popup(const char* name, ui_select_popup_info* info); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif //__UI_H_