ulfben icon

ArduboyLUTs (float)

ulfben | PRO | 03/08/20 06:54:45 PM UTC | 0 ⭐ | 1037 👁️ | Never ⏰ | []
C++ |

5.08 KB

|

None

|

0 👍

/

0 👎

//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";      
}

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  • Yuizcko icon
    05/18/26 01:01:26 PM UTC
    text |

    0 B

    |

    0 👍

    /

    0 👎

    Best t33n active cpx link daily updates!
     Copy and paste the link in a new browser tab and then hit enter!
     https://crazyporn.xxx/members/157354/?asgtbndr=1&play=true&spon=adworld&zone=400