335 lines
7.1 KiB
Odin
335 lines
7.1 KiB
Odin
package edit2d
|
|
|
|
import b2 "vendor:box2d"
|
|
import "core:fmt"
|
|
|
|
Static_Index :: i32
|
|
|
|
Static_Index_Global :: struct
|
|
{
|
|
index : i32,
|
|
level : string,
|
|
offset : b2.Vec2,
|
|
}
|
|
|
|
//DropProc :: #type proc "c" (window: WindowHandle, count: c.int, paths: [^]cstring)
|
|
|
|
/*
|
|
This file contains code to handle box2d stuffs of the game code
|
|
Don't put game's logic here
|
|
*/
|
|
|
|
|
|
Engine_Entity_Flags_Enum :: enum u64 {
|
|
POLYGON_IS_BOX,
|
|
MULTI_BODIES,
|
|
CHAIN,
|
|
CHAIN_CUSTOM,
|
|
MULTI_SHAPES,
|
|
}
|
|
|
|
Engine_Entity_Flags :: bit_set[Engine_Entity_Flags_Enum]
|
|
|
|
Engine_Entity_Def :: struct {
|
|
body_def : b2.BodyDef,
|
|
shape_def : b2.ShapeDef,
|
|
shape_type : b2.ShapeType,
|
|
|
|
|
|
radius, scale : f32,
|
|
centers : [2]b2.Vec2,
|
|
size : b2.Vec2,
|
|
is_loop : bool,
|
|
|
|
vertices : [dynamic; b2.MAX_POLYGON_VERTICES]b2.Vec2,
|
|
name_buf : [255]u8 `fmt:"-" cbor:"-"`,
|
|
|
|
entity_flags : Engine_Entity_Flags,
|
|
|
|
index : Static_Index,
|
|
|
|
//For chain bodies
|
|
//It will replicate itself to the body count and connect themselves with rev_joints
|
|
body_count : i32,
|
|
|
|
//If chain not custom then the dynamic list of link_length will be used to create the chain
|
|
//Handle the link_length like vertices
|
|
rev_joint : b2.RevoluteJointDef,
|
|
link_length_array : [dynamic]b2.Vec2,
|
|
}
|
|
|
|
default_engine_entity_def :: proc() -> Engine_Entity_Def
|
|
{
|
|
ret : Engine_Entity_Def
|
|
ret.body_def = b2.DefaultBodyDef()
|
|
ret.shape_def = b2.DefaultShapeDef()
|
|
ret.shape_type = .polygonShape
|
|
ret.scale = 1
|
|
ret.centers = {{-10, 0}, {10, 0}}
|
|
ret.size = {2, 2}
|
|
ret.radius = 10
|
|
ret.body_count = 10
|
|
ret.rev_joint = b2.DefaultRevoluteJointDef()
|
|
|
|
//for dynamic polygon
|
|
vs : [4]b2.Vec2 = {
|
|
{-1.0, -1.0},
|
|
{-1.0, 1.0},
|
|
{1.0, 1.0},
|
|
{1.0, -1.0},
|
|
}
|
|
ret.is_loop = true
|
|
|
|
for v in vs do append(&ret.vertices, v)
|
|
return ret
|
|
}
|
|
|
|
|
|
compare_engine_entity_def :: proc(a, b : Engine_Entity_Def) -> bool
|
|
{
|
|
ret := false
|
|
|
|
ret &= a.body_def == b.body_def
|
|
ret &= a.shape_def == b.shape_def
|
|
ret &= a.shape_type == b.shape_type
|
|
|
|
|
|
ret &= a.radius == b.radius
|
|
ret &= a.scale == b.scale
|
|
ret &= a.centers == b.centers
|
|
ret &= a.size == b.size
|
|
ret &= a.is_loop == b.is_loop
|
|
//ret &= a.vertices[:] == b.vertices[:]
|
|
ret &= a.name_buf == b.name_buf
|
|
|
|
ret &= a.entity_flags == b.entity_flags
|
|
ret &= a.index == b.index
|
|
|
|
ret &= a.body_count == b.body_count
|
|
ret &= a.rev_joint == b.rev_joint
|
|
//ret &= a.link_length[:] == b.link_length[:]
|
|
|
|
return ret
|
|
}
|
|
|
|
|
|
|
|
Engine_Entity :: struct {
|
|
body_id : b2.BodyId,
|
|
shape_id : b2.ShapeId,
|
|
|
|
//This is if the entity has multiple bodies
|
|
bodies : [dynamic]b2.BodyId,
|
|
shapes : [dynamic]b2.ShapeId,
|
|
joints : [dynamic]b2.JointId,
|
|
entity_flags : Engine_Entity_Flags,
|
|
index : ^Static_Index,
|
|
joint_id : b2.JointId,
|
|
}
|
|
|
|
|
|
|
|
engine_entity_single_body :: proc(def : ^Engine_Entity_Def, world_id: b2.WorldId, index : i32) -> Engine_Entity
|
|
{
|
|
|
|
def := def
|
|
|
|
new_entity : Engine_Entity
|
|
|
|
|
|
if def.index != 0
|
|
{
|
|
new_entity.index = new(Static_Index)
|
|
new_entity.index^ = def.index
|
|
}
|
|
|
|
new_entity.body_id = b2.CreateBody(world_id, def.body_def)
|
|
|
|
switch def.shape_type{
|
|
|
|
case .circleShape:
|
|
{
|
|
def.radius *= def.scale
|
|
circle := b2.Circle{ radius = def.radius }
|
|
|
|
def.scale = 1
|
|
|
|
new_entity.shape_id = b2.CreateCircleShape(new_entity.body_id, def.shape_def, circle)
|
|
}
|
|
|
|
case .capsuleShape:
|
|
{
|
|
def.radius *= def.scale
|
|
def.centers[0] *= def.scale
|
|
def.centers[1] *= def.scale
|
|
|
|
def.scale = 1
|
|
|
|
capsule := b2.Capsule{
|
|
center1 = def.centers[0],
|
|
center2 = def.centers[1],
|
|
radius = def.radius
|
|
}
|
|
|
|
new_entity.shape_id = b2.CreateCapsuleShape(
|
|
new_entity.body_id,
|
|
def.shape_def,
|
|
capsule
|
|
)
|
|
}
|
|
case .chainSegmentShape:
|
|
{
|
|
chain_def := b2.DefaultChainDef()
|
|
verts :[dynamic]b2.Vec2
|
|
|
|
for &v in def.vertices[:]{
|
|
v *= def.scale
|
|
}
|
|
|
|
|
|
for v in def.vertices[:]{
|
|
//If it's not a looped chain then it needs two defination
|
|
|
|
if !def.is_loop do append(&verts, v)
|
|
|
|
append(&verts, v)
|
|
}
|
|
|
|
|
|
chain_def.points = &verts[0]
|
|
chain_def.count = i32(len(verts))
|
|
chain_def.isLoop = def.is_loop
|
|
|
|
c := b2.CreateChain(new_entity.body_id, chain_def)
|
|
|
|
shapes_data :[10]b2.ShapeId
|
|
shapes := b2.Body_GetShapes(new_entity.body_id, shapes_data[:])
|
|
|
|
for shape in shapes{
|
|
b2.Shape_SetUserData(shape, rawptr(uintptr(index)))
|
|
}
|
|
|
|
def.scale = 1
|
|
|
|
|
|
}
|
|
case .segmentShape:
|
|
{
|
|
for &v in def.vertices[:]{
|
|
v *= def.scale
|
|
}
|
|
segment : b2.Segment = {point1 = def.vertices[0], point2 = def.vertices[2]}
|
|
|
|
new_entity.shape_id = b2.CreateSegmentShape(new_entity.body_id, def.shape_def, segment)
|
|
def.scale = 1
|
|
|
|
}
|
|
case .polygonShape:
|
|
{
|
|
poly : b2.Polygon
|
|
|
|
if .POLYGON_IS_BOX in def.entity_flags
|
|
{
|
|
def.size *= def.scale
|
|
poly = b2.MakeBox(def.size.x, def.size.y)
|
|
def.scale = 1
|
|
}else
|
|
{
|
|
//def.size *= def.scale
|
|
|
|
for &v in def.vertices[:]{
|
|
v *= def.scale
|
|
}
|
|
|
|
points := make([dynamic]b2.Vec2, 0)
|
|
|
|
for p, i in def.vertices[:]{
|
|
if i >= int(len(def.vertices)) do break
|
|
append_elem(&points, p)
|
|
}
|
|
sort_points_ccw(points[:])
|
|
|
|
hull := b2.ComputeHull(points[:])
|
|
poly = b2.MakePolygon(hull, 0)
|
|
delete(points)
|
|
def.scale = 1
|
|
}
|
|
new_entity.shape_id = b2.CreatePolygonShape(new_entity.body_id, def.shape_def, poly)
|
|
}
|
|
|
|
}
|
|
|
|
if def.shape_type != .chainSegmentShape{
|
|
b2.Shape_SetUserData(new_entity.shape_id, rawptr(uintptr(index)))
|
|
}
|
|
|
|
return new_entity
|
|
}
|
|
|
|
engine_create_chain_shape :: proc(
|
|
def : ^Engine_Entity_Def,
|
|
world_id : b2.WorldId,
|
|
index : i32
|
|
) -> Engine_Entity
|
|
{
|
|
joint_def := def.rev_joint
|
|
orig_pos := def.body_def.position
|
|
position := def.body_def.position
|
|
|
|
prev_body_id : b2.BodyId
|
|
|
|
engine_entity := engine_entity_single_body(def, world_id, index)
|
|
|
|
for i in def.link_length_array[:]
|
|
{
|
|
rot := b2.ComputeRotationBetweenUnitVectors(def.body_def.position, position)
|
|
|
|
def.body_def.rotation = rot
|
|
|
|
def.body_def.position = position
|
|
engine_entity = engine_entity_single_body(def, world_id, index)
|
|
pivot := position - i
|
|
|
|
|
|
if i != 0
|
|
{
|
|
joint_def.bodyIdA = prev_body_id
|
|
joint_def.bodyIdB = engine_entity.body_id
|
|
joint_def.localAnchorA = b2.Body_GetLocalPoint(joint_def.bodyIdA, pivot)
|
|
joint_def.localAnchorB = b2.Body_GetLocalPoint(joint_def.bodyIdB, pivot)
|
|
joint_id := b2.CreateRevoluteJoint(world_id, joint_def)
|
|
}
|
|
position += 2 * i
|
|
prev_body_id = engine_entity.body_id
|
|
}
|
|
def.body_def.position = orig_pos
|
|
return engine_entity
|
|
}
|
|
|
|
|
|
engine_create_entity :: proc(
|
|
def : ^Engine_Entity_Def,
|
|
world_id : b2.WorldId,
|
|
index : i32
|
|
) -> Engine_Entity
|
|
{
|
|
|
|
if .CHAIN not_in def.entity_flags
|
|
{
|
|
return engine_entity_single_body(def, world_id, index)
|
|
}
|
|
else
|
|
{
|
|
return engine_create_chain_shape(def, world_id, index)
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|