General Purpose library for Freestanding C++ and POSIX systems
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 line
3.2 KiB

  1. #pragma once
  2. #include "gp_config.hpp"
  3. #include "gp/algorithms/min_of.hpp"
  4. #include "gp/utils/allocators/buddy.hpp"
  5. #include "gp/functional/function.hpp"
  6. #include "gp/containers/indexed_array.hpp"
  7. #include "gp/math.hpp"
  8. #include "gp/math/rendering_math.hpp"
  9. // TODO: Namespace this correctly
  10. // BUG: The rendering behaves improperly, I don't know why
  11. namespace gp {
  12. namespace math {
  13. namespace rendering {
  14. using vec2 = gp::math::vec2_g<>;
  15. using vec3 = gp::math::vec3_g<>;
  16. using vec4 = gp::math::vec4_g<>;
  17. struct camera{
  18. vec3 position;
  19. vec3 normal;
  20. };
  21. using index_t = size_t;
  22. using distance_t = gp_config::rendering::default_type;
  23. using color_t = GP_CONFIG__RENDERING__COLOR_T;
  24. struct render_point{
  25. distance_t distance;
  26. index_t material;
  27. bool operator<(const render_point& rhs) {
  28. return distance < rhs.distance;
  29. }
  30. };
  31. using sdf_t = gp::function<render_point(vec3&)>;
  32. using material_t = gp::function<color_t(vec3&)>;
  33. /**
  34. * @brief A pure ray-marching renderer. Prints pixels on order.
  35. */
  36. class renderer {
  37. using g_t = gp_config::rendering::default_type;
  38. constexpr static auto epsilon = gp_config::rendering::epsilon;
  39. public:
  40. gp::indexed_array<sdf_t, 4096> scene_elements;
  41. gp::indexed_array<material_t, 4096> materials;
  42. gp::buddy<> allocator;
  43. material_t sky_box;
  44. vec2 _resolution{128,64};
  45. camera _camera{{0, 0, -5}, {0, 0, 0}};
  46. vec2 _fov{90, 45};
  47. distance_t projection_start = 1;
  48. distance_t projection_end = 50;
  49. size_t passes = 12;
  50. renderer(gp::buffer<char> allocation_buffer)
  51. : allocator(allocation_buffer.begin().data, allocation_buffer.size())
  52. , sky_box{gp::reference_wrapper<gp::buddy<>>{allocator}}
  53. {}
  54. render_point sdf(vec3& render_target) {
  55. return gp::min_of(
  56. scene_elements.begin(),
  57. scene_elements.end(),
  58. [&](auto& p){
  59. return p(render_target);
  60. }
  61. );
  62. }
  63. auto& get_allocator() {
  64. return allocator;
  65. }
  66. color_t render(vec2 pixel) {
  67. g_t depth = projection_start;
  68. vec3 target = _camera.normal;
  69. auto half_res = _resolution/vec2{2.0, 2.0};
  70. pixel = pixel - half_res;
  71. pixel = pixel / half_res;
  72. pixel = pixel * _fov;
  73. pixel = pixel / vec2{180, 180} * vec2{gp::math::pi<g_t>,gp::math::pi<g_t>};
  74. // Y-rot (adjusts x)
  75. target = vec3{
  76. target.x*gp::math::cos(pixel.x) + target.z*gp::math::sin(pixel.x),
  77. target.y,
  78. -target.x*gp::math::sin(pixel.x)+target.z*gp::math::cos(pixel.x)
  79. };
  80. // X-rot (adjusts y)
  81. target = vec3{
  82. target.x,
  83. target.y*gp::math::cos(pixel.y) - target.z*gp::math::sin(pixel.y),
  84. target.y*gp::math::sin(pixel.y) + target.z*gp::math::cos(pixel.y)
  85. };
  86. vec3 render_target{_camera.position};
  87. for(int i = 0; i < passes; ++i) {
  88. render_point distance = sdf(render_target);
  89. if(distance.distance < epsilon) {
  90. return materials[distance.material](render_target);
  91. }
  92. depth += distance.distance;
  93. if(depth >= projection_end) {
  94. break;
  95. }
  96. render_target = _camera.position+depth*target;
  97. }
  98. return sky_box(render_target);
  99. }
  100. };
  101. }
  102. }
  103. }