Joints
This commit is contained in:
+16
-7
@@ -17,20 +17,24 @@ static_index_global :: struct
|
|||||||
Don't put game's logic here
|
Don't put game's logic here
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
joint_common :: struct
|
||||||
|
{
|
||||||
|
entity_a, entity_b : static_index,
|
||||||
|
bodyIdA, bodyIdB : b2.BodyId,
|
||||||
|
}
|
||||||
|
|
||||||
revolt_joint_def :: struct
|
revolt_joint_def :: struct
|
||||||
{
|
{
|
||||||
using def : b2.RevoluteJointDef,
|
|
||||||
|
|
||||||
//Everything else can be stored in the def
|
//Everything else can be stored in the def
|
||||||
entity_a, entity_b : static_index,
|
entity_a, entity_b : static_index,
|
||||||
|
|
||||||
|
using def : b2.RevoluteJointDef,
|
||||||
}
|
}
|
||||||
|
|
||||||
distance_joint_def :: struct
|
distance_joint_def :: struct
|
||||||
{
|
{
|
||||||
using def : b2.DistanceJointDef,
|
|
||||||
|
|
||||||
//Everything else can be stored in the def
|
|
||||||
entity_a, entity_b : static_index,
|
entity_a, entity_b : static_index,
|
||||||
|
using def : b2.DistanceJointDef,
|
||||||
}
|
}
|
||||||
|
|
||||||
engine_world :: struct
|
engine_world :: struct
|
||||||
@@ -42,10 +46,15 @@ engine_world :: struct
|
|||||||
relations : map[^static_index][dynamic]static_index_global `cbor:"-"`,
|
relations : map[^static_index][dynamic]static_index_global `cbor:"-"`,
|
||||||
relations_serializeable : map[ static_index][dynamic]static_index_global,
|
relations_serializeable : map[ static_index][dynamic]static_index_global,
|
||||||
|
|
||||||
|
/*
|
||||||
|
Seems okay to put the joint defs in engine rather than in game because
|
||||||
|
we don't add more attributes in joints in the game
|
||||||
|
|
||||||
|
Can be changed later without requireing refactor
|
||||||
|
*/
|
||||||
revolute_joint_defs : [dynamic]revolt_joint_def,
|
revolute_joint_defs : [dynamic]revolt_joint_def,
|
||||||
distant_joint_defs : [dynamic]distance_joint_def,
|
distant_joint_defs : [dynamic]distance_joint_def,
|
||||||
|
joints : [dynamic]b2.JointId `cbor:"-"`,
|
||||||
revolute_joints : [dynamic]b2.JointId,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
engine_entity_flags_enum :: enum u64 {
|
engine_entity_flags_enum :: enum u64 {
|
||||||
|
|||||||
+44
-20
@@ -1,16 +1,18 @@
|
|||||||
package ion
|
package ion
|
||||||
import "base:runtime"
|
|
||||||
import "core:slice"
|
import "core:slice"
|
||||||
import "core:container/small_array"
|
import "core:container/small_array"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import im "shared:odin-imgui"
|
import im "shared:odin-imgui"
|
||||||
import "vendor:glfw"
|
|
||||||
import b2 "vendor:box2d"
|
import b2 "vendor:box2d"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This library will only account for box2d's entities editing
|
This library will only account for box2d's entities editing
|
||||||
|
|
||||||
It only deals with one world_id, which means typically one level
|
It only deals with one world_id, which means typically one level
|
||||||
|
|
||||||
|
All the interface follows a pattern
|
||||||
|
i.e. It takes interface_state pointer and returns a boolean indicating weather the world needs to be reloaded
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
EditMode :: enum
|
EditMode :: enum
|
||||||
@@ -18,23 +20,23 @@ EditMode :: enum
|
|||||||
ENTITY,
|
ENTITY,
|
||||||
VERTICES,
|
VERTICES,
|
||||||
OVERVIEW,
|
OVERVIEW,
|
||||||
|
JOINT,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface_state :: struct
|
interface_state :: struct
|
||||||
{
|
{
|
||||||
entity_defs: [dynamic]^engine_entity_def,
|
entity_defs : [dynamic]^engine_entity_def,
|
||||||
entities: [dynamic]^engine_entity,
|
entities : [dynamic]^engine_entity,
|
||||||
selected_entity: ^i32,
|
selected_entity : ^i32,
|
||||||
world: ^engine_world,
|
world : ^engine_world,
|
||||||
state: ^engine_state,
|
state : ^engine_state,
|
||||||
|
|
||||||
vertex_index : ^i32,
|
vertex_index : ^i32,
|
||||||
edit_mode : EditMode,
|
edit_mode : EditMode,
|
||||||
|
|
||||||
curr_revolt_joint : revolt_joint_def,
|
|
||||||
|
|
||||||
curr_joint_joint : distance_joint_def,
|
curr_joint_index : i32,
|
||||||
|
curr_joint_type : b2.JointType,
|
||||||
|
|
||||||
curr_static_index : static_index_global,
|
curr_static_index : static_index_global,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,15 +253,15 @@ interface_edit_static_index :: proc(interface:^interface_state, def: ^engine_ent
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
interface_edit_revolute_joint :: proc(interface: ^interface_state) -> bool
|
interface_edit_revolute_joint :: proc(interface: ^interface_state) -> bool
|
||||||
{
|
{
|
||||||
|
|
||||||
//Select static index and then get bodyId from it
|
//Select static index and then get bodyId from it
|
||||||
//If chain shapre then allow choosing index
|
//If chain shapre then allow choosing index
|
||||||
|
|
||||||
level := interface.world
|
level := interface.world
|
||||||
|
|
||||||
joint_def := &interface.curr_revolt_joint
|
joint_def := interface.curr_revolt_joint
|
||||||
|
|
||||||
if im.BeginCombo("Index A", fmt.ctprint(joint_def.entity_a))
|
if im.BeginCombo("Index A", fmt.ctprint(joint_def.entity_a))
|
||||||
{
|
{
|
||||||
@@ -317,13 +319,14 @@ interface_edit_revolute_joint :: proc(interface: ^interface_state) -> bool
|
|||||||
|
|
||||||
if im.Button("Add joint")
|
if im.Button("Add joint")
|
||||||
{
|
{
|
||||||
append(&level.revolute_joint_defs, interface.curr_revolt_joint)
|
//append(&level.revolute_joint_defs, interface.curr_revolt_joint)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
interface_entity :: proc(interface: ^interface_state) -> bool
|
interface_entity :: proc(interface: ^interface_state) -> bool
|
||||||
@@ -333,14 +336,14 @@ interface_entity :: proc(interface: ^interface_state) -> bool
|
|||||||
|
|
||||||
if entity_selected
|
if entity_selected
|
||||||
{
|
{
|
||||||
def := interface.entity_defs[interface.selected_entity^]
|
def := interface.entity_defs[interface.selected_entity^]
|
||||||
def_old := def^
|
def_old := def^
|
||||||
|
|
||||||
ret := false
|
ret := false
|
||||||
|
|
||||||
if im.BeginTabItem("Entity", nil, {.Leading})
|
if im.BeginTabItem("Entity", nil, {.Leading})
|
||||||
{
|
{
|
||||||
|
interface.edit_mode = .ENTITY
|
||||||
//Flags
|
//Flags
|
||||||
for flag in engine_entity_flags_enum
|
for flag in engine_entity_flags_enum
|
||||||
{
|
{
|
||||||
@@ -375,12 +378,26 @@ interface_entity :: proc(interface: ^interface_state) -> bool
|
|||||||
|
|
||||||
if im.BeginTabItem("Joints", nil , {})
|
if im.BeginTabItem("Joints", nil , {})
|
||||||
{
|
{
|
||||||
|
interface.edit_mode = .JOINT
|
||||||
if im.CollapsingHeader("Revolute Joints")
|
|
||||||
|
if im.BeginCombo("Joint type", fmt.ctprint(interface.curr_joint_type))
|
||||||
|
{
|
||||||
|
for type in b2.JointType
|
||||||
|
{
|
||||||
|
if im.Selectable(fmt.ctprint(type), type == interface.curr_joint_type) do interface.curr_joint_type = type
|
||||||
|
}
|
||||||
|
im.EndCombo()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if interface.curr_joint_type == .distanceJoint
|
||||||
|
{
|
||||||
|
ret |= interface_edit_distance_joint(interface)
|
||||||
|
}
|
||||||
|
if interface.curr_joint_type == .revoluteJoint
|
||||||
{
|
{
|
||||||
ret |= interface_edit_revolute_joint(interface)
|
ret |= interface_edit_revolute_joint(interface)
|
||||||
}
|
}
|
||||||
|
|
||||||
im.EndTabItem()
|
im.EndTabItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,3 +424,10 @@ interface_all :: proc(interface: ^interface_state) -> bool
|
|||||||
im.End()
|
im.End()
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,162 @@
|
|||||||
|
package ion
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
|
import b2 "vendor:box2d"
|
||||||
|
import im "shared:odin-imgui"
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO:
|
||||||
|
Delete joints
|
||||||
|
Angles in degree
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
All joints have bodyIdA and bodyIdB
|
||||||
|
*/
|
||||||
|
interface_edit_joint_common :: proc(joint_def : ^joint_common, interface: ^interface_state) -> bool
|
||||||
|
{
|
||||||
|
level := interface.world
|
||||||
|
{
|
||||||
|
if joint_def.entity_a in level.static_indexes{
|
||||||
|
entity_a := interface.entity_defs[level.static_indexes[joint_def.entity_a]]
|
||||||
|
points_add(&interface.state.draw.points, entity_a.body_def.position, 20.0, b2.HexColor.Plum)
|
||||||
|
}
|
||||||
|
if joint_def.entity_b in level.static_indexes{
|
||||||
|
entity_b := interface.entity_defs[level.static_indexes[joint_def.entity_b]]
|
||||||
|
points_add(&interface.state.draw.points, entity_b.body_def.position, 20.0, b2.HexColor.Plum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set body A and Body B on the basis of static index so that it can pesist after restart
|
||||||
|
*/
|
||||||
|
|
||||||
|
if im.BeginCombo("Index A", fmt.ctprint(joint_def.entity_a))
|
||||||
|
{
|
||||||
|
for i in level.static_indexes
|
||||||
|
{
|
||||||
|
if im.Selectable(fmt.ctprint(i), i == joint_def.entity_a) do joint_def.entity_a = i
|
||||||
|
}
|
||||||
|
im.EndCombo()
|
||||||
|
}
|
||||||
|
|
||||||
|
im.Separator()
|
||||||
|
|
||||||
|
if im.BeginCombo("Index B", fmt.ctprint(joint_def.entity_b))
|
||||||
|
{
|
||||||
|
for i in level.static_indexes
|
||||||
|
{
|
||||||
|
if im.Selectable(fmt.ctprint(i), i == joint_def.entity_b) do joint_def.entity_b = i
|
||||||
|
}
|
||||||
|
im.EndCombo()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface_edit_distance_joint :: proc( interface : ^interface_state ) -> bool
|
||||||
|
{
|
||||||
|
level := interface.world
|
||||||
|
interface.curr_joint_type = .distanceJoint
|
||||||
|
|
||||||
|
if len(level.distant_joint_defs) == 0 do im.Text("No distance joint created, Click add to create new")
|
||||||
|
|
||||||
|
if im.Button("Create new joint")
|
||||||
|
{
|
||||||
|
append(&level.distant_joint_defs, distance_joint_def{def = b2.DefaultDistanceJointDef()})
|
||||||
|
|
||||||
|
interface.curr_joint_index = i32(len(level.distant_joint_defs))
|
||||||
|
}
|
||||||
|
|
||||||
|
//Select index
|
||||||
|
{
|
||||||
|
if im.BeginCombo("Select joint", fmt.ctprint(interface.curr_joint_index))
|
||||||
|
{
|
||||||
|
for i in 0..<len(level.distant_joint_defs){
|
||||||
|
if im.Selectable(fmt.ctprint(i), i32(i) == interface.curr_joint_index) do interface.curr_joint_index = i32(i)
|
||||||
|
}
|
||||||
|
im.EndCombo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if interface.curr_joint_index >= i32(len(level.distant_joint_defs)) do return false
|
||||||
|
|
||||||
|
joint_def := &level.distant_joint_defs[interface.curr_joint_index]
|
||||||
|
old_def := joint_def^
|
||||||
|
|
||||||
|
if interface_edit_joint_common(cast(^joint_common)joint_def, interface) do return true
|
||||||
|
|
||||||
|
/*
|
||||||
|
Highlight the bodies here
|
||||||
|
*/
|
||||||
|
|
||||||
|
im.SliderFloat2("localAnchorA", &joint_def.localAnchorA, -5, 5)
|
||||||
|
im.SliderFloat2("localAnchorB", &joint_def.localAnchorB, -5, 5)
|
||||||
|
im.SliderFloat("Rest length", &joint_def.length, 0, 100)
|
||||||
|
im.Checkbox("Enable Spring", &joint_def.enableSpring)
|
||||||
|
im.InputFloat("Hertz ", &joint_def.hertz)
|
||||||
|
im.InputFloat("Damping Ratio", &joint_def.dampingRatio)
|
||||||
|
im.Checkbox("Enable Limit", &joint_def.enableLimit)
|
||||||
|
im.InputFloat("Min length", &joint_def.minLength)
|
||||||
|
im.InputFloat("Max length", &joint_def.maxLength)
|
||||||
|
im.Checkbox("Enable Motor", &joint_def.enableMotor)
|
||||||
|
im.InputFloat("Moror Torque", &joint_def.maxMotorForce)
|
||||||
|
im.InputFloat("Moror Speed", &joint_def.motorSpeed)
|
||||||
|
im.Checkbox("Collide Connected", &joint_def.collideConnected)
|
||||||
|
|
||||||
|
return old_def != joint_def^
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface_edit_revolute_joint :: proc( interface : ^interface_state ) -> bool
|
||||||
|
{
|
||||||
|
level := interface.world
|
||||||
|
interface.curr_joint_type = .revoluteJoint
|
||||||
|
|
||||||
|
if len(level.revolute_joint_defs) == 0 do im.Text("No revolute joint created, Click add to create new")
|
||||||
|
|
||||||
|
if im.Button("Create new joint")
|
||||||
|
{
|
||||||
|
append(&level.revolute_joint_defs, revolt_joint_def{def = b2.DefaultRevoluteJointDef()})
|
||||||
|
|
||||||
|
interface.curr_joint_index = i32(len(level.revolute_joint_defs))
|
||||||
|
}
|
||||||
|
|
||||||
|
//Select index
|
||||||
|
if im.BeginCombo("Select joint", fmt.ctprint(interface.curr_joint_index))
|
||||||
|
{
|
||||||
|
for i in 0..<len(level.revolute_joint_defs){
|
||||||
|
if im.Selectable(fmt.ctprint(i), i32(i) == interface.curr_joint_index) do interface.curr_joint_index = i32(i)
|
||||||
|
}
|
||||||
|
im.EndCombo()
|
||||||
|
}
|
||||||
|
|
||||||
|
if interface.curr_joint_index >= i32(len(level.revolute_joint_defs)) do return false
|
||||||
|
|
||||||
|
joint_def := &level.revolute_joint_defs[interface.curr_joint_index]
|
||||||
|
old_def := joint_def^
|
||||||
|
|
||||||
|
if interface_edit_joint_common(cast(^joint_common)joint_def, interface) do return true
|
||||||
|
|
||||||
|
/*
|
||||||
|
Highlight the bodies here
|
||||||
|
*/
|
||||||
|
|
||||||
|
im.SliderFloat2("localAnchorA", &joint_def.localAnchorA, -5, 5)
|
||||||
|
im.SliderFloat2("localAnchorB", &joint_def.localAnchorB, -5, 5)
|
||||||
|
im.SliderFloat("Refresh angle", &joint_def.referenceAngle, 0, 100)
|
||||||
|
im.SliderFloat("Target angle", &joint_def.targetAngle, 0, 100)
|
||||||
|
im.Checkbox("Enable Spring", &joint_def.enableSpring)
|
||||||
|
im.InputFloat("Hertz ", &joint_def.hertz)
|
||||||
|
im.InputFloat("Damping Ratio", &joint_def.dampingRatio)
|
||||||
|
im.InputFloat("Lower Angle", &joint_def.lowerAngle)
|
||||||
|
im.InputFloat("Upper Angle", &joint_def.upperAngle)
|
||||||
|
im.InputFloat("Max Motor Limit", &joint_def.maxMotorTorque)
|
||||||
|
im.InputFloat("Motor Speed", &joint_def.motorSpeed)
|
||||||
|
im.InputFloat("Draw Size", &joint_def.drawSize)
|
||||||
|
im.Checkbox("Enable Motor", &joint_def.enableMotor)
|
||||||
|
im.Checkbox("Enable Limit", &joint_def.enableLimit)
|
||||||
|
im.Checkbox("Collide Connected", &joint_def.collideConnected)
|
||||||
|
|
||||||
|
return old_def != joint_def^
|
||||||
|
}
|
||||||
@@ -40,7 +40,6 @@ input_state :: struct
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
This will only be called once to initilize the engine
|
This will only be called once to initilize the engine
|
||||||
|
|
||||||
initilize graphics library, glfw, callbacks
|
initilize graphics library, glfw, callbacks
|
||||||
*/
|
*/
|
||||||
engine_init :: proc(state: ^engine_state)
|
engine_init :: proc(state: ^engine_state)
|
||||||
|
|||||||
Reference in New Issue
Block a user