rudimentary raycasting
This commit is contained in:
parent
1839899027
commit
0e269f0e83
@ -1,7 +1,9 @@
|
|||||||
S_Ctx S = Zi;
|
S_Ctx S = Zi;
|
||||||
|
|
||||||
Readonly S_Ent S_NilEnt = {
|
Readonly S_Ent S_NilEnt = {
|
||||||
|
.last_xf = CompXformIdentity,
|
||||||
.xf = CompXformIdentity,
|
.xf = CompXformIdentity,
|
||||||
|
.look = { 0, -1 },
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -305,22 +307,19 @@ Vec2 S_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal)
|
|||||||
f32 vab_w = WedgeVec2(vab, normal);
|
f32 vab_w = WedgeVec2(vab, normal);
|
||||||
f32 vap_w = WedgeVec2(vap, normal);
|
f32 vap_w = WedgeVec2(vap, normal);
|
||||||
|
|
||||||
f32 t;
|
|
||||||
{
|
|
||||||
f32 w = 1 / vab_w;
|
f32 w = 1 / vab_w;
|
||||||
t = ClampF32(vap_w * w, 0, 1);
|
f32 t = ClampF32(vap_w * w, 0, 1);
|
||||||
}
|
|
||||||
|
|
||||||
Vec2 result = AddVec2(a, MulVec2(vab, t));
|
Vec2 result = AddVec2(a, MulVec2(vab, t));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1)
|
S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1, Vec2 sweep)
|
||||||
{
|
{
|
||||||
S_CollisionData result = Zi;
|
S_CollisionData result = Zi;
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
|
|
||||||
f32 tolerance = 0.005f; // How close can non-overlapping shapes be before collision is considered
|
f32 tolerance = 0.00005f; // How close can non-overlapping shapes be before collision is considered
|
||||||
f32 min_unique_pt_dist_sq = (0.001f * 0.001f); // NOTE: Should always be less than tolerance, since colliding = 1 if origin is within this distance.
|
f32 min_unique_pt_dist_sq = (0.001f * 0.001f); // NOTE: Should always be less than tolerance, since colliding = 1 if origin is within this distance.
|
||||||
u32 max_iterations = 64; // To prevent extremely large prototypes when origin is in exact center of rounded feature
|
u32 max_iterations = 64; // To prevent extremely large prototypes when origin is in exact center of rounded feature
|
||||||
|
|
||||||
@ -493,12 +492,14 @@ S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1)
|
|||||||
//- EPA
|
//- EPA
|
||||||
|
|
||||||
Vec2 normal = Zi;
|
Vec2 normal = Zi;
|
||||||
|
Vec2 sweep_dir = NormVec2(sweep);
|
||||||
|
b32 is_sweeping = !IsVec2Zero(sweep_dir);
|
||||||
S_MenkowskiSimplex closest_feature = Zi;
|
S_MenkowskiSimplex closest_feature = Zi;
|
||||||
{
|
{
|
||||||
S_MenkowskiPoint *proto = 0;
|
S_MenkowskiPoint *proto = 0;
|
||||||
u32 proto_count = 0;
|
|
||||||
if (is_overlapping)
|
if (is_overlapping)
|
||||||
{
|
{
|
||||||
|
u32 proto_count = 0;
|
||||||
proto = ArenaNext(scratch.arena, S_MenkowskiPoint);
|
proto = ArenaNext(scratch.arena, S_MenkowskiPoint);
|
||||||
{
|
{
|
||||||
Assert(simplex.count == 3);
|
Assert(simplex.count == 3);
|
||||||
@ -518,23 +519,51 @@ S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1)
|
|||||||
|
|
||||||
// Find dir from origin to closest edge
|
// Find dir from origin to closest edge
|
||||||
// FIXME: Winding order of ps & pe index
|
// FIXME: Winding order of ps & pe index
|
||||||
f32 closest_len_sq = Inf;
|
|
||||||
S_MenkowskiPoint closest_a = Zi;
|
S_MenkowskiPoint closest_a = Zi;
|
||||||
S_MenkowskiPoint closest_b = Zi;
|
S_MenkowskiPoint closest_b = Zi;
|
||||||
u32 closest_b_index = 0;
|
u32 closest_b_index = 0;
|
||||||
|
{
|
||||||
|
if (is_sweeping)
|
||||||
|
{
|
||||||
|
// Find edge segment on prototype furthest along the sweep direction
|
||||||
|
// FIXME: This is not very stable at the moment, needs refining
|
||||||
|
for (u32 i = 0; i < proto_count; ++i)
|
||||||
|
{
|
||||||
|
u32 a_index = i;
|
||||||
|
u32 b_index = (i < proto_count - 1) ? (i + 1) : 0;
|
||||||
|
S_MenkowskiPoint a = proto[a_index];
|
||||||
|
S_MenkowskiPoint b = proto[b_index];
|
||||||
|
Vec2 vab = SubVec2(b.p, a.p);
|
||||||
|
if (WedgeVec2(vab, sweep_dir) * winding > 0)
|
||||||
|
{
|
||||||
|
f32 wedge_a = WedgeVec2(sweep_dir, a.p);
|
||||||
|
f32 wedge_b = WedgeVec2(sweep_dir, b.p);
|
||||||
|
i32 wedge_sign_a = (wedge_a >= 0) - (wedge_a < 0);
|
||||||
|
i32 wedge_sign_b = (wedge_b >= 0) - (wedge_b < 0);
|
||||||
|
if (wedge_sign_a != wedge_sign_b)
|
||||||
|
{
|
||||||
|
closest_a = a;
|
||||||
|
closest_b = b;
|
||||||
|
closest_b_index = b_index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Find edge segment on prototype closest to the origin
|
||||||
|
f32 closest_len_sq = Inf;
|
||||||
for (u32 i = 0; i < proto_count; ++i)
|
for (u32 i = 0; i < proto_count; ++i)
|
||||||
{
|
{
|
||||||
u32 a_index = i;
|
u32 a_index = i;
|
||||||
u32 b_index = (i < proto_count - 1) ? (i + 1) : 0;
|
u32 b_index = (i < proto_count - 1) ? (i + 1) : 0;
|
||||||
S_MenkowskiPoint a = proto[a_index];
|
S_MenkowskiPoint a = proto[a_index];
|
||||||
S_MenkowskiPoint b = proto[b_index];
|
S_MenkowskiPoint b = proto[b_index];
|
||||||
|
|
||||||
Vec2 vab = SubVec2(b.p, a.p);
|
Vec2 vab = SubVec2(b.p, a.p);
|
||||||
Vec2 vao = NegVec2(a.p);
|
Vec2 vao = NegVec2(a.p);
|
||||||
|
|
||||||
f32 proj_ratio = ClampF32(DotVec2(vao, vab) / Vec2LenSq(vab), 0, 1);
|
f32 proj_ratio = ClampF32(DotVec2(vao, vab) / Vec2LenSq(vab), 0, 1);
|
||||||
Vec2 proj = AddVec2(a.p, MulVec2(vab, proj_ratio));
|
Vec2 proj = AddVec2(a.p, MulVec2(vab, proj_ratio));
|
||||||
|
|
||||||
f32 proj_len_sq = Vec2LenSq(proj);
|
f32 proj_len_sq = Vec2LenSq(proj);
|
||||||
if (proj_len_sq < closest_len_sq - min_unique_pt_dist_sq)
|
if (proj_len_sq < closest_len_sq - min_unique_pt_dist_sq)
|
||||||
{
|
{
|
||||||
@ -544,27 +573,19 @@ S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1)
|
|||||||
closest_len_sq = proj_len_sq;
|
closest_len_sq = proj_len_sq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Vec2 vab = SubVec2(closest_b.p, closest_a.p);
|
Vec2 vab = SubVec2(closest_b.p, closest_a.p);
|
||||||
|
|
||||||
// Find new point in dir
|
// Find new point in dir
|
||||||
Vec2 dir = MulVec2(PerpVec2(vab), winding);
|
Vec2 dir = MulVec2(PerpVec2(vab), winding);
|
||||||
S_MenkowskiPoint m = S_MenkowskiPointFromShapes(shape0, shape1, dir);
|
S_MenkowskiPoint m = S_MenkowskiPointFromShapes(shape0, shape1, dir);
|
||||||
|
|
||||||
// if (debug)
|
|
||||||
// {
|
|
||||||
// // If debug step count is reached, we still want to inspect the normal at the step
|
|
||||||
// normal = NormVec2(dir);
|
|
||||||
// closest_feature.a = closest_a;
|
|
||||||
// closest_feature.b = closest_b;
|
|
||||||
// closest_feature.count = 2;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Check validity of new point
|
// Check validity of new point
|
||||||
{
|
{
|
||||||
b32 valid = 1;
|
b32 valid = 1;
|
||||||
|
|
||||||
{
|
{
|
||||||
// NOTE: Changing this value affects how stable normals are for circular colliders
|
// NOTE: Changing this value affects how stable normals are for rounded colliders
|
||||||
//const f32 validity_epsilon = min_unique_pt_dist_sq; // Arbitrary
|
//const f32 validity_epsilon = min_unique_pt_dist_sq; // Arbitrary
|
||||||
//const f32 validity_epsilon = 0.00000000001f; // Arbitrary
|
//const f32 validity_epsilon = 0.00000000001f; // Arbitrary
|
||||||
const f32 validity_epsilon = min_unique_pt_dist_sq; // Arbitrary
|
const f32 validity_epsilon = min_unique_pt_dist_sq; // Arbitrary
|
||||||
@ -611,6 +632,30 @@ S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1)
|
|||||||
// Insert new point into prototype
|
// Insert new point into prototype
|
||||||
proto[closest_b_index] = m;
|
proto[closest_b_index] = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debug draw
|
||||||
|
// {
|
||||||
|
// S_DebugDrawPoint(simplex.a.p, VEC4(1, 0, 0, 0.5));
|
||||||
|
// S_DebugDrawPoint(simplex.b.p, VEC4(0, 1, 0, 0.5));
|
||||||
|
// S_DebugDrawPoint(simplex.c.p, VEC4(0, 0, 1, 0.5));
|
||||||
|
// S_DebugDrawLine(simplex.a.p, simplex.b.p, Color_Yellow);
|
||||||
|
// S_DebugDrawLine(simplex.b.p, simplex.c.p, Color_Yellow);
|
||||||
|
// S_DebugDrawLine(simplex.c.p, simplex.a.p, Color_Yellow);
|
||||||
|
// if (proto_count > 0)
|
||||||
|
// {
|
||||||
|
// for (i64 i = 0; i < proto_count; ++i)
|
||||||
|
// {
|
||||||
|
// i64 p1_idx = i + 1;
|
||||||
|
// if (p1_idx == proto_count)
|
||||||
|
// {
|
||||||
|
// p1_idx = 0;
|
||||||
|
// }
|
||||||
|
// Vec2 p0 = proto[i].p;
|
||||||
|
// Vec2 p1 = proto[p1_idx].p;
|
||||||
|
// S_DebugDrawLine(p0, p1, VEC4(0, 1, 0, 0.5));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -872,13 +917,32 @@ S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1)
|
|||||||
|
|
||||||
CopyStructs(result.collision_points, collision_points, countof(collision_points));
|
CopyStructs(result.collision_points, collision_points, countof(collision_points));
|
||||||
result.collision_points_count = collision_points_count;
|
result.collision_points_count = collision_points_count;
|
||||||
|
result.collision_normal = normal;
|
||||||
result.closest_p0 = closest_p0;
|
result.closest_p0 = closest_p0;
|
||||||
result.closest_p1 = closest_p1;
|
result.closest_p1 = closest_p1;
|
||||||
|
|
||||||
|
|
||||||
EndScratch(scratch);
|
EndScratch(scratch);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
S_RaycastData S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir)
|
||||||
|
{
|
||||||
|
S_RaycastData result = Zi;
|
||||||
|
|
||||||
|
// HACK: Create line shape as large as the world and perform a collision test
|
||||||
|
Vec2 ray_shape_p0 = ray_start;
|
||||||
|
Vec2 ray_shape_p1 = AddVec2(ray_start, MulVec2(NormVec2(ray_dir), S_WorldPitch * 1.414213562));
|
||||||
|
S_Shape ray_shape = S_ShapeFromDesc(.count = 2, .points = { ray_shape_p0, ray_shape_p1 });
|
||||||
|
|
||||||
|
S_CollisionData cls = S_CollisionDataFromShapes(ray_shape, shape, ray_dir);
|
||||||
|
result.is_intersecting = cls.collision_points_count > 0;
|
||||||
|
result.normal = NegVec2(cls.collision_normal);
|
||||||
|
result.p = cls.closest_p1;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Lookup helpers
|
//~ Lookup helpers
|
||||||
|
|
||||||
@ -1122,10 +1186,30 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
{
|
{
|
||||||
target->move = ClampVec2Len(cmd.move, 1);
|
target->move = ClampVec2Len(cmd.move, 1);
|
||||||
target->look = cmd.look;
|
target->look = cmd.look;
|
||||||
|
target->fire_held = cmd.fire_held;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Spawn entities
|
||||||
|
|
||||||
|
// {
|
||||||
|
// //////////////////////////////
|
||||||
|
// //- Push bullets
|
||||||
|
|
||||||
|
// for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
|
// {
|
||||||
|
// if (ent->fire_held)
|
||||||
|
// {
|
||||||
|
// if (ent->has_weapon)
|
||||||
|
// {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Integrate control forces
|
//- Integrate control forces
|
||||||
|
|
||||||
@ -1176,6 +1260,8 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
|
|
||||||
|
|
||||||
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
|
{
|
||||||
|
if (ent->is_player)
|
||||||
{
|
{
|
||||||
Xform last_xf = ent->last_xf;
|
Xform last_xf = ent->last_xf;
|
||||||
S_Shape last_world_shape = S_MulXformShape(last_xf, ent->local_shape);
|
S_Shape last_world_shape = S_MulXformShape(last_xf, ent->local_shape);
|
||||||
@ -1195,11 +1281,9 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
constraint->ent0 = ent->key;
|
constraint->ent0 = ent->key;
|
||||||
constraint->shape0 = world_shape;
|
constraint->shape0 = world_shape;
|
||||||
|
|
||||||
|
|
||||||
Rng2 test_rect = Zi;
|
Rng2 test_rect = Zi;
|
||||||
test_rect.p0 = VEC2(-1, -1);
|
test_rect.p0 = VEC2(-1, -1);
|
||||||
test_rect.p1 = VEC2(1, 1);
|
test_rect.p1 = VEC2(1, 1);
|
||||||
|
|
||||||
constraint->shape1 = S_ShapeFromDesc(
|
constraint->shape1 = S_ShapeFromDesc(
|
||||||
.radius = 0.5,
|
.radius = 0.5,
|
||||||
.count = 4,
|
.count = 4,
|
||||||
@ -1212,6 +1296,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
constraints_count += 1;
|
constraints_count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Solve constraints
|
//- Solve constraints
|
||||||
@ -1263,7 +1348,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
// Vec2 shape0_pt = S_SupportPointFromShape(shape0, shape_dir);
|
// Vec2 shape0_pt = S_SupportPointFromShape(shape0, shape_dir);
|
||||||
// Vec2 shape1_pt = S_SupportPointFromShape(shape1, neg_shape_dir);
|
// Vec2 shape1_pt = S_SupportPointFromShape(shape1, neg_shape_dir);
|
||||||
|
|
||||||
S_CollisionData collision_data = S_CollisionDataFromShapes(shape0, shape1);
|
S_CollisionData collision_data = S_CollisionDataFromShapes(shape0, shape1, VEC2(0, 0));
|
||||||
Vec2 shape0_pt = collision_data.closest_p0;
|
Vec2 shape0_pt = collision_data.closest_p0;
|
||||||
Vec2 shape1_pt = collision_data.closest_p1;
|
Vec2 shape1_pt = collision_data.closest_p1;
|
||||||
|
|
||||||
@ -1313,6 +1398,79 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
ent->xf = xf;
|
ent->xf = xf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Check for bullet collisions
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Not like this
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
Struct(S_Bullet)
|
||||||
|
{
|
||||||
|
Vec2 start;
|
||||||
|
Vec2 dir;
|
||||||
|
|
||||||
|
f32 speed;
|
||||||
|
};
|
||||||
|
|
||||||
|
PERSIST i64 bullets_count = 1;
|
||||||
|
PERSIST S_Bullet *bullets = 0;
|
||||||
|
if (!bullets)
|
||||||
|
{
|
||||||
|
bullets = PushStruct(PermArena(), S_Bullet);
|
||||||
|
S_Bullet *bullet = &bullets[0];
|
||||||
|
bullet->start = VEC2(1, 0);
|
||||||
|
bullet->dir = NormVec2(VEC2(1, -1));
|
||||||
|
bullet->speed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i64 bullet_idx = 0; bullet_idx < bullets_count; ++bullet_idx)
|
||||||
|
{
|
||||||
|
S_Bullet *bullet = &bullets[bullet_idx];
|
||||||
|
|
||||||
|
// Raycast
|
||||||
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
|
{
|
||||||
|
Xform xf = ent->xf;
|
||||||
|
S_Shape world_shape = S_MulXformShape(xf, ent->local_shape);
|
||||||
|
|
||||||
|
if (ent == S_FirstEnt(world))
|
||||||
|
{
|
||||||
|
bullet->start = AddVec2(world_shape.centroid, Vec2WithLen(ent->look, world_shape.radius));
|
||||||
|
bullet->dir = NormVec2(ent->look);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
S_RaycastData raycast = S_RaycastShape(world_shape, bullet->start, bullet->dir);
|
||||||
|
Vec2 isect = raycast.p;
|
||||||
|
|
||||||
|
if (raycast.is_intersecting)
|
||||||
|
{
|
||||||
|
S_DebugDrawPoint(isect, Color_Green);
|
||||||
|
S_DebugDrawLine(isect, AddVec2(isect, MulVec2(raycast.normal, 0.5)), Color_White);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
S_DebugDrawPoint(isect, Color_Purple);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
S_DebugDrawLine(bullet->start, AddVec2(bullet->start, Vec2WithLen(bullet->dir, 0.5)), Color_Red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Debug draw entities
|
//- Debug draw entities
|
||||||
|
|
||||||
@ -1425,7 +1583,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
S_Ent **ents_to_prune = PushStructsNoZero(frame_arena, S_Ent *, world->ents_count);
|
S_Ent **ents_to_prune = PushStructsNoZero(frame_arena, S_Ent *, world->ents_count);
|
||||||
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
{
|
{
|
||||||
if (ent->prune >= 1)
|
if (ent->exists <= 0)
|
||||||
{
|
{
|
||||||
ents_to_prune[ents_to_prune_count] = ent;
|
ents_to_prune[ents_to_prune_count] = ent;
|
||||||
ents_to_prune_count += 1;
|
ents_to_prune_count += 1;
|
||||||
|
|||||||
@ -46,17 +46,19 @@ Struct(S_Ent)
|
|||||||
S_Ent *next_in_bin;
|
S_Ent *next_in_bin;
|
||||||
S_Ent *prev_in_bin;
|
S_Ent *prev_in_bin;
|
||||||
|
|
||||||
b32 valid;
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Persistent data
|
//- Persistent data
|
||||||
|
|
||||||
S_Key key;
|
S_Key key;
|
||||||
|
b32 valid;
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Build data
|
//- Build data
|
||||||
|
|
||||||
f32 prune;
|
f32 exists;
|
||||||
|
|
||||||
|
b32 is_player;
|
||||||
|
f32 health;
|
||||||
|
|
||||||
Xform last_xf;
|
Xform last_xf;
|
||||||
Xform xf;
|
Xform xf;
|
||||||
@ -66,6 +68,7 @@ Struct(S_Ent)
|
|||||||
f32 move_speed;
|
f32 move_speed;
|
||||||
Vec2 move;
|
Vec2 move;
|
||||||
Vec2 look;
|
Vec2 look;
|
||||||
|
f32 fire_held;
|
||||||
|
|
||||||
b32 has_weapon;
|
b32 has_weapon;
|
||||||
|
|
||||||
@ -122,12 +125,20 @@ Struct(S_CollisionData)
|
|||||||
// Contact manifold
|
// Contact manifold
|
||||||
i32 collision_points_count;
|
i32 collision_points_count;
|
||||||
S_CollisionPoint collision_points[2];
|
S_CollisionPoint collision_points[2];
|
||||||
|
Vec2 collision_normal;
|
||||||
|
|
||||||
// Closest points
|
// Closest points
|
||||||
Vec2 closest_p0;
|
Vec2 closest_p0;
|
||||||
Vec2 closest_p1;
|
Vec2 closest_p1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Struct(S_RaycastData)
|
||||||
|
{
|
||||||
|
Vec2 p;
|
||||||
|
Vec2 normal;
|
||||||
|
b32 is_intersecting;
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Constraint types
|
//~ Constraint types
|
||||||
|
|
||||||
@ -219,6 +230,7 @@ Struct(S_Cmd)
|
|||||||
S_Key target;
|
S_Key target;
|
||||||
Vec2 move;
|
Vec2 move;
|
||||||
Vec2 look;
|
Vec2 look;
|
||||||
|
b32 fire_held;
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(S_CmdNode)
|
Struct(S_CmdNode)
|
||||||
@ -353,7 +365,9 @@ S_SupportPoint S_SupportPointFromShape(S_Shape shape, Vec2 dir);
|
|||||||
S_MenkowskiPoint S_MenkowskiPointFromShapes(S_Shape shape0, S_Shape shape1, Vec2 dir);
|
S_MenkowskiPoint S_MenkowskiPointFromShapes(S_Shape shape0, S_Shape shape1, Vec2 dir);
|
||||||
S_ClippedLine S_ClipLineToLine(Vec2 a0, Vec2 b0, Vec2 a1, Vec2 b1, Vec2 normal);
|
S_ClippedLine S_ClipLineToLine(Vec2 a0, Vec2 b0, Vec2 a1, Vec2 b1, Vec2 normal);
|
||||||
Vec2 S_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal);
|
Vec2 S_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal);
|
||||||
S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1);
|
|
||||||
|
S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1, Vec2 sweep);
|
||||||
|
S_RaycastData S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Lookup helpers
|
//~ Lookup helpers
|
||||||
|
|||||||
@ -103,7 +103,7 @@ S_TranscodeResult S_TranscodeWorld(Arena *arena, S_World *src_world, String src_
|
|||||||
{
|
{
|
||||||
for (i64 i = 0; i < ents_count; ++i)
|
for (i64 i = 0; i < ents_count; ++i)
|
||||||
{
|
{
|
||||||
S_Ent *raw_ent = (S_Ent *)BB_ReadBytesRaw(&br, ents_count * sizeof(S_Ent));
|
S_Ent *raw_ent = (S_Ent *)BB_ReadBytesRaw(&br, sizeof(S_Ent));
|
||||||
if (raw_ent)
|
if (raw_ent)
|
||||||
{
|
{
|
||||||
S_Ent *ent = PushStructNoZero(arena, S_Ent);
|
S_Ent *ent = PushStructNoZero(arena, S_Ent);
|
||||||
|
|||||||
@ -574,7 +574,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
S_Ent **ents_to_prune = PushStructsNoZero(frame->arena, S_Ent *, world->ents_count);
|
S_Ent **ents_to_prune = PushStructsNoZero(frame->arena, S_Ent *, world->ents_count);
|
||||||
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
{
|
{
|
||||||
if (ent->prune >= 1)
|
if (ent->exists <= 0)
|
||||||
{
|
{
|
||||||
ents_to_prune[ents_to_prune_count] = ent;
|
ents_to_prune[ents_to_prune_count] = ent;
|
||||||
ents_to_prune_count += 1;
|
ents_to_prune_count += 1;
|
||||||
@ -847,7 +847,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
{
|
{
|
||||||
b32 m1_held = frame->held_buttons[Button_M1];
|
b32 m1_held = frame->held_buttons[Button_M1];
|
||||||
b32 m2_held = frame->held_buttons[Button_M2];
|
b32 m2_held = frame->held_buttons[Button_M2];
|
||||||
frame->selection_mode = V_SelectionMode_Tile;
|
// frame->selection_mode = V_SelectionMode_Tile;
|
||||||
if (m1_held)
|
if (m1_held)
|
||||||
{
|
{
|
||||||
frame->is_selecting = 1;
|
frame->is_selecting = 1;
|
||||||
@ -908,7 +908,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
{
|
{
|
||||||
S_Shape ent_shape = S_MulXformShape(ent->xf, ent->local_shape);
|
S_Shape ent_shape = S_MulXformShape(ent->xf, ent->local_shape);
|
||||||
b32 is_hovered = S_CollisionDataFromShapes(ent_shape, cursor_shape).collision_points_count > 0;
|
b32 is_hovered = S_CollisionDataFromShapes(ent_shape, cursor_shape, VEC2(0, 0)).collision_points_count > 0;
|
||||||
if (is_hovered)
|
if (is_hovered)
|
||||||
{
|
{
|
||||||
hovered_ent = ent;
|
hovered_ent = ent;
|
||||||
@ -1021,7 +1021,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Build panels
|
//- Build panels
|
||||||
|
|
||||||
if (frame->is_editing)
|
if (TweakBool("Show editor UI", 0) && frame->is_editing)
|
||||||
{
|
{
|
||||||
Struct(PanelDfsNode) { PanelDfsNode *next; b32 visited; V_Panel *panel; UI_Checkpoint cp; };
|
Struct(PanelDfsNode) { PanelDfsNode *next; b32 visited; V_Panel *panel; UI_Checkpoint cp; };
|
||||||
PanelDfsNode *first_panel_dfs = PushStruct(frame->arena, PanelDfsNode);
|
PanelDfsNode *first_panel_dfs = PushStruct(frame->arena, PanelDfsNode);
|
||||||
@ -2117,6 +2117,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
UI_BuildLabelF("Cursor world pos: %F", FmtFloat2(frame->world_cursor));
|
UI_BuildLabelF("Cursor world pos: %F", FmtFloat2(frame->world_cursor));
|
||||||
UI_BuildLabelF("Cursor tile pos: %F", FmtSint2(tile_pos));
|
UI_BuildLabelF("Cursor tile pos: %F", FmtSint2(tile_pos));
|
||||||
UI_BuildLabelF("Cursor tile idx: %F", FmtSint(tile_idx));
|
UI_BuildLabelF("Cursor tile idx: %F", FmtSint(tile_idx));
|
||||||
|
UI_BuildLabelF("Hovered ent: %F", S_FmtKey(hovered_ent->key));
|
||||||
}
|
}
|
||||||
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
|
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
|
||||||
{
|
{
|
||||||
@ -2388,15 +2389,18 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
||||||
cmd->delta.kind = S_DeltaKind_RawEnt;
|
cmd->delta.kind = S_DeltaKind_RawEnt;
|
||||||
S_Ent *ent = &cmd->delta.ent;
|
S_Ent *ent = &cmd->delta.ent;
|
||||||
|
*ent = S_NilEnt;
|
||||||
ent->key = V.player_key;
|
ent->key = V.player_key;
|
||||||
ent->xf = XformFromPos(frame->world_cursor);
|
ent->xf = XformFromPos(frame->world_cursor);
|
||||||
ent->move_speed = 0.05;
|
ent->move_speed = 0.075;
|
||||||
|
ent->is_player = 1;
|
||||||
ent->local_shape = S_ShapeFromDesc(
|
ent->local_shape = S_ShapeFromDesc(
|
||||||
.mass = 10,
|
.mass = 10,
|
||||||
.count = 1,
|
.count = 1,
|
||||||
.radius = 0.3,
|
.radius = 0.3,
|
||||||
);
|
);
|
||||||
ent->has_weapon = 1;
|
ent->has_weapon = 1;
|
||||||
|
ent->exists = 1;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case V_CmdKind_spawn_dummy:
|
case V_CmdKind_spawn_dummy:
|
||||||
@ -2404,27 +2408,29 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
||||||
cmd->delta.kind = S_DeltaKind_RawEnt;
|
cmd->delta.kind = S_DeltaKind_RawEnt;
|
||||||
S_Ent *ent = &cmd->delta.ent;
|
S_Ent *ent = &cmd->delta.ent;
|
||||||
|
*ent = S_NilEnt;
|
||||||
ent->key = S_RandKey();
|
ent->key = S_RandKey();
|
||||||
ent->xf = XformFromPos(frame->world_cursor);
|
ent->xf = XformFromPos(frame->world_cursor);
|
||||||
ent->move_speed = 0.05;
|
ent->move_speed = 0.075;
|
||||||
|
ent->is_player = 1;
|
||||||
ent->local_shape = S_ShapeFromDesc(
|
ent->local_shape = S_ShapeFromDesc(
|
||||||
.mass = 10,
|
.mass = 10,
|
||||||
.count = 1,
|
.count = 1,
|
||||||
.radius = 0.3,
|
.radius = 0.3,
|
||||||
);
|
);
|
||||||
ent->has_weapon = 1;
|
ent->has_weapon = 1;
|
||||||
|
ent->exists = 1;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case V_CmdKind_delete:
|
case V_CmdKind_delete:
|
||||||
{
|
{
|
||||||
if (hovered_ent->valid)
|
if (hovered_ent->valid)
|
||||||
{
|
{
|
||||||
LogDebugF("Sending delete command for ent %F", S_FmtKey(hovered_ent->key));
|
|
||||||
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
||||||
cmd->delta.kind = S_DeltaKind_RawEnt;
|
cmd->delta.kind = S_DeltaKind_RawEnt;
|
||||||
S_Ent *ent = &cmd->delta.ent;
|
S_Ent *ent = &cmd->delta.ent;
|
||||||
ent->key = hovered_ent->key;
|
ent->key = hovered_ent->key;
|
||||||
ent->prune = 1;
|
ent->exists = 0;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
#define V_CmdsTableXMacro(X) \
|
#define V_CmdsTableXMacro(X) \
|
||||||
X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \
|
X(nop, NOP, V_CmdDescFlag_HideFromPalette, V_HOTKEY(0), ) \
|
||||||
X(exit_program, Exit Program, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_Escape ) ) \
|
X(exit_program, Exit Program, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_Escape ) ) \
|
||||||
X(toggle_palette, Toggle Command Palette, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_P, .ctrl = 1, .shift = 1 ), ) \
|
X(toggle_palette, Toggle Command Palette, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_E, .ctrl = 1 ), V_HOTKEY( Button_P, .ctrl = 1, .shift = 1 ), ) \
|
||||||
X(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \
|
X(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \
|
||||||
X(zoom_out, Zoom Out, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelDown ), ) \
|
X(zoom_out, Zoom Out, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelDown ), ) \
|
||||||
X(toggle_editor, Toggle Editor, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \
|
X(toggle_editor, Toggle Editor, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \
|
||||||
@ -15,7 +15,7 @@
|
|||||||
X(spawn, Spawn/Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_T ), ) \
|
X(spawn, Spawn/Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_T ), ) \
|
||||||
X(spawn_dummy, Spawn Dummy, V_CmdDescFlag_None, V_HOTKEY( Button_R ), ) \
|
X(spawn_dummy, Spawn Dummy, V_CmdDescFlag_None, V_HOTKEY( Button_R ), ) \
|
||||||
X(delete, Delete entity at cursor, V_CmdDescFlag_None, V_HOTKEY( Button_M2 ), ) \
|
X(delete, Delete entity at cursor, V_CmdDescFlag_None, V_HOTKEY( Button_M2 ), ) \
|
||||||
/* --------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Theme types
|
//~ Theme types
|
||||||
@ -197,6 +197,7 @@ Enum(V_DrawFlag)
|
|||||||
|
|
||||||
Enum(V_EditMode)
|
Enum(V_EditMode)
|
||||||
{
|
{
|
||||||
|
V_EditMode_None,
|
||||||
V_EditMode_Tile,
|
V_EditMode_Tile,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user