#pragma once #include "gp_config.hpp" #include "gp/math.hpp" #include "gp/function.hpp" #include "gp/algorithm/min_of.hpp" #include "gp/indexed_array.hpp" using vec2 = gp::vec2_g<>; using vec3 = gp::vec3_g<>; using vec4 = gp::vec4_g<>; struct camera{ vec3 position; vec3 normal; }; using index_t = size_t; using distance_t = gp_config::rendering::default_type; using color_t = GP_CONFIG__RENDERING__COLOR_T; struct render_point{ distance_t distance; index_t material; bool operator<(const render_point& rhs) { return distance < rhs.distance; } }; using sdf_t = gp::function; using material_t = gp::function; class renderer { using g_t = gp_config::rendering::default_type; constexpr static auto epsilon = gp_config::rendering::epsilon; public: gp::indexed_array scene_elements; gp::indexed_array materials; material_t sky_box = [](vec3) -> color_t { return vec4{0,0,0,0};}; vec2 _resolution{128,64}; camera _camera{{0, 0, -1}, {0, 0, 0}}; vec2 _fov{90, 45}; distance_t projection_start = 1; distance_t projection_end = 50; size_t passes = 12; renderer() = default; color_t render(vec2 pixel) { g_t depth = projection_start; vec3 target{0,0,0}; target = target.normalize(); vec3 render_target{_camera.position}; for(int i = 0; i < passes; ++i) { render_target = _camera.position+depth*target; render_point distance = gp::min_of( scene_elements.begin(), scene_elements.end(), [&](auto& p){ return p(render_target); } ); if(distance.distance < epsilon) { return materials[distance.material](render_target); } depth += distance.distance; if(depth >= projection_end) { break; } } return sky_box(render_target); } };