SpaceCadetPinball/SpaceCadetPinball/TLine.cpp

132 lines
3.0 KiB
C++

#include "pch.h"
#include "TLine.h"
#include "TTableLayer.h"
TLine::TLine(TCollisionComponent* collCmp, char* activeFlag, unsigned int collisionGroup, float x0, float y0, float x1,
float y1): TEdgeSegment(collCmp, activeFlag, collisionGroup)
{
X0 = x0;
Y0 = y0;
X1 = x1;
Y1 = y1;
maths::line_init(Line, x0, y0, x1, y1);
}
TLine::TLine(TCollisionComponent* collCmp, char* activeFlag, unsigned int collisionGroup, const vector2& start,
const vector2& end) : TEdgeSegment(collCmp, activeFlag, collisionGroup)
{
X0 = start.X;
Y0 = start.Y;
X1 = end.X;
Y1 = end.Y;
maths::line_init(Line, X0, Y0, X1, Y1);
}
void TLine::Offset(float offset)
{
float offX = offset * Line.PerpendicularC.X;
float offY = offset * Line.PerpendicularC.Y;
X0 += offX;
Y0 += offY;
X1 += offX;
Y1 += offY;
maths::line_init(Line, X0, Y0, X1, Y1);
}
float TLine::FindCollisionDistance(const ray_type& ray)
{
return maths::ray_intersect_line(ray, Line);
}
void TLine::EdgeCollision(TBall* ball, float distance)
{
CollisionComponent->Collision(
ball,
&Line.RayIntersect,
&Line.PerpendicularC,
distance,
this);
}
void TLine::place_in_grid(RectF* aabb)
{
if (aabb)
{
aabb->Merge({
std::max(X0, X1), std::max(Y0, Y1),
std::min(X0, X1), std::min(Y0, Y1)
});
}
auto edgeMan = TTableLayer::edge_manager;
auto xBox0 = edgeMan->box_x(X0);
auto yBox0 = edgeMan->box_y(Y0);
auto xBox1 = edgeMan->box_x(X1);
auto yBox1 = edgeMan->box_y(Y1);
int dirX = X0 >= X1 ? -1 : 1;
int dirY = Y0 >= Y1 ? -1 : 1;
if (yBox0 == yBox1)
{
if (dirX == 1)
{
while (xBox0 <= xBox1)
edgeMan->add_edge_to_box(xBox0++, yBox0, this);
}
else
{
while (xBox0 >= xBox1)
edgeMan->add_edge_to_box(xBox0--, yBox0, this);
}
}
else if (xBox0 == xBox1)
{
if (dirY == 1)
{
while (yBox0 <= yBox1)
edgeMan->add_edge_to_box(xBox0, yBox0++, this);
}
else
{
while (yBox0 >= yBox1)
edgeMan->add_edge_to_box(xBox0, yBox0--, this);
}
}
else
{
edgeMan->add_edge_to_box(xBox0, yBox0, this);
// Bresenham line formula: y = dYdX * (x - x0) + y0; dYdX = (y0 - y1) / (x0 - x1)
auto dyDx = (Y0 - Y1) / (X0 - X1);
// Precompute constant part: dYdX * (-x0) + y0
auto precomp = -X0 * dyDx + Y0;
// X and Y indexes are offset by one when going forwards, not sure why
auto xBias = dirX == 1 ? 1 : 0, yBias = dirY == 1 ? 1 : 0;
for (auto indexX = xBox0, indexY = yBox0; indexX != xBox1 || indexY != yBox1;)
{
// Calculate y from indexY and from line formula
auto yDiscrete = (indexY + yBias) * edgeMan->AdvanceY + edgeMan->MinY;
auto ylinear = ((indexX + xBias) * edgeMan->AdvanceX + edgeMan->MinX) * dyDx + precomp;
if (dirY == 1 ? ylinear >= yDiscrete : ylinear <= yDiscrete)
{
// Advance indexY when discrete value is ahead/behind
// Advance indexX when discrete value matches linear value
indexY += dirY;
if (ylinear == yDiscrete)
indexX += dirX;
}
else
{
// Advance indexX otherwise
indexX += dirX;
}
edgeMan->add_edge_to_box(indexX, indexY, this);
}
}
}