From: Brendan Hansen Date: Thu, 18 Feb 2021 20:20:04 +0000 (-0600) Subject: adding parsing; almost done with MVP work X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=524d60b9e92837c32b14c3ccdee30b428aa6a51e;p=onyx-prez.git adding parsing; almost done with MVP work --- diff --git a/dist/index.js b/dist/index.js index d484d49..a6d9989 100644 --- a/dist/index.js +++ b/dist/index.js @@ -108,6 +108,10 @@ let canvas_import_obj = { canvasCtx.font = str; }, + setColor(canvas, r, g, b, a) { + canvasCtx.fillStyle = `rgba(${r * 255}, ${g * 255}, ${b * 255}, ${a})`; + }, + measureText(canvas, text_ptr, text_len, measure_ptr) { const data = new Uint8Array(wasm_instance.exports.memory.buffer, text_ptr, text_len); const text = new TextDecoder().decode(data); @@ -131,8 +135,6 @@ let canvas_import_obj = { const data = new Uint8Array(wasm_instance.exports.memory.buffer, text_ptr, text_len); const str = new TextDecoder().decode(data); - canvasCtx.fillStyle = "#ffffff"; - if (max_width > 0) canvasCtx.fillText(str, x, y, max_width); else canvasCtx.fillText(str, x, y); }, diff --git a/src/build.onyx b/src/build.onyx index e5f5cde..4892f68 100644 --- a/src/build.onyx +++ b/src/build.onyx @@ -10,3 +10,4 @@ use package build_opts as build_opts #load "src/events" #load "src/slides" #load "src/canvas" +#load "src/show_parser" diff --git a/src/canvas.onyx b/src/canvas.onyx index 6dfe2ad..1bb1967 100644 --- a/src/canvas.onyx +++ b/src/canvas.onyx @@ -12,6 +12,7 @@ Canvas :: struct { set_size :: (handle: Handle, width: u32, height: u32) -> void #foreign "canvas" "set_size" --- set_font :: (handle: Handle, font_name: str) -> u32 #foreign "canvas" "setFont" --- + set_color :: (handle: Handle, r: f32, g: f32, b: f32, a := 1.0f) -> void #foreign "canvas" "setColor" --- TextMetrics :: struct { width : f32; diff --git a/src/prez.onyx b/src/prez.onyx index a3e26e4..6353357 100644 --- a/src/prez.onyx +++ b/src/prez.onyx @@ -60,82 +60,12 @@ loop :: () -> void #export "loop" { the_slideshow : Slideshow; -create_dummy_show :: () { - the_slideshow = slideshow_make(); - - { // Slide 1 - slide := slideshow_insert_slide(^the_slideshow); - slide_init(slide, background_color = Color.{ 0.1, 0.1, 0.2 }, item_count = 2); - - slide.items[0] = slideshow_make_item(^the_slideshow); - slide.items[0].kind = Slide_Item.Kind.Text; - slide.items[0].text.text = "Hello, World!"; - slide.items[0].text.y_pos = .5; - slide.items[0].text.font_name = "Arail"; - slide.items[0].text.font_size = 72; - slide.items[0].text.font_attr = Slide_Item_Text.FontAttributes.Bold; - slide.items[0].text.justify = Slide_Item_Text.Justify.Center; - - slide.items[1] = slideshow_make_item(^the_slideshow); - slide.items[1].kind = Slide_Item.Kind.Text; - slide.items[1].text.text = "Another, smaller, line of text below the first!"; - slide.items[1].text.y_pos = .6; - slide.items[1].text.font_name = "Arail"; - slide.items[1].text.font_size = 36; - slide.items[1].text.font_attr = Slide_Item_Text.FontAttributes.Italic; - slide.items[1].text.padding = .07; - slide.items[1].text.justify = Slide_Item_Text.Justify.Right; - } - - { // Slide 2 - slide := slideshow_insert_slide(^the_slideshow); - slide_init(slide, background_color = Color.{ 0.2, 0.1, 0.1 }, item_count = 4); - - slide.items[0] = slideshow_make_item(^the_slideshow); - slide.items[0].kind = Slide_Item.Kind.Text; - slide.items[0].text.text = "The Second Slide!"; - slide.items[0].text.y_pos = .2; - slide.items[0].text.font_name = "Arail"; - slide.items[0].text.font_size = 72; - slide.items[0].text.font_attr = Slide_Item_Text.FontAttributes.Bold; - slide.items[0].text.justify = Slide_Item_Text.Justify.Center; - - slide.items[1] = slideshow_make_item(^the_slideshow); - slide.items[1].kind = Slide_Item.Kind.Text; - slide.items[1].text.text = "Here is some monospace text."; - slide.items[1].text.y_pos = .3; - slide.items[1].text.font_name = "monospace"; - slide.items[1].text.font_size = 36; - slide.items[1].text.padding = .07; - slide.items[1].text.justify = Slide_Item_Text.Justify.Left; - - slide.items[2] = slideshow_make_item(^the_slideshow); - slide.items[2].text = Slide_Item_Text.{ - text = "Here is a block of much longer text that will not wrap correctly, which is annoying but I think the best thing to do is... I don't know yet.", - y_pos = .35, - font_name = "Calibri", - font_size = 36, - padding = .07, - justify = Slide_Item_Text.Justify.Left, - }; - - slideshow_load_image(^the_slideshow, "first_image", "images/first.jpg"); - - slide.items[3] = slideshow_make_item(^the_slideshow); - slide.items[3].image = Slide_Item_Image.{ - name = "first_image", - x = .3, - y = .4, - width = .4, - }; - } -} - main :: (args: [] cstr) { setup_canvas(); event.init(); - create_dummy_show(); + the_slideshow = slideshow_make(); + parse_slideshow(#file_contents "test.prez", ^the_slideshow); start_loop :: () -> void #foreign "host" "start_loop" --- start_loop(); diff --git a/src/show_parser.onyx b/src/show_parser.onyx new file mode 100644 index 0000000..b83e8ce --- /dev/null +++ b/src/show_parser.onyx @@ -0,0 +1,219 @@ +use package core + +parse_slideshow :: (source: str, slideshow: ^Slideshow) { + use io + + parse_arena := alloc.arena.make(context.allocator, arena_size = 16 * 1024); + defer alloc.arena.free(^parse_arena); + + parse_alloc := alloc.arena.make_allocator(^parse_arena); + + show_stream := string_stream_make(source); + show_reader := reader_make(^show_stream); + + default_text_style := Slide_Item_Text.{ + font_name = "Calibri", + font_size = 12, + text = "UNDEFINED TEXT", + y_pos = 0, padding = 0, justify = Slide_Item_Text.Justify.Left, + }; + + text_styles := map.make(str, Slide_Item_Text, default_text_style); + defer map.free(^text_styles); + + current_slide: ^Slide; + current_item_idx := 0; + current_text_style: Slide_Item_Text; + + while !stream_end_of_file(^show_stream) { + skip_whitespace(^show_reader); + defer skip_whitespace(^show_reader); + + _, next_byte := stream_peek_byte(^show_stream); + switch next_byte { + case #char "[" { + // Command + read_byte(^show_reader); + + command_name := read_word(^show_reader, allocator=parse_alloc); + printf("Parsing command: %s\n", command_name); + + if command_name == "slide" { + prev_slide := ^slideshow.slides[slideshow.slides.count - 1]; + current_slide = slideshow_insert_slide(slideshow); + current_item_idx = 0; + + // @Robustness @Incomplete: Currently, there is a fixed number of items + // on EVERY slide, which both wastes memory for small slides, and limits + // how many things can be in a slide. + slide_init(current_slide, background_color=prev_slide.background, item_count = 16); + } + elseif command_name == "background" { + r, g, b := parse_color(^show_reader); + current_slide.background = Color.{ r, g, b }; + } + elseif command_name == "y" { + y := read_u32(^show_reader); + current_text_style.y_pos = cast(f32) y / 100; + } + elseif command_name == "text_style" { + text_style_name := read_word(^show_reader, numeric_allowed=true); + if !map.has(^text_styles, text_style_name) { + printf("Text style '%s' was never defined.\n", text_style_name); + } + + text_style := map.get(^text_styles, text_style_name); + current_text_style = text_style; + + parse_text_style(^show_reader, ^current_text_style, parse_alloc); + } + elseif command_name == "define_text_style" { + text_style_name := read_word(^show_reader, numeric_allowed=true); + + current_text_style = default_text_style; + parse_text_style(^show_reader, ^current_text_style, parse_alloc); + map.put(^text_styles, text_style_name, current_text_style); + } + elseif command_name == "load_image" { + image_name := read_word(^show_reader, numeric_allowed=true); + image_path := parse_string(^show_reader, allocator=parse_alloc); + + slideshow_load_image(slideshow, image_name, image_path); + } + elseif command_name == "image" { + new_slide_image := slideshow_make_item(slideshow); + new_slide_image.kind = Slide_Item.Kind.Image; + parse_image_style(^show_reader, ^new_slide_image.image, parse_alloc); + + current_slide.items[current_item_idx] = new_slide_image; + current_item_idx += 1; + } + else { + printf("******** Unknown command: '%s'.\n", command_name); + } + + read_until(^show_reader, #char "]", allocator=parse_alloc, consume_end=true); + } + + // @Memory: should be able to use advance_line here instead, but + // there are some issue with that consuming two lines instead. + case #char "#" do read_line(^show_reader, allocator=parse_alloc); + + case #default { + // @Memory + text := read_line(^show_reader); + + new_slide_text := slideshow_make_item(slideshow); + new_slide_text.text = current_text_style; + new_slide_text.text.text = text; // Oofta... + + current_slide.items[current_item_idx] = new_slide_text; + current_item_idx += 1; + } + } + } + + printf("Total slide count: %i\n", slideshow.slides.count); +} + +#private_file +parse_text_style :: (reader: ^io.Reader, text_style: ^Slide_Item_Text, parse_alloc := context.allocator) { + use io + + while !stream_end_of_file(reader.stream) && peek_byte(reader) != #char "]" { + skip_whitespace(reader); + defer skip_whitespace(reader); + style_name := read_word(reader, allocator=parse_alloc); + + if style_name == "color" { + r, g, b := parse_color(reader); + text_style.color = Color.{ r, g, b }; + printf("Parsed color: %f %f %f\n", r, g, b); + } + elseif style_name == "font_size" { + text_style.font_size = read_u32(reader); + } + elseif style_name == "font_name" { + text_style.font_name = parse_string(reader); + } + elseif style_name == "font_attr" { + font_attr := read_word(reader, allocator=parse_alloc); + + if font_attr == "bold" do text_style.font_attr |= Slide_Item_Text.FontAttributes.Bold; + elseif font_attr == "italic" do text_style.font_attr |= Slide_Item_Text.FontAttributes.Italic; + } + elseif style_name == "padding" { + padding := read_u32(reader); + text_style.padding = cast(f32) padding / 100; + } + elseif style_name == "left" do text_style.justify = Slide_Item_Text.Justify.Left; + elseif style_name == "centered" do text_style.justify = Slide_Item_Text.Justify.Center; + elseif style_name == "right" do text_style.justify = Slide_Item_Text.Justify.Right; + else { + use package core { printf as pf } + pf("Unknown style option: '%s'\n", style_name); + advance_line(reader); + break; + } + } +} + +#private_file +parse_image_style :: (reader: ^io.Reader, image_style: ^Slide_Item_Image, parse_alloc := context.allocator) { + use io + + image_name := read_word(reader, numeric_allowed=true); + image_style.name = image_name; + + while !stream_end_of_file(reader.stream) && peek_byte(reader) != #char "]" { + skip_whitespace(reader); + defer skip_whitespace(reader); + style_name := read_word(reader, allocator=parse_alloc); + + if style_name == "x" { + x := read_u32(reader); + image_style.x = cast(f32) x / 100; + } + elseif style_name == "y" { + y := read_u32(reader); + image_style.y = cast(f32) y / 100; + } + elseif style_name == "width" { + width := read_u32(reader); + image_style.width = cast(f32) width / 100; + } + else { + use package core { printf as pf } + pf("Unknown style option: '%s'\n", style_name); + advance_line(reader); + break; + } + } +} + +#private_file +parse_color :: (reader: ^io.Reader) -> (f32, f32, f32) { + r := io.read_u32(reader); + g := io.read_u32(reader); + b := io.read_u32(reader); + + fr := cast(f32) r / 255; + fg := cast(f32) g / 255; + fb := cast(f32) b / 255; + + return fr, fg, fb; +} + +#private_file +parse_string :: (reader: ^io.Reader, allocator := context.allocator) -> str { + use io + + // @Cleanup + dummy := read_until(reader, #char "\"", context.temp_allocator); + read_byte(reader); + + str_contents := read_until(reader, #char "\"", allocator=allocator); + read_byte(reader); + + return str_contents; +} diff --git a/src/slides.onyx b/src/slides.onyx index 5b26633..122247d 100644 --- a/src/slides.onyx +++ b/src/slides.onyx @@ -171,6 +171,7 @@ slide_item_render :: (use slide_item: ^Slide_Item, slide: ^Slide) { switch kind { case Text { set_font_for_text(slide_item); + set_color(canvas, text.color.r, text.color.g, text.color.b, text.color.a); use Slide_Item_Text.Justify switch text.justify { @@ -205,6 +206,12 @@ slide_item_render :: (use slide_item: ^Slide_Item, slide: ^Slide) { width, height := cast(f32) get_width(canvas), cast(f32) get_height(canvas); // @Speed: There is a much better way of doing this... + // @Robustness: Currently, because HTML images are asynchronously loaded, + // the image dimensions are not known when the load_image call is made. + // These means that the dimensions need to be queried later once the image + // has been loaded. The real bad thing here, is that the 'html_image' being + // passed is a local copy from the image_map. This means everytime this image + // is drawn, it has to requery the image dimensions... Uck... store_image_size :: (html_image: ^HTML_Image) -> void #foreign "html" "store_image_size" --- store_image_size(^html_image); diff --git a/test.prez b/test.prez new file mode 100644 index 0000000..05936fc --- /dev/null +++ b/test.prez @@ -0,0 +1,39 @@ + +[define_text_style normal_text color 255 255 255 font_size 36 font_name "Arial" left padding 10] +[define_text_style bold_title color 255 255 255 font_attr bold font_size 72 font_name "Arial" centered] + +[load_image first_image "images/first.jpg"] + +# ------------------------------------------------------------------ +[slide] +[background 25 25 40] +[text_style bold_title] +[y 50] +First slide title! + +# ------------------------------------------------------------------ +[slide] +[background 40 25 25] +[text_style bold_title] +[y 10] +Second slide title! + +[text_style normal_text] +[y 20] +Some normal looking text is here. + +# Robustness: This shouldn't be necessary to declare. + +[text_style normal_text font_attr bold] +[y 25] +Some more normal looking text is here. + +[image first_image x 30 y 30 width 40] + +# ------------------------------------------------------------------ +[slide] +[text_style bold_title color 255 50 50 font_size 96 font_attr italic] +[y 10] +Bigger image! + +[image first_image x 25 width 50 y 15]