diff --git a/animation.odin b/animation.odin index 64128ee..0063275 100644 --- a/animation.odin +++ b/animation.odin @@ -1,6 +1,7 @@ package main import rl "libraries/raylib" +import "core:math/linalg" import "core:fmt" /* @@ -16,8 +17,17 @@ RectangleCorners :: struct { tl, tr, br, bl: v2, } +rectangle_corners_transform :: proc(m: mat3, corners: RectangleCorners) -> RectangleCorners { + return { + tl = (v3{**corners.tl, 1.0} * m).xy, + tr = (v3{**corners.tr, 1.0} * m).xy, + br = (v3{**corners.br, 1.0} * m).xy, + bl = (v3{**corners.bl, 1.0} * m).xy, + } +} + AnimationData_Rectangle :: struct { - origin, middle, previous, next, last: RectangleCorners + origin, middle, previous, next, last: RectangleCorners, } draw_transformation_rectangle :: proc(rectangle: RectangleCorners, color: rl.Color) { @@ -51,6 +61,13 @@ _animation_rectangle_reset :: proc(animation: ^AnimationInterface) { data.previous = data.origin } +_animation_rectangle_next_matrix :: proc(animation: ^AnimationInterface, next_matrix: mat3) { + data := cast(^AnimationData_Rectangle)animation.data + data.previous = data.next + data.middle = data.next + data.next = rectangle_corners_transform(next_matrix, data.next) +} + _animation_rectangle_update_last :: proc(animation: ^AnimationInterface, master_matrix: mat3) { data := cast(^AnimationData_Rectangle)animation.data data.last = { @@ -59,12 +76,16 @@ _animation_rectangle_update_last :: proc(animation: ^AnimationInterface, master_ br = (master_matrix * v3{**data.origin.br, 1.0}).xy, bl = (master_matrix * v3{**data.origin.bl, 1.0}).xy, } - fmt.println(data.last) - fmt.println(data.origin) } -_animation_rectangle_update :: proc(animation: ^AnimationInterface, current_matrix: mat3, progress: f32) { - +_animation_rectangle_update :: proc(animation: ^AnimationInterface, animation_progress: f32) { + data := cast(^AnimationData_Rectangle)animation.data + data.middle = { + tl = linalg.lerp(data.previous.tl, data.next.tl, animation_progress), + tr = linalg.lerp(data.previous.tr, data.next.tr, animation_progress), + br = linalg.lerp(data.previous.br, data.next.br, animation_progress), + bl = linalg.lerp(data.previous.bl, data.next.bl, animation_progress), + } } _animation_rectangle_update_goto_next :: proc(animation: ^AnimationInterface, next_matrix: mat3) { @@ -76,6 +97,8 @@ animation_create_rectangle :: proc(rectangle: ^AnimationData_Rectangle) -> Anima data = rectangle, reset = _animation_rectangle_reset, update_last = _animation_rectangle_update_last, + update = _animation_rectangle_update, + next_matrix = _animation_rectangle_next_matrix, draw_idle = _animation_rectangle_draw_idle, draw_active = _animation_rectangle_draw_active, } @@ -85,6 +108,8 @@ AnimationInterface :: struct { data: rawptr, reset: proc(animation: ^AnimationInterface), update_last: proc(animation: ^AnimationInterface, master_matrix: mat3), + update: proc(animation: ^AnimationInterface, animation_progress: f32), + next_matrix: proc(animation: ^AnimationInterface, next_matrix: mat3), draw_idle: proc(animation: AnimationInterface), draw_active: proc(animation: AnimationInterface), } diff --git a/main.odin b/main.odin index 600bfd4..7fb9ddf 100644 --- a/main.odin +++ b/main.odin @@ -5,7 +5,7 @@ import "base:runtime" WINDOW_WIDTH :: 1280 WINDOW_HEIGHT :: 720 -WINDOW_FRAMERATE :: 30 +WINDOW_FRAMERATE :: 60 WINDOW_CAPTION :: "Transformation Visualizer" init :: proc() { @@ -40,3 +40,7 @@ should_run :: proc() -> bool { } return true } + +delta_time_fraction :: proc() -> f32 { + return rl.GetFrameTime() / (1.0 / WINDOW_FRAMERATE) +} diff --git a/program.odin b/program.odin index f254006..0b763bb 100644 --- a/program.odin +++ b/program.odin @@ -4,6 +4,7 @@ import rl "libraries/raylib" import ui "libraries/snths_ui" import "core:fmt" import "core:math/linalg" +import "core:math/ease" RAYGUI_ICON_PLAY :: "#131#" RAYGUI_ICON_PAUSE :: "#132#" @@ -156,6 +157,9 @@ Program :: struct { animations: [AnimationType]AnimationInterface, animation: AnimationInterface, animation_matrix_index: int, + animation_matrix_progress: f32, + animation_speed: f32, + animation_ease: ease.Ease, } AnimationData :: struct { @@ -230,17 +234,16 @@ program_init :: proc(allocator := context.allocator) { .Rectangle = animation_create_rectangle(&program.animation_data.rectangle) } program.animation = program.animations[.Rectangle] + program.animation_speed = 0.02 + program.animation_ease = .Quadratic_Out } program_get_master_matrix :: proc() -> mat3 { matrices := (cast([^]mat3)raw_data(program.matrix_float_pool))[:program.matrix_count] master_matrix := linalg.identity_matrix(mat3) - fmt.println("master matrix: ", master_matrix) #reverse for mat in matrices { - fmt.println("master matrix: ", master_matrix, mat) master_matrix *= mat } - fmt.println("master matrix: ", master_matrix) return master_matrix } @@ -311,6 +314,14 @@ program_update :: proc() { grid_inner_position := rect_get_tl(grid.inner_area) draw_grid(grid.area, {32.0, 32.0}, rl.GRAY) + if program.animation_state == .Playing { + program.animation_matrix_progress += program.animation_speed * delta_time_fraction() + if program.animation_matrix_progress >= 1.0 { + program.animation_matrix_progress = 1.0; + } + program.animation.update(&program.animation, ease.ease(program.animation_ease, program.animation_matrix_progress)) + } + switch program.animation_state { case .Ready: program.animation.draw_idle(program.animation) @@ -350,16 +361,12 @@ program_add_translation_matrix :: proc(x, y, z: f32) { value_strings, values := matrix_pool_get_mat3() value_strings[0][0] = '1' values[0] = 1.0 - - fmt.bprint(value_strings[2][:], x) - values[2] = x - - fmt.bprint(value_strings[5][:], y) value_strings[4][0] = '1' - values[4] = 1.0 - values[5] = y - + fmt.bprint(value_strings[6][:], x) + values[6] = x + fmt.bprint(value_strings[7][:], y) + values[7] = y fmt.bprint(value_strings[8][:], z) values[8] = z } @@ -613,14 +620,15 @@ program_render_ui_and_handle_focus :: proc(ctx: ^ui.Context, focus_element_id: u case .StartTransformation: if program.matrix_count > 0 { program.animation_state = .Playing - // TOOD (synthas): Reset to initial transformation values + program.animation.reset(&program.animation) + program.animation.next_matrix(&program.animation, (cast(^mat3)raw_data(program.matrix_float_pool))^) } case .PauseTransformation: program.animation_state = .Paused case .ResumeTransformation: program.animation_state = .Playing case .ResetTransformation: - // TODO (synthas): Reset to initial transformation values + program.animation.reset(&program.animation) } if data.type in UiButtonRecalculateFinishGroup { program.animation.update_last(&program.animation, program_get_master_matrix()) @@ -692,8 +700,9 @@ ui_mat3 :: proc(mat: []f32, value_strings: []InputFloatField, dimensions: ui.Dim ui.container_begin(dimensions, config, container_data) matrix_input_config := ui.ElementConfiguration {margin = 4.0} matrix_input_dimensions := ui.Dimensions {ui.Size_Percentage(1.0 / 3.0), ui.Size_Percentage(1.0 / 3.0)} - #unroll for i in 0..<3 { - #unroll for j in 0..<3 { + // column first matrices + #unroll for j in 0..<3 { + #unroll for i in 0..<3 { data := new(UiElementData_FloatInput, allocator) index := i * 3 + j data^ = {value = &mat[index], value_string = cstring(&value_strings[index][0]), tag = {.UpdateMatrix}}