Basic grid zooming
This commit is contained in:
parent
8e9b468509
commit
bd47c52111
1 changed files with 92 additions and 32 deletions
126
program.odin
126
program.odin
|
|
@ -93,18 +93,22 @@ UiElementData_Button :: struct {
|
||||||
|
|
||||||
UI_ALLOWED_FOCUS :: bit_set[ui.ElementType]{.InputFloat}
|
UI_ALLOWED_FOCUS :: bit_set[ui.ElementType]{.InputFloat}
|
||||||
|
|
||||||
MatrixTypes :: enum {
|
HotkeyTypes :: enum {
|
||||||
Identity,
|
AddIdentity,
|
||||||
Translation,
|
AddTranslation,
|
||||||
Scale,
|
AddScale,
|
||||||
Rotation,
|
AddRotation,
|
||||||
|
ZoomXOnly,
|
||||||
|
ZoomYOnly,
|
||||||
}
|
}
|
||||||
|
|
||||||
@rodata hotkey_without_modifier := [MatrixTypes]rl.KeyboardKey {
|
@rodata hotkey_without_modifier := [HotkeyTypes]rl.KeyboardKey {
|
||||||
.Identity = .I,
|
.AddIdentity = .I,
|
||||||
.Translation = .T,
|
.AddTranslation = .T,
|
||||||
.Scale = .S,
|
.AddScale = .S,
|
||||||
.Rotation = .R,
|
.AddRotation = .R,
|
||||||
|
.ZoomXOnly = .X,
|
||||||
|
.ZoomYOnly = .Y,
|
||||||
}
|
}
|
||||||
|
|
||||||
HotkeyWithModifier :: enum {
|
HotkeyWithModifier :: enum {
|
||||||
|
|
@ -180,12 +184,14 @@ Program :: struct {
|
||||||
ui_overlay_queue_focus_first: bool,
|
ui_overlay_queue_focus_first: bool,
|
||||||
matrix_float_pool: []f32,
|
matrix_float_pool: []f32,
|
||||||
matrix_value_string_pool: []InputFloatField,
|
matrix_value_string_pool: []InputFloatField,
|
||||||
matrix_create_dropdown_value: MatrixTypes,
|
matrix_create_dropdown_value: HotkeyTypes,
|
||||||
matrix_count: int,
|
matrix_count: int,
|
||||||
matrix_scroll: f32,
|
matrix_scroll: f32,
|
||||||
matrix_scroll_speed: f32,
|
matrix_scroll_speed: f32,
|
||||||
mouse_state: MouseState,
|
mouse_state: MouseState,
|
||||||
grid: Grid,
|
grid: Grid,
|
||||||
|
grid_zoom_x_only: bool,
|
||||||
|
grid_zoom_y_only: bool,
|
||||||
font_style: FontStyle,
|
font_style: FontStyle,
|
||||||
state: ProgramState,
|
state: ProgramState,
|
||||||
message_type: ProgramMessageType,
|
message_type: ProgramMessageType,
|
||||||
|
|
@ -213,9 +219,9 @@ AnimationState :: enum {
|
||||||
}
|
}
|
||||||
|
|
||||||
Grid :: struct {
|
Grid :: struct {
|
||||||
area: rect2,
|
cell_size: v2,
|
||||||
inner_area: rect2,
|
zoom_previous, zoom: v2,
|
||||||
zoom: f32,
|
world_position, world_size, offset: v2,
|
||||||
}
|
}
|
||||||
|
|
||||||
float_slice_get_mat3 :: proc(floats: []f32, index: int) -> ^mat3 {
|
float_slice_get_mat3 :: proc(floats: []f32, index: int) -> ^mat3 {
|
||||||
|
|
@ -275,9 +281,10 @@ program_init :: proc(allocator := context.allocator) {
|
||||||
spacing = 1.0
|
spacing = 1.0
|
||||||
}
|
}
|
||||||
program.grid = {
|
program.grid = {
|
||||||
area = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT},
|
cell_size = 32.0,
|
||||||
inner_area = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT},
|
|
||||||
zoom = 1.0,
|
zoom = 1.0,
|
||||||
|
world_position = 0.0,
|
||||||
|
world_size = {WINDOW_WIDTH, WINDOW_HEIGHT}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.init(&program.ui_context, 4000, ui_measure_text, &program.font_style, allocator)
|
ui.init(&program.ui_context, 4000, ui_measure_text, &program.font_style, allocator)
|
||||||
|
|
@ -326,12 +333,12 @@ program_set_transformation_state :: proc(state: AnimationState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
program_update :: proc() {
|
program_update :: proc() {
|
||||||
ui_elements, matrix_container := program_build_workspace_ui(&program.ui_context)
|
ui_elements, top_bar_container, matrix_container := program_build_workspace_ui(&program.ui_context)
|
||||||
ui_overlay_elements: []ui.Element
|
ui_overlay_elements: []ui.Element
|
||||||
|
|
||||||
switch program.state {
|
switch program.state {
|
||||||
case .Normal:
|
case .Normal:
|
||||||
program.mouse_state = program_handle_mouse_workspace(program.mouse_state, matrix_container)
|
program.mouse_state = program_handle_mouse_workspace(program.mouse_state, top_bar_container, matrix_container)
|
||||||
if rl.IsKeyPressed(.TAB) {
|
if rl.IsKeyPressed(.TAB) {
|
||||||
program.ui_element_focus = ui.focus_next_element(program.ui_element_focus, ui_elements, UI_ALLOWED_FOCUS)
|
program.ui_element_focus = ui.focus_next_element(program.ui_element_focus, ui_elements, UI_ALLOWED_FOCUS)
|
||||||
}
|
}
|
||||||
|
|
@ -348,19 +355,35 @@ program_update :: proc() {
|
||||||
} else {
|
} else {
|
||||||
for hotkey, index in hotkey_without_modifier {
|
for hotkey, index in hotkey_without_modifier {
|
||||||
if rl.IsKeyPressed(hotkey) {
|
if rl.IsKeyPressed(hotkey) {
|
||||||
switch index {
|
#partial switch index {
|
||||||
case .Identity:
|
case .AddIdentity:
|
||||||
program_add_identity_matrix()
|
program_add_identity_matrix()
|
||||||
program.ui_overlay_queue_focus_first = true
|
program.ui_overlay_queue_focus_first = true
|
||||||
case .Translation:
|
case .AddTranslation:
|
||||||
program_show_dialog(&program, .CreateTranslationMatrix)
|
program_show_dialog(&program, .CreateTranslationMatrix)
|
||||||
program.ui_overlay_queue_focus_first = true
|
program.ui_overlay_queue_focus_first = true
|
||||||
case .Scale:
|
case .AddScale:
|
||||||
program_show_dialog(&program, .CreateScaleMatrix)
|
program_show_dialog(&program, .CreateScaleMatrix)
|
||||||
program.ui_overlay_queue_focus_first = true
|
program.ui_overlay_queue_focus_first = true
|
||||||
case .Rotation:
|
case .AddRotation:
|
||||||
program_show_dialog(&program, .CreateRotationMatrix)
|
program_show_dialog(&program, .CreateRotationMatrix)
|
||||||
program.ui_overlay_queue_focus_first = true
|
program.ui_overlay_queue_focus_first = true
|
||||||
|
case .ZoomXOnly:
|
||||||
|
if program.grid_zoom_x_only {
|
||||||
|
program.grid_zoom_x_only = false
|
||||||
|
program.grid_zoom_y_only = false
|
||||||
|
} else {
|
||||||
|
program.grid_zoom_x_only = true
|
||||||
|
program.grid_zoom_y_only = false
|
||||||
|
}
|
||||||
|
case .ZoomYOnly:
|
||||||
|
if program.grid_zoom_y_only {
|
||||||
|
program.grid_zoom_x_only = false
|
||||||
|
program.grid_zoom_y_only = false
|
||||||
|
} else {
|
||||||
|
program.grid_zoom_x_only = false
|
||||||
|
program.grid_zoom_y_only = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -393,8 +416,32 @@ program_update :: proc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
grid := program.grid
|
grid := program.grid
|
||||||
grid_inner_position := rect_get_tl(grid.inner_area)
|
zoom_amount := grid_get_zoom_amount(grid.zoom)
|
||||||
draw_grid(grid.area, {32.0, 32.0}, rl.GRAY)
|
world_to_grid_matrix := (
|
||||||
|
mat3 {
|
||||||
|
1, 0, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
grid.offset.x, grid.offset.y, 1,
|
||||||
|
} *
|
||||||
|
linalg.matrix3_scale(v3{**zoom_amount, 1.0}))
|
||||||
|
grid_to_world_matrix := linalg.inverse(world_to_grid_matrix)
|
||||||
|
grid_world_br := grid.world_position + grid.world_size
|
||||||
|
|
||||||
|
grid_tl := (v3{**grid.world_position, 1.0} * world_to_grid_matrix).xy
|
||||||
|
grid_tl = linalg.floor(grid_tl / grid.cell_size) * grid.cell_size
|
||||||
|
grid_br := (v3{**grid_world_br, 1.0} * world_to_grid_matrix).xy
|
||||||
|
for x: f32 = grid_tl.x; x < grid_br.x; x += grid.cell_size.x {
|
||||||
|
world_position := (v3{x, 0.0, 1.0} * grid_to_world_matrix).x
|
||||||
|
p1 := v2{world_position, grid.world_position.y}
|
||||||
|
p2 := v2{world_position, grid_world_br.y}
|
||||||
|
rl.DrawLineV(p1, p2, {255, 255, 255, 128})
|
||||||
|
}
|
||||||
|
for y: f32 = grid_tl.y; y < grid_br.y; y += grid.cell_size.y {
|
||||||
|
world_position := (v3{0.0, y, 1.0} * grid_to_world_matrix).y
|
||||||
|
p1 := v2{grid.world_position.x, world_position}
|
||||||
|
p2 := v2{grid_world_br.x, world_position}
|
||||||
|
rl.DrawLineV(p1, p2, {255, 255, 255, 128})
|
||||||
|
}
|
||||||
|
|
||||||
if program.animation_state == .Playing {
|
if program.animation_state == .Playing {
|
||||||
program.animation_matrix_progress += program.animation_speed * delta_time_fraction()
|
program.animation_matrix_progress += program.animation_speed * delta_time_fraction()
|
||||||
|
|
@ -517,11 +564,12 @@ program_build_dialog_ui :: proc(ctx: ^ui.Context, dialog_type: ProgramDialogType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
program_build_workspace_ui :: proc(ctx: ^ui.Context) -> (elements: []ui.Element, matrix_container: ^ui.Element) {
|
program_build_workspace_ui :: proc(ctx: ^ui.Context) ->
|
||||||
|
(elements: []ui.Element, top_bar_container, matrix_container: ^ui.Element) {
|
||||||
ui.start(ctx, {0, 0}, {WINDOW_WIDTH, WINDOW_HEIGHT})
|
ui.start(ctx, {0, 0}, {WINDOW_WIDTH, WINDOW_HEIGHT})
|
||||||
top_bar_container_config := ui.ElementConfiguration {margin = 4.0}
|
top_bar_container_config := ui.ElementConfiguration {margin = 4.0}
|
||||||
top_bar_element_margin: f32 = 4.0
|
top_bar_element_margin: f32 = 4.0
|
||||||
top_bar_container := ui.container_begin({ui.Size_Percentage(1.0), ui.Size_Pixels(48.0)}, top_bar_container_config)
|
top_bar_container = ui.container_begin({ui.Size_Percentage(1.0), ui.Size_Pixels(48.0)}, top_bar_container_config)
|
||||||
top_bar_inner_height := ui.get_element_inner_area(top_bar_container^).height
|
top_bar_inner_height := ui.get_element_inner_area(top_bar_container^).height
|
||||||
top_bar_button_dimensions := ui.Dimensions {ui.Size_Pixels(top_bar_inner_height), ui.Size_Pixels(top_bar_inner_height)}
|
top_bar_button_dimensions := ui.Dimensions {ui.Size_Pixels(top_bar_inner_height), ui.Size_Pixels(top_bar_inner_height)}
|
||||||
top_bar_button_config := ui.ElementConfiguration {margin = top_bar_element_margin}
|
top_bar_button_config := ui.ElementConfiguration {margin = top_bar_element_margin}
|
||||||
|
|
@ -595,22 +643,34 @@ program_build_workspace_ui :: proc(ctx: ^ui.Context) -> (elements: []ui.Element,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
program_handle_mouse_workspace :: proc(mouse_state: MouseState, matrix_container: ^ui.Element) -> MouseState {
|
grid_get_zoom_amount :: proc(zoom: v2) -> v2 {
|
||||||
|
return linalg.pow(v2{2.0, 2.0}, zoom) - 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
program_handle_mouse_workspace :: proc(mouse_state: MouseState, top_bar_container, matrix_container: ^ui.Element) -> MouseState {
|
||||||
mouse := rl.GetMousePosition()
|
mouse := rl.GetMousePosition()
|
||||||
|
mouse_wheel := rl.GetMouseWheelMoveV()
|
||||||
switch mouse_state {
|
switch mouse_state {
|
||||||
case .Hover:
|
case .Hover:
|
||||||
if rl.IsMouseButtonPressed(.LEFT) {
|
if rect_has_point(rect2(matrix_container.area), mouse) {
|
||||||
return .DraggingGrid
|
|
||||||
} else if rect_has_point(rect2(matrix_container.area), mouse) {
|
|
||||||
return .HoverMatrices
|
return .HoverMatrices
|
||||||
}
|
}
|
||||||
|
if rect_has_point(rect2(top_bar_container.area), mouse) {
|
||||||
|
return mouse_state
|
||||||
|
}
|
||||||
|
if rl.IsMouseButtonPressed(.LEFT) {
|
||||||
|
return .DraggingGrid
|
||||||
|
}
|
||||||
|
program.grid.zoom_previous = program.grid.zoom
|
||||||
|
grid_zoom_dimension_lock := v2{1.0 - f32(int(program.grid_zoom_y_only)), 1.0 - f32(int(program.grid_zoom_x_only))}
|
||||||
|
program.grid.zoom += grid_zoom_dimension_lock * mouse_wheel.y * 0.01
|
||||||
case .DraggingGrid:
|
case .DraggingGrid:
|
||||||
program.grid.inner_area = rect_translate(program.grid.inner_area, rl.GetMouseDelta())
|
program.grid.offset -= rl.GetMouseDelta()
|
||||||
if !rl.IsMouseButtonDown(.LEFT) {
|
if !rl.IsMouseButtonDown(.LEFT) {
|
||||||
return .Hover
|
return .Hover
|
||||||
}
|
}
|
||||||
case .HoverMatrices:
|
case .HoverMatrices:
|
||||||
program.matrix_scroll = max(0, program.matrix_scroll - rl.GetMouseWheelMove() * program.matrix_scroll_speed)
|
program.matrix_scroll = max(0, program.matrix_scroll - mouse_wheel.y * program.matrix_scroll_speed)
|
||||||
if !rect_has_point(rect2(matrix_container.area), mouse) {
|
if !rect_has_point(rect2(matrix_container.area), mouse) {
|
||||||
return .Hover
|
return .Hover
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue