Files
Server_Monitor/code/lib/geometry.h
2023-09-26 19:40:16 +02:00

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