import old collision detection code
This commit is contained in:
parent
235cf72018
commit
54f77c87be
@ -108,9 +108,9 @@ Struct(CLD_GjkData)
|
|||||||
CLD_MenkowskiSimplex simplex;
|
CLD_MenkowskiSimplex simplex;
|
||||||
Vec2 final_dir;
|
Vec2 final_dir;
|
||||||
|
|
||||||
// If 1, simplex represents triangle inside of CLD_Menkowski difference
|
// If 1, simplex represents triangle inside of menkowski difference
|
||||||
// encapsulating the origin. If 0, simplex represents the closest
|
// encapsulating the origin. If 0, simplex represents the closest
|
||||||
// feature on CLD_Menkowski difference to the origin.
|
// feature on menkowski difference to the origin.
|
||||||
b32 overlapping;
|
b32 overlapping;
|
||||||
|
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
@ -124,7 +124,7 @@ Struct(CLD_GjkData)
|
|||||||
Struct(CLD_EpaData)
|
Struct(CLD_EpaData)
|
||||||
{
|
{
|
||||||
Vec2 normal;
|
Vec2 normal;
|
||||||
CLD_MenkowskiFeature closest_feature; // Represents closest feature (edge or point) to origin on CLD_Menkowski difference
|
CLD_MenkowskiFeature closest_feature; // Represents closest feature (edge or point) to origin on menkowski difference
|
||||||
|
|
||||||
#if COLLIDER_DEBUG
|
#if COLLIDER_DEBUG
|
||||||
CLD_Prototype prototype;
|
CLD_Prototype prototype;
|
||||||
|
|||||||
@ -947,7 +947,7 @@ G_ResourceHandle G_PushResource(G_ArenaHandle arena_handle, G_CommandListHandle
|
|||||||
d3d_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
d3d_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||||
d3d_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
d3d_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||||
d3d_desc.Format = DXGI_FORMAT_UNKNOWN;
|
d3d_desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||||
d3d_desc.Width = AlignU64(MaxU64(desc.buffer.size, min_buffer_size), 4);
|
d3d_desc.Width = AlignU64ToNextPow2(MaxU64(desc.buffer.size, min_buffer_size));
|
||||||
d3d_desc.Height = 1;
|
d3d_desc.Height = 1;
|
||||||
d3d_desc.DepthOrArraySize = 1;
|
d3d_desc.DepthOrArraySize = 1;
|
||||||
d3d_desc.MipLevels = 1;
|
d3d_desc.MipLevels = 1;
|
||||||
|
|||||||
@ -153,32 +153,12 @@ S_Shape S_MulXformShape(Xform xf, S_Shape shape)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir)
|
|
||||||
{
|
|
||||||
// FIXME: Properly handle rounded polygons
|
|
||||||
Vec2 result = Zi;
|
|
||||||
Vec2 dir_norm = NormVec2(dir);
|
|
||||||
f32 max_dot = -Inf;
|
|
||||||
for (i32 i = 0; i < shape.points_count; ++i)
|
|
||||||
{
|
|
||||||
Vec2 p = shape.points[i];
|
|
||||||
f32 dot = DotVec2(p, dir_norm);
|
|
||||||
if (dot > max_dot)
|
|
||||||
{
|
|
||||||
max_dot = dot;
|
|
||||||
result = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = AddVec2(result, MulVec2(dir_norm, shape.radius));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rng2 S_BoundingBoxFromShape(S_Shape shape)
|
Rng2 S_BoundingBoxFromShape(S_Shape shape)
|
||||||
{
|
{
|
||||||
Vec2 left = S_SupportPointFromShape(shape, VEC2(-1, 0));
|
Vec2 left = S_SupportPointFromShape(shape, VEC2(-1, 0)).p;
|
||||||
Vec2 top = S_SupportPointFromShape(shape, VEC2(0, -1));
|
Vec2 top = S_SupportPointFromShape(shape, VEC2(0, -1)).p;
|
||||||
Vec2 right = S_SupportPointFromShape(shape, VEC2(1, 0));
|
Vec2 right = S_SupportPointFromShape(shape, VEC2(1, 0)).p;
|
||||||
Vec2 bottom = S_SupportPointFromShape(shape, VEC2(0, 1));
|
Vec2 bottom = S_SupportPointFromShape(shape, VEC2(0, 1)).p;
|
||||||
|
|
||||||
Rng2 result = Zi;
|
Rng2 result = Zi;
|
||||||
result.p0 = VEC2(left.x, top.y);
|
result.p0 = VEC2(left.x, top.y);
|
||||||
@ -186,6 +166,673 @@ Rng2 S_BoundingBoxFromShape(S_Shape shape)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Collision
|
||||||
|
|
||||||
|
// NOTE: Everything here is pretty much copied directly from the old physics
|
||||||
|
// prototype. It's slow and does more than what we need. For example we should
|
||||||
|
// probably just switch from GJK to SAT for shape collision testing.
|
||||||
|
|
||||||
|
S_SupportPoint S_SupportPointFromShapeEx(S_Shape shape, Vec2 dir, i32 ignore_idx)
|
||||||
|
{
|
||||||
|
S_SupportPoint result = Zi;
|
||||||
|
Vec2 dir_norm = NormVec2(dir);
|
||||||
|
f32 max_dot = -Inf;
|
||||||
|
if (shape.points_count == 1)
|
||||||
|
{
|
||||||
|
// Don't ignore for single-point colliders
|
||||||
|
ignore_idx = -1;
|
||||||
|
}
|
||||||
|
for (i32 point_idx = 0; point_idx < shape.points_count; ++point_idx)
|
||||||
|
{
|
||||||
|
if (point_idx != ignore_idx)
|
||||||
|
{
|
||||||
|
Vec2 p = shape.points[point_idx];
|
||||||
|
f32 dot = DotVec2(p, dir_norm);
|
||||||
|
if (dot > max_dot)
|
||||||
|
{
|
||||||
|
max_dot = dot;
|
||||||
|
result.p = p;
|
||||||
|
result.id = point_idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.p = AddVec2(result.p, MulVec2(dir_norm, shape.radius));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
S_SupportPoint S_SupportPointFromShape(S_Shape shape, Vec2 dir)
|
||||||
|
{
|
||||||
|
return S_SupportPointFromShapeEx(shape, dir, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
S_MenkowskiPoint S_MenkowskiPointFromShapes(S_Shape shape0, S_Shape shape1, Vec2 dir)
|
||||||
|
{
|
||||||
|
S_MenkowskiPoint result = Zi;
|
||||||
|
result.s0 = S_SupportPointFromShape(shape0, dir);
|
||||||
|
result.s1 = S_SupportPointFromShape(shape1, NegVec2(dir));
|
||||||
|
result.p = SubVec2(result.s0.p, result.s1.p);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
S_ClippedLine S_ClipLineToLine(Vec2 a0, Vec2 b0, Vec2 a1, Vec2 b1, Vec2 normal)
|
||||||
|
{
|
||||||
|
Vec2 vab0 = SubVec2(b0, a0);
|
||||||
|
Vec2 vab1 = SubVec2(b1, a1);
|
||||||
|
Vec2 va0a1 = SubVec2(a1, a0);
|
||||||
|
Vec2 vb0b1 = SubVec2(b1, b0);
|
||||||
|
f32 vab0_w = WedgeVec2(vab0, normal);
|
||||||
|
f32 vab1_w = WedgeVec2(vab1, normal);
|
||||||
|
f32 va0a1_w = WedgeVec2(va0a1, normal);
|
||||||
|
f32 vb0b1_w = WedgeVec2(vb0b1, normal);
|
||||||
|
|
||||||
|
// FIXME: Handle 0 denominator
|
||||||
|
f32 a0t;
|
||||||
|
f32 b0t;
|
||||||
|
{
|
||||||
|
f32 w = 1 / vab0_w;
|
||||||
|
a0t = ClampF32(va0a1_w * w, 0, 1);
|
||||||
|
b0t = ClampF32(vb0b1_w * -w, 0, 1);
|
||||||
|
}
|
||||||
|
f32 a1t;
|
||||||
|
f32 b1t;
|
||||||
|
{
|
||||||
|
f32 w = 1 / vab1_w;
|
||||||
|
a1t = ClampF32(-va0a1_w * w, 0, 1);
|
||||||
|
b1t = ClampF32(-vb0b1_w * -w, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
S_ClippedLine result = Zi;
|
||||||
|
result.a0_clipped = AddVec2(a0, MulVec2(vab0, a0t));
|
||||||
|
result.a1_clipped = AddVec2(a1, MulVec2(vab1, a1t));
|
||||||
|
result.b0_clipped = AddVec2(b0, MulVec2(vab0, -b0t));
|
||||||
|
result.b1_clipped = AddVec2(b1, MulVec2(vab1, -b1t));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 S_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal)
|
||||||
|
{
|
||||||
|
Vec2 vab = SubVec2(b, a);
|
||||||
|
Vec2 vap = SubVec2(p, a);
|
||||||
|
|
||||||
|
f32 vab_w = WedgeVec2(vab, normal);
|
||||||
|
f32 vap_w = WedgeVec2(vap, normal);
|
||||||
|
|
||||||
|
f32 t;
|
||||||
|
{
|
||||||
|
f32 w = 1 / vab_w;
|
||||||
|
t = ClampF32(vap_w * w, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 result = AddVec2(a, MulVec2(vab, t));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1)
|
||||||
|
{
|
||||||
|
S_CollisionData result = Zi;
|
||||||
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
|
|
||||||
|
f32 tolerance = 0.005f; // 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.
|
||||||
|
u32 max_iterations = 64; // To prevent extremely large prototypes when origin is in exact center of rounded feature
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- GJK
|
||||||
|
|
||||||
|
S_MenkowskiSimplex simplex = Zi;
|
||||||
|
Vec2 non_overlapping_dir = Zi;
|
||||||
|
b32 is_overlapping = 0;
|
||||||
|
{
|
||||||
|
S_MenkowskiPoint m = Zi;
|
||||||
|
|
||||||
|
// First point is support point in shape's general directions to eachother
|
||||||
|
Vec2 dir = SubVec2(shape1.centroid, shape0.centroid);
|
||||||
|
if (IsVec2Zero(dir)) dir = VEC2(1, 0);
|
||||||
|
simplex.a = S_MenkowskiPointFromShapes(shape0, shape1, dir);
|
||||||
|
simplex.count = 1;
|
||||||
|
|
||||||
|
Vec2 removed_a = Zi;
|
||||||
|
Vec2 removed_b = Zi;
|
||||||
|
u32 num_removed = 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
//////////////////////////////
|
||||||
|
//- Find initial points in simplex
|
||||||
|
|
||||||
|
if (simplex.count == 1)
|
||||||
|
{
|
||||||
|
// Second point is support point towards origin
|
||||||
|
dir = NegVec2(simplex.a.p);
|
||||||
|
|
||||||
|
m = S_MenkowskiPointFromShapes(shape0, shape1, dir);
|
||||||
|
// Check that new point is far enough away from existing point
|
||||||
|
if (Vec2LenSq(SubVec2(m.p, simplex.a.p)) < min_unique_pt_dist_sq)
|
||||||
|
{
|
||||||
|
is_overlapping = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
simplex.b = simplex.a;
|
||||||
|
simplex.a = m;
|
||||||
|
simplex.count = 2;
|
||||||
|
|
||||||
|
// Third point is support point in direction of line normal towards origin
|
||||||
|
dir = PerpVec2TowardsDir(SubVec2(simplex.b.p, simplex.a.p), NegVec2(simplex.a.p));
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Find third piont in simplex
|
||||||
|
|
||||||
|
{
|
||||||
|
m = S_MenkowskiPointFromShapes(shape0, shape1, dir);
|
||||||
|
// Check that new point is far enough away from existing points
|
||||||
|
if (
|
||||||
|
Vec2LenSq(SubVec2(m.p, simplex.a.p)) < min_unique_pt_dist_sq ||
|
||||||
|
Vec2LenSq(SubVec2(m.p, simplex.b.p)) < min_unique_pt_dist_sq || (
|
||||||
|
(num_removed >= 1) && (
|
||||||
|
(Vec2LenSq(SubVec2(m.p, removed_a)) < min_unique_pt_dist_sq) ||
|
||||||
|
(num_removed >= 2 && Vec2LenSq(SubVec2(m.p, removed_b)) < min_unique_pt_dist_sq)
|
||||||
|
)
|
||||||
|
) ||
|
||||||
|
AbsF32(WedgeVec2(SubVec2(simplex.b.p, simplex.a.p), SubVec2(m.p, simplex.a.p))) < min_unique_pt_dist_sq
|
||||||
|
)
|
||||||
|
{
|
||||||
|
is_overlapping = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
simplex.c = simplex.b;
|
||||||
|
simplex.b = simplex.a;
|
||||||
|
simplex.a = m;
|
||||||
|
simplex.count = 3;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(AbsF32(WedgeVec2(SubVec2(simplex.b.p, simplex.a.p), NegVec2(simplex.a.p))) <= min_unique_pt_dist_sq) ||
|
||||||
|
(AbsF32(WedgeVec2(SubVec2(simplex.c.p, simplex.b.p), NegVec2(simplex.b.p))) <= min_unique_pt_dist_sq) ||
|
||||||
|
(AbsF32(WedgeVec2(SubVec2(simplex.c.p, simplex.a.p), NegVec2(simplex.a.p))) <= min_unique_pt_dist_sq)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Simplex lies on origin
|
||||||
|
is_overlapping = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Determine origin region
|
||||||
|
|
||||||
|
Vec2 vab = SubVec2(simplex.b.p, simplex.a.p);
|
||||||
|
Vec2 vac = SubVec2(simplex.c.p, simplex.a.p);
|
||||||
|
Vec2 vbc = SubVec2(simplex.c.p, simplex.b.p);
|
||||||
|
|
||||||
|
Vec2 rab_dir = PerpVec2TowardsDir(vab, NegVec2(vac));
|
||||||
|
Vec2 rac_dir = PerpVec2TowardsDir(vac, NegVec2(vab));
|
||||||
|
Vec2 rbc_dir = PerpVec2TowardsDir(vbc, vab);
|
||||||
|
|
||||||
|
f32 rab_dot = DotVec2(rab_dir, NegVec2(simplex.a.p));
|
||||||
|
f32 rac_dot = DotVec2(rac_dir, NegVec2(simplex.a.p));
|
||||||
|
f32 rbc_dot = DotVec2(rbc_dir, NegVec2(simplex.b.p));
|
||||||
|
|
||||||
|
f32 vab_dot = DotVec2(vab, NegVec2(simplex.a.p)) / Vec2LenSq(vab);
|
||||||
|
f32 vac_dot = DotVec2(vac, NegVec2(simplex.a.p)) / Vec2LenSq(vac);
|
||||||
|
f32 vbc_dot = DotVec2(vbc, NegVec2(simplex.b.p)) / Vec2LenSq(vbc);
|
||||||
|
|
||||||
|
if (rab_dot >= 0 && vab_dot >= 0 && vab_dot <= 1)
|
||||||
|
{
|
||||||
|
// Region ab, remove c
|
||||||
|
num_removed = 1;
|
||||||
|
removed_a = simplex.c.p;
|
||||||
|
simplex.count = 2;
|
||||||
|
dir = rab_dir; // Next third point is in direction of region ab
|
||||||
|
}
|
||||||
|
else if (rac_dot >= 0 && vac_dot >= 0 && vac_dot <= 1)
|
||||||
|
{
|
||||||
|
// Region ac, remove b
|
||||||
|
num_removed = 1;
|
||||||
|
removed_a = simplex.b.p;
|
||||||
|
simplex.count = 2;
|
||||||
|
simplex.b = simplex.c;
|
||||||
|
dir = rac_dir; // Next third point is in direction of region ac
|
||||||
|
}
|
||||||
|
else if (rbc_dot >= 0 && vbc_dot >= 0 && vbc_dot <= 1)
|
||||||
|
{
|
||||||
|
// Region bc, remove a
|
||||||
|
num_removed = 1;
|
||||||
|
removed_a = simplex.a.p;
|
||||||
|
simplex.count = 2;
|
||||||
|
simplex.a = simplex.b;
|
||||||
|
simplex.b = simplex.c;
|
||||||
|
dir = rbc_dir; // Next third point is in direction of region bc
|
||||||
|
}
|
||||||
|
else if (vab_dot <= 0 && vac_dot <= 0)
|
||||||
|
{
|
||||||
|
// Region a, remove bc
|
||||||
|
num_removed = 2;
|
||||||
|
removed_a = simplex.b.p;
|
||||||
|
removed_b = simplex.c.p;
|
||||||
|
simplex.count = 1;
|
||||||
|
}
|
||||||
|
else if (vab_dot >= 1 && vbc_dot <= 0)
|
||||||
|
{
|
||||||
|
// Region b, remove ac
|
||||||
|
num_removed = 2;
|
||||||
|
removed_a = simplex.a.p;
|
||||||
|
removed_b = simplex.c.p;
|
||||||
|
simplex.count = 1;
|
||||||
|
simplex.a = simplex.b;
|
||||||
|
}
|
||||||
|
else if (vac_dot >= 1 && vbc_dot >= 1)
|
||||||
|
{
|
||||||
|
// Region c, remove ab
|
||||||
|
num_removed = 2;
|
||||||
|
removed_a = simplex.a.p;
|
||||||
|
removed_b = simplex.b.p;
|
||||||
|
simplex.count = 1;
|
||||||
|
simplex.a = simplex.c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No region, must be in simplex
|
||||||
|
is_overlapping = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!is_overlapping)
|
||||||
|
{
|
||||||
|
non_overlapping_dir = dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- EPA
|
||||||
|
|
||||||
|
Vec2 normal = Zi;
|
||||||
|
S_MenkowskiSimplex closest_feature = Zi;
|
||||||
|
{
|
||||||
|
S_MenkowskiPoint *proto = 0;
|
||||||
|
u32 proto_count = 0;
|
||||||
|
if (is_overlapping)
|
||||||
|
{
|
||||||
|
proto = ArenaNext(scratch.arena, S_MenkowskiPoint);
|
||||||
|
{
|
||||||
|
Assert(simplex.count == 3);
|
||||||
|
S_MenkowskiPoint *tmp = PushStructsNoZero(scratch.arena, S_MenkowskiPoint, 3);
|
||||||
|
tmp[0] = simplex.a;
|
||||||
|
tmp[1] = simplex.b;
|
||||||
|
tmp[2] = simplex.c;
|
||||||
|
proto_count = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 winding = WindingFromVec2(SubVec2(simplex.c.p, simplex.a.p), SubVec2(simplex.b.p, simplex.a.p));
|
||||||
|
|
||||||
|
u32 epa_iterations = 0;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
++epa_iterations;
|
||||||
|
|
||||||
|
// Find dir from origin to closest edge
|
||||||
|
// FIXME: Winding order of ps & pe index
|
||||||
|
f32 closest_len_sq = Inf;
|
||||||
|
S_MenkowskiPoint closest_a = Zi;
|
||||||
|
S_MenkowskiPoint closest_b = Zi;
|
||||||
|
u32 closest_b_index = 0;
|
||||||
|
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);
|
||||||
|
Vec2 vao = NegVec2(a.p);
|
||||||
|
|
||||||
|
f32 proj_ratio = ClampF32(DotVec2(vao, vab) / Vec2LenSq(vab), 0, 1);
|
||||||
|
Vec2 proj = AddVec2(a.p, MulVec2(vab, proj_ratio));
|
||||||
|
|
||||||
|
f32 proj_len_sq = Vec2LenSq(proj);
|
||||||
|
if (proj_len_sq < closest_len_sq - min_unique_pt_dist_sq)
|
||||||
|
{
|
||||||
|
closest_a = a;
|
||||||
|
closest_b = b;
|
||||||
|
closest_b_index = b_index;
|
||||||
|
closest_len_sq = proj_len_sq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Vec2 vab = SubVec2(closest_b.p, closest_a.p);
|
||||||
|
|
||||||
|
// Find new point in dir
|
||||||
|
Vec2 dir = MulVec2(PerpVec2(vab), winding);
|
||||||
|
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
|
||||||
|
{
|
||||||
|
b32 valid = 1;
|
||||||
|
|
||||||
|
{
|
||||||
|
// NOTE: Changing this value affects how stable normals are for circular colliders
|
||||||
|
//const f32 validity_epsilon = min_unique_pt_dist_sq; // Arbitrary
|
||||||
|
//const f32 validity_epsilon = 0.00000000001f; // Arbitrary
|
||||||
|
const f32 validity_epsilon = min_unique_pt_dist_sq; // Arbitrary
|
||||||
|
|
||||||
|
Vec2 vam = SubVec2(m.p, closest_a.p);
|
||||||
|
Vec2 vbm = SubVec2(closest_b.p, closest_a.p);
|
||||||
|
|
||||||
|
f32 dot = DotVec2(vab, vam) / Vec2LenSq(vab);
|
||||||
|
|
||||||
|
if (dot >= -validity_epsilon && dot <= 1 - validity_epsilon && (WedgeVec2(vab, vam) * -winding) >= -validity_epsilon)
|
||||||
|
{
|
||||||
|
// New point is not between edge
|
||||||
|
valid = 0;
|
||||||
|
}
|
||||||
|
else if (Vec2LenSq(vam) < min_unique_pt_dist_sq || Vec2LenSq(vbm) < min_unique_pt_dist_sq)
|
||||||
|
{
|
||||||
|
// New point is too close to existing
|
||||||
|
valid = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valid || epa_iterations >= max_iterations)
|
||||||
|
{
|
||||||
|
normal = NormVec2(dir);
|
||||||
|
closest_feature.a = closest_a;
|
||||||
|
closest_feature.b = closest_b;
|
||||||
|
closest_feature.count = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expand prototype
|
||||||
|
PushStructNoZero(scratch.arena, S_MenkowskiPoint);
|
||||||
|
++proto_count;
|
||||||
|
|
||||||
|
// Shift points in prototype to make room
|
||||||
|
for (u32 i = proto_count - 1; i > closest_b_index; --i)
|
||||||
|
{
|
||||||
|
u32 shift_from = (i > 0) ? i - 1 : proto_count - 1;
|
||||||
|
u32 shift_to = i;
|
||||||
|
proto[shift_to] = proto[shift_from];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert new point into prototype
|
||||||
|
proto[closest_b_index] = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
normal = NormVec2(non_overlapping_dir);
|
||||||
|
closest_feature.count = simplex.count;
|
||||||
|
closest_feature.a = simplex.a;
|
||||||
|
closest_feature.b = simplex.b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Determine collision
|
||||||
|
|
||||||
|
b32 is_colliding = 0;
|
||||||
|
{
|
||||||
|
if (is_overlapping)
|
||||||
|
{
|
||||||
|
is_colliding = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Shapes not overlapping, determine if distance between shapes within tolerance
|
||||||
|
if (closest_feature.count == 1)
|
||||||
|
{
|
||||||
|
Vec2 p = NegVec2(closest_feature.a.p);
|
||||||
|
if (Vec2LenSq(p) <= (tolerance * tolerance))
|
||||||
|
{
|
||||||
|
is_colliding = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Project origin to determine if distance is within tolerance.
|
||||||
|
Assert(closest_feature.count == 2);
|
||||||
|
Vec2 vab = SubVec2(closest_feature.b.p, closest_feature.a.p);
|
||||||
|
Vec2 vao = NegVec2(closest_feature.a.p);
|
||||||
|
f32 ratio = ClampF32(DotVec2(vab, vao) / DotVec2(vab, vab), 0, 1);
|
||||||
|
Vec2 p = AddVec2(closest_feature.a.p, MulVec2(vab, ratio));
|
||||||
|
if (Vec2LenSq(p) <= (tolerance * tolerance))
|
||||||
|
{
|
||||||
|
is_colliding = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Compute collision points
|
||||||
|
|
||||||
|
// Clip to determine final points
|
||||||
|
i32 collision_points_count = 0;
|
||||||
|
S_CollisionPoint collision_points[2] = Zi;
|
||||||
|
if (is_colliding)
|
||||||
|
{
|
||||||
|
// Max vertices must be < 16 to fit in 4 bit ids
|
||||||
|
StaticAssert(countof(shape0.points) <= 16);
|
||||||
|
{
|
||||||
|
b32 collapse0 = 0;
|
||||||
|
b32 collapse1 = 0;
|
||||||
|
|
||||||
|
S_SupportPoint a0 = closest_feature.a.s0;
|
||||||
|
S_SupportPoint a1 = closest_feature.a.s1;
|
||||||
|
S_SupportPoint b0 = closest_feature.b.s0;
|
||||||
|
S_SupportPoint b1 = closest_feature.b.s1;
|
||||||
|
// FIXME: Manually account for shapes w/ 1 & 2 points
|
||||||
|
if (closest_feature.count == 2)
|
||||||
|
{
|
||||||
|
if (a0.id == b0.id)
|
||||||
|
{
|
||||||
|
if (shape0.points_count > 1)
|
||||||
|
{
|
||||||
|
b0 = S_SupportPointFromShapeEx(shape0, normal, b0.id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
collapse0 = 1;
|
||||||
|
b0 = a0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (a1.id == b1.id)
|
||||||
|
{
|
||||||
|
if (shape1.points_count > 1)
|
||||||
|
{
|
||||||
|
b1 = S_SupportPointFromShapeEx(shape1, NegVec2(normal), b1.id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
collapse1 = 1;
|
||||||
|
b1 = a1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
collapse0 = 1;
|
||||||
|
collapse1 = 1;
|
||||||
|
b0 = a0;
|
||||||
|
b1 = a1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 vab0 = SubVec2(b0.p, a0.p);
|
||||||
|
Vec2 vab1 = SubVec2(b1.p, a1.p);
|
||||||
|
Vec2 vab0_norm = NormVec2(vab0);
|
||||||
|
Vec2 vab1_norm = NormVec2(vab1);
|
||||||
|
|
||||||
|
// Swap points based on normal direction for consistent clipping
|
||||||
|
if (WedgeVec2(normal, vab0) < 0)
|
||||||
|
{
|
||||||
|
S_SupportPoint tmp = a0;
|
||||||
|
a0 = b0;
|
||||||
|
b0 = tmp;
|
||||||
|
vab0 = NegVec2(vab0);
|
||||||
|
}
|
||||||
|
if (WedgeVec2(normal, vab1) < 0)
|
||||||
|
{
|
||||||
|
S_SupportPoint tmp = a1;
|
||||||
|
a1 = b1;
|
||||||
|
b1 = tmp;
|
||||||
|
vab1 = NegVec2(vab1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collapse lines that are too far in the direction of the normal to be accurately clipped
|
||||||
|
f32 collapse_epsilon = 0.05f;
|
||||||
|
collapse0 = collapse0 || AbsF32(WedgeVec2(normal, vab0_norm)) < collapse_epsilon;
|
||||||
|
collapse1 = collapse1 || AbsF32(WedgeVec2(normal, vab1_norm)) < collapse_epsilon;
|
||||||
|
|
||||||
|
// Collapse lines into deepest point
|
||||||
|
if (collapse0)
|
||||||
|
{
|
||||||
|
if (DotVec2(normal, vab0) > 0)
|
||||||
|
{
|
||||||
|
a0 = b0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Remove this (debugging)
|
||||||
|
b0 = a0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (collapse1)
|
||||||
|
{
|
||||||
|
if (DotVec2(normal, vab1) < 0)
|
||||||
|
{
|
||||||
|
a1 = b1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Remove this (debugging)
|
||||||
|
b1 = a1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 a_sep = Inf;
|
||||||
|
f32 b_sep = Inf;
|
||||||
|
Vec2 a_midpoint = Zi;
|
||||||
|
Vec2 b_midpoint = Zi;
|
||||||
|
b32 ignore_a = 1;
|
||||||
|
b32 ignore_b = 1;
|
||||||
|
if (!collapse0 && !collapse1)
|
||||||
|
{
|
||||||
|
// Clip line to line
|
||||||
|
S_ClippedLine clip_result = S_ClipLineToLine(a0.p, b0.p, a1.p, b1.p, normal);
|
||||||
|
Vec2 a0_clipped = clip_result.a0_clipped;
|
||||||
|
Vec2 a1_clipped = clip_result.a1_clipped;
|
||||||
|
Vec2 b0_clipped = clip_result.b0_clipped;
|
||||||
|
Vec2 b1_clipped = clip_result.b1_clipped;
|
||||||
|
// Calc midpoint between clipped a & b
|
||||||
|
Vec2 va0a1_clipped = SubVec2(a1_clipped, a0_clipped);
|
||||||
|
Vec2 vb0b1_clipped = SubVec2(b1_clipped, b0_clipped);
|
||||||
|
a_sep = DotVec2(va0a1_clipped, normal);
|
||||||
|
b_sep = DotVec2(vb0b1_clipped, normal);
|
||||||
|
a_midpoint = AddVec2(a0_clipped, MulVec2(va0a1_clipped, 0.5f));
|
||||||
|
b_midpoint = AddVec2(b0_clipped, MulVec2(vb0b1_clipped, 0.5f));
|
||||||
|
ignore_a = 0;
|
||||||
|
ignore_b = 0;
|
||||||
|
Vec2 vfin = SubVec2(b_midpoint, a_midpoint);
|
||||||
|
if (Vec2LenSq(vfin) < (0.005 * 0.005))
|
||||||
|
{
|
||||||
|
if (a_sep > b_sep)
|
||||||
|
{
|
||||||
|
ignore_a = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ignore_b = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vec2 p0 = a0.p;
|
||||||
|
Vec2 p1 = a1.p;
|
||||||
|
// TODO: Choose ID based on closest clipped point
|
||||||
|
if (collapse1 && !collapse0)
|
||||||
|
{
|
||||||
|
// Project a1 onto vab0
|
||||||
|
p0 = S_ClipPointToLine(a0.p, b0.p, a1.p, normal);
|
||||||
|
}
|
||||||
|
if (collapse0 && !collapse1)
|
||||||
|
{
|
||||||
|
// Project a0 onto vab1
|
||||||
|
p1 = S_ClipPointToLine(a1.p, b1.p, a0.p, normal);
|
||||||
|
}
|
||||||
|
// Calc midpoint
|
||||||
|
Vec2 vsep = SubVec2(p1, p0);
|
||||||
|
a_midpoint = AddVec2(p0, MulVec2(vsep, 0.5f));
|
||||||
|
a_sep = DotVec2(normal, p1) - DotVec2(normal, p0);
|
||||||
|
ignore_a = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert points
|
||||||
|
if (!ignore_a && a_sep < tolerance)
|
||||||
|
{
|
||||||
|
S_CollisionPoint *point = &collision_points[collision_points_count++];
|
||||||
|
point->id = a0.id | (a1.id << 4);
|
||||||
|
point->separation = a_sep;
|
||||||
|
point->p = a_midpoint;
|
||||||
|
}
|
||||||
|
if (!ignore_b && b_sep < tolerance)
|
||||||
|
{
|
||||||
|
S_CollisionPoint *point = &collision_points[collision_points_count++];
|
||||||
|
point->id = b0.id | (b1.id << 4);
|
||||||
|
point->separation = b_sep;
|
||||||
|
point->p = b_midpoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Compute closest points
|
||||||
|
|
||||||
|
Vec2 closest_p0 = Zi;
|
||||||
|
Vec2 closest_p1 = Zi;
|
||||||
|
if (closest_feature.count == 1)
|
||||||
|
{
|
||||||
|
closest_p0 = closest_feature.a.s0.p;
|
||||||
|
closest_p1 = closest_feature.a.s1.p;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert(closest_feature.count == 2);
|
||||||
|
// FIXME: Winding order dependent?
|
||||||
|
f32 ratio = 0;
|
||||||
|
{
|
||||||
|
// Determine ratio between edge a & b that projected origin lies
|
||||||
|
Vec2 vab = SubVec2(closest_feature.b.p, closest_feature.a.p);
|
||||||
|
Vec2 vao = NegVec2(closest_feature.a.p);
|
||||||
|
ratio = ClampF32(DotVec2(vab, vao) / DotVec2(vab, vab), 0, 1);
|
||||||
|
}
|
||||||
|
// Shape 0
|
||||||
|
closest_p0 = SubVec2(closest_feature.b.s0.p, closest_feature.a.s0.p);
|
||||||
|
closest_p0 = MulVec2(closest_p0, ratio);
|
||||||
|
closest_p0 = AddVec2(closest_p0, closest_feature.a.s0.p);
|
||||||
|
// Shape 1
|
||||||
|
closest_p1 = SubVec2(closest_feature.b.s1.p, closest_feature.a.s1.p);
|
||||||
|
closest_p1 = MulVec2(closest_p1, ratio);
|
||||||
|
closest_p1 = AddVec2(closest_p1, closest_feature.a.s1.p);
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyStructs(result.collision_points, collision_points, countof(collision_points));
|
||||||
|
result.collision_points_count = collision_points_count;
|
||||||
|
result.closest_p0 = closest_p0;
|
||||||
|
result.closest_p1 = closest_p1;
|
||||||
|
|
||||||
|
EndScratch(scratch);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Lookup helpers
|
//~ Lookup helpers
|
||||||
|
|
||||||
@ -594,7 +1241,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
test_rect.p1 = VEC2(1, 1);
|
test_rect.p1 = VEC2(1, 1);
|
||||||
|
|
||||||
constraint->shape1 = S_ShapeFromDesc(
|
constraint->shape1 = S_ShapeFromDesc(
|
||||||
.radius = 0.2,
|
.radius = 0.5,
|
||||||
.count = 4,
|
.count = 4,
|
||||||
.points[0] = VEC2(test_rect.p0.x, test_rect.p0.y),
|
.points[0] = VEC2(test_rect.p0.x, test_rect.p0.y),
|
||||||
.points[1] = VEC2(test_rect.p1.x, test_rect.p0.y),
|
.points[1] = VEC2(test_rect.p1.x, test_rect.p0.y),
|
||||||
@ -653,8 +1300,12 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
Vec2 normal = NormVec2(shape_dir);
|
Vec2 normal = NormVec2(shape_dir);
|
||||||
Vec2 neg_normal = NegVec2(normal);
|
Vec2 neg_normal = NegVec2(normal);
|
||||||
|
|
||||||
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);
|
||||||
|
Vec2 shape0_pt = collision_data.closest_p0;
|
||||||
|
Vec2 shape1_pt = collision_data.closest_p1;
|
||||||
|
|
||||||
Vec2 sep = SubVec2(shape1_pt, shape0_pt);
|
Vec2 sep = SubVec2(shape1_pt, shape0_pt);
|
||||||
f32 sep_along_normal = DotVec2(sep, normal);
|
f32 sep_along_normal = DotVec2(sep, normal);
|
||||||
@ -663,13 +1314,11 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
|
|
||||||
// f32 sep_normal = DotVec2(sep, normal);
|
// f32 sep_normal = DotVec2(sep, normal);
|
||||||
|
|
||||||
|
|
||||||
S_DebugDrawPoint(shape0_pt, Color_Cyan);
|
S_DebugDrawPoint(shape0_pt, Color_Cyan);
|
||||||
S_DebugDrawPoint(shape1_pt, Color_Cyan);
|
S_DebugDrawPoint(shape1_pt, Color_Cyan);
|
||||||
|
|
||||||
|
S_DebugDrawPoint(collision_data.collision_points[0].p, Color_Red);
|
||||||
|
S_DebugDrawPoint(collision_data.collision_points[0].p, Color_Red);
|
||||||
|
|
||||||
|
|
||||||
if (sep_along_normal < 0)
|
if (sep_along_normal < 0)
|
||||||
{
|
{
|
||||||
@ -732,7 +1381,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
{
|
{
|
||||||
Vec4 color = VEC4(0.8, 0.8, 0.8, 1);
|
Vec4 color = VEC4(0.8, 0.8, 0.8, 1);
|
||||||
Vec2 p0 = world_shape.centroid;
|
Vec2 p0 = world_shape.centroid;
|
||||||
Vec2 p1 = S_SupportPointFromShape(world_shape, ent->look);
|
Vec2 p1 = S_SupportPointFromShape(world_shape, ent->look).p;
|
||||||
S_DebugDrawLine(p0, p1, color);
|
S_DebugDrawLine(p0, p1, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,6 +110,52 @@ Struct(S_EntList)
|
|||||||
u64 count;
|
u64 count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Collision types
|
||||||
|
|
||||||
|
Struct(S_SupportPoint)
|
||||||
|
{
|
||||||
|
Vec2 p;
|
||||||
|
i32 id; // Index of the originating piont in the shape
|
||||||
|
};
|
||||||
|
|
||||||
|
Struct(S_CollisionPoint)
|
||||||
|
{
|
||||||
|
Vec2 p;
|
||||||
|
f32 separation;
|
||||||
|
u32 id; // Based on polygon edge-to-edge
|
||||||
|
};
|
||||||
|
|
||||||
|
Struct(S_MenkowskiPoint)
|
||||||
|
{
|
||||||
|
Vec2 p; // Menkowski difference point
|
||||||
|
S_SupportPoint s0; // Support point of first shape in dir
|
||||||
|
S_SupportPoint s1; // Support point of second shape in -dir
|
||||||
|
};
|
||||||
|
|
||||||
|
Struct(S_MenkowskiSimplex)
|
||||||
|
{
|
||||||
|
i32 count;
|
||||||
|
S_MenkowskiPoint a, b, c;
|
||||||
|
};
|
||||||
|
|
||||||
|
Struct(S_ClippedLine)
|
||||||
|
{
|
||||||
|
Vec2 a0_clipped, b0_clipped;
|
||||||
|
Vec2 a1_clipped, b1_clipped;
|
||||||
|
};
|
||||||
|
|
||||||
|
Struct(S_CollisionData)
|
||||||
|
{
|
||||||
|
// Contact manifold
|
||||||
|
i32 collision_points_count;
|
||||||
|
S_CollisionPoint collision_points[2];
|
||||||
|
|
||||||
|
// Closest points
|
||||||
|
Vec2 closest_p0;
|
||||||
|
Vec2 closest_p1;
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Constraint types
|
//~ Constraint types
|
||||||
|
|
||||||
@ -324,10 +370,18 @@ S_Shape S_ShapeFromDescEx(S_ShapeDesc desc);
|
|||||||
#define S_ShapeFromDesc(...) S_ShapeFromDescEx((S_ShapeDesc) { __VA_ARGS__ })
|
#define S_ShapeFromDesc(...) S_ShapeFromDescEx((S_ShapeDesc) { __VA_ARGS__ })
|
||||||
|
|
||||||
S_Shape S_MulXformShape(Xform xf, S_Shape shape);
|
S_Shape S_MulXformShape(Xform xf, S_Shape shape);
|
||||||
|
|
||||||
Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir);
|
|
||||||
Rng2 S_BoundingBoxFromShape(S_Shape shape);
|
Rng2 S_BoundingBoxFromShape(S_Shape shape);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Collision
|
||||||
|
|
||||||
|
S_SupportPoint S_SupportPointFromShapeEx(S_Shape shape, Vec2 dir, i32 ignore_idx);
|
||||||
|
S_SupportPoint S_SupportPointFromShape(S_Shape shape, 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);
|
||||||
|
Vec2 S_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal);
|
||||||
|
S_CollisionData S_CollisionDataFromShapes(S_Shape shape0, S_Shape shape1);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Lookup helpers
|
//~ Lookup helpers
|
||||||
|
|
||||||
|
|||||||
@ -191,7 +191,7 @@ void V_DrawShape(S_Shape shape, Vec4 srgb, i32 detail, V_DrawFlag flags)
|
|||||||
{
|
{
|
||||||
f32 rad = ((f32)i / (f32)detail) * Tau;
|
f32 rad = ((f32)i / (f32)detail) * Tau;
|
||||||
Vec2 dir = Vec2FromAngle(rad);
|
Vec2 dir = Vec2FromAngle(rad);
|
||||||
Vec2 sp = S_SupportPointFromShape(shape, dir);
|
Vec2 sp = S_SupportPointFromShape(shape, dir).p;
|
||||||
draw_points.points[i] = sp;
|
draw_points.points[i] = sp;
|
||||||
}
|
}
|
||||||
V_DrawPoly(draw_points, srgb, flags);
|
V_DrawPoly(draw_points, srgb, flags);
|
||||||
@ -237,8 +237,7 @@ V_WidgetTheme V_GetWidgetTheme(void)
|
|||||||
theme.icon_font = UI_BuiltinIconFont();
|
theme.icon_font = UI_BuiltinIconFont();
|
||||||
|
|
||||||
// theme.font_size = 14;
|
// theme.font_size = 14;
|
||||||
// theme.font_size = TweakFloat("Font size", 14, 6, 50, .precision = 0);
|
theme.font_size = TweakFloat("Font size", 14, 6, 50, .precision = 0);
|
||||||
theme.font_size = TweakFloat("Font size", 14, 6, 50, .precision = 2);
|
|
||||||
theme.h1 = 2.00;
|
theme.h1 = 2.00;
|
||||||
theme.h2 = 1.50;
|
theme.h2 = 1.50;
|
||||||
theme.h3 = 1.25;
|
theme.h3 = 1.25;
|
||||||
@ -247,8 +246,6 @@ V_WidgetTheme V_GetWidgetTheme(void)
|
|||||||
theme.h6 = 0.75;
|
theme.h6 = 0.75;
|
||||||
theme.micro = 0.50;
|
theme.micro = 0.50;
|
||||||
|
|
||||||
// theme.rounding = 0;
|
|
||||||
// theme.rounding = 1;
|
|
||||||
theme.rounding = TweakFloat("Rounding", 1, 0, 1);
|
theme.rounding = TweakFloat("Rounding", 1, 0, 1);
|
||||||
|
|
||||||
theme.text_padding_x = 5;
|
theme.text_padding_x = 5;
|
||||||
@ -1511,7 +1508,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
UI_Push(BorderColor, window_border_color);
|
UI_Push(BorderColor, window_border_color);
|
||||||
// UI_Push(BorderSize, theme.window_bd_sz);
|
// UI_Push(BorderSize, theme.window_bd_sz);
|
||||||
UI_Push(BorderSize, 1);
|
UI_Push(BorderSize, 1);
|
||||||
UI_Push(Rounding, UI_RGROW(0.095 * theme.rounding));
|
UI_Push(Rounding, UI_RGROW(0.06 * theme.rounding));
|
||||||
UI_Push(Width, UI_FNT(40, 0));
|
UI_Push(Width, UI_FNT(40, 0));
|
||||||
UI_Push(Height, UI_SHRINK(0, 0));
|
UI_Push(Height, UI_SHRINK(0, 0));
|
||||||
UI_Push(ChildLayoutAxis, Axis_Y);
|
UI_Push(ChildLayoutAxis, Axis_Y);
|
||||||
@ -1707,28 +1704,6 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
String new_tweak_str = tweak_var.value;
|
String new_tweak_str = tweak_var.value;
|
||||||
b32 is_default = MatchString(new_tweak_str, tweak_var.initial);
|
b32 is_default = MatchString(new_tweak_str, tweak_var.initial);
|
||||||
|
|
||||||
// Tweak label
|
|
||||||
{
|
|
||||||
UI_BuildSpacer(UI_PIX(spacing, 1), Axis_X);
|
|
||||||
if (is_default)
|
|
||||||
{
|
|
||||||
UI_SetNext(TextColor, theme.col.hint);
|
|
||||||
UI_SetNext(FontSize, UI_Top(FontSize) * theme.h5);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UI_SetNext(TextColor, Color_White);
|
|
||||||
}
|
|
||||||
UI_SetNext(ChildAlignment, UI_Region_Left);
|
|
||||||
UI_SetNext(Width, UI_SHRINK(0, 1));
|
|
||||||
UI_SetNext(Height, UI_SHRINK(0, 1));
|
|
||||||
UI_SetNext(Text, new_tweak_str);
|
|
||||||
UI_SetNext(Flags, UI_BoxFlag_DrawText);
|
|
||||||
UI_SetNext(BackgroundColor, 0);
|
|
||||||
UI_SetNext(BorderColor, 0);
|
|
||||||
UI_BuildBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset button
|
// Reset button
|
||||||
if (!is_default)
|
if (!is_default)
|
||||||
{
|
{
|
||||||
@ -1769,6 +1744,28 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
UI_BuildIconEx(reset_key, theme.icon_font, UI_Icon_Loop2);
|
UI_BuildIconEx(reset_key, theme.icon_font, UI_Icon_Loop2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tweak label
|
||||||
|
{
|
||||||
|
UI_BuildSpacer(UI_PIX(spacing, 1), Axis_X);
|
||||||
|
if (is_default)
|
||||||
|
{
|
||||||
|
UI_SetNext(TextColor, theme.col.hint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UI_SetNext(TextColor, Color_White);
|
||||||
|
}
|
||||||
|
UI_SetNext(FontSize, UI_Top(FontSize) * theme.h5);
|
||||||
|
UI_SetNext(ChildAlignment, UI_Region_Left);
|
||||||
|
UI_SetNext(Width, UI_SHRINK(0, 1));
|
||||||
|
UI_SetNext(Height, UI_SHRINK(0, 1));
|
||||||
|
UI_SetNext(Text, new_tweak_str);
|
||||||
|
UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_NoTextTruncation);
|
||||||
|
UI_SetNext(BackgroundColor, 0);
|
||||||
|
UI_SetNext(BorderColor, 0);
|
||||||
|
UI_BuildBox();
|
||||||
|
}
|
||||||
|
|
||||||
UI_BuildSpacer(UI_PIX(spacing, 1), Axis_X);
|
UI_BuildSpacer(UI_PIX(spacing, 1), Axis_X);
|
||||||
|
|
||||||
switch (tweak_var.kind)
|
switch (tweak_var.kind)
|
||||||
@ -2299,7 +2296,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
S_Ent *ent = &cmd->ent;
|
S_Ent *ent = &cmd->ent;
|
||||||
*ent = *S_EntFromKey(&V.lookup, V.player_key);
|
*ent = *S_EntFromKey(&V.lookup, V.player_key);
|
||||||
ent->key = V.player_key;
|
ent->key = V.player_key;
|
||||||
ent->move_speed = 0.1;
|
ent->move_speed = 0.05;
|
||||||
ent->local_shape = S_ShapeFromDesc(
|
ent->local_shape = S_ShapeFromDesc(
|
||||||
.mass = 10,
|
.mass = 10,
|
||||||
.count = 1,
|
.count = 1,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user