Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //CONSTANTS are from: https://github.com/ulfben/ArduboyRayCaster/blob/master/Config.h
- // tangent tables equivalent to slopes, used to compute initial intersections with ray
- std::array<float, ANGLE_360> tan_table;
- std::array<float, ANGLE_360> inv_tan_table;
- // step tables used to find next intersection, equivalent to slopes times width and height of cell
- std::array<float, ANGLE_360> y_step;
- std::array<float, ANGLE_360> x_step;
- // 1/cos and 1/sin tables used to compute distance of intersection very quickly
- // Optimization: cos(X) == sin(X+90), so for cos lookups we can simply re-use the sin-table with an offset of ANGLE_90.
- std::array<float, ANGLE_360 + ANGLE_90> inv_sin_table; //+90 degrees to make room for the tail-end of the offset cos values.
- float* inv_cos_table = &inv_sin_table[ANGLE_90]; //cos(X) == sin(X+90).
- // cos table used to fix view distortion caused by radial projection (eg: cancel out fishbowl effect)
- std::array<float, HALF_FOV_ANGLE * 2> cos_table;
- constexpr inline bool isFacingLeft(const int view_angle) const noexcept {
- return (view_angle >= ANGLE_90 && view_angle < ANGLE_270);
- }
- constexpr inline bool isFacingRight(const int view_angle) const noexcept {
- return (view_angle < ANGLE_90 || view_angle >= ANGLE_270);
- }
- constexpr inline bool isFacingDown(const int view_angle) const noexcept {
- return (view_angle >= ANGLE_0 && view_angle < ANGLE_180);
- }
- constexpr inline bool isFacingUp(const int view_angle) const noexcept {
- return (view_angle >= ANGLE_180 && view_angle < ANGLE_360);
- }
- void buildLookupTables() noexcept {
- constexpr auto TENTH_OF_A_RADIAN = ANGLE_TO_RADIANS * 0.1f;
- for (int ang = ANGLE_0; ang < ANGLE_360; ang++) {
- const auto rad_angle = TENTH_OF_A_RADIAN + (ang * ANGLE_TO_RADIANS); //adding a small offset to avoid edge cases with 0.
- tan_table[ang] = std::tan(rad_angle);
- inv_tan_table[ang] = 1.0f / tan_table[ang];
- inv_sin_table[ang] = 1.0f / std::sin(rad_angle);
- // tangent has the incorrect signs in all quadrants except 1, so manually fix the signs of each quadrant.
- if (isFacingDown(ang)) {
- y_step[ang] = std::abs(tan_table[ang] * CELL_SIZE);
- } else {
- assert(isFacingUp(ang) && "isFacingUp() should be the exact inverse of isFacingDown(). Have you changed the coordinate system?");
- y_step[ang] = -std::abs(tan_table[ang] * CELL_SIZE);
- }
- if (isFacingLeft(ang)) {
- x_step[ang] = -std::abs(inv_tan_table[ang] * CELL_SIZE);
- } else {
- assert(isFacingRight(ang) && "isFacingRight() should be the exact inverse of isFacingDown(). Have you changed the coordinate system?");
- x_step[ang] = std::abs(inv_tan_table[ang] * CELL_SIZE);
- }
- assert(std::fabs(y_step[ang]) != 0.0f && "Potential asymtotic ray on the y-axis produced while building lookup tables.");
- assert(std::fabs(x_step[ang]) != 0.0f && "Potential asymtotic ray on the x-axis produced while building lookup tables.");
- }
- //duplicate the first 90 sin values at the end of the array, to complete the joint sin & cos lookup table.
- auto end = std::end(inv_sin_table) - ANGLE_90;
- std::copy_n(std::begin(inv_sin_table), ANGLE_90, end);
- // create view filter table. Without this we would see a fishbowl effect. There is a cosine wave modulated on top of the view distance as a side effect of casting from a fixed point.
- // to cancel this effect out, we multiple by the inverse of the cosine and the result is the proper scale.
- // inverse cosine would be 1/cos(rad_angle), but 1 is too small to give us good sized slivers, hence the constant K which is arbitrarily chosen for what looks good.
- for (int ang = -HALF_FOV_ANGLE; ang < HALF_FOV_ANGLE; ang++) {
- const auto rad_angle = TENTH_OF_A_RADIAN + (ang * ANGLE_TO_RADIANS);
- const auto index = ang + HALF_FOV_ANGLE;
- cos_table[index] = (K / std::cos(rad_angle));
- }
- }
- template <class Container>
- [[nodiscard]] std::string join(const Container values, std::string delimiter = ","s){
- using T = typename Container::value_type;
- return std::accumulate(
- std::begin(values),
- std::end(values),
- std::string(),
- [delimiter](std::string a, T b) -> std::string {
- std::string delim(a.length() > 0 ? delimiter : ""s);
- return a + delim + std::to_string(b);
- });
- }
- template<typename T>
- void printTableDefinition(const char* name, const T table, const size_t size) const noexcept {
- //std::cout << "std::array<float, " << size << "> " << name << "{\n"; //PC
- std::cout << "constexpr float " << name << "[" << size << "] PROGMEM {\n"; //ArduBoy
- std::cout << "\t" << join(table, size, "f,");
- std::cout << "f};\n";
- }
- void prettyPrintLUTs() noexcept {
- printTableDefinition("tan_table", tan_table, tan_table.size());
- printTableDefinition("y_step", y_step, y_step.size());
- printTableDefinition("x_step", x_step, x_step.size());
- printTableDefinition("inv_sin_table", inv_sin_table, inv_sin_table.size());
- printTableDefinition("inv_tan_table", inv_tan_table, inv_tan_table.size());
- printTableDefinition("cos_table", cos_table, cos_table.size());
- std::cout << "const float* inv_cos_table = &inv_sin_table[" << ANGLE_90 << "];\n";
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement