5#include "./SelectionFrustum.h"
6constexpr float LINE_THRESHOLD = 5.0f;
7template<
typename RectType>
8inline bool checkCollision(
const RectType& recA,
const RectType& recB) {
9 static_assert(std::is_same<RectType, SDL_Rect>::value || std::is_same<RectType, SDL_FRect>::value,
10 "checkCollision: RectType must be either SDL_Rect or SDL_FRect");
12 if (recA.x >= recB.x + recB.w || recA.x + recA.w <= recB.x ||
13 recA.y >= recB.y + recB.h || recA.y + recA.h <= recB.y) {
19inline bool checkCollision(
const SDL_Rect& recA,
const SDL_FRect& recB) {
20 SDL_FRect convertedA = {
static_cast<float>(recA.x),
static_cast<float>(recA.y),
21 static_cast<float>(recA.w),
static_cast<float>(recA.h) };
22 return checkCollision(convertedA, recB);
25inline bool checkCollision(
const SDL_FRect& recA,
const SDL_Rect& recB) {
26 return checkCollision(recB, recA);
29inline bool checkCollision3D(
const glm::vec3& centerA,
const glm::vec3& halfSizeA,
30 const glm::vec3& centerB,
const glm::vec3& halfSizeB,
31 float padding = 0.0f) {
33 glm::vec3 paddedHalfSizeA = halfSizeA + glm::vec3(padding);
34 glm::vec3 paddedHalfSizeB = halfSizeB + glm::vec3(padding);
37 return !(centerA.x + paddedHalfSizeA.x <= centerB.x - paddedHalfSizeB.x ||
38 centerA.x - paddedHalfSizeA.x >= centerB.x + paddedHalfSizeB.x ||
39 centerA.y + paddedHalfSizeA.y <= centerB.y - paddedHalfSizeB.y ||
40 centerA.y - paddedHalfSizeA.y >= centerB.y + paddedHalfSizeB.y ||
41 centerA.z + paddedHalfSizeA.z <= centerB.z - paddedHalfSizeB.z ||
42 centerA.z - paddedHalfSizeA.z >= centerB.z + paddedHalfSizeB.z);
45inline float pointLineDistance(glm::vec2 point, glm::vec2 lineStartPoint, glm::vec2 lineEndPoint) {
46 float num = std::abs((lineEndPoint.y - lineStartPoint.y) * point.x - (lineEndPoint.x - lineStartPoint.x) * point.y + lineEndPoint.x * lineStartPoint.y - lineEndPoint.y * lineStartPoint.x);
47 float den = std::sqrt((lineEndPoint.y - lineStartPoint.y) * (lineEndPoint.y - lineStartPoint.y) + (lineEndPoint.x - lineStartPoint.x) * (lineEndPoint.x - lineStartPoint.x));
51inline bool rayIntersectsRectangle(
const glm::vec3& rayOrigin,
const glm::vec3& rayDirection,
52 const glm::vec3& planePoint,
const glm::vec3& planeNormal,
53 float xMin,
float xMax,
float yMin,
float yMax) {
55 float denom = glm::dot(planeNormal, rayDirection);
58 if (std::abs(denom) < 1e-6) {
63 float t = glm::dot(planeNormal, planePoint - rayOrigin) / denom;
71 glm::vec3 intersectionPoint = rayOrigin + t * rayDirection;
74 if (intersectionPoint.x >= xMin && intersectionPoint.x <= xMax &&
75 intersectionPoint.y >= yMin && intersectionPoint.y <= yMax) {
83inline bool rayIntersectsSphere(
84 const glm::vec3& rayOrigin,
85 const glm::vec3& rayDirection,
86 const glm::vec3& sphereCenter,
90 glm::vec3 oc = rayOrigin - sphereCenter;
92 float A = glm::dot(rayDirection, rayDirection);
93 float B = 2.0f * glm::dot(oc, rayDirection);
94 float C = glm::dot(oc, oc) - radius * radius;
96 float discriminant = B * B - 4 * A * C;
98 if (discriminant < 0) {
103 float sqrtDiscriminant = sqrt(discriminant);
104 float t0 = (-B - sqrtDiscriminant) / (2.0f * A);
105 float t1 = (-B + sqrtDiscriminant) / (2.0f * A);
108 t = rayOrigin + t0 * rayDirection;
112 t = rayOrigin + t1 * rayDirection;
119inline bool sphereIntersectsBox(
120 const glm::vec3& sphereCenter,
float sphereRadius,
121 const glm::vec3& boxMin,
const glm::vec3& boxMax,
122 glm::vec3& intersectionPoint)
124 glm::vec3 closestPoint = glm::clamp(sphereCenter, boxMin, boxMax);
126 intersectionPoint = closestPoint;
128 glm::vec3 diff = closestPoint - sphereCenter;
129 float distanceSquared = glm::dot(diff, diff);
131 return distanceSquared <= (sphereRadius * sphereRadius);
134inline bool rayIntersectsBox(
135 const glm::vec3& rayOrigin,
136 const glm::vec3& rayDirection,
137 const glm::vec3& boxMin,
138 const glm::vec3& boxMax,
139 glm::vec3& intersectionPoint,
140 float* tOut =
nullptr
143 float tMax = std::numeric_limits<float>::max();
146 for (
int i = 0; i < 3; i++) {
147 if (abs(rayDirection[i]) < 1e-8f) {
149 if (rayOrigin[i] < boxMin[i] || rayOrigin[i] > boxMax[i]) {
155 float invD = 1.0f / rayDirection[i];
156 float t1 = (boxMin[i] - rayOrigin[i]) * invD;
157 float t2 = (boxMax[i] - rayOrigin[i]) * invD;
160 if (t1 > t2) std::swap(t1, t2);
163 tMin = std::max(tMin, t1);
164 tMax = std::min(tMax, t2);
179 float t = (tMin >= 0) ? tMin : tMax;
180 intersectionPoint = rayOrigin + t * rayDirection;
191inline bool rayIntersectsLineSegment(
192 const glm::vec3& rayOrigin,
193 const glm::vec3& rayDirection,
194 const glm::vec3& segmentStart,
195 const glm::vec3& segmentEnd,
196 glm::vec3& intersectionPoint,
197 float* tOut =
nullptr
199 glm::vec3 lineVec = segmentEnd - segmentStart;
200 glm::vec3 w = rayOrigin - segmentStart;
202 float a = glm::dot(rayDirection, rayDirection);
203 float b = glm::dot(rayDirection, lineVec);
204 float c = glm::dot(lineVec, lineVec);
205 float d = glm::dot(rayDirection, w);
206 float e = glm::dot(lineVec, w);
208 float denom = a * c - b * b;
210 if (abs(denom) < 1e-6f) {
214 float s = (b * e - c * d) / denom;
215 float t = (a * e - b * d) / denom;
218 t = glm::clamp(t, 0.0f, 1.0f);
225 glm::vec3 pointOnRay = rayOrigin + s * rayDirection;
226 glm::vec3 pointOnSegment = segmentStart + t * lineVec;
228 float distance = glm::distance(pointOnRay, pointOnSegment);
230 if (distance <= LINE_THRESHOLD) {
231 intersectionPoint = pointOnSegment;
242inline bool checkCircleLineCollision(glm::vec2 center,
int circleRadius, glm::vec2 lineStartPoint, glm::vec2 lineEndPoint) {
243 float dist = pointLineDistance(center, lineStartPoint, lineEndPoint);
245 if (dist <= circleRadius) {
246 float dx = lineEndPoint.x - lineStartPoint.x;
247 float dy = lineEndPoint.y - lineStartPoint.y;
248 float t = ((center.x - lineStartPoint.x) * dx + (center.y - lineStartPoint.y) * dy) / (dx * dx + dy * dy);
250 t = std::max(0.0f, std::min(1.0f, t));
252 float closestX = lineStartPoint.x + t * dx;
253 float closestY = lineStartPoint.y + t * dy;
255 float distanceToCircle = std::sqrt((closestX - center.x) * (closestX - center.x) +
256 (closestY - center.y) * (closestY - center.y));
257 return distanceToCircle <= circleRadius;
263inline bool isPointInFrustum(
const glm::vec3& point,
const SelectionFrustum& frustum) {
264 for (
int i = 0; i < 6; i++) {
265 float distance = glm::dot(glm::vec3(frustum.planes[i]), point) + frustum.planes[i].w;
Definition SelectionFrustum.h:5