320 lines
5.4 KiB
C
320 lines
5.4 KiB
C
#ifndef _PIUMA_LIB_GEOMETRY_H_
|
|
#define _PIUMA_LIB_GEOMETRY_H_
|
|
|
|
#include "types.h"
|
|
#include "math.h"
|
|
|
|
// Rect
|
|
union Rect
|
|
{
|
|
struct
|
|
{
|
|
f32 x, y;
|
|
f32 w, h;
|
|
};
|
|
struct
|
|
{
|
|
v2 position; // Usually, the top-left corner of the rectangle
|
|
v2 size;
|
|
};
|
|
};
|
|
|
|
inline bool is_inside(Rect rect, v2 p)
|
|
{
|
|
bool in_range_x = rect.x <= p.x && p.x <= (rect.x + rect.w);
|
|
bool in_range_y = rect.y <= p.y && p.y <= (rect.y + rect.h);
|
|
return in_range_x && in_range_y;
|
|
}
|
|
|
|
// @Feature: add Cube/Parallelepiped? Unlike Box, it has rotations
|
|
// Box
|
|
struct Box
|
|
{
|
|
v3 min;
|
|
v3 max;
|
|
};
|
|
|
|
inline bool is_inside(Box b, v3 p)
|
|
{
|
|
return
|
|
(p.x < b.min.x || p.x > b.max.x) ||
|
|
(p.y < b.min.y || p.y > b.max.y) ||
|
|
(p.z < b.min.z || p.z > b.max.z);
|
|
}
|
|
|
|
inline bool overlaps(Box a, Box b)
|
|
{
|
|
if(a.min.x > b.max.x) // no overlap
|
|
return false;
|
|
if(a.max.x < b.min.x) // no overlap
|
|
return false;
|
|
if(a.min.y > b.max.y) // no overlap
|
|
return false;
|
|
if(a.max.y < b.min.y) // no overlap
|
|
return false;
|
|
if(a.min.z > b.max.z) // no overlap
|
|
return false;
|
|
if(a.max.z < b.min.z) // no overlap
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
inline Box box_from_point_cloud(v3 *points, u32 count)
|
|
{
|
|
if(count == 0)
|
|
return Box{.min = {0,0,0}, .max = {0,0,0}};
|
|
|
|
Box box;
|
|
box.min = points[0];
|
|
box.max = points[0];
|
|
for(u32 i = 0; i < count; i++)
|
|
{
|
|
v3 p = points[i];
|
|
box.min.x = minimum(box.min.x, p.x);
|
|
box.min.y = minimum(box.min.y, p.y);
|
|
box.min.z = minimum(box.min.z, p.z);
|
|
box.max.x = maximum(box.max.x, p.x);
|
|
box.max.y = maximum(box.max.y, p.y);
|
|
box.max.z = maximum(box.max.z, p.z);
|
|
}
|
|
return box;
|
|
}
|
|
|
|
inline v3 box_closest_point(Box b, v3 point);
|
|
inline f32 box_SDF(Box b, v3 point, v3* res_closest = NULL)
|
|
{
|
|
v3 closest = box_closest_point(b, point);
|
|
f32 sign = -1 * is_inside(b, point);
|
|
|
|
if(res_closest)
|
|
*res_closest = closest;
|
|
return sign * distance(closest, point);
|
|
}
|
|
|
|
|
|
// Ray
|
|
struct Ray
|
|
{
|
|
v3 position;
|
|
v3 direction;
|
|
};
|
|
|
|
|
|
// Circle
|
|
// @Cleanup: Should Circle be merged with Sphere?
|
|
struct Circle
|
|
{
|
|
v2 center;
|
|
f32 radius;
|
|
};
|
|
|
|
inline bool is_inside(Circle c, v2 p)
|
|
{
|
|
v2 v = p - c.center;
|
|
return dot(v, v) <= square(c.radius);
|
|
}
|
|
|
|
// Sphere
|
|
struct Sphere
|
|
{
|
|
v3 center;
|
|
f32 radius;
|
|
};
|
|
|
|
inline bool is_inside(Sphere s, v3 p)
|
|
{
|
|
v3 v = p - s.center;
|
|
return dot(v, v) <= square(s.radius); // distance² <= radius²
|
|
}
|
|
|
|
inline f32 sphere_SDF(Sphere s, v3 point)
|
|
{
|
|
return distance(s.center, point) - s.radius;
|
|
}
|
|
|
|
|
|
// Segment
|
|
struct Segment
|
|
{
|
|
v3 a;
|
|
v3 b;
|
|
};
|
|
|
|
|
|
// Plane
|
|
struct Plane
|
|
{
|
|
v3 normal;
|
|
f32 offset;
|
|
};
|
|
|
|
inline f32 plane_SDF(Plane plane, v3 point)
|
|
{
|
|
f32 projected = dot(point, plane.normal);
|
|
return plane.offset - projected;
|
|
}
|
|
|
|
|
|
|
|
// Projections
|
|
inline f32 project_point_on_vector(v3 vector, v3 point)
|
|
{
|
|
return dot(vector, point);
|
|
}
|
|
|
|
inline v3 project_point_on_plane(Plane plane, v3 point)
|
|
{
|
|
f32 distance = plane_SDF(plane, point);
|
|
return point - plane.normal * distance;
|
|
}
|
|
|
|
|
|
// Closest point
|
|
inline v3 segment_closest_point(Segment seg, v3 point)
|
|
{
|
|
v3 ab = seg.b - seg.a;
|
|
v3 ap = point - seg.a;
|
|
f32 u = dot(ab, ap);
|
|
return seg.a + ab * clamp(0.0, 1.0, u);
|
|
}
|
|
|
|
inline v3 box_closest_point(Box b, v3 point)
|
|
{
|
|
v3 closest;
|
|
// Closest point on the box is the one with coords closer to the ones of the point,
|
|
// so for each axis we can clamp to the nearest point of the border.
|
|
|
|
f32 dx1 = abs(b.min.x - point.x);
|
|
f32 dx2 = abs(b.max.x - point.x);
|
|
closest.x = (dx1 < dx2) ? b.min.x : b.max.x;
|
|
f32 dy1 = abs(b.min.y - point.y);
|
|
f32 dy2 = abs(b.max.y - point.y);
|
|
closest.y = (dy1 < dy2) ? b.min.y : b.max.y;
|
|
f32 dz1 = abs(b.min.z - point.z);
|
|
f32 dz2 = abs(b.max.z - point.z);
|
|
closest.z = (dz1 < dz2) ? b.min.z : b.max.z;
|
|
|
|
return closest;
|
|
}
|
|
|
|
|
|
|
|
// Triangles functions
|
|
inline v3 triangle_normal(v3 a, v3 b, v3 c)
|
|
{
|
|
v3 ba = b - a;
|
|
v3 ca = c - a;
|
|
v3 orthogonal = cross(ba, ca);
|
|
return normalize(orthogonal);
|
|
}
|
|
|
|
|
|
// Transformations (all angles in radians)
|
|
inline m4 rotation_x(f32 angle)
|
|
{
|
|
f32 c = cos(angle);
|
|
f32 s = sin(angle);
|
|
|
|
m4 result = m4_identity;
|
|
result.E[1][1] = c;
|
|
result.E[1][2] = -s;
|
|
result.E[2][1] = s;
|
|
result.E[2][2] = c;
|
|
|
|
return result;
|
|
}
|
|
|
|
inline m4 rotation_y(f32 angle)
|
|
{
|
|
f32 c = cos(angle);
|
|
f32 s = sin(angle);
|
|
|
|
m4 result = m4_identity;
|
|
result.E[0][0] = c;
|
|
result.E[0][2] = s;
|
|
result.E[2][0] = -s;
|
|
result.E[2][2] = c;
|
|
|
|
return result;
|
|
}
|
|
|
|
inline m4 rotation_z(f32 angle)
|
|
{
|
|
f32 c = cos(angle);
|
|
f32 s = sin(angle);
|
|
|
|
m4 result = m4_identity;
|
|
result.E[0][0] = c;
|
|
result.E[0][1] = -s;
|
|
result.E[1][0] = s;
|
|
result.E[1][1] = c;
|
|
|
|
return result;
|
|
}
|
|
|
|
inline m4 rotation(f32 x, f32 y, f32 z)
|
|
{
|
|
return rotation_z(z) * rotation_y(y) * rotation_x(x);
|
|
}
|
|
|
|
inline m4 rotation_v3(v3 angle)
|
|
{
|
|
return rotation(angle.x, angle.y, angle.z);
|
|
}
|
|
|
|
|
|
inline m4 translation(f32 x, f32 y, f32 z)
|
|
{
|
|
m4 result = m4_identity;
|
|
|
|
result.E[0][3] = x;
|
|
result.E[1][3] = y;
|
|
result.E[2][3] = z;
|
|
|
|
return result;
|
|
}
|
|
|
|
inline m4 translation_v3(v3 t)
|
|
{
|
|
return translation(t.x, t.y, t.z);
|
|
}
|
|
|
|
inline m4 scale(f32 x, f32 y, f32 z)
|
|
{
|
|
m4 result = m4_zero;
|
|
|
|
result.E[0][0] = x;
|
|
result.E[1][1] = y;
|
|
result.E[2][2] = z;
|
|
result.E[3][3] = 1.0;
|
|
|
|
return result;
|
|
}
|
|
|
|
inline m4 scale_v3(v3 factor)
|
|
{
|
|
return scale(factor.x, factor.y, factor.z);
|
|
}
|
|
|
|
inline m4 scale(f32 factor)
|
|
{
|
|
return scale(factor, factor, factor);
|
|
}
|
|
|
|
|
|
|
|
|
|
// Primitives
|
|
// Pass array of 8 elements to fill with coordinates
|
|
inline void build_cube_vertices(v3 *vertices)
|
|
{
|
|
for(int x = 0; x < 2; x++)
|
|
for(int y = 0; y < 2; y++)
|
|
for(int z = 0; z < 2; z++)
|
|
vertices[x*2*2 + y*2 + z] = v3{.x = x - 0.5f, .y = y - 0.5f, .z = z - 0.5f};
|
|
}
|
|
|
|
|
|
|
|
#endif
|