added printing of notes; added initial ui module
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 6 Jun 2021 04:39:57 +0000 (23:39 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 6 Jun 2021 04:39:57 +0000 (23:39 -0500)
14 files changed:
bin/onyx
include/onyxastnodes.h
modules/immediate_mode/module.onyx
modules/ui/flow.onyx [new file with mode: 0644]
modules/ui/module.onyx [new file with mode: 0644]
modules/ui/resources/font.data [new file with mode: 0644]
modules/ui/resources/font_2.data [new file with mode: 0644]
modules/ui/ui.onyx [new file with mode: 0644]
src/onyx.c
src/onyxastnodes.c
src/onyxchecker.c
src/onyxentities.c
src/onyxparser.c
src/onyxwasm.c

index 92494b97dca9749225e652172fefebe84d78179e..daf1e170b4927e19390c5704a3ea109718bcaad3 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index ab98b6069ec6f293ec51291f3e87bb8975a2f410..dae2a82a8aea49795ff07b46fcb02af1d09fe6ca 100644 (file)
@@ -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;
 
index acdc17694575651162121b8a2a6ba458369b7a07..fc992e234dee0258cc3aa7ecb57355b8b6e847a6 100644 (file)
@@ -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 (file)
index 0000000..64f2869
--- /dev/null
@@ -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 (file)
index 0000000..834d1ed
--- /dev/null
@@ -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 (file)
index 0000000..615eafb
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 (file)
index 0000000..85287d4
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 (file)
index 0000000..90bbff3
--- /dev/null
@@ -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);
+}
+
+
+
index 0a7b1d50c85438feaaaa74482340c7094cc7dc34..a6ff73c9e75c9186146ff0b0ef974e5241968932 100644 (file)
@@ -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;
             }
index d185a243cd04a3e07b68138c790e52e885362b20..531090b28414eeba7930b83f464802d562a77bad 100644 (file)
@@ -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)",
index 0a4a82fd4a9fb2a0aa748bcf3a769878701c5555..44f5d097a89b327ff0cdd3b9add567e46884144e 100644 (file)
@@ -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 value. Expected a value of type '%s'.",
                 type_get_name(expected_return_type));
             return Check_Error;
         }
index e3f6afcca9175fd3c4fac728ebf38795902b84e3..3ba43d5614c914d78d9d15de7316b48fc6665e74 100644 (file)
@@ -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;
index 7643dc9c309f70d8942c7da6023d626c4f764187..8cebcf1f37c02428d8d8bb3f2de37a66e03565cf 100644 (file)
@@ -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);
index 4e8e92483f2ed4f7315e96930f49e93164a7ffe6..ed1824d5ce9219665abac1119d67151b3c2fd9fc 100644 (file)
@@ -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;
     }