From: Brendan Hansen Date: Sun, 6 Jun 2021 04:39:57 +0000 (-0500) Subject: added printing of notes; added initial ui module X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=a64edd973b03048858121e1884b8016b8e9a7d90;p=onyx.git added printing of notes; added initial ui module --- diff --git a/bin/onyx b/bin/onyx index 92494b97..daf1e170 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index ab98b606..dae2a82a 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -80,6 +80,8 @@ NODE(SolidifiedFunction) \ NODE(PolyProc) \ \ + NODE(Note) \ + \ NODE(Package) #define NODE(name) typedef struct Ast ## name Ast ## name; @@ -179,6 +181,8 @@ typedef enum AstKind { Ast_Kind_Directive_Operator, Ast_Kind_Directive_Export, + Ast_Kind_Note, + Ast_Kind_Count } AstKind; @@ -934,6 +938,10 @@ struct AstDirectiveExport { AstTyped* export; }; +struct AstNote { + AstNode_base; +}; + typedef enum EntityState { Entity_State_Error, @@ -956,6 +964,7 @@ typedef enum EntityType { Entity_Type_Unknown, Entity_Type_Error, + Entity_Type_Note, Entity_Type_Load_Path, Entity_Type_Load_File, Entity_Type_Binding, @@ -1077,10 +1086,11 @@ struct CompileOptions { bh_allocator allocator; CompileAction action; - u32 verbose_output : 28; + u32 verbose_output : 2; b32 fun_output : 1; b32 print_function_mappings : 1; b32 print_static_if_results : 1; + b32 print_notes : 1; b32 use_post_mvp_features : 1; diff --git a/modules/immediate_mode/module.onyx b/modules/immediate_mode/module.onyx index acdc1769..fc992e23 100644 --- a/modules/immediate_mode/module.onyx +++ b/modules/immediate_mode/module.onyx @@ -1,4 +1,4 @@ - +@Rename package immediate_mode #load "./immediate_renderer" diff --git a/modules/ui/flow.onyx b/modules/ui/flow.onyx new file mode 100644 index 00000000..64f28692 --- /dev/null +++ b/modules/ui/flow.onyx @@ -0,0 +1,58 @@ +package ui + +// UI Flow + +Flow :: struct { + split_vertical :: proc { + (r: Rectangle, left_percent: f32) -> (left: Rectangle, right: Rectangle) { + return split_vertical(r, left_width=left_percent * Rectangle.width(r)); + }, + + (r: Rectangle, right_percent: f32) -> (left: Rectangle, right: Rectangle) { + return split_vertical(r, right_width=right_percent * Rectangle.width(r)); + }, + + (r: Rectangle, left_width: f32) -> (left: Rectangle, right: Rectangle) { + x0, y0 := Rectangle.top_left(r); + x1, y1 := Rectangle.bottom_right(r); + + return .{ x0=x0, x1=x0+left_width, y0=y0, y1=y1 }, + .{ x0=x0+left_width, x1=x1, y0=y0, y1=y1 }; + }, + + (r: Rectangle, right_width: f32) -> (left: Rectangle, right: Rectangle) { + x0, y0 := Rectangle.top_left(r); + x1, y1 := Rectangle.bottom_right(r); + + return .{ x0=x0, x1=x1-right_width, y0=y0, y1=y1 }, + .{ x0=x1-right_width, x1=x1, y0=y0, y1=y1 }; + } + } + + + split_horizontal :: proc { + (r: Rectangle, top_percent: f32) -> (top: Rectangle, bottom: Rectangle) { + return split_horizontal(r, top_height=top_percent * Rectangle.height(r)); + }, + + (r: Rectangle, bottom_percent: f32) -> (top: Rectangle, bottom: Rectangle) { + return split_horizontal(r, bottom_height=bottom_percent * Rectangle.height(r)); + }, + + (r: Rectangle, top_height: f32) -> (top: Rectangle, bottom: Rectangle) { + x0, y0 := Rectangle.top_left(r); + x1, y1 := Rectangle.bottom_right(r); + + return .{ x0=x0, x1=x1, y0=y0, y1=y0+top_height }, + .{ x0=x0, x1=x1, y0=y0+top_height, y1=y1 }; + }, + + (r: Rectangle, bottom_height: f32) -> (top: Rectangle, bottom: Rectangle) { + x0, y0 := Rectangle.top_left(r); + x1, y1 := Rectangle.bottom_right(r); + + return .{ x0=x0, x1=x1, y0=y0, y1=y1-bottom_height }, + .{ x0=x0, x1=x1, y0=y1-bottom_height, y1=y1 }; + } + } +} \ No newline at end of file diff --git a/modules/ui/module.onyx b/modules/ui/module.onyx new file mode 100644 index 00000000..834d1edd --- /dev/null +++ b/modules/ui/module.onyx @@ -0,0 +1,23 @@ +@Todo // document this module better + + +/* + +The goal of this module is to provide a low-friction method of producing simple +user interfaces in WebGL (and OpenGL when Onyx compiles to C). + +*/ + + + + + + + +@Rename +package ui + +use package immediate_mode // The immediate_mode module needs to be accessible + +#load "./ui" +#load "./flow" \ No newline at end of file diff --git a/modules/ui/resources/font.data b/modules/ui/resources/font.data new file mode 100644 index 00000000..615eafbd Binary files /dev/null and b/modules/ui/resources/font.data differ diff --git a/modules/ui/resources/font_2.data b/modules/ui/resources/font_2.data new file mode 100644 index 00000000..85287d47 Binary files /dev/null and b/modules/ui/resources/font_2.data differ diff --git a/modules/ui/ui.onyx b/modules/ui/ui.onyx new file mode 100644 index 00000000..90bbff38 --- /dev/null +++ b/modules/ui/ui.onyx @@ -0,0 +1,138 @@ +package ui + +#private_file gfx :: package immediate_mode +#private_file bitmap_font :: package bitmap_font +#private_file gl :: package gl +#private_file math :: package core.math + +#private font : bitmap_font.Bitmap_Font; +#private font_texture : gl.GLTexture; + +@Temporary +DEFAULT_TEXT_SIZE :: 32.0f + + + +init_ui :: () { + init_font(); +} + +#private init_font :: () { + font_data := #file_contents "./resources/font_2.data"; + + bft := bitmap_font.Bitmap_Font_Texture.{ + data = font_data, + width = 256, + height = 256, + }; + + font = bitmap_font.bitmap_font_create(bft, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 \xff:"); + + font_texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, font_texture); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 256, 256, 0, gl.RGBA, gl.UNSIGNED_BYTE, font_data); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.bindTexture(gl.TEXTURE_2D, -1); +} + +get_text_width :: (text: str, size := DEFAULT_TEXT_SIZE) -> f32 { + return font->get_width(text, size); +} + +// 'x' and 'y' are the top-left coordinates of the text. 'y' is NOT the baseline. +draw_text :: (text: str, x: f32, y: f32, size := DEFAULT_TEXT_SIZE, color := gfx.Color4.{1,1,1}) { + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, font_texture); + gfx.set_texture(0); + + for char: text { + glyph := font->get_glyph(char); + + if glyph == null { + glyph = font->get_glyph(255); + assert(glyph != null, "NO NULL GLYPH"); + } + + // Round to the nearest pixel + tx, ty := math.floor(x + .5), math.floor(y + .5); + w := math.floor(glyph.w * size * font.em + .5); + h := math.floor(glyph.h * size * font.em + .5); + + gfx.textured_rect( + .{ tx, ty }, + .{ w, h }, + .{ glyph.x0, glyph.y0 }, + .{ glyph.x1 - glyph.x0, glyph.y1 - glyph.y0 }, + color = color); + + x += glyph.w * size * font.em; + } + + gfx.flush(); + gl.bindTexture(gl.TEXTURE_2D, -1); +} + +draw_rect :: proc { + (use r: Rectangle, color := gfx.Color4.{1,1,1}) { + gfx.set_texture(); + + width, height := Rectangle.dimensions(r); + gfx.rect(.{ x0, y0 }, .{ width, height }, color); + }, + + (x: f32, y: f32, w: f32, h: f32, color := gfx.Color4.{1,1,1}) { + gfx.set_texture(); + gfx.rect(.{ x, y }, .{ w, h }, color); + } +} + +@Themeing +draw_button :: (use r: Rectangle, text: str) -> bool { + gfx.set_texture(); + + padding :: 10.0f @RawPixels + + width, height := Rectangle.dimensions(r); + + gfx.rect(.{ x0, y0 }, .{ width, height }, .{ 0.2, 0.2, 0.2 }); + gfx.rect(.{ x0 + padding, y0 + padding }, .{ width - padding * 2, height - padding * 2 }, .{ 0.1, 0.1, 0.1 }); + + font_size := height * .4; + text_width := font->get_width(text, font_size); + text_height := font->get_height(text, font_size); + + draw_text(text, x0 + (width - text_width) / 2, y0 + (height - text_height) / 2, font_size, .{ 1, 1, 1 }); + return false; +} + + + +Rectangle :: struct { + // + // x0,y0 ------------+ + // | | + // | | + // +------------ x1, y1 + // + + x0: f32 = 0; + y0: f32 = 0; + x1: f32 = 0; + y1: f32 = 0; + + width :: (use r: Rectangle) -> f32 do return math.abs(x1 - x0); + height :: (use r: Rectangle) -> f32 do return math.abs(y1 - y0); + + dimensions :: (use r: Rectangle) -> (width: f32, height: f32) { + return math.abs(x1 - x0), math.abs(y1 - y0); + } + + top_left :: (use r: Rectangle) -> (x: f32, y: f32) do return math.min(x0, x1), math.min(y0, y1); + bottom_right :: (use r: Rectangle) -> (x: f32, y: f32) do return math.max(x0, x1), math.max(y0, y1); +} + + + diff --git a/src/onyx.c b/src/onyx.c index 0a7b1d50..a6ff73c9 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -47,6 +47,7 @@ static const char* docstring = "Onyx compiler version " VERSION "\n" "Developer flags:\n" "\t--print-function-mappings Prints a mapping from WASM function index to source location.\n" "\t--print-static-if-results Prints the conditional result of each #if statement. Useful for debugging.\n" + "\t--print-notes Prints the location of notes throughout the loaded code.\n" "\n"; @@ -101,6 +102,9 @@ static CompileOptions compile_opts_parse(bh_allocator alloc, int argc, char *arg else if (!strcmp(argv[i], "--print-static-if-results")) { options.print_static_if_results = 1; } + else if (!strcmp(argv[i], "--print-notes")) { + options.print_notes = 1; + } else if (!strcmp(argv[i], "--use-post-mvp-features")) { options.use_post_mvp_features = 1; } diff --git a/src/onyxastnodes.c b/src/onyxastnodes.c index d185a243..531090b2 100644 --- a/src/onyxastnodes.c +++ b/src/onyxastnodes.c @@ -85,6 +85,8 @@ static const char* ast_node_names[] = { "OPERATOR OVERLOAD", "EXPORT", + "NOTE", + "AST_NODE_KIND_COUNT", }; @@ -120,6 +122,7 @@ const char* entity_state_strings[Entity_State_Count] = { const char* entity_type_strings[Entity_Type_Count] = { "Unknown", "Error", + "Note", "Add to Load Path", "Load File", "Binding (Declaration)", diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 0a4a82fd..44f5d097 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -118,7 +118,7 @@ CheckStatus check_return(AstReturn* retnode) { } else { if (expected_return_type->Basic.size > 0) { onyx_report_error(retnode->token->pos, - "Returning from non-void function without value. Expected a value of type '%s'.", + "Returning from non-void function without a value. Expected a value of type '%s'.", type_get_name(expected_return_type)); return Check_Error; } diff --git a/src/onyxentities.c b/src/onyxentities.c index e3f6afcc..3ba43d56 100644 --- a/src/onyxentities.c +++ b/src/onyxentities.c @@ -319,6 +319,14 @@ void add_entities_for_node(bh_arr(Entity *) *target_arr, AstNode* node, Scope* s ENTITY_INSERT(ent); break; } + + case Ast_Kind_Note: { + ent.type = Entity_Type_Note; + ent.expr = (AstTyped *) node; + ent.state = Entity_State_Code_Gen; + ENTITY_INSERT(ent); + break; + } default: { ent.type = Entity_Type_Expression; diff --git a/src/onyxparser.c b/src/onyxparser.c index 7643dc9c..8cebcf1f 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -76,8 +76,15 @@ static void consume_token(OnyxParser* parser) { parser->prev = parser->curr; // :LinearTokenDependent parser->curr++; - while (parser->curr->type == Token_Type_Comment || parser->curr->type == Token_Type_Note) + while (parser->curr->type == Token_Type_Comment || parser->curr->type == Token_Type_Note) { + if (parser->curr->type == Token_Type_Note) { + AstNote* note = make_node(AstNode, Ast_Kind_Note); + note->token = parser->curr; + ENTITY_SUBMIT(note); + } + parser->curr++; + } } static OnyxToken* find_matching_paren(OnyxToken* paren) { @@ -2487,7 +2494,7 @@ void onyx_parser_free(OnyxParser* parser) { void onyx_parse(OnyxParser *parser) { // NOTE: Skip comments at the beginning of the file - while (consume_token_if_next(parser, Token_Type_Comment)); + while (consume_token_if_next(parser, Token_Type_Comment) || consume_token_if_next(parser, Token_Type_Note)); parser->package = parse_file_package(parser); parser->file_scope = scope_create(parser->allocator, parser->package->private_scope, parser->tokenizer->tokens[0].pos); diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 4e8e9248..ed1824d5 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -3314,6 +3314,18 @@ void emit_entity(Entity* ent) { case Entity_Type_Function: emit_function(module, ent->function); break; case Entity_Type_Global: emit_global(module, ent->global); break; + // Cleanup: Maybe these should be printed elsewhere? + case Entity_Type_Note: { + if (!context.options->print_notes) break; + + AstNote* note = (AstNote *) ent->expr; + OnyxFilePos pos = note->token->pos; + + bh_printf("Note: %b %s:%d:%d\n", note->token->text, note->token->length, pos.filename, pos.line, pos.column); + + break; + } + default: break; }