ArduboyLUTs (float)

Mar 8th, 2020
483
0
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 {
34.     for (int ang = ANGLE_0; ang < ANGLE_360; ang++) {
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++) {
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. }