diff --git a/interface_entity.odin b/interface_entity.odin new file mode 100644 index 0000000..125560b --- /dev/null +++ b/interface_entity.odin @@ -0,0 +1,273 @@ +package ion + +import b2 "vendor:box2d" +import im "shared:odin-imgui" +import "core:slice" +import "core:container/small_array" +import "core:fmt" + + +/* + This is mostly stable + + Handles + 1. Body Defination + 2. Shape defination + 3. Static index + + TODO: + Handle multiple shapes? + Could use more tweaks on min and max values +*/ + + +/* + We don't need to return bool from this function because we can see the difference + By doing comparasion on def +*/ + +interface_body_def_editor :: proc(def: ^engine_entity_def) +{ + if im.BeginCombo("Body Type", fmt.ctprint(def.body_def.type)) + { + for type in b2.BodyType + { + if im.Selectable(fmt.ctprint(type), def.body_def.type == type) do def.body_def.type = type + } + im.EndCombo() + } + + im.SliderFloat2("Position", &def.body_def.position, -50, 50) + + angle := RAD2DEG * b2.Rot_GetAngle(def.body_def.rotation) + + if im.SliderFloat("Rotation", &angle, 0, 359) + { + def.body_def.rotation = b2.MakeRot(DEG2RAD * angle) + } + + im.SliderFloat2("Linear velocity", &def.body_def.linearVelocity, 0, 500) + im.SliderFloat( "Angular velocity", &def.body_def.angularVelocity, 0, 500) + im.SliderFloat( "Linear Damping", &def.body_def.linearDamping, 0, 500) + im.SliderFloat( "Angular Damping", &def.body_def.angularDamping, 0, 500) + im.SliderFloat( "Gravity Scale", &def.body_def.gravityScale, 0, 100) + im.Checkbox( "Fixed rotation", &def.body_def.fixedRotation) + + if im.InputText("Body Name", cstring(&def.name_buf[0]), 255) + { + def.body_def.name = cstring(&def.name_buf[0]) + } +} + +interface_edit_static_index :: proc(interface:^interface_state, def: ^engine_entity_def) -> bool +{ + + curr_index := &interface.curr_static_index + entity := interface.entities[interface.selected_entity^] + + level := interface.world + + + if level.relations[entity.index] == nil + { + level.relations[entity.index] = {} + } + + indexes := &level.relations[entity.index] + + if im.InputInt("Index Value", &def.index) do return true + + ret := false + + if def.index != 0 + { + //For now only select from current room + + if im.BeginCombo("Edit Select index", fmt.ctprint(curr_index.index)) + { + for index in level.static_indexes + { + if im.Selectable(fmt.ctprint(index), curr_index.index == index) + { + curr_index.index = index + } + } + im.EndCombo() + } + if curr_index.index != 0 + { + if indexes != nil + { + if im.Button("Add relation") + { + if !slice.contains(indexes[:], interface.curr_static_index) + { + append(indexes, interface.curr_static_index) + } + } + } + } + + if indexes != nil{ + for val, i in indexes + { + im.Text("%d", val.index) + im.SameLine() + if im.Button("Delete") { + ordered_remove(indexes, i) + } + } + } + } + return false +} + + +interface_shape_def_editor :: proc(def: ^engine_entity_def) -> bool +{ + shape_def := &def.shape_def + + + if im.BeginCombo("Shape Type", fmt.ctprint(def.shape_type)) { + + for type in b2.ShapeType + { + if im.Selectable(fmt.ctprint(type), def.shape_type == type) + { + def.shape_type = type + } + } + + im.EndCombo() + } + + switch def.shape_type { + + case .circleShape: + { + im.SliderFloat("radius", &def.radius, 0, 40) + } + + case .polygonShape: + { + im.SliderFloat2("Size", &def.size, -500, 500) + } + + case .capsuleShape: + { + im.SliderFloat2("Center 1", &def.centers[0], -100, 100) + im.SliderFloat2("Center 2", &def.centers[1], -100, 100) + im.SliderFloat("Radius", &def.radius, 0, 40) + } + + case .chainSegmentShape: + { + im.Checkbox("is loop", &def.is_loop) + } + + case .segmentShape: + { + //TODO + } + + } + + im.SliderFloat("Density", &def.shape_def.density, 0, 100) + + if im.Button("Flip horizontally") do flip_points(small_array.slice(&def.vertices), .Horizontal) + if im.Button("Flip Vertically ") do flip_points(small_array.slice(&def.vertices), .Vertical) + + if im.TreeNode("Events and contacts") { + im.Checkbox("Is sensor", &def.shape_def.isSensor) + im.Checkbox("Enable Sensor Events", &def.shape_def.enableSensorEvents) + im.Checkbox("Enable Contact Events", &def.shape_def.enableContactEvents) + im.Checkbox("Enable Hit Events", &def.shape_def.enableHitEvents) + im.Checkbox("Enable Presolve Events", &def.shape_def.enablePreSolveEvents) + im.Checkbox("Invoke contact Creation", &def.shape_def.invokeContactCreation) + im.Checkbox("Update body mass ", &def.shape_def.updateBodyMass) + im.TreePop() + } + + if im.TreeNode("Material") { + im.Separator() + + im.SliderFloat("Friction", &def.shape_def.material.friction, 0, 1) + im.SliderFloat("Restitution", &def.shape_def.material.restitution, 0, 1) + im.SliderFloat("Rolling Resistance", &def.shape_def.material.rollingResistance, 0, 1) + im.SliderFloat("Tangent Speed", &def.shape_def.material.tangentSpeed, 0, 1) + im.InputInt("User material id", &def.shape_def.material.userMaterialId) + + //Colorpicker + + if im.TreeNode("Color") { + color_f32 := u32_to_float4(def.shape_def.material.customColor) + + if im.ColorPicker4("Custom Color", &color_f32, {.Uint8, .InputRGB}) { + def.shape_def.material.customColor = float4_to_u32(color_f32) + } + im.TreePop() + } + + im.Separator() + im.TreePop() + } + + return false +} + +interface_entity :: proc(interface: ^interface_state) -> bool +{ + entity_selected := interface.selected_entity^ != -1 + + if entity_selected + { + def := interface.entity_defs[interface.selected_entity^] + def_old := def^ + + ret := false + + interface.edit_mode = .ENTITY + //Flags + for flag in engine_entity_flags_enum + { + contains := flag in def.entity_flags + if im.Checkbox(fmt.ctprint(flag), &contains) do def.entity_flags ~= {flag} + } + + if .CHAIN in def.entity_flags + { + + im.InputInt("Body Count", &def.body_count, 1) + im.SliderFloat("Half Link Length", &def.half_link_length, 1, 10) + + } + + im.Separator() + + if im.CollapsingHeader("Shape Edit") + { + interface_shape_def_editor(def) + } + + im.Separator() + + if im.CollapsingHeader("Body Edit") + { + interface_body_def_editor(def) + } + + if im.CollapsingHeader("Static Index") + { + ret |= interface_edit_static_index(interface, def) + } + + if .CHAIN in def.entity_flags + { + interface_edit_rev_joint_minimal(&def.rev_joint) + } + + return def^ != def_old || ret + } + + return false +} diff --git a/ols.json b/ols.json new file mode 100644 index 0000000..a766859 --- /dev/null +++ b/ols.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://raw.githubusercontent.com/DanielGavin/ols/master/misc/ols.schema.json", + "enable_semantic_tokens": false, + "enable_document_symbols": true, + "enable_hover": true, + "enable_snippets": true, + "profile": "default", + "profiles": [ + { "name": "default", "checker_path": ["src"], "defines": { "ODIN_DEBUG": "false" }}, + { "name": "linux_profile", "os": "linux", "checker_path": ["src/main.odin"], "defines": { "ODIN_DEBUG": "false" }}, + { "name": "mac_profile", "os": "darwin", "arch": "arm64", "defines": { "ODIN_DEBUG": "false" }}, + { "name": "windows_profile", "os": "windows", "checker_path": ["src"], "defines": { "ODIN_DEBUG": "false" }} + ] +} \ No newline at end of file