package edit2d import b2 "vendor:box2d" //import im "shared:odin-imgui" import mu "vendor:microui" import "core:slice" import draw "./draw" 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 := draw.RAD2DEG * b2.Rot_GetAngle(def.body_def.rotation) if im.SliderFloat("Rotation", &angle, 0, 359) { def.body_def.rotation = b2.MakeRot(draw.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]) } } */ mu_interface_body_def_editor :: proc(interface: ^interface_state, def : ^engine_entity_def) { ctx := &interface.state.mu_ctx if .ACTIVE in mu.begin_treenode(ctx, "Body Type") { for type in b2.BodyType { state := def.body_def.type == type if .CHANGE in mu.checkbox(ctx, fmt.tprint(type), &state) { def.body_def.type = type } } mu.end_treenode(ctx) } mu.label(ctx, "Position") mu.slider(ctx, &def.body_def.position[0], -50, 50) mu.slider(ctx, &def.body_def.position[1], -50, 50) angle := draw.RAD2DEG * b2.Rot_GetAngle(def.body_def.rotation) mu.label(ctx, "Rotation") if .CHANGE in mu.slider(ctx, &angle, 0, 359) { def.body_def.rotation = b2.MakeRot(draw.DEG2RAD * angle) } mu.label(ctx, "Linear Velocity") mu.slider(ctx, &def.body_def.linearVelocity[0], 0, 500) mu.slider(ctx, &def.body_def.linearVelocity[1], 0, 500) mu.label(ctx, "Angular Velocity") mu.slider(ctx, &def.body_def.angularVelocity, 0, 500) mu.label(ctx, "Linear Damping") mu.slider(ctx, &def.body_def.linearDamping, 0, 500) mu.label(ctx, "Angular Damping") mu.slider(ctx, &def.body_def.angularDamping, 0, 500) mu.label(ctx, "Gravity Scale") mu.slider(ctx, &def.body_def.gravityScale, 0, 100) mu.checkbox(ctx, "Fixed rotation", &def.body_def.fixedRotation) } /* 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 } */ mu_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 ctx := &interface.state.mu_ctx if level.relations[entity.index] == nil { level.relations[entity.index] = {} } indexes := &level.relations[entity.index] //if mu.slider() return true } mu_interface_shape_def_editor :: proc( state : ^engine_state, def : ^engine_entity_def) -> bool { shape_def := &def.shape_def mu.label(&state.mu_ctx, "Shape Type") for type in b2.ShapeType { b := def.shape_type == type if .CHANGE in mu.checkbox(&state.mu_ctx, fmt.tprint(type), &b) do def.shape_type = type } switch def.shape_type { case .circleShape:{ mu.label(&state.mu_ctx, "Radius") mu.slider(&state.mu_ctx, &def.radius, 0, 40) } case .polygonShape:{ mu.label(&state.mu_ctx, "Size") mu.slider(&state.mu_ctx, &def.size[0], -500, 500) mu.slider(&state.mu_ctx, &def.size[1], -500, 500) } case .capsuleShape:{ mu.label(&state.mu_ctx, "Center 1") mu.slider(&state.mu_ctx, &def.centers[0][0], -100, 100) mu.slider(&state.mu_ctx, &def.centers[0][1], -100, 100) mu.label(&state.mu_ctx, "Center 2") mu.slider(&state.mu_ctx, &def.centers[1][0], -100, 100) mu.slider(&state.mu_ctx, &def.centers[1][1], -100, 100) mu.label(&state.mu_ctx, "Radius") mu.slider(&state.mu_ctx, &def.radius, 0, 40) } case .chainSegmentShape:{ mu.checkbox(&state.mu_ctx, "Is Loop", &def.is_loop) } case .segmentShape:{ } } mu.label(&state.mu_ctx, "Density") mu.slider(&state.mu_ctx, &def.shape_def.density, 0, 100) if .SUBMIT in mu.button(&state.mu_ctx, "Flip horizontally") do flip_points(def.vertices[:], .Horizontal) if .SUBMIT in mu.button(&state.mu_ctx, "Flip Vertically ") do flip_points(def.vertices[:], .Vertical) if .ACTIVE in mu.begin_treenode(&state.mu_ctx, "Events and contacts") { mu.checkbox(&state.mu_ctx, "Is sensor", &def.shape_def.isSensor) mu.checkbox(&state.mu_ctx, "Enable Sensor Events", &def.shape_def.enableSensorEvents) mu.checkbox(&state.mu_ctx, "Enable Contact Events", &def.shape_def.enableContactEvents) mu.checkbox(&state.mu_ctx, "Enable Hit Events", &def.shape_def.enableHitEvents) mu.checkbox(&state.mu_ctx, "Enable Presolve Events", &def.shape_def.enablePreSolveEvents) mu.checkbox(&state.mu_ctx, "Invoke contact Creation", &def.shape_def.invokeContactCreation) mu.checkbox(&state.mu_ctx, "Update body mass ", &def.shape_def.updateBodyMass) mu.end_treenode(&state.mu_ctx) } if .ACTIVE in mu.begin_treenode(&state.mu_ctx, "Material") { mu.label(&state.mu_ctx, "Friction") mu.slider(&state.mu_ctx, &def.shape_def.material.friction, 0, 1) mu.label(&state.mu_ctx, "Restitution") mu.slider(&state.mu_ctx, &def.shape_def.material.restitution, 0, 1) mu.label(&state.mu_ctx, "Rolling Resistance") mu.slider(&state.mu_ctx, &def.shape_def.material.rollingResistance, 0, 1) mu.label(&state.mu_ctx, "Tangent Speed") mu.slider(&state.mu_ctx, &def.shape_def.material.tangentSpeed, 0, 1) //if .ACTIVE in mu.begin_treenode(&state.mu_ctx, "Color") mu.end_treenode(&state.mu_ctx) } 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(def.vertices[:], .Horizontal) if im.Button("Flip Vertically ") do flip_points(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) && len(interface.entity_defs) > 0 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 mu.checkbox(fmt.tprint(flag), &contains) do def.entity_flags ~= {flag} } if .ACTIVE in mu.begin_treenode(&interface.state.mu_ctx, "Body Def") { mu_interface_body_def_editor(interface, def) mu.end_treenode(&interface.state.mu_ctx) } if .ACTIVE in mu.begin_treenode(&interface.state.mu_ctx, "Shape Def") { mu_interface_shape_def_editor(interface.state, def) mu.end_treenode(&interface.state.mu_ctx) } if .ACTIVE in mu.begin_treenode(&interface.state.mu_ctx, "Static Index") { //ret |= interface_edit_static_index(interface, def) } /* if .CHAIN in def.entity_flags { im.InputInt("Body Count", &def.body_count) //im.SliderFloat2("Half Link Length", &def.link_length, -10, 10) if im.CollapsingHeader("Chain joint def") { interface_edit_rev_joint_minimal(&def.rev_joint) } } */ return !compare_engine_entity_def(def^, def_old) || ret } return false }