SpaceCadetPinball/SpaceCadetPinball/maths.cpp

272 lines
6.4 KiB
C++

#include "pch.h"
#include "maths.h"
void maths::enclosing_box(rectangle_type* rect1, rectangle_type* rect2, rectangle_type* dstRect)
{
int xPos1 = rect1->XPosition;
int yPos1 = rect1->YPosition;
int width1 = rect1->Width;
int height1 = rect1->Height;
int xPos2 = rect2->XPosition;
bool rect2XPosLessRect1 = rect2->XPosition < rect1->XPosition;
int yPos2 = rect2->YPosition;
int width2 = rect2->Width;
int height2 = rect2->Height;
int xPos2_2 = rect2->XPosition;
if (rect2XPosLessRect1)
{
width1 += xPos1 - xPos2;
xPos1 = xPos2;
}
if (yPos2 < yPos1)
{
height1 += yPos1 - yPos2;
yPos1 = yPos2;
}
if (width2 + xPos2 > xPos1 + width1)
width1 = xPos2_2 + width2 - xPos1;
int height1_2 = height1;
if (height2 + yPos2 > height1 + yPos1)
height1_2 = yPos2 + height2 - yPos1;
dstRect->YPosition = yPos1;
dstRect->Height = height1_2;
dstRect->XPosition = xPos1;
dstRect->Width = width1;
}
int maths::rectangle_clip(rectangle_type* rect1, rectangle_type* rect2, rectangle_type* dstRect)
{
int xPos1 = rect1->XPosition;
int yPos1 = rect1->YPosition;
int height1 = rect1->Height;
int xRight2 = rect2->XPosition + rect2->Width;
int width1 = rect1->Width;
int yRight2 = rect2->YPosition + rect2->Height;
if (xPos1 + width1 < rect2->XPosition)
return 0;
if (xPos1 >= xRight2)
return 0;
int yPos2 = yPos1;
if (yPos1 + height1 < rect2->YPosition || yPos1 >= yRight2)
return 0;
if (xPos1 < rect2->XPosition)
{
width1 += xPos1 - rect2->XPosition;
xPos1 = rect2->XPosition;
}
if (xPos1 + width1 > xRight2)
width1 = xRight2 - xPos1;
int height2 = height1;
if (yPos1 < rect2->YPosition)
{
height2 = yPos1 - rect2->YPosition + height1;
yPos2 = rect2->YPosition;
}
if (height2 + yPos2 > yRight2)
height2 = yRight2 - yPos2;
if (!width1 || !height2)
return 0;
if (dstRect)
{
dstRect->XPosition = xPos1;
dstRect->YPosition = yPos2;
dstRect->Width = width1;
dstRect->Height = height2;
}
return 1;
}
int maths::overlapping_box(rectangle_type* rect1, rectangle_type* rect2, rectangle_type* dstRect)
{
int v3;
int v4;
int v6;
int v7;
if (rect1->XPosition >= rect2->XPosition)
{
dstRect->XPosition = rect2->XPosition;
v3 = rect1->Width - rect2->XPosition;
v4 = rect1->XPosition;
}
else
{
dstRect->XPosition = rect1->XPosition;
v3 = rect2->Width - rect1->XPosition;
v4 = rect2->XPosition;
}
dstRect->Width = v3 + v4 + 1;
int v5 = rect1->YPosition;
if (v5 >= rect2->YPosition)
{
dstRect->YPosition = rect2->YPosition;
v6 = rect1->Height - rect2->YPosition;
v7 = rect1->YPosition;
}
else
{
dstRect->YPosition = v5;
v6 = rect2->Height - rect1->YPosition;
v7 = rect2->YPosition;
}
dstRect->Height = v6 + v7 + 1;
return dstRect->Width <= rect2->Width + rect1->Width && dstRect->Height <= rect2->Height + rect1->Height;
}
float maths::ray_intersect_circle(ray_type* ray, circle_type* circle)
{
// O - ray origin
// D - ray direction
// C - circle center
// R - circle radius
// L, C - O, vector between O and C
float Lx = circle->Center.X - ray->Origin.X;
float Ly = circle->Center.Y - ray->Origin.Y;
// Tca, L dot D, projection of L on D
float Tca = Ly * ray->Direction.Y + Lx * ray->Direction.X;
if (Tca < 0.0) // No intersection if Tca is negative
return 1000000000.0f;
// L dot L, distance from ray origin to circle center
float LMagSq = Ly * Ly + Lx * Lx;
// If ray origin is inside of the circle
// T0 = Tca - Sqrt(rad^2 - d^2). d = sqrt(L dot L - Tca dot Tca)
if (LMagSq < circle->RadiusSq)
return Tca - sqrt(circle->RadiusSq - LMagSq + Tca * Tca);
// Thc^2 = rad^2 - d = rad^2 - L dot L + Tca dot Tca
float ThcSq = circle->RadiusSq - LMagSq + Tca * Tca;
if (ThcSq < 0.0) // No intersection if Thc is negative
return 1000000000.0f;
// T0 = Tca - Thc, distance from origin to first intersection
float T0 = Tca - sqrt(ThcSq);
if (T0 < 0.0 || T0 > ray->MaxDistance)
return 1000000000.0f;
return T0;
}
float maths::normalize_2d(vector_type* vec)
{
float mag = sqrt(vec->X * vec->X + vec->Y * vec->Y);
if (0.0 != mag)
{
vec->X = 1.0f / mag * vec->X;
vec->Y = 1.0f / mag * vec->Y;
}
return mag;
}
void maths::line_init(line_type* line, float x0, float y0, float x1, float y1)
{
float v9;
bool lineDirection;
float v11;
line->Direction.X = x1 - x0;
line->Direction.Y = y1 - y0;
normalize_2d(&line->Direction);
line->PerpendicularL.X = line->Direction.Y;
line->PerpendicularL.Y = -line->Direction.X;
line->PreComp1 = -(line->Direction.Y * x0) + (line->Direction.X * y0);
if (line->Direction.X >= 0.000000001 || line->Direction.X <= -0.000000001)
{
v9 = x1;
lineDirection = x0 >= x1;
v11 = x0;
}
else
{
line->Direction.X = 0.0;
v9 = y1;
lineDirection = y0 >= y1;
v11 = y0;
}
if (lineDirection)
{
line->OriginX = v9;
line->OriginY = v11;
}
else
{
line->OriginY = v9;
line->OriginX = v11;
}
}
float maths::ray_intersect_line(ray_type* ray, line_type* line)
{
// Similar to https://rootllama.wordpress.com/2014/06/20/ray-line-segment-intersection-test-in-2d/
float perpDot;
float result;
float v4;
bool v5;
bool v6;
float v7;
perpDot = line->PerpendicularL.Y * ray->Direction.Y + ray->Direction.X * line->PerpendicularL.X;
if (perpDot < 0.0)
{
result = -((ray->Origin.X * line->PerpendicularL.X + ray->Origin.Y * line->PerpendicularL.Y + line->PreComp1)
/ perpDot);
if (result >= -ray->MinDistance && result <= ray->MaxDistance)
{
line->CompTmp1 = result * ray->Direction.X + ray->Origin.X;
v4 = result * ray->Direction.Y + ray->Origin.Y;
line->Unknown10 = v4;
if (0.0 == line->Direction.X)
{
if (v4 >= line->OriginX)
{
v5 = v4 < line->OriginY;
v6 = v4 == line->OriginY;
if (v5 || v6)
return result;
return 1000000000.0;
}
}
else if (line->OriginX <= line->CompTmp1)
{
v7 = line->CompTmp1;
v5 = v7 < line->OriginY;
v6 = v7 == line->OriginY;
if (v5 || v6)
return result;
return 1000000000.0;
}
}
}
return 1000000000.0;
}
void maths::cross(vector_type* vec1, vector_type* vec2, vector_type* dstVec)
{
dstVec->X = vec2->Z * vec1->Y - vec2->Y * vec1->Z;
dstVec->Y = vec2->X * vec1->Z - vec1->X * vec2->Z;
dstVec->Z = vec1->X * vec2->Y - vec2->X * vec1->Y;
}
float maths::magnitude(vector_type* vec)
{
float result;
auto magSq = vec->X * vec->X + vec->Y * vec->Y + vec->Z * vec->Z;
if (magSq == 0.0)
result = 0.0;
else
result = sqrt(magSq);
return result;
}
void maths::vector_add(vector_type* vec1Dst, vector_type* vec2)
{
vec1Dst->X += vec2->X;
vec1Dst->Y += vec2->Y;
}