mirror of
https://github.com/k4zmu2a/SpaceCadetPinball.git
synced 2024-11-14 19:25:18 -05:00
Cleaned up Bresenham line in TLine and TEdgeManager.
This commit is contained in:
parent
2d2ca0ab2a
commit
0cb75ecf7f
2 changed files with 83 additions and 227 deletions
|
@ -14,11 +14,11 @@ TEdgeManager::TEdgeManager(float posX, float posY, float width, float height)
|
||||||
Y = posY;
|
Y = posY;
|
||||||
MaxBoxX = 10;
|
MaxBoxX = 10;
|
||||||
MaxBoxY = 15;
|
MaxBoxY = 15;
|
||||||
AdvanceX = width / 10.0f;
|
AdvanceX = width / static_cast<float>(MaxBoxX);
|
||||||
AdvanceY = height / 15.0f;
|
AdvanceY = height / static_cast<float>(MaxBoxY);
|
||||||
AdvanceXInv = 1.0f / AdvanceX;
|
AdvanceXInv = 1.0f / AdvanceX;
|
||||||
AdvanceYInv = 1.0f / AdvanceY;
|
AdvanceYInv = 1.0f / AdvanceY;
|
||||||
BoxArray = new TEdgeBox[150];
|
BoxArray = new TEdgeBox[MaxBoxX * MaxBoxY];
|
||||||
}
|
}
|
||||||
|
|
||||||
TEdgeManager::~TEdgeManager()
|
TEdgeManager::~TEdgeManager()
|
||||||
|
@ -48,18 +48,26 @@ int TEdgeManager::increment_box_y(int y)
|
||||||
|
|
||||||
void TEdgeManager::add_edge_to_box(int x, int y, TEdgeSegment* edge)
|
void TEdgeManager::add_edge_to_box(int x, int y, TEdgeSegment* edge)
|
||||||
{
|
{
|
||||||
BoxArray[x + y * MaxBoxX].EdgeList.push_back(edge);
|
assertm((unsigned)x < (unsigned)MaxBoxX && (unsigned)y < (unsigned)MaxBoxY, "Box coordinates out of range");
|
||||||
|
|
||||||
|
auto& list = BoxArray[x + y * MaxBoxX].EdgeList;
|
||||||
|
assertm(std::find(list.begin(), list.end(), edge) == list.end(), "Duplicate inserted into box");
|
||||||
|
list.push_back(edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TEdgeManager::add_field_to_box(int x, int y, field_effect_type* field)
|
void TEdgeManager::add_field_to_box(int x, int y, field_effect_type* field)
|
||||||
{
|
{
|
||||||
BoxArray[x + y * MaxBoxX].FieldList.push_back(field);
|
assertm((unsigned)x < (unsigned)MaxBoxX && (unsigned)y < (unsigned)MaxBoxY, "Box coordinates out of range");
|
||||||
|
|
||||||
|
auto& list = BoxArray[x + y * MaxBoxX].FieldList;
|
||||||
|
assertm(std::find(list.begin(), list.end(), field) == list.end(), "Duplicate inserted into box");
|
||||||
|
list.push_back(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
int TEdgeManager::TestGridBox(int x, int y, float* distPtr, TEdgeSegment** edgeDst, ray_type* ray, TBall* ball,
|
int TEdgeManager::TestGridBox(int x, int y, float* distPtr, TEdgeSegment** edgeDst, ray_type* ray, TBall* ball,
|
||||||
int edgeIndex)
|
int edgeIndex)
|
||||||
{
|
{
|
||||||
if (x >= 0 && x < 10 && y >= 0 && y < 15)
|
if (x >= 0 && x < MaxBoxX && y >= 0 && y < MaxBoxY)
|
||||||
{
|
{
|
||||||
TEdgeBox* edgeBox = &BoxArray[x + y * MaxBoxX];
|
TEdgeBox* edgeBox = &BoxArray[x + y * MaxBoxX];
|
||||||
TEdgeSegment** edgePtr = &EdgeArray[edgeIndex];
|
TEdgeSegment** edgePtr = &EdgeArray[edgeIndex];
|
||||||
|
@ -111,157 +119,83 @@ float TEdgeManager::FindCollisionDistance(ray_type* ray, TBall* ball, TEdgeSegme
|
||||||
auto distance = 1000000000.0f;
|
auto distance = 1000000000.0f;
|
||||||
auto edgeIndex = 0;
|
auto edgeIndex = 0;
|
||||||
|
|
||||||
auto rayX = ray->Origin.X;
|
auto x0 = ray->Origin.X;
|
||||||
auto rayY = ray->Origin.Y;
|
auto y0 = ray->Origin.Y;
|
||||||
auto rayBoxX = box_x(rayX);
|
auto x1 = ray->Direction.X * ray->MaxDistance + ray->Origin.X;
|
||||||
auto rayBoxY = box_y(rayY);
|
auto y1 = ray->Direction.Y * ray->MaxDistance + ray->Origin.Y;
|
||||||
|
|
||||||
auto rayEndX = ray->Direction.X * ray->MaxDistance + ray->Origin.X;
|
auto xBox0 = box_x(x0);
|
||||||
auto rayEndY = ray->Direction.Y * ray->MaxDistance + ray->Origin.Y;
|
auto yBox0 = box_y(y0);
|
||||||
auto rayEndBoxX = box_x(rayEndX);
|
auto xBox1 = box_x(x1);
|
||||||
auto rayEndBoxY = box_y(rayEndY);
|
auto yBox1 = box_y(y1);
|
||||||
|
|
||||||
auto rayDirX = rayX >= rayEndX ? -1 : 1;
|
auto dirX = x0 >= x1 ? -1 : 1;
|
||||||
auto rayDirY = rayY >= rayEndY ? -1 : 1;
|
auto dirY = y0 >= y1 ? -1 : 1;
|
||||||
|
|
||||||
if (rayBoxY == rayEndBoxY)
|
if (yBox0 == yBox1)
|
||||||
{
|
{
|
||||||
if (rayDirX == 1)
|
if (dirX == 1)
|
||||||
{
|
{
|
||||||
for (auto indexX = rayBoxX; indexX <= rayEndBoxX; indexX++)
|
for (auto indexX = xBox0; indexX <= xBox1; indexX++)
|
||||||
{
|
{
|
||||||
edgeIndex = TestGridBox(indexX, rayBoxY, &distance, edge, ray, ball, edgeIndex);
|
edgeIndex = TestGridBox(indexX, yBox0, &distance, edge, ray, ball, edgeIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (auto indexX = rayBoxX; indexX >= rayEndBoxX; indexX--)
|
for (auto indexX = xBox0; indexX >= xBox1; indexX--)
|
||||||
{
|
{
|
||||||
edgeIndex = TestGridBox(indexX, rayBoxY, &distance, edge, ray, ball, edgeIndex);
|
edgeIndex = TestGridBox(indexX, yBox0, &distance, edge, ray, ball, edgeIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (rayBoxX == rayEndBoxX)
|
else if (xBox0 == xBox1)
|
||||||
{
|
{
|
||||||
if (rayDirY == 1)
|
if (dirY == 1)
|
||||||
{
|
{
|
||||||
for (auto indexY = rayBoxY; indexY <= rayEndBoxY; indexY++)
|
for (auto indexY = yBox0; indexY <= yBox1; indexY++)
|
||||||
{
|
{
|
||||||
edgeIndex = TestGridBox(rayBoxX, indexY, &distance, edge, ray, ball, edgeIndex);
|
edgeIndex = TestGridBox(xBox0, indexY, &distance, edge, ray, ball, edgeIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (auto indexY = rayBoxY; indexY >= rayEndBoxY; indexY--)
|
for (auto indexY = yBox0; indexY >= yBox1; indexY--)
|
||||||
{
|
{
|
||||||
edgeIndex = TestGridBox(rayBoxX, indexY, &distance, edge, ray, ball, edgeIndex);
|
edgeIndex = TestGridBox(xBox0, indexY, &distance, edge, ray, ball, edgeIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto rayDyDX = (rayY - rayEndY) / (rayX - rayEndX);
|
edgeIndex = TestGridBox(xBox0, yBox0, &distance, edge, ray, ball, 0);
|
||||||
auto indexX = rayBoxX;
|
|
||||||
auto indexY = rayBoxY;
|
// Bresenham line formula: y = dYdX * (x - x0) + y0; dYdX = (y0 - y1) / (x0 - x1)
|
||||||
auto bresIndexX = rayBoxX + 1;
|
auto dyDx = (y0 - y1) / (x0 - x1);
|
||||||
auto bresIndexY = rayBoxY + 1;
|
// Precompute constant part: dYdX * (-x0) + y0
|
||||||
auto bresXAdd = rayY - rayDyDX * rayX;
|
auto precomp = -x0 * dyDx + y0;
|
||||||
edgeIndex = TestGridBox(rayBoxX, rayBoxY, &distance, edge, ray, ball, 0);
|
// X and Y indexes are offset by one when going forwards, not sure why
|
||||||
if (rayDirX == 1)
|
auto xBias = dirX == 1 ? 1 : 0, yBias = dirY == 1 ? 1 : 0;
|
||||||
|
|
||||||
|
for (auto indexX = xBox0, indexY = yBox0; indexX != xBox1 || indexY != yBox1;)
|
||||||
{
|
{
|
||||||
if (rayDirY == 1)
|
// Calculate y from indexY and from line formula
|
||||||
|
auto yDiscrete = (indexY + yBias) * AdvanceY + Y;
|
||||||
|
auto ylinear = ((indexX + xBias) * AdvanceX + X) * dyDx + precomp;
|
||||||
|
if (dirY == 1 ? ylinear >= yDiscrete : ylinear <= yDiscrete)
|
||||||
{
|
{
|
||||||
do
|
// Advance indexY when discrete value is ahead/behind
|
||||||
{
|
// Advance indexX when discrete value matches linear value
|
||||||
auto yCoord = bresIndexY * AdvanceY + Y;
|
indexY += dirY;
|
||||||
auto xCoord = (bresIndexX * AdvanceX + X) * rayDyDX + bresXAdd;
|
if (ylinear == yDiscrete)
|
||||||
if (xCoord >= yCoord)
|
indexX += dirX;
|
||||||
{
|
|
||||||
if (xCoord == yCoord)
|
|
||||||
{
|
|
||||||
++indexX;
|
|
||||||
++bresIndexX;
|
|
||||||
}
|
|
||||||
++indexY;
|
|
||||||
++bresIndexY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++indexX;
|
|
||||||
++bresIndexX;
|
|
||||||
}
|
|
||||||
edgeIndex = TestGridBox(indexX, indexY, &distance, edge, ray, ball, edgeIndex);
|
|
||||||
}
|
|
||||||
while (indexX < rayEndBoxX || indexY < rayEndBoxY);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
do
|
// Advance indexX otherwise
|
||||||
{
|
indexX += dirX;
|
||||||
auto yCoord = indexY * AdvanceY + Y;
|
|
||||||
auto xCoord = (bresIndexX * AdvanceX + X) * rayDyDX + bresXAdd;
|
|
||||||
if (xCoord <= yCoord)
|
|
||||||
{
|
|
||||||
if (xCoord == yCoord)
|
|
||||||
{
|
|
||||||
++indexX;
|
|
||||||
++bresIndexX;
|
|
||||||
}
|
|
||||||
--indexY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++indexX;
|
|
||||||
++bresIndexX;
|
|
||||||
}
|
|
||||||
edgeIndex = TestGridBox(indexX, indexY, &distance, edge, ray, ball, edgeIndex);
|
|
||||||
}
|
|
||||||
while (indexX < rayEndBoxX || indexY > rayEndBoxY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (rayDirY == 1)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
auto yCoord = bresIndexY * AdvanceY + Y;
|
|
||||||
auto xCoord = (indexX * AdvanceX + X) * rayDyDX + bresXAdd;
|
|
||||||
if (xCoord >= yCoord)
|
|
||||||
{
|
|
||||||
if (xCoord == yCoord)
|
|
||||||
--indexX;
|
|
||||||
++indexY;
|
|
||||||
++bresIndexY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
--indexX;
|
|
||||||
}
|
|
||||||
edgeIndex = TestGridBox(indexX, indexY, &distance, edge, ray, ball, edgeIndex);
|
|
||||||
}
|
|
||||||
while (indexX > rayEndBoxX || indexY < rayEndBoxY);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
auto yCoord = indexY * AdvanceY + Y;
|
|
||||||
auto xCoord = (indexX * AdvanceX + X) * rayDyDX + bresXAdd;
|
|
||||||
if (xCoord <= yCoord)
|
|
||||||
{
|
|
||||||
if (xCoord == yCoord)
|
|
||||||
--indexX;
|
|
||||||
--indexY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
--indexX;
|
|
||||||
}
|
|
||||||
edgeIndex = TestGridBox(indexX, indexY, &distance, edge, ray, ball, edgeIndex);
|
|
||||||
}
|
|
||||||
while (indexX > rayEndBoxX || indexY > rayEndBoxY);
|
|
||||||
}
|
}
|
||||||
|
edgeIndex = TestGridBox(indexX, indexY, &distance, edge, ray, ball, edgeIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,123 +79,45 @@ void TLine::place_in_grid()
|
||||||
{
|
{
|
||||||
if (dirY == 1)
|
if (dirY == 1)
|
||||||
{
|
{
|
||||||
if (yBox0 <= yBox1)
|
while (yBox0 <= yBox1)
|
||||||
{
|
edgeMan->add_edge_to_box(xBox0, yBox0++, this);
|
||||||
do
|
|
||||||
edgeMan->add_edge_to_box(xBox0, yBox0++, this);
|
|
||||||
while (yBox0 <= yBox1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (yBox0 >= yBox1)
|
else
|
||||||
{
|
{
|
||||||
do
|
while (yBox0 >= yBox1)
|
||||||
edgeMan->add_edge_to_box(xBox0, yBox0--, this);
|
edgeMan->add_edge_to_box(xBox0, yBox0--, this);
|
||||||
while (yBox0 >= yBox1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float yCoord, xCoord;
|
|
||||||
int indexX1 = xBox0, indexY1 = yBox0;
|
|
||||||
int bresIndexX = xBox0 + 1, bresIndexY = yBox0 + 1;
|
|
||||||
auto bresDyDx = (Y0 - Y1) / (X0 - X1);
|
|
||||||
auto bresXAdd = Y0 - bresDyDx * X0;
|
|
||||||
edgeMan->add_edge_to_box(xBox0, yBox0, this);
|
edgeMan->add_edge_to_box(xBox0, yBox0, this);
|
||||||
if (dirX == 1)
|
|
||||||
|
// 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;)
|
||||||
{
|
{
|
||||||
if (dirY == 1)
|
// Calculate y from indexY and from line formula
|
||||||
|
auto yDiscrete = (indexY + yBias) * edgeMan->AdvanceY + edgeMan->Y;
|
||||||
|
auto ylinear = ((indexX + xBias) * edgeMan->AdvanceX + edgeMan->X) * dyDx + precomp;
|
||||||
|
if (dirY == 1 ? ylinear >= yDiscrete : ylinear <= yDiscrete)
|
||||||
{
|
{
|
||||||
do
|
// Advance indexY when discrete value is ahead/behind
|
||||||
{
|
// Advance indexX when discrete value matches linear value
|
||||||
yCoord = bresIndexY * edgeMan->AdvanceY + edgeMan->Y;
|
indexY += dirY;
|
||||||
xCoord = (bresIndexX * edgeMan->AdvanceX + edgeMan->X) * bresDyDx + bresXAdd;
|
if (ylinear == yDiscrete)
|
||||||
if (xCoord >= yCoord)
|
indexX += dirX;
|
||||||
{
|
|
||||||
if (xCoord == yCoord)
|
|
||||||
{
|
|
||||||
++indexX1;
|
|
||||||
++bresIndexX;
|
|
||||||
}
|
|
||||||
++indexY1;
|
|
||||||
++bresIndexY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++indexX1;
|
|
||||||
++bresIndexX;
|
|
||||||
}
|
|
||||||
edgeMan->add_edge_to_box(indexX1, indexY1, this);
|
|
||||||
}
|
|
||||||
while (indexX1 != xBox1 || indexY1 != yBox1);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
do
|
// Advance indexX otherwise
|
||||||
{
|
indexX += dirX;
|
||||||
yCoord = indexY1 * edgeMan->AdvanceY + edgeMan->Y;
|
|
||||||
xCoord = (bresIndexX * edgeMan->AdvanceX + edgeMan->X) * bresDyDx + bresXAdd;
|
|
||||||
if (xCoord <= yCoord)
|
|
||||||
{
|
|
||||||
if (xCoord == yCoord)
|
|
||||||
{
|
|
||||||
++indexX1;
|
|
||||||
++bresIndexX;
|
|
||||||
}
|
|
||||||
--indexY1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++indexX1;
|
|
||||||
++bresIndexX;
|
|
||||||
}
|
|
||||||
edgeMan->add_edge_to_box(indexX1, indexY1, this);
|
|
||||||
}
|
|
||||||
while (indexX1 != xBox1 || indexY1 != yBox1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (dirY == 1)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
xCoord = bresIndexY * edgeMan->AdvanceY + edgeMan->Y;
|
|
||||||
yCoord = (indexX1 * edgeMan->AdvanceX + edgeMan->X) * bresDyDx + bresXAdd;
|
|
||||||
if (yCoord >= xCoord)
|
|
||||||
{
|
|
||||||
if (yCoord == xCoord)
|
|
||||||
--indexX1;
|
|
||||||
++indexY1;
|
|
||||||
++bresIndexY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
--indexX1;
|
|
||||||
}
|
|
||||||
edgeMan->add_edge_to_box(indexX1, indexY1, this);
|
|
||||||
}
|
|
||||||
while (indexX1 != xBox1 || indexY1 != yBox1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
yCoord = indexY1 * edgeMan->AdvanceY + edgeMan->Y;
|
|
||||||
xCoord = (indexX1 * edgeMan->AdvanceX + edgeMan->X) * bresDyDx + bresXAdd;
|
|
||||||
if (xCoord <= yCoord)
|
|
||||||
{
|
|
||||||
if (xCoord == yCoord)
|
|
||||||
--indexX1;
|
|
||||||
--indexY1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
--indexX1;
|
|
||||||
}
|
|
||||||
edgeMan->add_edge_to_box(indexX1, indexY1, this);
|
|
||||||
}
|
|
||||||
while (indexX1 != xBox1 || indexY1 != yBox1);
|
|
||||||
}
|
}
|
||||||
|
edgeMan->add_edge_to_box(indexX, indexY, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue