ulfben

ArduboyLUTs (float)

Mar 8th, 2020
96
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //CONSTANTS are from: https://github.com/ulfben/ArduboyRayCaster/blob/master/Config.h
  2.  
  3. // tangent tables equivalent to slopes, used to compute initial intersections with ray
  4. std::array<float, ANGLE_360> tan_table;
  5. std::array<float, ANGLE_360> inv_tan_table;
  6.  
  7. // step tables used to find next intersection, equivalent to slopes times width and height of cell    
  8. std::array<float, ANGLE_360> y_step;
  9. std::array<float, ANGLE_360> x_step;
  10.  
  11. // 1/cos and 1/sin tables used to compute distance of intersection very quickly  
  12. // Optimization: cos(X) == sin(X+90), so for cos lookups we can simply re-use the sin-table with an offset of ANGLE_90.    
  13. std::array<float, ANGLE_360 + ANGLE_90> inv_sin_table; //+90 degrees to make room for the tail-end of the offset cos values.    
  14. float* inv_cos_table = &inv_sin_table[ANGLE_90]; //cos(X) == sin(X+90).    
  15.  
  16. // cos table used to fix view distortion caused by radial projection (eg: cancel out fishbowl effect)
  17. std::array<float, HALF_FOV_ANGLE * 2> cos_table;
  18.    
  19. constexpr inline bool isFacingLeft(const int view_angle) const noexcept {
  20.     return (view_angle >= ANGLE_90 && view_angle < ANGLE_270);
  21. }
  22. constexpr inline bool isFacingRight(const int view_angle) const noexcept {
  23.     return (view_angle < ANGLE_90 || view_angle >= ANGLE_270);
  24. }
  25. constexpr inline bool isFacingDown(const int view_angle) const noexcept {
  26.     return (view_angle >= ANGLE_0 && view_angle < ANGLE_180);
  27. }
  28. constexpr inline bool isFacingUp(const int view_angle) const noexcept {
  29.     return (view_angle >= ANGLE_180 && view_angle < ANGLE_360);
  30. }
  31.  
  32. void buildLookupTables() noexcept {
  33.     constexpr auto TENTH_OF_A_RADIAN = ANGLE_TO_RADIANS * 0.1f;      
  34.     for (int ang = ANGLE_0; ang < ANGLE_360; ang++) {
  35.         const auto rad_angle = TENTH_OF_A_RADIAN + (ang * ANGLE_TO_RADIANS); //adding a small offset to avoid edge cases with 0.
  36.         tan_table[ang] = std::tan(rad_angle);
  37.         inv_tan_table[ang] = 1.0f / tan_table[ang];
  38.         inv_sin_table[ang] = 1.0f / std::sin(rad_angle);
  39.  
  40.         // tangent has the incorrect signs in all quadrants except 1, so manually fix the signs of each quadrant.
  41.         if (isFacingDown(ang)) {
  42.             y_step[ang] = std::abs(tan_table[ang] * CELL_SIZE);
  43.         } else {
  44.             assert(isFacingUp(ang) && "isFacingUp() should be the exact inverse of isFacingDown(). Have you changed the coordinate system?");
  45.             y_step[ang] = -std::abs(tan_table[ang] * CELL_SIZE);
  46.         }
  47.         if (isFacingLeft(ang)) {
  48.             x_step[ang] = -std::abs(inv_tan_table[ang] * CELL_SIZE);
  49.         } else {
  50.             assert(isFacingRight(ang) && "isFacingRight() should be the exact inverse of isFacingDown(). Have you changed the coordinate system?");
  51.             x_step[ang] = std::abs(inv_tan_table[ang] * CELL_SIZE);
  52.         }
  53.         assert(std::fabs(y_step[ang]) != 0.0f && "Potential asymtotic ray on the y-axis produced while building lookup tables.");
  54.         assert(std::fabs(x_step[ang]) != 0.0f && "Potential asymtotic ray on the x-axis produced while building lookup tables.");            
  55.     }
  56.  
  57.     //duplicate the first 90 sin values at the end of the array, to complete the joint sin & cos lookup table.
  58.     auto end = std::end(inv_sin_table) - ANGLE_90;
  59.     std::copy_n(std::begin(inv_sin_table), ANGLE_90, end);
  60.  
  61.     // 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.
  62.     // to cancel this effect out, we multiple by the inverse of the cosine and the result is the proper scale.
  63.     // 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.
  64.     for (int ang = -HALF_FOV_ANGLE; ang < HALF_FOV_ANGLE; ang++) {
  65.         const auto rad_angle = TENTH_OF_A_RADIAN + (ang * ANGLE_TO_RADIANS);
  66.         const auto index = ang + HALF_FOV_ANGLE;
  67.         cos_table[index] = (K / std::cos(rad_angle));
  68.     }
  69. }
  70.  
  71. template <class Container>
  72. [[nodiscard]] std::string join(const Container values, std::string delimiter = ","s){
  73.     using T = typename Container::value_type;    
  74.     return std::accumulate(
  75.         std::begin(values),  
  76.         std::end(values),
  77.         std::string(),
  78.         [delimiter](std::string a, T b) -> std::string {
  79.             std::string delim(a.length() > 0 ? delimiter : ""s);
  80.             return a + delim + std::to_string(b);
  81.     });
  82. }
  83.  
  84. template<typename T>
  85. void printTableDefinition(const char* name, const T table, const size_t size) const noexcept {        
  86.     //std::cout << "std::array<float, " << size << "> " << name << "{\n"; //PC
  87.     std::cout << "constexpr float " << name << "[" << size << "] PROGMEM {\n"; //ArduBoy
  88.     std::cout << "\t" << join(table, size, "f,");
  89.     std::cout << "f};\n";
  90. }
  91.  
  92. void prettyPrintLUTs() noexcept {
  93.     printTableDefinition("tan_table", tan_table, tan_table.size());
  94.     printTableDefinition("y_step", y_step, y_step.size());
  95.     printTableDefinition("x_step", x_step, x_step.size());
  96.     printTableDefinition("inv_sin_table", inv_sin_table, inv_sin_table.size());
  97.     printTableDefinition("inv_tan_table", inv_tan_table, inv_tan_table.size());
  98.     printTableDefinition("cos_table", cos_table, cos_table.size());
  99.     std::cout << "const float* inv_cos_table = &inv_sin_table[" << ANGLE_90 << "];\n";      
  100. }
RAW Paste Data