aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvimene <vincent.menegaux@gmail.com>2023-12-05 10:42:35 +0100
committervimene <vincent.menegaux@gmail.com>2023-12-05 10:42:35 +0100
commit9b70ca7b3a1b7bfd3bf434d8b84bde42f5572ca0 (patch)
tree7078a70f7fc5b590c61386f55f4fbcc67e36b0f3
parent48ec7df0fd27fab05c9918e83a3a7da1cc32d7a0 (diff)
downloadengine-9b70ca7b3a1b7bfd3bf434d8b84bde42f5572ca0.tar.gz
added renderer, improved various things
- Added renderer to unify frame buffers - Added FrameBuffer class as a parent for frame buffers' classes - Improved formatting in Makefile.am - Added const modifier in Matrix4's methods
-rw-r--r--Makefile.am23
-rw-r--r--src/engine.cpp36
-rw-r--r--src/fb/chfb.cpp119
-rw-r--r--src/fb/chfb.h12
-rw-r--r--src/fb/fb.h20
-rw-r--r--src/fb/pixfb.cpp116
-rw-r--r--src/fb/pixfb.h11
-rw-r--r--src/math/mat4.cpp24
-rw-r--r--src/math/mat4.h15
-rw-r--r--src/o3d/vertex_data.cpp4
-rw-r--r--src/o3d/vertex_data.h4
-rw-r--r--src/renderer.cpp145
-rw-r--r--src/renderer.h30
13 files changed, 276 insertions, 283 deletions
diff --git a/Makefile.am b/Makefile.am
index c0f1b53..ecfea3a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,22 +1,23 @@
EXTRA_DIST = m4/NOTES
SUBDIRS =
if ENABLE_TESTS
- SUBDIRS += tests
+ SUBDIRS += tests
endif
ACLOCAL_AMFLAGS = -Im4 --install
bin_PROGRAMS = engine
-engine_SOURCES = src/engine.cpp \
- src/fb/chfb.h src/fb/chfb.cpp src/fb/pixfb.h src/fb/pixfb.cpp \
- src/math/vector.h src/math/vector.cpp \
- src/math/mat4.h src/math/mat4.cpp \
- src/o3d/mesh.h src/o3d/mesh.cpp src/o3d/tri_vertex.h \
- src/o3d/obj3d.h src/o3d/obj3d.cpp src/o3d/tri_vertex.h \
- src/o3d/tri_vertex.cpp src/o3d/vertex.h src/o3d/vertex.cpp \
- src/o3d/vertex_data.h src/o3d/vertex_data.cpp \
- src/o3d/camera.h src/o3d/camera.cpp \
- src/o3d/scene.h src/o3d/scene.cpp
+engine_SOURCES = \
+ src/engine.cpp src/renderer.h src/renderer.cpp \
+ src/fb/fb.h src/fb/chfb.h src/fb/chfb.cpp src/fb/pixfb.h src/fb/pixfb.cpp \
+ src/math/vector.h src/math/vector.cpp \
+ src/math/mat4.h src/math/mat4.cpp \
+ src/o3d/mesh.h src/o3d/mesh.cpp src/o3d/tri_vertex.h \
+ src/o3d/obj3d.h src/o3d/obj3d.cpp src/o3d/tri_vertex.h \
+ src/o3d/tri_vertex.cpp src/o3d/vertex.h src/o3d/vertex.cpp \
+ src/o3d/vertex_data.h src/o3d/vertex_data.cpp \
+ src/o3d/camera.h src/o3d/camera.cpp \
+ src/o3d/scene.h src/o3d/scene.cpp
engine_CPPFLAGS = -Wall -Wextra $(DEPS_CPPFLAGS)
engine_LDFLAGS = -Wall -Wextra
engine_LDADD = $(DEPS_LIBS)
diff --git a/src/engine.cpp b/src/engine.cpp
index aeae21c..91c0b80 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -10,6 +10,8 @@
#include <functional>
#include <utility>
#include <iterator>
+#include <memory>
+#include <utility>
#include <SDL.h>
#ifdef ENABLE_NCURSES
@@ -27,6 +29,7 @@
#include "o3d/camera.h"
#include "math/vector.h"
#include "math/mat4.h"
+#include "renderer.h"
#define FPS 60
@@ -50,8 +53,7 @@ static void usage_error_exit() {
std::exit(EXIT_FAILURE);
}
-template <class FB>
-static void scene_main(FB& fb, std::function<bool()> update_frame) {
+static void scene_main(engine::Renderer& renderer, engine::math::Matrix4 final_transform_mat, std::function<bool()> update_frame) {
float dist = 4.f;
float rad = 5.f;
bool cont = true;
@@ -76,7 +78,7 @@ static void scene_main(FB& fb, std::function<bool()> update_frame) {
scene.camera.rot_y += .0065f;
scene.camera.rot_z += .0080f;
- fb.clear();
+ renderer.clear();
auto transform_mat =
engine::math::Matrix4::translate(-scene.camera.loc)
* engine::math::Matrix4::rot_x(-scene.camera.rot_x)
@@ -86,15 +88,16 @@ static void scene_main(FB& fb, std::function<bool()> update_frame) {
transform_mat * engine::math::Matrix4::translate(engine::math::Vector3{-.5f * rad, -.5f * rad, -.5f * rad}) * scale_mat,
transform_mat * engine::math::Matrix4::translate(engine::math::Vector3{+.5f * rad, +.5f * rad, +.5f * rad}) * scale_mat,
}};
- auto projection_mat = engine::math::Matrix4::projection(static_cast<float>(fb.height()) / static_cast<float>(fb.width()), 2.f, 50.f);
+ auto pre_final_mat = final_transform_mat
+ * engine::math::Matrix4::projection(static_cast<float>(renderer.height()) / static_cast<float>(renderer.width()), 2.f, 50.f);
for (int i = 0; i < 2; i++) {
- auto final_mat = projection_mat * mats[i];
+ auto final_mat = pre_final_mat * mats[i];
const auto& mesh = scene.objs[i].mesh;
std::vector<engine::o3d::Vertex4> pts;
for (const auto& vert : mesh.pts)
pts.push_back({ final_mat * engine::math::Vector4{vert.point}, vert.data });
for (auto face : mesh.faces)
- fb.draw_triangle({pts[face[0]], pts[face[1]], pts[face[2]]});
+ renderer.draw_triangle({pts[face[0]], pts[face[1]], pts[face[2]]});
}
cont = update_frame();
}
@@ -121,10 +124,13 @@ static int main_term() {
int w, h;
getmaxyx(stdscr, h, w);
- engine::fb::CharacterFrameBuffer cfb{static_cast<unsigned int>(w), static_cast<unsigned int>(h)};
+ engine::Renderer renderer{
+ std::make_unique<engine::fb::CharacterFrameBuffer>(static_cast<unsigned int>(w), static_cast<unsigned int>(h))};
- scene_main(cfb, [&]() {
- mvaddnstr(0, 0, cfb.chars(), cfb.width() * cfb.height());
+ scene_main(renderer, engine::math::Matrix4::scale(engine::math::Vector3(2.f, 1.f, 1.f)), [&]() {
+ mvaddnstr(0, 0,
+ static_cast<engine::fb::CharacterFrameBuffer*>(renderer.fb.get())->chars(),
+ renderer.width() * renderer.height());
bool cont = true;
//timeout(1000 / FPS);
@@ -156,7 +162,7 @@ static int main_term() {
}
getmaxyx(stdscr, h, w);
- cfb.resize(static_cast<unsigned int>(w), static_cast<unsigned int>(h));
+ renderer.resize(static_cast<unsigned int>(w), static_cast<unsigned int>(h));
return cont;
});
@@ -183,17 +189,21 @@ static int main_graphical() {
}
window = SDL_CreateWindow("Engine", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (window == NULL) {
+ SDL_Quit();
std::cerr << "Error: SDL_CreateWindow error: " << SDL_GetError() << std::endl;
return EXIT_FAILURE;
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT);
- engine::fb::PixelFrameBuffer pfb{SCREEN_WIDTH, SCREEN_HEIGHT};
+ engine::Renderer engine_renderer{
+ std::make_unique<engine::fb::PixelFrameBuffer>(SCREEN_WIDTH, SCREEN_HEIGHT)};
SDL_Event e;
- scene_main(pfb, [&]() {
- SDL_UpdateTexture(texture, NULL, pfb.pixels(), SCREEN_WIDTH * 4);
+ scene_main(engine_renderer, engine::math::Matrix4::idty(), [&]() {
+ SDL_UpdateTexture(texture, NULL,
+ static_cast<engine::fb::PixelFrameBuffer*>(engine_renderer.fb.get())->pixels(),
+ SCREEN_WIDTH * 4);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderPresent(renderer);
diff --git a/src/fb/chfb.cpp b/src/fb/chfb.cpp
index c0e5cc7..b5c0ae0 100644
--- a/src/fb/chfb.cpp
+++ b/src/fb/chfb.cpp
@@ -17,7 +17,6 @@ void CharacterFrameBuffer::resize(unsigned int w, unsigned int h) {
this->w = w;
this->h = h;
chars_vector.resize(w * h);
- depth_buf.resize(w * h);
clear();
}
@@ -35,124 +34,14 @@ const char* CharacterFrameBuffer::chars() const {
void CharacterFrameBuffer::clear() {
std::fill(chars_vector.begin(), chars_vector.end(), ' ');
- std::fill(depth_buf.begin(), depth_buf.end(), 1.f);
- face_ind = -1;
}
-void CharacterFrameBuffer::_draw_cropped_triangle(engine::o3d::TriangleVertex3 triangle) {
- std::array<engine::o3d::Vertex3*, 3> sorted_vs = { &triangle.vertex1, &triangle.vertex2, &triangle.vertex3 };
-
-#define SWAP_IF_LT(X,Y) ({\
- if (sorted_vs[X]->point.y < sorted_vs[Y]->point.y) {\
- engine::o3d::Vertex3* temp = sorted_vs[X];\
- sorted_vs[X] = sorted_vs[Y];\
- sorted_vs[Y] = temp;\
- }\
- })
- SWAP_IF_LT(1, 0);
- SWAP_IF_LT(2, 1);
- SWAP_IF_LT(1, 0);
-#undef SWAP_IF_LT
-
- engine::o3d::Vertex3 middle_vl = *sorted_vs[1];
- float fac = (sorted_vs[1]->point.y - sorted_vs[0]->point.y) / (sorted_vs[2]->point.y - sorted_vs[0]->point.y);
- engine::o3d::Vertex3 middle_vr{
- {
- sorted_vs[0]->point.x + fac * (sorted_vs[2]->point.x - sorted_vs[0]->point.x),
- sorted_vs[1]->point.y,
- sorted_vs[0]->point.z + fac * (sorted_vs[2]->point.z - sorted_vs[0]->point.z)
- },
- engine::o3d::VertexData::lerp(sorted_vs[0]->data, sorted_vs[2]->data, fac)
- };
- if (middle_vr.point.x < middle_vl.point.x) {
- engine::o3d::Vertex3 temp = middle_vr;
- middle_vr = middle_vl;
- middle_vl = temp;
- }
-
- // top triangle
- {
- if (sorted_vs[0]->point.y != sorted_vs[1]->point.y) {
- int top_y = static_cast<int>(std::floor(sorted_vs[0]->point.y + 1.f));
- int bottom_y = static_cast<int>(std::ceil(sorted_vs[1]->point.y - 1.f));
- for (int y = top_y; y <= bottom_y; y++) {
- float iy = static_cast<float>(y);
- float s = (iy - sorted_vs[0]->point.y) / (sorted_vs[1]->point.y - sorted_vs[0]->point.y);
- float xl = sorted_vs[0]->point.x + s * (middle_vl.point.x - sorted_vs[0]->point.x);
- float xr = sorted_vs[0]->point.x + s * (middle_vr.point.x - sorted_vs[0]->point.x);
- int left_x = static_cast<int>(std::ceil(xl));
- int right_x = static_cast<int>(std::ceil(xr - 1.f));
- for (int x = left_x; x <= right_x; x++) {
- float ix = static_cast<float>(x);
- float t = (ix - xl) / (xr - xl);
- // depth and vd don't take into account perspective
- float depth = sorted_vs[0]->point.z + s * (middle_vl.point.z - sorted_vs[0]->point.z + t * (middle_vr.point.z - middle_vl.point.z));
- // VertexData vd = VertexData::bilerp(sorted_vs[0]->data, middle_vl.data, middle_vr.data, s, t);
- if (depth < depth_buf[x + y * w]) {
- depth_buf[x + y * w] = depth;
- chars_vector[x + y * w] = face_char();
- }
- }
- }
- }
- }
-
- // bottom triangle
- {
- if (sorted_vs[1]->point.y != sorted_vs[2]->point.y) {
- int bottom_y = static_cast<int>(std::floor(sorted_vs[2]->point.y));
- int top_y = static_cast<int>(std::ceil(sorted_vs[1]->point.y));
- for (int y = top_y; y <= bottom_y; y++) {
- float iy = static_cast<float>(y);
- float s = (iy - sorted_vs[2]->point.y) / (sorted_vs[1]->point.y - sorted_vs[2]->point.y);
- float xl = sorted_vs[2]->point.x + s * (middle_vl.point.x - sorted_vs[2]->point.x);
- float xr = sorted_vs[2]->point.x + s * (middle_vr.point.x - sorted_vs[2]->point.x);
- int left_x = static_cast<int>(std::ceil(xl));
- int right_x = static_cast<int>(std::ceil(xr - 1.f));
- for (int x = left_x; x <= right_x; x++) {
- float ix = static_cast<float>(x);
- float t = (ix - xl) / (xr - xl);
- // depth and vd don't take into account perspective
- float depth = sorted_vs[2]->point.z + s * (middle_vl.point.z - sorted_vs[2]->point.z + t * (middle_vr.point.z - middle_vl.point.z));
- // VertexData vd = VertexData::bilerp(sorted_vs[2]->data, middle_vl.data, middle_vr.data, s, t);
- if (depth < depth_buf[x + y * w]) {
- depth_buf[x + y * w] = depth;
- chars_vector[x + y * w] = face_char();
- }
- }
- }
- }
- }
-}
-
-void CharacterFrameBuffer::draw_triangle(engine::o3d::TriangleVertex4 triangle) {
- face_ind++;
- for (auto t1 : triangle.crop_z_out(-1.f, 1.f)) {
- auto t1_2 = t1.div_by_w();
- t1_2.vertex1.point.x *= 2.f;
- t1_2.vertex2.point.x *= 2.f;
- t1_2.vertex3.point.x *= 2.f;
- for (auto t2 : t1_2.crop_xy_out(-1.f, 1.f, -1.f, 1.f)) {
- engine::math::Vector2 pp1 = t2.vertex1.point.xy(),
- pp2 = t2.vertex2.point.xy(),
- pp3 = t2.vertex3.point.xy();
- if ((pp2 - pp1).det(pp3 - pp1) >= 0.f) continue;
- t2.vertex1.point = (t2.vertex1.point + engine::math::Vector3{1.f, 1.f, 0.f}) / 2.f;
- t2.vertex2.point = (t2.vertex2.point + engine::math::Vector3{1.f, 1.f, 0.f}) / 2.f;
- t2.vertex3.point = (t2.vertex3.point + engine::math::Vector3{1.f, 1.f, 0.f}) / 2.f;
- float fw = static_cast<float>(w), fh = static_cast<float>(h);
- t2.vertex1.point.x = t2.vertex1.point.x * fw - .5f;
- t2.vertex1.point.y = t2.vertex1.point.y * fh - .5f;
- t2.vertex2.point.x = t2.vertex2.point.x * fw - .5f;
- t2.vertex2.point.y = t2.vertex2.point.y * fh - .5f;
- t2.vertex3.point.x = t2.vertex3.point.x * fw - .5f;
- t2.vertex3.point.y = t2.vertex3.point.y * fh - .5f;
- _draw_cropped_triangle(t2);
- }
- }
+void CharacterFrameBuffer::draw_point(int x, int y, engine::math::Vector3 loc, const engine::o3d::VertexData& vd) {
+ (void) vd;
+ chars_vector[x + y * w] = face_char(static_cast<int>(loc.x));
}
-char CharacterFrameBuffer::face_char() const {
+char CharacterFrameBuffer::face_char(int face_ind) const {
int n = 1 + face_ind / 2;
return (n < 10 ? '0' : 'A' - 10) + n;
}
diff --git a/src/fb/chfb.h b/src/fb/chfb.h
index 9e10a0d..280f6d8 100644
--- a/src/fb/chfb.h
+++ b/src/fb/chfb.h
@@ -2,12 +2,11 @@
#define FB_CHFB_H
#include <vector>
-#include "math/vector.h"
-#include "o3d/tri_vertex.h"
+#include "fb/fb.h"
namespace engine::fb {
-class CharacterFrameBuffer {
+class CharacterFrameBuffer : public FrameBuffer {
public:
CharacterFrameBuffer(unsigned int w, unsigned int h);
void resize(unsigned int w, unsigned int h);
@@ -15,16 +14,13 @@ class CharacterFrameBuffer {
unsigned int height() const;
const char* chars() const;
void clear();
- void draw_triangle(engine::o3d::TriangleVertex4 triangle);
+ void draw_point(int x, int y, engine::math::Vector3 loc, const engine::o3d::VertexData& vd);
private:
unsigned int w, h;
std::vector<char> chars_vector;
- std::vector<float> depth_buf;
- int face_ind;
- void _draw_cropped_triangle(engine::o3d::TriangleVertex3 triangle);
- char face_char() const;
+ char face_char(int face_inf) const;
};
}
diff --git a/src/fb/fb.h b/src/fb/fb.h
new file mode 100644
index 0000000..04b13ee
--- /dev/null
+++ b/src/fb/fb.h
@@ -0,0 +1,20 @@
+#ifndef FB_FB_H
+#define FB_FB_H
+
+#include "math/vector.h"
+#include "o3d/vertex_data.h"
+
+namespace engine::fb {
+
+class FrameBuffer {
+ public:
+ virtual void resize(unsigned int w, unsigned int h) = 0;
+ virtual unsigned int width() const = 0;
+ virtual unsigned int height() const = 0;
+ virtual void clear() = 0;
+ virtual void draw_point(int x, int y, engine::math::Vector3 loc, const engine::o3d::VertexData& vd) = 0;
+};
+
+}
+
+#endif // FB_FB_H
diff --git a/src/fb/pixfb.cpp b/src/fb/pixfb.cpp
index af220c6..26bc8f2 100644
--- a/src/fb/pixfb.cpp
+++ b/src/fb/pixfb.cpp
@@ -3,6 +3,7 @@
#include <cmath>
#include <vector>
#include <cstdint>
+#include <algorithm>
#include "math/vector.h"
#include "o3d/vertex.h"
#include "o3d/tri_vertex.h"
@@ -18,7 +19,6 @@ void PixelFrameBuffer::resize(unsigned int w, unsigned int h) {
this->w = w;
this->h = h;
pixels_vector.resize(w * h);
- depth_buf.resize(w * h);
clear();
}
@@ -36,120 +36,14 @@ const uint32_t* PixelFrameBuffer::pixels() const {
void PixelFrameBuffer::clear() {
std::fill(pixels_vector.begin(), pixels_vector.end(), 0x000000FF);
- std::fill(depth_buf.begin(), depth_buf.end(), 1.f);
- face_ind = -1;
}
-void PixelFrameBuffer::_draw_cropped_triangle(engine::o3d::TriangleVertex3 triangle) {
- std::array<engine::o3d::Vertex3*, 3> sorted_vs = { &triangle.vertex1, &triangle.vertex2, &triangle.vertex3 };
-
-#define SWAP_IF_LT(X,Y) ({\
- if (sorted_vs[X]->point.y < sorted_vs[Y]->point.y) {\
- engine::o3d::Vertex3* temp = sorted_vs[X];\
- sorted_vs[X] = sorted_vs[Y];\
- sorted_vs[Y] = temp;\
- }\
- })
- SWAP_IF_LT(1, 0);
- SWAP_IF_LT(2, 1);
- SWAP_IF_LT(1, 0);
-#undef SWAP_IF_LT
-
- engine::o3d::Vertex3 middle_vl = *sorted_vs[1];
- float fac = (sorted_vs[1]->point.y - sorted_vs[0]->point.y) / (sorted_vs[2]->point.y - sorted_vs[0]->point.y);
- engine::o3d::Vertex3 middle_vr{
- {
- sorted_vs[0]->point.x + fac * (sorted_vs[2]->point.x - sorted_vs[0]->point.x),
- sorted_vs[1]->point.y,
- sorted_vs[0]->point.z + fac * (sorted_vs[2]->point.z - sorted_vs[0]->point.z)
- },
- engine::o3d::VertexData::lerp(sorted_vs[0]->data, sorted_vs[2]->data, fac)
- };
- if (middle_vr.point.x < middle_vl.point.x) {
- engine::o3d::Vertex3 temp = middle_vr;
- middle_vr = middle_vl;
- middle_vl = temp;
- }
-
- // top triangle
- {
- if (sorted_vs[0]->point.y != sorted_vs[1]->point.y) {
- int top_y = static_cast<int>(std::floor(sorted_vs[0]->point.y + 1.f));
- int bottom_y = static_cast<int>(std::ceil(sorted_vs[1]->point.y - 1.f));
- for (int y = top_y; y <= bottom_y; y++) {
- float iy = static_cast<float>(y);
- float s = (iy - sorted_vs[0]->point.y) / (sorted_vs[1]->point.y - sorted_vs[0]->point.y);
- float xl = sorted_vs[0]->point.x + s * (middle_vl.point.x - sorted_vs[0]->point.x);
- float xr = sorted_vs[0]->point.x + s * (middle_vr.point.x - sorted_vs[0]->point.x);
- int left_x = static_cast<int>(std::ceil(xl));
- int right_x = static_cast<int>(std::ceil(xr - 1.f));
- for (int x = left_x; x <= right_x; x++) {
- float ix = static_cast<float>(x);
- float t = (ix - xl) / (xr - xl);
- // depth and vd don't take into account perspective
- float depth = sorted_vs[0]->point.z + s * (middle_vl.point.z - sorted_vs[0]->point.z + t * (middle_vr.point.z - middle_vl.point.z));
- // VertexData vd = VertexData::bilerp(sorted_vs[0]->data, middle_vl.data, middle_vr.data, s, t);
- if (depth < depth_buf[x + y * w]) {
- depth_buf[x + y * w] = depth;
- pixels_vector[x + y * w] = face_color();
- }
- }
- }
- }
- }
-
- // bottom triangle
- {
- if (sorted_vs[1]->point.y != sorted_vs[2]->point.y) {
- int bottom_y = static_cast<int>(std::floor(sorted_vs[2]->point.y));
- int top_y = static_cast<int>(std::ceil(sorted_vs[1]->point.y));
- for (int y = top_y; y <= bottom_y; y++) {
- float iy = static_cast<float>(y);
- float s = (iy - sorted_vs[2]->point.y) / (sorted_vs[1]->point.y - sorted_vs[2]->point.y);
- float xl = sorted_vs[2]->point.x + s * (middle_vl.point.x - sorted_vs[2]->point.x);
- float xr = sorted_vs[2]->point.x + s * (middle_vr.point.x - sorted_vs[2]->point.x);
- int left_x = static_cast<int>(std::ceil(xl));
- int right_x = static_cast<int>(std::ceil(xr - 1.f));
- for (int x = left_x; x <= right_x; x++) {
- float ix = static_cast<float>(x);
- float t = (ix - xl) / (xr - xl);
- // depth and vd don't take into account perspective
- float depth = sorted_vs[2]->point.z + s * (middle_vl.point.z - sorted_vs[2]->point.z + t * (middle_vr.point.z - middle_vl.point.z));
- // VertexData vd = VertexData::bilerp(sorted_vs[2]->data, middle_vl.data, middle_vr.data, s, t);
- if (depth < depth_buf[x + y * w]) {
- depth_buf[x + y * w] = depth;
- pixels_vector[x + y * w] = face_color();
- }
- }
- }
- }
- }
-}
-
-void PixelFrameBuffer::draw_triangle(engine::o3d::TriangleVertex4 triangle) {
- face_ind++;
- for (auto t1 : triangle.crop_z_out(-1.f, 1.f)) {
- for (auto t2 : t1.div_by_w().crop_xy_out(-1.f, 1.f, -1.f, 1.f)) {
- engine::math::Vector2 pp1 = t2.vertex1.point.xy(),
- pp2 = t2.vertex2.point.xy(),
- pp3 = t2.vertex3.point.xy();
- if ((pp2 - pp1).det(pp3 - pp1) >= 0.f) continue;
- t2.vertex1.point = (t2.vertex1.point + engine::math::Vector3{1.f, 1.f, 0.f}) / 2.f;
- t2.vertex2.point = (t2.vertex2.point + engine::math::Vector3{1.f, 1.f, 0.f}) / 2.f;
- t2.vertex3.point = (t2.vertex3.point + engine::math::Vector3{1.f, 1.f, 0.f}) / 2.f;
- float fw = static_cast<float>(w), fh = static_cast<float>(h);
- t2.vertex1.point.x = t2.vertex1.point.x * fw - .5f;
- t2.vertex1.point.y = t2.vertex1.point.y * fh - .5f;
- t2.vertex2.point.x = t2.vertex2.point.x * fw - .5f;
- t2.vertex2.point.y = t2.vertex2.point.y * fh - .5f;
- t2.vertex3.point.x = t2.vertex3.point.x * fw - .5f;
- t2.vertex3.point.y = t2.vertex3.point.y * fh - .5f;
- _draw_cropped_triangle(t2);
- }
- }
+void PixelFrameBuffer::draw_point(int x, int y, engine::math::Vector3 loc, const engine::o3d::VertexData& vd) {
+ (void) vd;
+ pixels_vector[x + y * w] = face_color(static_cast<int>(loc.x));
}
-uint32_t PixelFrameBuffer::face_color() const {
+uint32_t PixelFrameBuffer::face_color(int face_ind) const {
int n = face_ind / 2;
return ((n % 2 ? 0xFF000000 : 0x55000000) >> ((n % 6) / 2 * 8)) | 0xFF;
}
diff --git a/src/fb/pixfb.h b/src/fb/pixfb.h
index cdfac18..84bce2c 100644
--- a/src/fb/pixfb.h
+++ b/src/fb/pixfb.h
@@ -3,12 +3,11 @@
#include <vector>
#include <cstdint>
-#include "math/vector.h"
-#include "o3d/tri_vertex.h"
+#include "fb/fb.h"
namespace engine::fb {
-class PixelFrameBuffer {
+class PixelFrameBuffer : public FrameBuffer {
public:
PixelFrameBuffer(unsigned int w, unsigned int h);
void resize(unsigned int w, unsigned int h);
@@ -16,16 +15,14 @@ class PixelFrameBuffer {
unsigned int height() const;
const uint32_t* pixels() const;
void clear();
- void draw_triangle(engine::o3d::TriangleVertex4 triangle);
+ void draw_point(int x, int y, engine::math::Vector3 loc, const engine::o3d::VertexData& vd);
private:
unsigned int w, h;
std::vector<uint32_t> pixels_vector;
- std::vector<float> depth_buf;
int face_ind;
- void _draw_cropped_triangle(engine::o3d::TriangleVertex3 triangle);
- uint32_t face_color() const;
+ uint32_t face_color(int face_ind) const;
};
}
diff --git a/src/math/mat4.cpp b/src/math/mat4.cpp
index f1f28b7..b9dff15 100644
--- a/src/math/mat4.cpp
+++ b/src/math/mat4.cpp
@@ -22,6 +22,7 @@ Matrix4 Matrix4::translate(Vector3 v) {
0.f, 0.f, 0.f, 1.f,
};
}
+
Matrix4 Matrix4::scale(float fac) {
return {
fac, 0.f, 0.f, 0.f,
@@ -31,6 +32,15 @@ Matrix4 Matrix4::scale(float fac) {
};
}
+Matrix4 Matrix4::scale(Vector3 facs) {
+ return {
+ facs.x, 0.f, 0.f, 0.f,
+ 0.f, facs.y, 0.f, 0.f,
+ 0.f, 0.f, facs.z, 0.f,
+ 0.f, 0.f, 0.f, 1.f,
+ };
+}
+
Matrix4 Matrix4::rot_x(float a) {
float c = std::cos(a);
float s = std::sin(a);
@@ -73,11 +83,11 @@ Matrix4 Matrix4::projection(float aspect_ratio, float min_z, float max_z) {
}};
}
-Matrix4 Matrix4::operator+() {
+Matrix4 Matrix4::operator+() const {
return *this;
}
-Matrix4 Matrix4::operator-() {
+Matrix4 Matrix4::operator-() const {
return {
-values[ 0], -values[ 1], -values[ 2], -values[ 3],
-values[ 4], -values[ 5], -values[ 6], -values[ 7],
@@ -86,7 +96,7 @@ Matrix4 Matrix4::operator-() {
};
}
-Matrix4 Matrix4::operator+(Matrix4 m) {
+Matrix4 Matrix4::operator+(Matrix4 m) const {
return {
values[ 0] + m.values[ 0], values[ 1] + m.values[ 1], values[ 2] + m.values[ 2], values[ 3] + m.values[ 3],
values[ 4] + m.values[ 4], values[ 5] + m.values[ 5], values[ 6] + m.values[ 6], values[ 7] + m.values[ 7],
@@ -95,11 +105,11 @@ Matrix4 Matrix4::operator+(Matrix4 m) {
};
}
-Matrix4 Matrix4::operator-(Matrix4 m) {
+Matrix4 Matrix4::operator-(Matrix4 m) const {
return *this + (-m);
}
-Matrix4 Matrix4::operator*(Matrix4 m) {
+Matrix4 Matrix4::operator*(Matrix4 m) const {
Matrix4 ret;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
@@ -111,7 +121,7 @@ Matrix4 Matrix4::operator*(Matrix4 m) {
return ret;
}
-Vector4 Matrix4::operator*(Vector4 v) {
+Vector4 Matrix4::operator*(Vector4 v) const {
return {
values[ 0] * v.x + values[ 1] * v.y + values[ 2] * v.z + values[ 3] * v.w,
values[ 4] * v.x + values[ 5] * v.y + values[ 6] * v.z + values[ 7] * v.w,
@@ -120,7 +130,7 @@ Vector4 Matrix4::operator*(Vector4 v) {
};
}
-std::array<Vector4, 4> Matrix4::to_vecs() {
+std::array<Vector4, 4> Matrix4::to_vecs() const {
return {{
{ values[ 0], values[ 4], values[ 8], values[12] },
{ values[ 1], values[ 5], values[ 9], values[13] },
diff --git a/src/math/mat4.h b/src/math/mat4.h
index 66d6cd2..35b1ad2 100644
--- a/src/math/mat4.h
+++ b/src/math/mat4.h
@@ -11,6 +11,7 @@ class Matrix4 {
static Matrix4 idty();
static Matrix4 translate(Vector3 v);
static Matrix4 scale(float fac);
+ static Matrix4 scale(Vector3 facs);
static Matrix4 rot_x(float a);
static Matrix4 rot_y(float a);
static Matrix4 rot_z(float a);
@@ -18,13 +19,13 @@ class Matrix4 {
std::array<float, 16> values;
- Matrix4 operator+();
- Matrix4 operator-();
- Matrix4 operator+(Matrix4 m);
- Matrix4 operator-(Matrix4 m);
- Matrix4 operator*(Matrix4 m);
- Vector4 operator*(Vector4 v);
- std::array<Vector4, 4> to_vecs();
+ Matrix4 operator+() const;
+ Matrix4 operator-() const;
+ Matrix4 operator+(Matrix4 m) const;
+ Matrix4 operator-(Matrix4 m) const;
+ Matrix4 operator*(Matrix4 m) const;
+ Vector4 operator*(Vector4 v) const;
+ std::array<Vector4, 4> to_vecs() const;
};
Matrix4 operator*(float fac, Matrix4 m);
diff --git a/src/o3d/vertex_data.cpp b/src/o3d/vertex_data.cpp
index 4e0ab04..ea8c5fd 100644
--- a/src/o3d/vertex_data.cpp
+++ b/src/o3d/vertex_data.cpp
@@ -2,14 +2,14 @@
using namespace engine::o3d;
-VertexData VertexData::lerp(VertexData& vd1, VertexData& vd2, float s) {
+VertexData VertexData::lerp(const VertexData& vd1, const VertexData& vd2, float s) {
(void) vd1;
(void) vd2;
(void) s;
return {};
}
-VertexData VertexData::bilerp(VertexData& vd1, VertexData& vd2, VertexData& vd3, float s, float t) {
+VertexData VertexData::bilerp(const VertexData& vd1, const VertexData& vd2, const VertexData& vd3, float s, float t) {
(void) vd1;
(void) vd2;
(void) vd3;
diff --git a/src/o3d/vertex_data.h b/src/o3d/vertex_data.h
index dda881b..ec5fa25 100644
--- a/src/o3d/vertex_data.h
+++ b/src/o3d/vertex_data.h
@@ -5,8 +5,8 @@ namespace engine::o3d {
class VertexData {
public:
- static VertexData lerp(VertexData& vd1, VertexData& vd2, float s);
- static VertexData bilerp(VertexData& vd1, VertexData& vd2, VertexData& vd3, float s, float t);
+ static VertexData lerp(const VertexData& vd1, const VertexData& vd2, float s);
+ static VertexData bilerp(const VertexData& vd1, const VertexData& vd2, const VertexData& vd3, float s, float t);
VertexData();
};
diff --git a/src/renderer.cpp b/src/renderer.cpp
new file mode 100644
index 0000000..a946ce3
--- /dev/null
+++ b/src/renderer.cpp
@@ -0,0 +1,145 @@
+#include "renderer.h"
+#include <array>
+#include <cmath>
+#include <algorithm>
+#include <memory>
+#include "math/vector.h"
+#include "o3d/vertex.h"
+#include "o3d/tri_vertex.h"
+#include "o3d/vertex_data.h"
+
+using namespace engine;
+
+Renderer::Renderer(std::unique_ptr<engine::fb::FrameBuffer> fb) : fb{std::move(fb)} {
+ depth_buf.resize(this->fb->width() * this->fb->height());
+}
+
+void Renderer::resize(unsigned int w, unsigned int h) {
+ fb->resize(w, h);
+ depth_buf.resize(fb->width() * fb->height());
+}
+
+unsigned int Renderer::width() const {
+ return fb->width();
+}
+
+unsigned int Renderer::height() const {
+ return fb->height();
+}
+
+void Renderer::clear() {
+ std::fill(depth_buf.begin(), depth_buf.end(), 1.f);
+ face_ind = -1;
+ fb->clear();
+}
+
+void Renderer::_draw_cropped_triangle(engine::o3d::TriangleVertex3 triangle) {
+ std::array<engine::o3d::Vertex3*, 3> sorted_vs = { &triangle.vertex1, &triangle.vertex2, &triangle.vertex3 };
+
+#define SWAP_IF_LT(X,Y) ({\
+ if (sorted_vs[X]->point.y < sorted_vs[Y]->point.y) {\
+ engine::o3d::Vertex3* temp = sorted_vs[X];\
+ sorted_vs[X] = sorted_vs[Y];\
+ sorted_vs[Y] = temp;\
+ }\
+ })
+ SWAP_IF_LT(1, 0);
+ SWAP_IF_LT(2, 1);
+ SWAP_IF_LT(1, 0);
+#undef SWAP_IF_LT
+
+ engine::o3d::Vertex3 middle_vl = *sorted_vs[1];
+ float fac = (sorted_vs[1]->point.y - sorted_vs[0]->point.y) / (sorted_vs[2]->point.y - sorted_vs[0]->point.y);
+ engine::o3d::Vertex3 middle_vr{
+ {
+ sorted_vs[0]->point.x + fac * (sorted_vs[2]->point.x - sorted_vs[0]->point.x),
+ sorted_vs[1]->point.y,
+ sorted_vs[0]->point.z + fac * (sorted_vs[2]->point.z - sorted_vs[0]->point.z)
+ },
+ engine::o3d::VertexData::lerp(sorted_vs[0]->data, sorted_vs[2]->data, fac)
+ };
+ if (middle_vr.point.x < middle_vl.point.x) {
+ engine::o3d::Vertex3 temp = middle_vr;
+ middle_vr = middle_vl;
+ middle_vl = temp;
+ }
+
+ // top triangle
+ {
+ if (sorted_vs[0]->point.y != sorted_vs[1]->point.y) {
+ int top_y = static_cast<int>(std::floor(sorted_vs[0]->point.y + 1.f));
+ int bottom_y = static_cast<int>(std::ceil(sorted_vs[1]->point.y - 1.f));
+ for (int y = top_y; y <= bottom_y; y++) {
+ float iy = static_cast<float>(y);
+ float s = (iy - sorted_vs[0]->point.y) / (sorted_vs[1]->point.y - sorted_vs[0]->point.y);
+ float xl = sorted_vs[0]->point.x + s * (middle_vl.point.x - sorted_vs[0]->point.x);
+ float xr = sorted_vs[0]->point.x + s * (middle_vr.point.x - sorted_vs[0]->point.x);
+ int left_x = static_cast<int>(std::ceil(xl));
+ int right_x = static_cast<int>(std::ceil(xr - 1.f));
+ for (int x = left_x; x <= right_x; x++) {
+ float ix = static_cast<float>(x);
+ float t = (ix - xl) / (xr - xl);
+ // depth and vd don't take into account perspective
+ float u = s, v = t;
+ float depth = sorted_vs[0]->point.z + u * (middle_vl.point.z - sorted_vs[0]->point.z + v * (middle_vr.point.z - middle_vl.point.z));
+ if (depth < depth_buf[x + y * fb->width()]) {
+ depth_buf[x + y * fb->width()] = depth;
+ fb->draw_point(x, y, engine::math::Vector3{static_cast<float>(face_ind) + .5f, 0.f, 0.f},
+ engine::o3d::VertexData::bilerp(sorted_vs[0]->data, middle_vl.data, middle_vr.data, u, v));
+ }
+ }
+ }
+ }
+ }
+
+ // bottom triangle
+ {
+ if (sorted_vs[1]->point.y != sorted_vs[2]->point.y) {
+ int bottom_y = static_cast<int>(std::floor(sorted_vs[2]->point.y));
+ int top_y = static_cast<int>(std::ceil(sorted_vs[1]->point.y));
+ for (int y = top_y; y <= bottom_y; y++) {
+ float iy = static_cast<float>(y);
+ float s = (iy - sorted_vs[2]->point.y) / (sorted_vs[1]->point.y - sorted_vs[2]->point.y);
+ float xl = sorted_vs[2]->point.x + s * (middle_vl.point.x - sorted_vs[2]->point.x);
+ float xr = sorted_vs[2]->point.x + s * (middle_vr.point.x - sorted_vs[2]->point.x);
+ int left_x = static_cast<int>(std::ceil(xl));
+ int right_x = static_cast<int>(std::ceil(xr - 1.f));
+ for (int x = left_x; x <= right_x; x++) {
+ float ix = static_cast<float>(x);
+ float t = (ix - xl) / (xr - xl);
+ // depth and vd don't take into account perspective
+ float u = s, v = t;
+ float depth = sorted_vs[2]->point.z + u * (middle_vl.point.z - sorted_vs[2]->point.z + v * (middle_vr.point.z - middle_vl.point.z));
+ if (depth < depth_buf[x + y * fb->width()]) {
+ depth_buf[x + y * fb->width()] = depth;
+ fb->draw_point(x, y, engine::math::Vector3{static_cast<float>(face_ind) + .5f, 0.f, 0.f},
+ engine::o3d::VertexData::bilerp(sorted_vs[2]->data, middle_vl.data, middle_vr.data, u, v));
+ }
+ }
+ }
+ }
+ }
+}
+
+void Renderer::draw_triangle(engine::o3d::TriangleVertex4 triangle) {
+ face_ind++;
+ for (auto t1 : triangle.crop_z_out(-1.f, 1.f)) {
+ for (auto t2 : t1.div_by_w().crop_xy_out(-1.f, 1.f, -1.f, 1.f)) {
+ engine::math::Vector2 pp1 = t2.vertex1.point.xy(),
+ pp2 = t2.vertex2.point.xy(),
+ pp3 = t2.vertex3.point.xy();
+ if ((pp2 - pp1).det(pp3 - pp1) >= 0.f) continue;
+ t2.vertex1.point = (t2.vertex1.point + engine::math::Vector3{1.f, 1.f, 0.f}) / 2.f;
+ t2.vertex2.point = (t2.vertex2.point + engine::math::Vector3{1.f, 1.f, 0.f}) / 2.f;
+ t2.vertex3.point = (t2.vertex3.point + engine::math::Vector3{1.f, 1.f, 0.f}) / 2.f;
+ float fw = static_cast<float>(fb->width()), fh = static_cast<float>(fb->height());
+ t2.vertex1.point.x = t2.vertex1.point.x * fw - .5f;
+ t2.vertex1.point.y = t2.vertex1.point.y * fh - .5f;
+ t2.vertex2.point.x = t2.vertex2.point.x * fw - .5f;
+ t2.vertex2.point.y = t2.vertex2.point.y * fh - .5f;
+ t2.vertex3.point.x = t2.vertex3.point.x * fw - .5f;
+ t2.vertex3.point.y = t2.vertex3.point.y * fh - .5f;
+ _draw_cropped_triangle(t2);
+ }
+ }
+}
diff --git a/src/renderer.h b/src/renderer.h
new file mode 100644
index 0000000..211a6fc
--- /dev/null
+++ b/src/renderer.h
@@ -0,0 +1,30 @@
+#ifndef RENDERER_H
+#define RENDERER_H
+
+#include <memory>
+#include "fb/fb.h"
+#include "o3d/tri_vertex.h"
+
+namespace engine {
+
+class Renderer {
+ public:
+ std::unique_ptr<engine::fb::FrameBuffer> fb;
+
+ Renderer(std::unique_ptr<engine::fb::FrameBuffer> fb);
+ void resize(unsigned int w, unsigned int h);
+ unsigned int width() const;
+ unsigned int height() const;
+ void clear();
+ void draw_triangle(engine::o3d::TriangleVertex4 triangle);
+
+ private:
+ std::vector<float> depth_buf;
+ int face_ind;
+
+ void _draw_cropped_triangle(engine::o3d::TriangleVertex3 triangle);
+};
+
+}
+
+#endif // RENDERER_H