osb/source/game/StarCollisionGenerator.cpp
Kai Blaschke 431a9c00a5
Fixed a huge amount of Clang warnings
On Linux and macOS, using Clang to compile OpenStarbound produces about 400 MB worth of warnings during the build, making the compiler output unreadable and slowing the build down considerably.

99% of the warnings were unqualified uses of std::move and std::forward, which are now all properly qualified.

Fixed a few other minor warnings about non-virtual destructors and some uses of std::move preventing copy elision on temporary objects.

Most remaining warnings are now unused parameters.
2024-02-19 16:55:19 +01:00

234 lines
7.7 KiB
C++

#include "StarCollisionGenerator.hpp"
namespace Star {
void CollisionGenerator::init(CollisionKindAccessor accessor) {
m_accessor = accessor;
}
List<CollisionBlock> CollisionGenerator::getBlocks(RectI const& region) const {
if (region.isNull())
return {};
List<CollisionBlock> list;
populateCollisionBuffer(region);
getBlocksMarchingSquares(list, region, CollisionKind::Dynamic);
getBlocksPlatforms(list, region, CollisionKind::Platform);
return list;
}
void CollisionGenerator::getBlocksPlatforms(List<CollisionBlock>& list, RectI const& region, CollisionKind kind) const {
int xMin = region.xMin();
int xMax = region.xMax();
int yMin = region.yMin();
int yMax = region.yMax();
for (int x = xMin; x < xMax; ++x) {
for (int y = yMin; y < yMax; ++y) {
if (collisionKind(x, y) == kind) {
auto addBlock = [&](PolyF::VertexList vertices) {
CollisionBlock block;
block.space = Vec2I(x, y);
block.kind = kind;
block.poly = PolyF(std::move(vertices));
block.polyBounds = block.poly.boundBox();
list.append(std::move(block));
};
// This was once simple and elegant and made sense but then I made it
// match the actual platform rendering more closely and now it's a big
// shitty pile of special cases again. RIP.
bool right = collisionKind(x + 1, y) == kind;
bool left = collisionKind(x - 1, y) == kind;
bool downRight = collisionKind(x + 1, y - 1) == kind && collisionKind(x + 1, y) != kind;
bool downLeft = collisionKind(x - 1, y - 1) == kind && collisionKind(x - 1, y) != kind;
bool upRight = collisionKind(x + 1, y + 1) == kind && !left && !right;
bool upLeft = collisionKind(x - 1, y + 1) == kind && !left && !right;
bool above = collisionKind(x, y + 1) == kind;
bool below = collisionKind(x, y - 1) == kind;
if (downRight && downLeft && upRight && upLeft) {
addBlock({Vec2F(x, y), Vec2F(x + 1, y + 1)});
addBlock({Vec2F(x + 1, y), Vec2F(x, y + 1)});
} else if (above && below) {
addBlock({Vec2F(x, y + 1), Vec2F(x + 1, y + 1)});
} else if (upLeft && downLeft && !upRight && !downRight) {
addBlock({Vec2F(x + 1, y), Vec2F(x, y + 1)});
} else if (upRight && downRight && !upLeft && !upRight) {
addBlock({Vec2F(x, y), Vec2F(x + 1, y + 1)});
} else if (upRight && downLeft) {
addBlock({Vec2F(x, y), Vec2F(x + 1, y + 1)});
// special case block for connecting flat platform above
if (above && collisionKind(x + 1, y + 1) == kind)
addBlock({Vec2F(x + 1, y + 1), Vec2F(x + 2, y + 2)});
} else if (upLeft && downRight) {
addBlock({Vec2F(x + 1, y), Vec2F(x, y + 1)});
// special case block for connecting flat platform above
if (above && collisionKind(x - 1, y + 1) == kind)
addBlock({Vec2F(x, y + 1), Vec2F(x - 1, y + 2)});
} else if (above && !downRight && !downLeft) {
addBlock({Vec2F(x, y + 1), Vec2F(x + 1, y + 1)});
} else if (upLeft && !upRight) {
addBlock({Vec2F(x + 1, y), Vec2F(x, y + 1)});
} else if (upRight && !upLeft) {
addBlock({Vec2F(x, y), Vec2F(x + 1, y + 1)});
} else if (downRight && (left || !below)) {
addBlock({Vec2F(x + 1, y), Vec2F(x, y + 1)});
} else if (downLeft && (right || !below)) {
addBlock({Vec2F(x, y), Vec2F(x + 1, y + 1)});
} else {
addBlock({Vec2F(x, y + 1), Vec2F(x + 1, y + 1)});
}
}
}
}
}
void CollisionGenerator::getBlocksMarchingSquares(List<CollisionBlock>& list, RectI const& region, CollisionKind kind) const {
// uses binary masking to assign each group of 4 tiles a value between 0 and 15
// with corners ul = 1, ur = 2, lr = 4, ll = 8
// points spaced at 0.5 around the edge of a 1x1 square, clockwise from bottom left,
// plus the center point for special cases
static Vec2F const msv[9] = {
Vec2F(0.5, 0.5),
Vec2F(0.5, 1.0),
Vec2F(0.5, 1.5),
Vec2F(1.0, 1.5),
Vec2F(1.5, 1.5),
Vec2F(1.5, 1.0),
Vec2F(1.5, 0.5),
Vec2F(1.0, 0.5),
Vec2F(1.0, 1.0)
};
// refers to vertex offset indices in msv, with 8 being no vertex
static unsigned const msp[22][6] = {
{9, 9, 9, 9, 9, 9},
{1, 2, 3, 9, 9, 9},
{3, 4, 5, 9, 9, 9},
{1, 2, 4, 5, 9, 9},
{7, 5, 6, 9, 9, 9},
{1, 2, 3, 5, 6, 7},
{7, 3, 4, 6, 9, 9},
{1, 2, 4, 6, 7, 9},
{0, 1, 7, 9, 9, 9},
{0, 2, 3, 7, 9, 9},
{0, 1, 3, 4, 5, 7},
{0, 2, 4, 5, 7, 9},
{0, 1, 5, 6, 9, 9},
{0, 2, 3, 5, 6, 9},
{0, 1, 3, 4, 6, 9},
{0, 2, 4, 6, 9, 9},
// special cases for squared off top corners
{5, 6, 7, 8, 9, 9}, // top left corner
{0, 1, 8, 7, 9, 9}, // top right corner
// special cases for hollowed out bottom corners
{0, 2, 3, 8, 9, 9}, // lower left corner part 1
{0, 8, 5, 6, 9, 9}, // lower left corner part 2
{0, 1, 8, 6, 9, 9}, // lower right corner part 1
{6, 8, 3, 4, 9, 9} // lower right corner part 2
};
auto addBlock = [&](int x, int y, uint8_t svi) {
CollisionBlock block;
block.space = Vec2I(x, y);
block.poly.clear();
for (auto i : msp[svi]) {
if (i == 9)
break;
block.poly.add(Vec2F(x, y) + msv[i]);
}
block.polyBounds = block.poly.boundBox();
block.kind = std::max({collisionKind(x, y), collisionKind(x + 1, y), collisionKind(x, y + 1), collisionKind(x + 1, y + 1)});
list.append(std::move(block));
};
int xMin = region.xMin();
int xMax = region.xMax();
int yMin = region.yMin();
int yMax = region.yMax();
for (int x = xMin; x < xMax; ++x) {
for (int y = yMin; y < yMax; ++y) {
uint8_t neighborMask = 0;
if (collisionKind(x, y + 1) >= kind)
neighborMask |= 1;
if (collisionKind(x + 1, y + 1) >= kind)
neighborMask |= 2;
if (collisionKind(x + 1, y) >= kind)
neighborMask |= 4;
if (collisionKind(x, y) >= kind)
neighborMask |= 8;
if (neighborMask == 4) {
if (collisionKind(x + 2, y) >= kind &&
collisionKind(x + 2, y + 1) < kind &&
collisionKind(x, y - 1) < kind) {
addBlock(x, y, 16);
continue;
}
} else if (neighborMask == 8) {
if (collisionKind(x - 1, y) >= kind &&
collisionKind(x - 1, y + 1) < kind &&
collisionKind(x + 1, y - 1) < kind) {
addBlock(x, y, 17);
continue;
}
} else if (neighborMask == 13) {
if (collisionKind(x, y + 2) >= kind &&
collisionKind(x + 1, y + 2) < kind &&
collisionKind(x + 2, y) >= kind) {
addBlock(x, y, 18);
addBlock(x, y, 19);
continue;
}
} else if (neighborMask == 14) {
if (collisionKind(x, y + 2) < kind &&
collisionKind(x + 1, y + 2) >= kind &&
collisionKind(x - 1, y) >= kind) {
addBlock(x, y, 20);
addBlock(x, y, 21);
continue;
}
}
if (neighborMask != 0)
addBlock(x, y, neighborMask);
}
}
}
void CollisionGenerator::populateCollisionBuffer(RectI const& region) const {
int xmin = region.xMin() - BlockInfluenceRadius;
int ymin = region.yMin() - BlockInfluenceRadius;
int xmax = region.xMax() + BlockInfluenceRadius;
int ymax = region.yMax() + BlockInfluenceRadius;
m_collisionBufferCorner = {xmin, ymin};
m_collisionBuffer.resize(xmax - xmin, ymax - ymin);
for (int x = xmin; x < xmax; ++x)
for (int y = ymin; y < ymax; ++y)
m_collisionBuffer(x - xmin, y - ymin) = m_accessor(x, y);
}
CollisionKind CollisionGenerator::collisionKind(int x, int y) const {
return m_collisionBuffer(x - m_collisionBufferCorner[0], y - m_collisionBufferCorner[1]);
}
}