summaryrefslogtreecommitdiff
path: root/src/main.odin
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.odin')
-rw-r--r--src/main.odin492
1 files changed, 440 insertions, 52 deletions
diff --git a/src/main.odin b/src/main.odin
index dacbc87..11cea8e 100644
--- a/src/main.odin
+++ b/src/main.odin
@@ -6,15 +6,18 @@ import "core:math"
import "core:os"
import "core:strconv"
import "core:reflect"
+import "core:strings"
-waveform_a : []f32 : {0.0, 0.1, 0.5, 0.3, 0.1, -0.1, 0.0, 0.0, 0.0, 0.0, 0.1, 0.3, 0.0}
-waveform_b : []f32 : {0.0, 0.0, 0.0, 0.2, 0.4, 0.2, -0.1, 0.0, 0.0, 0.1, 0.3, 0.1, 0.0}
+MONO_FONT :: #load("../res/RedHatMono.ttf")
+font : rl.Font
+BLACK : rl.Color = {16, 16, 16, 255}
YELLOW : rl.Color = {254, 175, 1, 255}
ORANGE : rl.Color = {238, 123, 26, 255}
RED : rl.Color = {222, 73, 50, 255}
-LERP_SPEED :: 0.20
+LERP_SPEED :: 0.10
+HIGHLIGHT_THICKNESS :: 4
layout :: struct {
wave_a_start : rl.Vector2,
@@ -26,31 +29,272 @@ layout :: struct {
wave_b_amp : f32,
grid_opacity : f32,
- grid_highlight_opacity : f32,
- grid_highlight_position : rl.Vector2,
+ grid_data_opacity : f32,
+ highlight_opacity : f32,
+ highlight_index : int,
+ highlight_position : rl.Vector2,
+ highlight_dimensions : rl.Vector2,
+ arrow_thickness : f32,
+ arrow_chopping : f32,
+ heatmap_opacity : f32,
+
+ billing : f32,
+
+ camera_position : rl.Vector2,
+ camera_zoom : f32,
+
+ grid_start : rl.Vector2
+ grid_end : rl.Vector2
}
+waveform_a := [?]f32{0.0, 0.1, 0.5, 0.3, 0.1, -0.1, 0.0, 0.0, 0.0, 0.1, 0.3, 0.0}
+waveform_b := [?]f32{0.0, 0.0, 0.0, 0.2, 0.4, 0.2, -0.1, 0.0, 0.1, 0.3, 0.1, 0.0}
+
+data_frames : [dynamic][len(waveform_a)*len(waveform_b)]cell
+
+
+
slides : [dynamic]layout
state : layout
target : layout
+data_state : [len(waveform_a)*len(waveform_b)]cell
+data_target : [len(waveform_a)*len(waveform_b)]cell
delta : f32
+
+
+
init_slides :: proc() {
- // 0
- current_slide : layout = {
- wave_a_start = {-600, -250},
- wave_a_end = {600, -250},
- wave_a_amp = 250,
+ // ---------------------------- Waveforms
+ c : layout = {
+ wave_a_start = {-600, -200},
+ wave_a_end = {600, -200},
+ wave_a_amp = 260,
- wave_b_start = {-600, 250},
- wave_b_end = {600, 250},
- wave_b_amp = 250,
+ wave_b_start = {-600, 200},
+ wave_b_end = {600, 200},
+ wave_b_amp = 260,
grid_opacity = 0,
- grid_highlight_opacity = 0,
- grid_highlight_position = 0,
+ grid_data_opacity = 0,
+ highlight_opacity = 0,
+ highlight_position = 0,
+ arrow_thickness = 3,
+ arrow_chopping = 0.3,
+
+ heatmap_opacity = 0.5,
+
+ billing = f32(len(waveform_a)),
+
+ grid_start = {-400, 350},
+ grid_end = { 400, -450},
+ }
+ d : [12*12]cell
+ highlight_rect := rect_from_index(0, HIGHLIGHT_THICKNESS)
+ c.highlight_dimensions = {highlight_rect.width, highlight_rect.height}
+ c.highlight_position = {highlight_rect.x, highlight_rect.y}
+
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- Move waveforms into place
+ c.wave_a_start = {grid_start.x, grid_start.y+120}
+ c.wave_a_end = {grid_end.x , grid_start.y+120}
+ c.wave_b_start = {grid_start.x-120, grid_start.y}
+ c.wave_b_end = {grid_start.x-120, grid_end.y}
+ c.wave_a_amp = 120
+ c.wave_b_amp = 130
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- Show grid
+ c.grid_opacity = 1
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- Show data numbers
+ c.grid_data_opacity = 1
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- Infinity coating
+ for _, i in waveform_a {
+ if i==0 do continue
+ d[i_from_xy(i, 0)].cost = math.INF_F32
+ d[i_from_xy(0, i)].cost = math.INF_F32
}
- append(&slides, current_slide)
+ append(&slides, c)
+ append(&data_frames, d)
+
+
+
+ // ---------------------------- FIRST CELL
+ d[i_from_xy(1,1)].cost = distance(waveform_a[1], waveform_b[1])
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- Detecting minimum direction for first cost calculation
+ d[i_from_xy(1,1)].direction = .DIAGONAL
+ append(&slides, c)
+ append(&data_frames, d)
+
+
+
+ // ---------------------------- SECOND CELL
+ d[i_from_xy(2,1)].cost = distance(waveform_a[2], waveform_b[1])
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- Detecting minimum direction for second cost calculation
+
+ d[i_from_xy(2,1)].direction = .LEFT
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- Adding previous minimum to second cost calculation
+ d[i_from_xy(2,1)].cost += d[i_from_xy(1,1)].cost
+ append(&slides, c)
+ append(&data_frames, d)
+
+
+
+ // ---------------------------- THIRD CELL
+ d[i_from_xy(1,2)].cost += distance(waveform_a[1], waveform_b[2])
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- Detect minimum
+ d[i_from_xy(1,2)].direction = .DOWN
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- Add minimum
+ d[i_from_xy(1,2)].cost += d[i_from_xy(1,1)].cost
+ append(&slides, c)
+ append(&data_frames, d)
+
+
+
+ // ---------------------------- FOURTH CELL
+ d[i_from_xy(2,2)].cost += distance(waveform_a[2], waveform_b[2])
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- Detect minimum
+ a_cost, a_direction := three_min(d[i_from_xy(1,2)],
+ d[i_from_xy(1,1)],
+ d[i_from_xy(2,1)])
+ d[i_from_xy(2,2)].cost += a_cost
+ d[i_from_xy(2,2)].direction = a_direction
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- FIFTH CELL
+ full_calc(d[:], 1, 3)
+ append(&slides, c)
+ append(&data_frames, d)
+
+
+ // ---------------------------- SIXTH CELL
+ full_calc(d[:], 3, 1)
+ append(&slides, c)
+ append(&data_frames, d)
+
+
+ // ---------------------------- WAVEFRONT first half
+ for i in 4..<len(waveform_a) {
+ coord : [2]int = {i, 1}
+ for {
+ full_calc(d[:], coord.x, coord.y)
+ if coord.x==1 do break
+ coord += {-1, 1}
+ }
+ append(&slides, c)
+ append(&data_frames, d)
+ }
+ // ---------------------------- WAVEFRONT second half
+ for i in 2..<len(waveform_a) {
+ coord : [2]int = {len(waveform_a)-1, i}
+ for {
+ full_calc(d[:], coord.x, coord.y)
+ if coord.y==len(waveform_b)-1 do break
+ coord += {-1, 1}
+ }
+ append(&slides, c)
+ append(&data_frames, d)
+ }
+
+ // ---------------------------- Disregard the numbers
+ c.grid_data_opacity = 0
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- Follow the arrows
+ c.arrow_thickness = 6
+ c.arrow_chopping = 0.25
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- Pathfollowing
+ coord : [2]int = {len(waveform_a)-1, len(waveform_b)-1}
+ for {
+ d[i_from_xy(coord.x, coord.y)].stepped_in = 1
+ #partial switch d[i_from_xy(coord.x, coord.y)].direction {
+ case .LEFT:
+ coord -= {1, 0}
+ case .DIAGONAL:
+ coord -= {1, 1}
+ case .DOWN:
+ coord -= {0, 1}
+ }
+ append(&slides, c)
+ append(&data_frames, d)
+ if coord == {0,0} do break
+ }
+
+ // ---------------------------- Final step
+ d[0].stepped_in = 1
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ---------------------------- Look at the pattern
+ c.arrow_thickness = 0
+ c.arrow_chopping = 0.49
+ c.heatmap_opacity = 1
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ----------------------------
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ----------------------------
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ----------------------------
+ append(&slides, c)
+ append(&data_frames, d)
+
+ // ----------------------------
+ append(&slides, c)
+ append(&data_frames, d)
+}
+
+rect_from_index :: proc(i : int, thickness : f32 = 0) -> rl.Rectangle {
+ // rect is top left corener and dimensions
+ width := abs(grid_end.x - grid_start.x)
+ height := abs(grid_end.y - grid_start.y)
+ intergrid_dimensions : rl.Vector2 = {width, height}
+ cell_dimensions := intergrid_dimensions/f32(len(waveform_a)-1)
+ position_zero := grid_start-(cell_dimensions/2)
+ output := position_zero + cell_dimensions * {f32(i%len(waveform_a)), -f32(i/len(waveform_b))}
+ thickness_offset := thickness/2
+ return {output.x-thickness_offset, output.y-thickness_offset, cell_dimensions.x+thickness_offset, cell_dimensions.y+thickness_offset}
+}
+
+i_from_xy :: proc(x : int, y : int) -> int {
+ return y * len(waveform_a) + x
}
lerp :: proc() {
@@ -75,24 +319,41 @@ lerp :: proc() {
// Type switch to lerp and write directly back to state
switch field_type.id {
- case typeid_of(f32):
- from_val := (cast(^f32)state_ptr)^
- to_val := (cast(^f32)target_ptr)^
- (cast(^f32)state_ptr)^ = from_val + (to_val - from_val) * (1.0 - math.pow(LERP_SPEED, delta))
-
- case typeid_of(rl.Vector2):
- from_val := (cast(^rl.Vector2)state_ptr)^
- to_val := (cast(^rl.Vector2)target_ptr)^
- (cast(^rl.Vector2)state_ptr)^ = from_val + (to_val - from_val) * (1.0 - math.pow(LERP_SPEED, delta))
+ case typeid_of(f32):
+ from_val := (cast(^f32)state_ptr)^
+ to_val := (cast(^f32)target_ptr)^
+ (cast(^f32)state_ptr)^ = from_val + (to_val - from_val) * (1.0 - math.pow(LERP_SPEED, delta))
+
+ case typeid_of(rl.Vector2):
+ from_val := (cast(^rl.Vector2)state_ptr)^
+ to_val := (cast(^rl.Vector2)target_ptr)^
+ (cast(^rl.Vector2)state_ptr)^ = from_val + (to_val - from_val) * (1.0 - math.pow(LERP_SPEED, delta))
}
}
+
+ for cell, i in data_state {
+
+ from_val := data_state[i].cost
+ to_val := data_target[i].cost
+ if data_target[i].cost != math.INF_F32 && data_state[i].cost != math.nan_f32() {
+ data_state[i].cost = from_val + (to_val - from_val) * (1.0 - math.pow(LERP_SPEED, delta)*0.9)
+ } else {
+ data_state[i].cost = data_target[i].cost
+ }
+
+ from_val = data_state[i].stepped_in
+ to_val = data_target[i].stepped_in
+ data_state[i].stepped_in = from_val + (to_val - from_val) * (1.0 - math.pow(LERP_SPEED, delta))
+
+ data_state[i].direction = data_target[i].direction
+ }
}
normalize :: proc(v : rl.Vector2) -> rl.Vector2 {
return v / math.sqrt((v.x*v.x) + (v.y*v.y))
}
-draw_waveform :: proc(wave : []f32, start : rl.Vector2, end : rl.Vector2, amp : f32) {
+draw_waveform :: proc(wave : []f32, start : rl.Vector2, end : rl.Vector2, amp : f32, name : cstring) {
samples := len(wave)
lines := samples-1
@@ -107,27 +368,121 @@ draw_waveform :: proc(wave : []f32, start : rl.Vector2, end : rl.Vector2, amp :
end_base := start + (step*f32(i+1))
start_pos : rl.Vector2 = start_base + (perpendicular*wave[i]*amp)
end_pos = end_base + (perpendicular*wave[i+1]*amp)
- rl.DrawLineEx(start_pos, end_pos, 4, rl.PURPLE)
- rl.DrawCircleV(start_pos, 5, rl.RED)
+ rl.DrawLineEx(start_pos, end_pos, 4, ORANGE)
+ rl.DrawCircleV(start_pos, 5, YELLOW)
+
+ // Text on each point
+ point_font_size :: 24
+ end_value := wave[i+1]
+ end_text := fmt.caprintf("%.1f", end_value, allocator = context.temp_allocator)
+ value_pos := (end_base + (perpendicular*(wave[i+1]*amp-25))) - (rl.MeasureTextEx(font, end_text, point_font_size, 0)*0.5)
+ rl.DrawTextEx(font, end_text, value_pos, point_font_size, 0, rl.GRAY)
+ }
+ rl.DrawCircleV(end_pos, 5, YELLOW)
+
+ rl.DrawTextEx(font, name, start, 32, 0, rl.LIGHTGRAY)
+}
+
+draw_grid :: proc(first : rl.Vector2, last : rl.Vector2, data : []cell) {
+ highest_cost : f32 = 0
+ for c in data {
+ if c.cost > highest_cost && c.cost != math.INF_F32 {
+ highest_cost = c.cost
+ }
+ }
+ color := rl.DARKGRAY
+ color.a = u8(255.0*state.grid_opacity)
+ text_color := rl.WHITE
+ text_color.a = u8(255.0*state.grid_data_opacity)
+ cost_font_size :: 28
+ for cell, i in data {
+
+ // Cell bg color
+ cell_bg := RED
+ cell_bg.a = u8(255*cell.cost/highest_cost*state.heatmap_opacity)
+ if cell.cost == math.INF_F32 do cell_bg = YELLOW
+ rect := rect_from_index(i, 2)
+ rl.DrawRectangleRec(rect, cell_bg)
+
+ // Stepped in
+ stepped_bg := rl.WHITE
+ stepped_bg.a = u8(255*cell.stepped_in*0.8)
+ rl.DrawRectangleRec(rect, stepped_bg)
+
+ // Outline
+ rl.DrawRectangleLinesEx(rect, 2*state.grid_opacity, color)
+
+ // Cost value text
+ cost_string := fmt.caprintf("%.2f", cell.cost, allocator = context.temp_allocator)
+ text_dim := rl.MeasureTextEx(font, cost_string, cost_font_size, 0)
+ text_draw_point := rl.Vector2{rect.x, rect.y}+(({rect.width, rect.height}-text_dim)*0.5)
+ rl.DrawTextEx(font, fmt.ctprintf("%.2f", cell.cost), text_draw_point, cost_font_size, 0, text_color)
+
+ if cell.direction != .NONE {
+ target_point : rl.Vector2
+ #partial switch cell.direction {
+ case .LEFT:
+ target_point = middle_of_rect(rect_from_index(i-1))
+ case .DIAGONAL:
+ target_point = middle_of_rect(rect_from_index(i-len(waveform_a)-1))
+ case .DOWN:
+ target_point = middle_of_rect(rect_from_index(i-len(waveform_a)))
+ }
+ arrow_start := middle_of_rect(rect)
+ arrow_end := target_point
+ diff := arrow_end - arrow_start
+ arrow_start += diff*state.arrow_chopping
+ arrow_end -= diff*state.arrow_chopping
+ draw_arrow(arrow_start, arrow_end)
+ }
}
- rl.DrawCircleV(end_pos, 5, rl.RED)
}
-draw_grid :: proc(first : rl.Vector2, last : rl.Vector2) {
+middle_of_rect :: proc(rect : rl.Rectangle) -> rl.Vector2 {
+ return {rect.x+(rect.width*0.5), rect.y+(rect.height*0.5)}
+}
+
+draw_arrow :: proc(start, end : rl.Vector2) {
+ thickness := state.arrow_thickness
+ outline := thickness*0.8
+
+ total_direction := end - start
+ perpendicular : rl.Vector2 = normalize({total_direction.y, -total_direction.x})
+ reverse : rl.Vector2 = normalize({-total_direction.x, -total_direction.y})
+
+ right_hand : rl.Vector2 = end + (reverse*10) + (perpendicular*-10)
+ left_hand : rl.Vector2 = end + (reverse*10) + (perpendicular*10)
+
+ rl.DrawLineEx(start, end, thickness+outline, BLACK)
+ rl.DrawLineEx(end, right_hand, thickness+outline, BLACK)
+ rl.DrawLineEx(end, left_hand, thickness+outline, BLACK)
+
+ rl.DrawCircleV(start, (thickness+outline)*0.5, BLACK)
+ rl.DrawCircleV(end, (thickness+outline)*0.5, BLACK)
+ rl.DrawCircleV(right_hand, (thickness+outline)*0.5, BLACK)
+ rl.DrawCircleV(left_hand, (thickness+outline)*0.5, BLACK)
+
+
+ rl.DrawLineEx(start, end, thickness, ORANGE)
+ rl.DrawLineEx(end, right_hand, thickness, ORANGE)
+ rl.DrawLineEx(end, left_hand, thickness, ORANGE)
+
+ rl.DrawCircleV(start, thickness*0.5, ORANGE)
+ rl.DrawCircleV(end, thickness*0.5, ORANGE)
+ rl.DrawCircleV(right_hand, thickness*0.5, ORANGE)
+ rl.DrawCircleV(left_hand, thickness*0.5, ORANGE)
}
main :: proc() {
- fast_forward := -1
- if len(os.args) > 1 {
- fast_forward, _ = strconv.parse_int(os.args[1])
- }
- fmt.println("Hello")
// Initialization
//--------------------------------------------------------------------------------------
slide : int = 0
+ if len(os.args) > 1 {
+ slide, _ = strconv.parse_int(os.args[1])
+ }
rotation : f32 = 0.0
@@ -147,6 +502,9 @@ main :: proc() {
camera.offset = {f32(rl.GetScreenWidth()) / 2, f32(rl.GetScreenHeight()) / 2}
camera.zoom = f32(rl.GetScreenHeight())/1080
+ font = rl.LoadFontFromMemory(".ttf", raw_data(MONO_FONT), i32(len(MONO_FONT)), 128, nil, 0)
+ //rl.ToggleBorderlessWindowed()
+
for !rl.WindowShouldClose() {
delta = rl.GetFrameTime()
if rl.IsWindowResized() {
@@ -162,45 +520,45 @@ main :: proc() {
mousePosition := rl.GetMousePosition()
left_clicked := rl.IsMouseButtonReleased(rl.MouseButton(0))
right_clicked := rl.IsMouseButtonReleased(rl.MouseButton(1))
- right_arrow := rl.IsKeyReleased(.RIGHT)
- left_arrow := rl.IsKeyReleased(.LEFT)
- go_forward = left_clicked || right_arrow
- go_back = right_clicked || left_arrow
-
- if slide < fast_forward {
- go_forward = true
- } else {
- fast_forward = -1
- }
+ go_forward = left_clicked || rl.IsKeyReleased(.RIGHT) || rl.IsKeyReleased(.PAGE_DOWN)
+ go_back = right_clicked || rl.IsKeyReleased(.LEFT) || rl.IsKeyReleased(.PAGE_UP)
// Process
//----------------------------------------------------------------------------------
- if go_forward {
+ if go_forward && slide < len(slides)-1 {
slide += 1
fmt.printfln("Forward! To slide #{}", slide)
- } else if go_back {
+ rect_from_index(1)
+ } else if go_back && slide > 0 {
slide -= 1
- fmt.printfln("Back up! To slide #{}", slide)
+ fmt.printfln("Back! To slide #{}", slide)
}
target = slides[slide]
+ data_target = data_frames[slide]
lerp()
// Draw
//----------------------------------------------------------------------------------
rl.BeginDrawing()
- rl.ClearBackground(rl.Color{16, 16, 16, 255})
+ rl.ClearBackground(BLACK)
rl.BeginMode2D(camera)
// World-space drawing
- draw_waveform(waveform_a, state.wave_a_start, state.wave_a_end, state.wave_a_amp)
- draw_waveform(waveform_b, state.wave_b_start, state.wave_b_end, state.wave_b_amp)
-
+ draw_waveform(waveform_a[:], state.wave_a_start, state.wave_a_end, state.wave_a_amp, "Boom")
+ draw_waveform(waveform_b[:], state.wave_b_start, state.wave_b_end, state.wave_b_amp, "Lav")
+ draw_grid(grid_start, grid_end, data_state[:])
+ highlight_color := YELLOW
+ highlight_color.a = u8(255*state.highlight_opacity)
+ rl.DrawRectangleLinesEx({state.highlight_position.x,
+ state.highlight_position.y,
+ state.highlight_dimensions.x,
+ state.highlight_dimensions.y}, HIGHLIGHT_THICKNESS, highlight_color)
rl.EndMode2D()
@@ -215,3 +573,33 @@ main :: proc() {
rl.CloseWindow()
}
+
+distance :: proc(a, b : f32) -> f32 {
+ //return (a - b)*(a - b);
+ return math.abs(a - b);
+}
+three_min :: proc(left, diagonal, down : cell) -> (f32, DIRECTION) {
+ if (left.cost <= diagonal.cost && left.cost <= down.cost) do return left.cost, .LEFT
+ if (down.cost <= diagonal.cost && down.cost <= left.cost) do return down.cost, .DOWN
+ return diagonal.cost, .DIAGONAL;
+}
+full_calc :: proc(d: []cell, x, y : int) {
+ d[i_from_xy(x,y)].cost = distance(waveform_a[x], waveform_b[y])
+ a_cost, a_direction := three_min(d[i_from_xy(x-1, y )],
+ d[i_from_xy(x-1, y-1)],
+ d[i_from_xy(x , y-1)])
+ d[i_from_xy(x,y)].cost += a_cost
+ d[i_from_xy(x,y)].direction = a_direction
+}
+
+cell :: struct {
+ cost : f32,
+ direction : DIRECTION,
+ stepped_in : f32,
+}
+DIRECTION :: enum {
+ NONE,
+ LEFT,
+ DIAGONAL,
+ DOWN,
+} \ No newline at end of file