Browse Source

renderer works

devel
Ludovic 'Archivist' Lagouardette 4 years ago
parent
commit
11c5760110
5 changed files with 358 additions and 11 deletions
  1. +1
    -0
      .gitignore
  2. +104
    -0
      include/gp/math.hpp
  3. +138
    -0
      include/gp/rendering/bmp_viewport.hpp
  4. +34
    -11
      include/gp/rendering/renderer.hpp
  5. +81
    -0
      tests/math.cpp

+ 1
- 0
.gitignore View File

@ -37,3 +37,4 @@ default.profraw
bin/tests.profdata
bin/tests.profraw
bin/test_n
render.bmp

+ 104
- 0
include/gp/math.hpp View File

@ -5,13 +5,68 @@
#if !defined(NO_FP_MATH)
# include "gp/math/fp_math.hpp"
#endif
#include "gp/algorithm/repeat.hpp"
namespace gp {
template<typename T, size_t fixed_passes = 16>
T fixed_sqrt(T value) {
if(value == 0) return 0;
T ret = value / 2;
T tmp;
gp::repeat(fixed_passes, [&](){
tmp = ret;
ret = (value / tmp + tmp) / 2;
});
return ret;
}
template<typename T, size_t cap_passes = 16>
T epsilon_sqrt(T value) {
if(value == 0) return 0;
T ret = value / 2;
T tmp;
constexpr T epsilon = gp_config::rendering::epsilon;
size_t cnt = 0;
while(
!(
(ret+epsilon)*ret > value
&& (ret-epsilon)*ret < value
)
&& cnt < cap_passes
){
tmp = ret;
ret = (value / tmp + tmp) / 2;
++cnt;
};
return ret;
}
template<typename T, size_t cap_passes = 16>
T stable_sqrt(T value) {
if(value == 0) return 0;
T ret = value / 2;
T tmp;
while(ret != tmp){
tmp = ret;
ret = (value / tmp + tmp) / 2;
};
return ret;
}
template<typename T = gp_config::rendering::default_type>
struct vec2_g {
T x;
T y;
vec2_g()
: x{}
, y{}
{}
vec2_g(
T _x,
T _y
@ -27,10 +82,21 @@ namespace gp {
};
}
vec2_g operator*(vec2_g rhs) {
return {
x * rhs.x,
y * rhs.y
};
}
vec2_g operator+(vec2_g oth) {
return {x+oth.x, y+oth.y};
}
vec2_g operator-(vec2_g oth) {
return {x-oth.x, y-oth.y};
}
vec2_g normalize() {
T ilen = fast_isqrt(x*x+y*y);
return {x*ilen, y*ilen};
@ -43,6 +109,12 @@ namespace gp {
T y;
T z;
vec3_g()
: x{}
, y{}
, z{}
{}
vec3_g(
T _x,
T _y,
@ -73,10 +145,22 @@ namespace gp {
};
}
vec3_g operator*(vec3_g rhs) {
return {
x * rhs.x,
y * rhs.y,
z * rhs.z
};
}
vec3_g operator+(vec3_g oth) {
return {x+oth.x, y+oth.y, z+oth.z};
}
vec3_g operator-(vec3_g oth) {
return {x-oth.x, y-oth.y, z-oth.z};
}
vec3_g normalize() {
T ilen = fast_isqrt(x*x+y*y+z*z);
return {x*ilen, y*ilen, z*ilen};
@ -90,6 +174,13 @@ namespace gp {
T z;
T w;
vec4_g()
: x{}
, y{}
, z{}
, w{}
{}
vec4_g(
T _x,
T _y,
@ -125,10 +216,23 @@ namespace gp {
};
}
vec4_g operator*(vec4_g rhs) {
return {
x * rhs.x,
y * rhs.y,
z * rhs.z,
w * rhs.w
};
}
vec4_g operator+(vec4_g oth) {
return {x+oth.x, y+oth.y, z+oth.z, w+oth.w};
}
vec4_g operator-(vec4_g oth) {
return {x-oth.x, y-oth.y, z-oth.w, z-oth.w};
}
vec4_g normalize() {
T ilen = fast_isqrt(x*x+y*y+z*z+w*w);
return {x*ilen, y*ilen, z*ilen, w*ilen};

+ 138
- 0
include/gp/rendering/bmp_viewport.hpp View File

@ -0,0 +1,138 @@
#pragma once
#include "gp/function.hpp"
#include "gp/buffer.hpp"
#include "gp/math.hpp"
#include "gp/bitops.hpp"
#include "gp/algorithm/tmp_manip.hpp"
#include <iostream>
namespace gp{
template<bool lazy, typename color_type>
class bmp_viewport {
using src_t = typename gp::either<lazy,
gp::function<color_type(gp::vec2_g<int32_t>)>,
gp::buffer<gp::buffer<color_type>>
>::type;
src_t source;
gp::vec2_g<int32_t> resolution;
color_type get(int32_t x, int32_t y) {
gp_config::assertion(x>=0, "getting an x below zero");
gp_config::assertion(y>=0, "getting an y below zero");
if constexpr (lazy) {
return source({x, y});
} else {
return source[x][y];
}
}
public:
bmp_viewport(gp::vec2_g<int32_t> res, src_t src)
: source{src}
, resolution{res}
{}
gp::buffer<char>::associated_iterator write(gp::buffer<char> destination) {
using sle16 = /*gp::endian_wrapper<*/int16_t/*, gp::endian::little>*/;
using sbe16 = /*gp::endian_wrapper<*/int16_t/*, gp::endian::big>*/;
using sle32 = /*gp::endian_wrapper<*/int32_t/*, gp::endian::little>*/;
using sbe32 = /*gp::endian_wrapper<*/int32_t/*, gp::endian::big>*/;
auto it = destination.begin();
*(it++) = 'B';
*(it++) = 'M';
auto& filesize = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
it = it+4;
*(it++) = 0;
*(it++) = 0;
*(it++) = 0;
*(it++) = 0;
auto& pixel_array_offset = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
it = it+4;
auto dib_start = it;
auto& dibsize = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
it = it+4;
auto& width = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
width = resolution.x;
it = it+4;
auto& height = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
it = it+4;
height = resolution.y;
auto& plane_cnt = gp::buffer<char>{it.data, (it+2).data}.cast<sle16>()[0];
it = it+2;
plane_cnt = 1;
auto& bit_per_pixel = gp::buffer<char>{it.data, (it+2).data}.cast<sle16>()[0];
it = it+2;
bit_per_pixel = sizeof(color_type)*8; // TODO: correct the size
auto& compression_method = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
it = it+4;
compression_method = 0;
auto& image_size = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
it = it+4;
auto& h_pixel_per_meter = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
it = it+4;
h_pixel_per_meter = 2835;
auto& v_pixel_per_meter = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
it = it+4;
v_pixel_per_meter = 2835;
auto& colors_in_palette = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
it = it+4;
colors_in_palette = 0;
auto& important_colors = gp::buffer<char>{it.data, (it+4).data}.cast<sle32>()[0];
it = it+4;
important_colors = 0;
auto dib_end = it;
dibsize = dib_end - dib_start;
auto pixel_array_start = it;
for(int32_t line = resolution.y - 1; line >= 0; line--)
{
int32_t len = 0;
for(int32_t row = 0; row < resolution.x; row++)
{
// TODO: add more default color modes
if constexpr (std::is_same<color_type, gp::vec4_g<uint8_t>>::value)
{
auto color = get(row, line);
*(it++) = color.x;
*(it++) = color.y;
*(it++) = color.z;
*(it++) = color.w;
} else {
it = it + sizeof(color_type);
}
len+=sizeof(color_type);
}
for(;len % 4; ++len)
{
*(it++) = 0;
}
}
auto pixel_array_end = it;
pixel_array_offset = pixel_array_start - destination.begin();
filesize = pixel_array_end - destination.begin();
image_size = pixel_array_end - pixel_array_start;
std::cout << width << std::endl;
std::cout << height << std::endl;
std::cout << filesize << std::endl;
std::cout << image_size << std::endl;
return it;
}
};
}

+ 34
- 11
include/gp/rendering/renderer.hpp View File

@ -46,20 +46,41 @@ public:
renderer() = default;
render_point sdf(vec3 render_target) {
return gp::min_of(
scene_elements.begin(),
scene_elements.end(),
[&](auto& p){
return p(render_target);
}
);
}
color_t render(vec2 pixel) {
g_t depth = projection_start;
vec3 target{0,0,0};
target = target.normalize();
vec3 target = _camera.normal;
auto half_res = _resolution/vec2{2.0, 2.0};
pixel = pixel - half_res;
pixel = pixel / half_res;
pixel = pixel * _fov;
pixel = pixel / vec2{180, 180} * vec2{gp::pi<g_t>,gp::pi<g_t>};
// Y-rot (adjusts x)
target = vec3{
target.x*gp::cos(pixel.x) + target.z*gp::sin(pixel.x),
target.y,
-target.x*gp::sin(pixel.x)+target.z*gp::cos(pixel.x)
};
// X-rot (adjusts y)
target = vec3{
target.x,
target.y*gp::cos(pixel.y) - target.z*gp::sin(pixel.y),
target.y*gp::sin(pixel.y) + target.z*gp::cos(pixel.y)
};
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);
}
);
for(int i = 1; i < passes; ++i) {
render_point distance = sdf(render_target);
if(distance.distance < epsilon) {
return materials[distance.material](render_target);
@ -70,6 +91,8 @@ public:
if(depth >= projection_end) {
break;
}
render_target = _camera.position+depth*target;
}
return sky_box(render_target);
}

+ 81
- 0
tests/math.cpp View File

@ -1,7 +1,13 @@
#include "test_scaffold.h"
#include "gp/array.hpp"
#include "gp/math.hpp"
#include "gp/rendering/renderer.hpp"
#include "gp/rendering/bmp_viewport.hpp"
#include <cmath>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <chrono>
struct sin_test : public test_scaffold {
@ -39,6 +45,81 @@ struct render_test : public test_scaffold {
virtual int run() {
int res = 0;
renderer a;
a._resolution = vec2{1000,500};
a.sky_box = [](vec3) -> color_t {return {0,0,0,0};};
auto v = a.materials.push(
[&](vec3 p) -> color_t {
//return color_t{0,0,1,1};
const float EPSILON = 0.001;
/*vec3(
a.sdf(vec3(p.x + EPSILON, p.y, p.z)).distance - a.sdf(vec3(p.x - EPSILON, p.y, p.z)).distance,
a.sdf(vec3(p.x, p.y + EPSILON, p.z)).distance - a.sdf(vec3(p.x, p.y - EPSILON, p.z)).distance,
a.sdf(vec3(p.x, p.y, p.z + EPSILON)).distance - a.sdf(vec3(p.x, p.y, p.z - EPSILON)).distance
)*/
auto normals = p.normalize();
auto light = vec3(1,1,1).normalize();
auto tmp = light*p;
auto color = tmp.x+tmp.y+tmp.z;
return vec4(vec3(color, color, color), 1.0);
//return {v.normalize(), 1.0};
}
);
auto sphere = a.scene_elements.push(
[=](vec3 pos) -> render_point {
render_point ret;
ret.distance = gp::fixed_sqrt<float, 6>(pos.x*pos.x + pos.y*pos.y + pos.z*pos.z) - 1.0;
ret.material = v;
return ret;
}
);
a._camera.position = vec3{0, 0, -2};
a._camera.normal = vec3{0, 0, 1};
using pic_color = gp::vec4_g<uint8_t>;
gp::bmp_viewport<true, pic_color> vp{
{1000,500},
[&](gp::vec2_g<int32_t> p) -> pic_color {
auto orig = a.render({(float)p.x,(float)p.y});
pic_color ret{};
ret.x = (uint8_t)(orig.x*255);
ret.y = (uint8_t)(orig.y*255);
ret.z = (uint8_t)(orig.z*255);
ret.w = (uint8_t)(orig.w*255);
return ret;
}
};
gp::array<char, 400000000>* buff = new gp::array<char, 400000000>();
auto begin = std::chrono::steady_clock::now();
auto r_end = vp.write(buff->as_buffer());
auto end = std::chrono::steady_clock::now();
std::cout << "render time: " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << std::endl;
auto myfile = std::fstream("render.bmp", std::ios::out | std::ios::binary);
myfile.write(buff->begin().data, r_end - buff->begin());
myfile.close();
delete buff;
//gp_config::assertion(a.render(vec2{64,32}).x == color_t{1.0,0,0,1.0}.x, "red sphere not perceived");
//gp_config::assertion(a.render(vec2{0,0}).x == color_t{0.0,0,1.0,1.0}.x, "blue sky not perceived");
return res;
}

Loading…
Cancel
Save