diff --git a/default b/default new file mode 100755 index 0000000..be3f2c4 Binary files /dev/null and b/default differ diff --git a/program.odin b/program.odin index 7df8a4e..20f7fc1 100644 --- a/program.odin +++ b/program.odin @@ -6,6 +6,8 @@ import "core:fmt" import "core:math/linalg" import "core:math/ease" import "core:math" +import "core:strings" +import "core:os" RAYGUI_ICON_PLAY :: "#131#" RAYGUI_ICON_PAUSE :: "#132#" @@ -16,6 +18,8 @@ TRANSFORMATION_RECTANGLE_COLOR_MIDDLE :: rl.MAGENTA TRANSFORMATION_RECTANGLE_COLOR_NEXT :: rl.GRAY TRANSFORMATION_RECTANGLE_COLOR_LAST :: rl.BLUE +DEFAULT_PROJECT_LOAD_LOCATION :: "default" + UiContainerType :: enum { Normal, Matrix, @@ -202,6 +206,10 @@ Grid :: struct { zoom: f32, } +float_slice_get_mat3 :: proc(floats: []f32, index: int) -> ^mat3 { + return cast(^mat3)(&floats[index * 9]) +} + matrix_pool_max :: proc() -> int { return len(program.matrix_float_pool) / 9 } @@ -217,6 +225,22 @@ matrix_pool_get_mat3 :: proc() -> (value_strings: []InputFloatField, values: []f return value_strings, values } +program_save_project :: proc(program: ^Program, path: string) -> os.Error { + project := ProjectData { + matrix_count = u32(program.matrix_count), + matrices = program.matrix_float_pool, + } + project_write(&project, string(program.dialog_data.input_text_buffers[0][:])) or_return + return nil +} + +program_load_project :: proc(program: ^Program, path: string) -> ProjectReadError { + project: ProjectData + project_read(&project, path) or_return + fmt.println(project.version) + return nil +} + program_show_dialog :: proc(program: ^Program, dialog_type: ProgramDialogType) { program.dialog_data = {} program.ui_overlay_queue_focus_first = true @@ -254,6 +278,10 @@ program_init :: proc(allocator := context.allocator) { program.animation = program.animations[.Rectangle] program.animation_speed = 0.02 program.animation_ease = .Quadratic_Out + + if err := program_load_project(&program, DEFAULT_PROJECT_LOAD_LOCATION); err != nil { + fmt.println(err) + } } program_get_master_matrix :: proc() -> mat3 { @@ -282,10 +310,6 @@ program_set_transformation_state :: proc(state: AnimationState) { } } -float_slice_get_mat3 :: proc(floats: []f32, index: int) -> ^mat3 { - return cast(^mat3)(&floats[index * 9]) -} - program_update :: proc() { ui_elements, matrix_container := program_build_workspace_ui(&program.ui_context) ui_overlay_elements: []ui.Element @@ -339,6 +363,13 @@ program_update :: proc() { case .CreateScaleMatrix: program_add_scalar_matrix(vals[0], vals[1], vals[2]) case .CreateRotationMatrix: program_add_rotation_matrix(vals[0]) case .SaveProject: + input := &program.dialog_data.input_text_buffers[0][0] + path := strings.string_from_null_terminated_ptr(input, DIALOG_STATE_TEXT_INPUT_FIELD_SIZE) + if err := program_save_project(&program, path); err != nil { + // TODO (Synthas): show error message + } else { + program.state = .Normal + } case .LoadProject: } animation_update_last(&program.animation, program_get_master_matrix()) @@ -437,26 +468,6 @@ program_add_rotation_matrix :: proc(angle: f32) { values[4] = rotmat[1, 1] } -ui_labeled_input_float_element :: proc(label: cstring, margin: f32, value: ^f32, value_string: ^InputFloatField, allocator := context.temp_allocator) -> ^ui.Element { - label := fmt.ctprintf("%s: ", label) - label_element := ui.element(.Label, {}, {label = label, color = ui.col(rl.WHITE), margin = margin}) - dimensions := ui.Dimensions{ui.Size_Pixels(64.0), ui.dimensions_pixels(ui.rect_get_size(ui.get_element_outer_area(label_element^))).height} - ui.same_line() - input_data := new(UiElementData_FloatInput, context.temp_allocator) - input_data^ = {value = value, value_string = cstring(&value_string[0])} - return ui.element(.InputFloat, dimensions, {margin = margin}, input_data) -} - -ui_labeled_input_text_element :: proc(label: cstring, margin: f32, str: []byte, allocator := context.temp_allocator) -> ^ui.Element { - label := fmt.ctprintf("%s: ", label) - label_element := ui.element(.Label, {}, {label = label, color = ui.col(rl.WHITE), margin = margin}) - dimensions := ui.Dimensions{ui.Size_Pixels(64.0), ui.dimensions_pixels(ui.rect_get_size(ui.get_element_outer_area(label_element^))).height} - ui.same_line() - input_data := new(UiElementData_TextInput, context.temp_allocator) - input_data^ = {str = cstring(&str[0])} - return ui.element(.InputText, dimensions, {margin = margin}, input_data) -} - program_build_dialog_ui :: proc(ctx: ^ui.Context, dialog_type: ProgramDialogType) -> []ui.Element { size := v2{WINDOW_WIDTH, WINDOW_HEIGHT} container_margin := size * 0.33 @@ -490,17 +501,6 @@ program_build_dialog_ui :: proc(ctx: ^ui.Context, dialog_type: ProgramDialogType return ui.end() } -ui_add_matrix_footer_buttons :: proc(button_type_add: UiButtonType, margin: f32) { - button_data: ^UiElementData_Button - button_data = new(UiElementData_Button, context.temp_allocator) - button_data^ = {type = button_type_add} - ui.element(.Button, ui.dimensions_pixels(96.0, 32.0), {label = "Add", margin = margin}, button_data) - - button_data = new(UiElementData_Button, context.temp_allocator) - button_data^ = {type = .ExitDialog} - ui.same_line() - ui.element(.Button, ui.dimensions_pixels(96.0, 32.0), {label = "Cancel", margin = margin}, button_data) -} program_build_workspace_ui :: proc(ctx: ^ui.Context) -> (elements: []ui.Element, matrix_container: ^ui.Element) { ui.start(ctx, {0, 0}, {WINDOW_WIDTH, WINDOW_HEIGHT}) @@ -689,12 +689,10 @@ program_render_ui_and_handle_focus :: proc(ctx: ^ui.Context, focus_element_id: u case .ResetTransformation: animation_reset(&program.animation) case .SaveProjectConfirm: - project := ProjectData { - matrix_count = u32(program.matrix_count), - matrices = program.matrix_float_pool, - } - if error := project_write(&project, string(program.dialog_data.input_text_buffers[0][:])); error != nil { - // TODO (synthas): Generic error message + input := &program.dialog_data.input_text_buffers[0][0] + path := strings.string_from_null_terminated_ptr(input, DIALOG_STATE_TEXT_INPUT_FIELD_SIZE) + if err := program_save_project(&program, path); err != nil { + // TODO (Synthas): show error message } else { program.state = .Normal } @@ -763,6 +761,18 @@ program_render_ui_and_handle_focus :: proc(ctx: ^ui.Context, focus_element_id: u return focus_element_id } +ui_add_matrix_footer_buttons :: proc(button_type_add: UiButtonType, margin: f32) { + button_data: ^UiElementData_Button + button_data = new(UiElementData_Button, context.temp_allocator) + button_data^ = {type = button_type_add} + ui.element(.Button, ui.dimensions_pixels(96.0, 32.0), {label = "Add", margin = margin}, button_data) + + button_data = new(UiElementData_Button, context.temp_allocator) + button_data^ = {type = .ExitDialog} + ui.same_line() + ui.element(.Button, ui.dimensions_pixels(96.0, 32.0), {label = "Cancel", margin = margin}, button_data) +} + ui_measure_text :: proc(str: cstring, font_data: rawptr) -> ui.v2 { style := cast(^FontStyle)font_data return rl.MeasureTextEx(style.font, str, style.size, style.spacing) @@ -787,3 +797,23 @@ ui_mat3 :: proc(mat: []f32, value_strings: []InputFloatField, dimensions: ui.Dim } ui.container_end() } + +ui_labeled_input_float_element :: proc(label: cstring, margin: f32, value: ^f32, value_string: ^InputFloatField, allocator := context.temp_allocator) -> ^ui.Element { + label := fmt.ctprintf("%s: ", label) + label_element := ui.element(.Label, {}, {label = label, color = ui.col(rl.WHITE), margin = margin}) + dimensions := ui.Dimensions{ui.Size_Pixels(64.0), ui.dimensions_pixels(ui.rect_get_size(ui.get_element_outer_area(label_element^))).height} + ui.same_line() + input_data := new(UiElementData_FloatInput, context.temp_allocator) + input_data^ = {value = value, value_string = cstring(&value_string[0])} + return ui.element(.InputFloat, dimensions, {margin = margin}, input_data) +} + +ui_labeled_input_text_element :: proc(label: cstring, margin: f32, str: []byte, allocator := context.temp_allocator) -> ^ui.Element { + label := fmt.ctprintf("%s: ", label) + label_element := ui.element(.Label, {}, {label = label, color = ui.col(rl.WHITE), margin = margin}) + dimensions := ui.Dimensions{ui.Size_Pixels(64.0), ui.dimensions_pixels(ui.rect_get_size(ui.get_element_outer_area(label_element^))).height} + ui.same_line() + input_data := new(UiElementData_TextInput, context.temp_allocator) + input_data^ = {str = cstring(&str[0])} + return ui.element(.InputText, dimensions, {margin = margin}, input_data) +} diff --git a/project.odin b/project.odin index 9a4824d..924c9db 100644 --- a/project.odin +++ b/project.odin @@ -2,6 +2,7 @@ package main import "core:os" import "core:io" +import "core:mem" PROJECT_DATA_HEADER :: "WOWOWOW THIS IS HEADER WOWOWOW" PROJECT_DATA_VERSION :: 1 @@ -22,11 +23,48 @@ WriteProjectErrorType :: enum { project_write :: proc(project: ^ProjectData, path: string) -> os.Error { f := os.open(path, {.Create, .Trunc, .Write}) or_return + defer os.close(f) w := io.to_writer(os.to_stream(f)) version: u32 = PROJECT_DATA_VERSION + header := PROJECT_DATA_HEADER + + io.write_full(w, transmute([]u8)header) io.write_ptr(w, &version, size_of(version)) io.write_ptr(w, &project.matrix_count, size_of(project.matrix_count)) io.write_ptr(w, raw_data(project.matrices), int(project.matrix_count) * 9 * size_of(f32)) os.close(f) return nil } + +ProjectReadError :: union { + os.Error, + io.Error, + ProjectReadErrorType, +} + +ProjectReadErrorType :: enum { + FailedReadingHeader, + BadHeader, + VersionNeedsUpgrade, +} + +project_read :: proc(project: ^ProjectData, path: string) -> ProjectReadError { + f := os.open(path, {.Read}) or_return + defer os.close(f) + r := io.to_reader(os.to_stream(f)) + header := PROJECT_DATA_HEADER + header_buffer: [len(PROJECT_DATA_HEADER)]byte + if num, err := io.read_full(r, header_buffer[:]); err != nil { + return ProjectReadErrorType.FailedReadingHeader + } + if mem.compare(transmute([]byte)header[:], header_buffer[:]) != 0 { + return ProjectReadErrorType.BadHeader + } + version: u32 + _ = io.read_ptr(r, &version, size_of(u32)) or_return + if version != PROJECT_DATA_VERSION { + return ProjectReadErrorType.VersionNeedsUpgrade + } + project.version = version + return nil +}