Files
Edit2D/entity.odin
T
2026-03-28 13:42:24 +05:45

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)
}
}