aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvimene <vincent.menegaux@gmail.com>2024-12-31 03:40:14 +0100
committervimene <vincent.menegaux@gmail.com>2024-12-31 03:40:14 +0100
commitcc6fb8c33637566a7b116d46440e6063f016deea (patch)
tree5cc83f84525507994add57df7dd974e6611d675a
parent6b765a85cf81bf4b7162e4c9280dd4054581c611 (diff)
downloadengine-cc6fb8c33637566a7b116d46440e6063f016deea.tar.gz
various improvements
- added quaternions and rewrote all rotations to use them - added transforms to put all object transforms in a single place - added Wavefront .obj file parser - removed frame buffer's abstract class - improved vectors, matrices, triangles, vertices and vertices data by putting all code in header file - added vector's operations - changed from NULL to nullptr - miscellaneous improvements
-rw-r--r--.gitignore2
-rw-r--r--Makefile.am28
-rw-r--r--src/engine.cpp115
-rw-r--r--src/fb/chfb.cpp25
-rw-r--r--src/fb/chfb.h26
-rw-r--r--src/fb/fb.h20
-rw-r--r--src/fb/pixfb.cpp34
-rw-r--r--src/fb/pixfb.h26
-rw-r--r--src/math/mat4.cpp149
-rw-r--r--src/math/mat4.h166
-rw-r--r--src/math/quat.h74
-rw-r--r--src/math/tform.h35
-rw-r--r--src/math/vector.cpp175
-rw-r--r--src/math/vector.h266
-rw-r--r--src/o3d/camera.cpp7
-rw-r--r--src/o3d/camera.h13
-rw-r--r--src/o3d/deriv_vertex.cpp11
-rw-r--r--src/o3d/deriv_vertex.h14
-rw-r--r--src/o3d/mesh.cpp30
-rw-r--r--src/o3d/mesh.h19
-rw-r--r--src/o3d/obj3d.cpp9
-rw-r--r--src/o3d/obj3d.h17
-rw-r--r--src/o3d/scene.cpp12
-rw-r--r--src/o3d/scene.h10
-rw-r--r--src/o3d/tri.cpp16
-rw-r--r--src/o3d/tri.h15
-rw-r--r--src/o3d/tri_deriv.cpp8
-rw-r--r--src/o3d/tri_deriv.h19
-rw-r--r--src/o3d/vertex.cpp9
-rw-r--r--src/o3d/vertex.h11
-rw-r--r--src/o3d/vertex_data.cpp20
-rw-r--r--src/o3d/vertex_data.h20
-rw-r--r--src/obj_parser.cpp81
-rw-r--r--src/obj_parser.h12
-rw-r--r--src/renderer.cpp122
-rw-r--r--src/renderer.h23
36 files changed, 841 insertions, 798 deletions
diff --git a/.gitignore b/.gitignore
index b584a8b..725c763 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,8 @@ Makefile.in
/autom4te.cache/
/config.log
/config.status
+/configure.scan
+/autoscan.log
# vim
.*.swp
diff --git a/Makefile.am b/Makefile.am
index ac2c3b6..680bc68 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,19 +8,23 @@ ACLOCAL_AMFLAGS = -Im4 --install
bin_PROGRAMS = engine
engine_SOURCES = \
- src/engine.cpp src/renderer.h src/renderer.cpp \
+ src/engine.cpp \
+ src/renderer.h src/renderer.cpp \
+ src/obj_parser.h src/obj_parser.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/math/vector.h \
+ src/math/mat4.h \
+ src/math/quat.h \
+ src/math/tform.h \
src/o3d/mesh.h src/o3d/mesh.cpp \
- src/o3d/obj3d.h src/o3d/obj3d.cpp \
- src/o3d/vertex_data.h src/o3d/vertex_data.cpp \
- src/o3d/vertex.h src/o3d/vertex.cpp \
- src/o3d/deriv_vertex.h src/o3d/deriv_vertex.cpp \
- src/o3d/tri.h src/o3d/tri.cpp \
+ src/o3d/obj3d.h \
+ src/o3d/vertex_data.h \
+ src/o3d/vertex.h \
+ src/o3d/deriv_vertex.h \
+ src/o3d/tri.h \
src/o3d/tri_deriv.h src/o3d/tri_deriv.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
+ src/o3d/camera.h \
+ src/o3d/scene.h
+engine_CPPFLAGS = -std=gnu++23 -Wall -Wextra $(DEPS_CPPFLAGS)
+engine_LDFLAGS = -std=gnu++23 -Wall -Wextra
engine_LDADD = $(DEPS_LIBS)
diff --git a/src/engine.cpp b/src/engine.cpp
index e8cde92..c484b0d 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -13,6 +13,7 @@
#include <memory>
#include <utility>
#include <SDL.h>
+#include <numbers>
#ifdef ENABLE_NCURSES
#include <ncurses.h>
@@ -28,7 +29,22 @@
#include "o3d/camera.h"
#include "math/vector.h"
#include "math/mat4.h"
+#include "math/quat.h"
+#include "math/tform.h"
#include "renderer.h"
+#include "obj_parser.h"
+
+using
+ engine::Renderer,
+ engine::fb::CharacterFrameBuffer,
+ engine::fb::PixelFrameBuffer,
+ engine::o3d::Scene,
+ engine::o3d::Mesh,
+ engine::o3d::Triangle,
+ engine::math::Vector3,
+ engine::math::Vector4,
+ engine::math::Matrix4,
+ engine::math::Quaternion;
#define FPS 60
@@ -52,49 +68,55 @@ static void usage_error_exit() {
std::exit(EXIT_FAILURE);
}
-static void scene_main(engine::Renderer& renderer, engine::math::Matrix4 final_transform_mat, std::function<bool()> update_frame) {
+extern Quaternion camera_quat;
+Quaternion camera_quat = Quaternion::one();
+
+template<typename FrameBuffer, typename UpdateFrameFn>
+static void scene_main(Renderer<FrameBuffer>& renderer, const Matrix4& final_transform_mat, UpdateFrameFn update_frame) {
float dist = 1.5f;
float rad = 5.f;
bool cont = true;
- engine::o3d::Scene scene{
- {{0.f, 0.f, rad * dist}, 0.f, 0.f, 0.f}, // camera
- { // objects
- engine::o3d::Object3D{
- engine::o3d::Mesh::plane(),
- -rad * engine::math::Vector3(.5f, .5f, .5f),
- rad, 0.f, 0.f, 0.f
+ Scene scene{
+ {{{0.f, 0.f, rad * dist}, {1.f, 0.f, 0.f, 0.f}, {1.f, 1.f, 1.f}}},
+ {
+ // {
+ // Mesh::plane(),
+ // {
+ // Vector3(0.f, 0.f, 0.f),
+ // {1.f, 0.f, 0.f, 0.f},
+ // Vector3(rad, rad, rad),
+ // }
+ // },
+ {
+ engine::parse_object("../assets/suzanne.obj"),
+ {
+ Vector3(0.f, 0.f, 0.f),
+ {1.f, 0.f, 0.f, 0.f},
+ Vector3(rad, rad, rad),
+ }
},
}
};
- auto scale_mat = engine::math::Matrix4::scale(rad);
+ float mul_angle = 0.f;
while (cont) {
- scene.camera.rot_x += .0050f;
- scene.camera.rot_y += .0065f;
- scene.camera.rot_z += .0080f;
+ camera_quat = Quaternion::euler_zyx(mul_angle * .0050f, mul_angle * .0065f, mul_angle * .0080f);
+ mul_angle += 1.f;
+ scene.camera.transform.rot = camera_quat;
renderer.clear();
- auto transform_mat =
- engine::math::Matrix4::translate(-scene.camera.loc)
- * engine::math::Matrix4::rot_x(-scene.camera.rot_x)
- * engine::math::Matrix4::rot_y(-scene.camera.rot_y)
- * engine::math::Matrix4::rot_z(-scene.camera.rot_z);
- std::array<engine::math::Matrix4, 1> mats{{
- transform_mat * scale_mat,
- }};
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 < 1; i++) {
- auto final_mat = pre_final_mat * mats[i];
- const auto& mesh = scene.objs[i].mesh;
- std::vector<engine::math::Vector4> vertices;
+ * Matrix4::projection(static_cast<float>(renderer.height()) / static_cast<float>(renderer.width()), 2.f, 50.f)
+ * scene.camera.transform.opposite().to_mat4();
+ for (const auto& obj : scene.objs) {
+ auto final_mat = pre_final_mat * obj.transform.to_mat4();
+ const auto& mesh = obj.mesh;
+ std::vector<Vector4> vertices;
for (const auto& vertex : mesh.vertices)
vertices.push_back(final_mat * vertex);
- for (auto triangle_indices : mesh.indices) {
- renderer.draw_triangle({
- {vertices[triangle_indices[0][0]], mesh.normals[triangle_indices[0][1]], mesh.vertices_data[triangle_indices[0][2]]},
- {vertices[triangle_indices[1][0]], mesh.normals[triangle_indices[1][1]], mesh.vertices_data[triangle_indices[1][2]]},
- {vertices[triangle_indices[2][0]], mesh.normals[triangle_indices[2][1]], mesh.vertices_data[triangle_indices[2][2]]},
- });
+ for (const auto& triangle_indices : mesh.indices) {
+ [&]<std::size_t... j>(std::integer_sequence<std::size_t, j...>) {
+ renderer.draw_triangle({{vertices[triangle_indices[j][0]], mesh.normals[triangle_indices[j][1]], mesh.vertices_data[triangle_indices[j][2]]}...});
+ }(std::make_integer_sequence<std::size_t, 3>());
}
}
cont = update_frame();
@@ -122,13 +144,10 @@ static int main_term() {
int w, h;
getmaxyx(stdscr, h, w);
- engine::Renderer renderer{
- std::make_unique<engine::fb::CharacterFrameBuffer>(static_cast<unsigned int>(w), static_cast<unsigned int>(h))};
+ Renderer<CharacterFrameBuffer> renderer{CharacterFrameBuffer{static_cast<unsigned int>(w), static_cast<unsigned int>(h)}};
- 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());
+ scene_main(renderer, Matrix4::scale(Vector3(2.f, 1.f, 1.f)), [&]() {
+ mvaddnstr(0, 0, renderer.fb.chars(), renderer.width() * renderer.height());
bool cont = true;
//timeout(1000 / FPS);
@@ -176,9 +195,9 @@ static int main_term() {
#define SCREEN_HEIGHT 480
static int main_graphical() {
- SDL_Window* window = NULL;
- SDL_Renderer* renderer = NULL;
- SDL_Texture* texture = NULL;
+ SDL_Window* window = nullptr;
+ SDL_Renderer* renderer = nullptr;
+ SDL_Texture* texture = nullptr;
// init
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
@@ -186,24 +205,21 @@ static int main_graphical() {
return EXIT_FAILURE;
}
window = SDL_CreateWindow("Engine", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
- if (window == NULL) {
+ if (window == nullptr) {
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::Renderer engine_renderer{
- std::make_unique<engine::fb::PixelFrameBuffer>(SCREEN_WIDTH, SCREEN_HEIGHT)};
+ Renderer<PixelFrameBuffer> engine_renderer{PixelFrameBuffer{SCREEN_WIDTH, SCREEN_HEIGHT}};
SDL_Event e;
- 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);
+ scene_main(engine_renderer, Matrix4::idty(), [&]() {
+ SDL_UpdateTexture(texture, nullptr, engine_renderer.fb.pixels(), SCREEN_WIDTH * 4);
SDL_RenderClear(renderer);
- SDL_RenderCopy(renderer, texture, NULL, NULL);
+ SDL_RenderCopy(renderer, texture, nullptr, nullptr);
SDL_RenderPresent(renderer);
SDL_UpdateWindowSurface(window);
bool cont = true;
@@ -297,7 +313,6 @@ int main(int argc, char *argv[]) {
case MODE_GRAPHICAL:
return main_graphical();
default:
- ; // unreachable
+ std::unreachable();
}
- return EXIT_SUCCESS; // unreachable
}
diff --git a/src/fb/chfb.cpp b/src/fb/chfb.cpp
index 029d619..cfd7635 100644
--- a/src/fb/chfb.cpp
+++ b/src/fb/chfb.cpp
@@ -4,6 +4,7 @@
#include "o3d/vertex_data.h"
using namespace engine::fb;
+using engine::math::Vector3, engine::o3d::VertexData;
CharacterFrameBuffer::CharacterFrameBuffer(unsigned int w, unsigned int h) {
resize(w, h);
@@ -16,29 +17,15 @@ void CharacterFrameBuffer::resize(unsigned int w, unsigned int h) {
clear();
}
-unsigned int CharacterFrameBuffer::width() const {
- return w;
-}
-
-unsigned int CharacterFrameBuffer::height() const {
- return h;
-}
-
-const char* CharacterFrameBuffer::chars() const {
- return chars_vector.data();
-}
-
void CharacterFrameBuffer::clear() {
std::fill(chars_vector.begin(), chars_vector.end(), ' ');
}
-void CharacterFrameBuffer::draw_point(int x, int y, engine::math::Vector3 loc, const engine::o3d::VertexData& vd) {
+void CharacterFrameBuffer::draw_point(int x, int y, const Vector3& loc, const VertexData& vd, const engine::math::Vector3& normal) {
+ (void) x;
+ (void) y;
(void) loc;
(void) vd;
- chars_vector[x + y * w] = face_char(0);
-}
-
-char CharacterFrameBuffer::face_char(int face_ind) const {
- int n = 1 + face_ind / 2;
- return (n < 10 ? '0' : 'A' - 10) + n;
+ (void) normal;
+ chars_vector[x + y * w] = 'A';
}
diff --git a/src/fb/chfb.h b/src/fb/chfb.h
index 280f6d8..7c786fc 100644
--- a/src/fb/chfb.h
+++ b/src/fb/chfb.h
@@ -2,25 +2,35 @@
#define FB_CHFB_H
#include <vector>
-#include "fb/fb.h"
+#include "math/vector.h"
+#include "o3d/vertex_data.h"
namespace engine::fb {
-class CharacterFrameBuffer : public FrameBuffer {
+using engine::math::Vector3, engine::o3d::VertexData;
+
+class CharacterFrameBuffer {
public:
CharacterFrameBuffer(unsigned int w, unsigned int h);
void resize(unsigned int w, unsigned int h);
- unsigned int width() const;
- unsigned int height() const;
- const char* chars() const;
void clear();
- void draw_point(int x, int y, engine::math::Vector3 loc, const engine::o3d::VertexData& vd);
+ void draw_point(int x, int y, const engine::math::Vector3& loc, const engine::o3d::VertexData& vd, const engine::math::Vector3& normal);
+
+ constexpr unsigned int width() const & {
+ return w;
+ }
+
+ constexpr unsigned int height() const & {
+ return h;
+ }
+
+ constexpr const char* chars() const & {
+ return chars_vector.data();
+ }
private:
unsigned int w, h;
std::vector<char> chars_vector;
-
- char face_char(int face_inf) const;
};
}
diff --git a/src/fb/fb.h b/src/fb/fb.h
deleted file mode 100644
index 04b13ee..0000000
--- a/src/fb/fb.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#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 10f2d02..a8d6bee 100644
--- a/src/fb/pixfb.cpp
+++ b/src/fb/pixfb.cpp
@@ -2,9 +2,11 @@
#include <cstdint>
#include <algorithm>
#include "math/vector.h"
+#include "math/quat.h"
#include "o3d/vertex_data.h"
using namespace engine::fb;
+using engine::math::Vector3, engine::o3d::VertexData;
PixelFrameBuffer::PixelFrameBuffer(unsigned int w, unsigned int h) {
resize(w, h);
@@ -17,30 +19,20 @@ void PixelFrameBuffer::resize(unsigned int w, unsigned int h) {
clear();
}
-unsigned int PixelFrameBuffer::width() const {
- return w;
-}
-
-unsigned int PixelFrameBuffer::height() const {
- return h;
-}
-
-const uint32_t* PixelFrameBuffer::pixels() const {
- return pixels_vector.data();
-}
-
void PixelFrameBuffer::clear() {
std::fill(pixels_vector.begin(), pixels_vector.end(), 0x000000FF);
}
-void PixelFrameBuffer::draw_point(int x, int y, engine::math::Vector3 loc, const engine::o3d::VertexData& vd) {
- (void) loc;
- int ir = ((int) (((float) ((int) (vd.tx * 10.f))) * 25.5f));
- int ig = ((int) (((float) ((int) (vd.ty * 10.f))) * 25.5f));
- pixels_vector[x + y * w] = (ir << 24) | (ig << 16) | 0xFFFF;
-}
+extern engine::math::Quaternion camera_quat;
-uint32_t PixelFrameBuffer::face_color(int face_ind) const {
- int n = face_ind / 2;
- return ((n % 2 ? 0xFF000000 : 0x55000000) >> ((n % 6) / 2 * 8)) | 0xFF;
+void PixelFrameBuffer::draw_point(int x, int y, const Vector3& loc, const VertexData& vd, const Vector3& normal) {
+ (void) loc;
+ (void) vd;
+ // int ir = ((int) (((float) ((int) (vd.tx * 10.f))) * 25.5f));
+ // int ig = ((int) (((float) ((int) (vd.ty * 10.f))) * 25.5f));
+ // pixels_vector[x + y * w] = (ir << 24) | (ig << 16) | 0xFFFF;
+ auto v = normal.rot(camera_quat.conjugate());
+ float light = .1f + (v.z < 0.f ? 0.f : v.z) * .9f;
+ std::uint32_t c = (int) (light * 255.f);
+ pixels_vector[x + y * w] = c << 24 | c << 16 | c << 8 | 0xff;
}
diff --git a/src/fb/pixfb.h b/src/fb/pixfb.h
index 84bce2c..81a7ac3 100644
--- a/src/fb/pixfb.h
+++ b/src/fb/pixfb.h
@@ -3,26 +3,36 @@
#include <vector>
#include <cstdint>
-#include "fb/fb.h"
+#include "math/vector.h"
+#include "o3d/vertex_data.h"
namespace engine::fb {
-class PixelFrameBuffer : public FrameBuffer {
+using engine::math::Vector3, engine::o3d::VertexData;
+
+class PixelFrameBuffer {
public:
PixelFrameBuffer(unsigned int w, unsigned int h);
void resize(unsigned int w, unsigned int h);
- unsigned int width() const;
- unsigned int height() const;
- const uint32_t* pixels() const;
void clear();
- void draw_point(int x, int y, engine::math::Vector3 loc, const engine::o3d::VertexData& vd);
+ void draw_point(int x, int y, const Vector3& loc, const VertexData& vd, const Vector3& normal);
+
+ constexpr unsigned int width() const & {
+ return w;
+ }
+
+ constexpr unsigned int height() const & {
+ return h;
+ }
+
+ constexpr const uint32_t* pixels() const & {
+ return pixels_vector.data();
+ }
private:
unsigned int w, h;
std::vector<uint32_t> pixels_vector;
int face_ind;
-
- uint32_t face_color(int face_ind) const;
};
}
diff --git a/src/math/mat4.cpp b/src/math/mat4.cpp
deleted file mode 100644
index b9dff15..0000000
--- a/src/math/mat4.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-#include "math/mat4.h"
-#include <array>
-#include <cmath>
-#include "math/vector.h"
-
-using namespace engine::math;
-
-Matrix4 Matrix4::idty() {
- return {
- 1.f, 0.f, 0.f, 0.f,
- 0.f, 1.f, 0.f, 0.f,
- 0.f, 0.f, 1.f, 0.f,
- 0.f, 0.f, 0.f, 1.f,
- };
-}
-
-Matrix4 Matrix4::translate(Vector3 v) {
- return {
- 1.f, 0.f, 0.f, v.x,
- 0.f, 1.f, 0.f, v.y,
- 0.f, 0.f, 1.f, v.z,
- 0.f, 0.f, 0.f, 1.f,
- };
-}
-
-Matrix4 Matrix4::scale(float fac) {
- return {
- fac, 0.f, 0.f, 0.f,
- 0.f, fac, 0.f, 0.f,
- 0.f, 0.f, fac, 0.f,
- 0.f, 0.f, 0.f, 1.f,
- };
-}
-
-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);
- return {
- 1.f, 0.f, 0.f, 0.f,
- 0.f, c, -s, 0.f,
- 0.f, s, c, 0.f,
- 0.f, 0.f, 0.f, 1.f,
- };
-}
-
-Matrix4 Matrix4::rot_y(float a) {
- float c = std::cos(a);
- float s = std::sin(a);
- return {
- c, 0.f, s, 0.f,
- 0.f, 1.f, 0.f, 0.f,
- -s, 0.f, c, 0.f,
- 0.f, 0.f, 0.f, 1.f,
- };
-}
-
-Matrix4 Matrix4::rot_z(float a) {
- float c = std::cos(a);
- float s = std::sin(a);
- return {
- c, -s, 0.f, 0.f,
- s, c, 0.f, 0.f,
- 0.f, 0.f, 1.f, 0.f,
- 0.f, 0.f, 0.f, 1.f,
- };
-}
-
-Matrix4 Matrix4::projection(float aspect_ratio, float min_z, float max_z) {
- return {{
- aspect_ratio, 0.f, 0.f, 0.f,
- 0.f, -1.f, 0.f, 0.f,
- 0.f, 0.f, -2.f / (max_z - min_z), -(max_z + min_z) / (max_z - min_z),
- 0.f, 0.f, -1.f, 0.f,
- }};
-}
-
-Matrix4 Matrix4::operator+() const {
- return *this;
-}
-
-Matrix4 Matrix4::operator-() const {
- return {
- -values[ 0], -values[ 1], -values[ 2], -values[ 3],
- -values[ 4], -values[ 5], -values[ 6], -values[ 7],
- -values[ 8], -values[ 9], -values[10], -values[11],
- -values[12], -values[13], -values[14], -values[15],
- };
-}
-
-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],
- values[ 8] + m.values[ 8], values[ 9] + m.values[ 9], values[10] + m.values[10], values[11] + m.values[11],
- values[12] + m.values[12], values[13] + m.values[13], values[14] + m.values[14], values[15] + m.values[15],
- };
-}
-
-Matrix4 Matrix4::operator-(Matrix4 m) const {
- return *this + (-m);
-}
-
-Matrix4 Matrix4::operator*(Matrix4 m) const {
- Matrix4 ret;
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- ret.values[i * 4 + j] = 0.f;
- for (int k = 0; k < 4; k++)
- ret.values[i * 4 + j] += values[i * 4 + k] * m.values[k * 4 + j];
- }
- }
- return ret;
-}
-
-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,
- values[ 8] * v.x + values[ 9] * v.y + values[10] * v.z + values[11] * v.w,
- values[12] * v.x + values[13] * v.y + values[14] * v.z + values[15] * v.w,
- };
-}
-
-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] },
- { values[ 2], values[ 6], values[10], values[14] },
- { values[ 3], values[ 7], values[11], values[15] },
- }};
-}
-
-Matrix4 engine::math::operator*(float fac, Matrix4 m) {
- return {
- fac * m.values[ 0], fac * m.values[ 1], fac * m.values[ 2], fac * m.values[ 3],
- fac * m.values[ 4], fac * m.values[ 5], fac * m.values[ 6], fac * m.values[ 7],
- fac * m.values[ 8], fac * m.values[ 9], fac * m.values[10], fac * m.values[11],
- fac * m.values[12], fac * m.values[13], fac * m.values[14], fac * m.values[15],
- };
-}
diff --git a/src/math/mat4.h b/src/math/mat4.h
index 35b1ad2..adb2059 100644
--- a/src/math/mat4.h
+++ b/src/math/mat4.h
@@ -2,33 +2,157 @@
#define MATH_MAT4_H
#include <array>
+#include <cmath>
#include "math/vector.h"
namespace engine::math {
-class Matrix4 {
- public:
- 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);
- static Matrix4 projection(float aspect_ratio, float min_z, float max_z);
-
- std::array<float, 16> values;
-
- 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;
+struct Matrix4 {
+ static constexpr Matrix4 idty() {
+ return {
+ 1.f, 0.f, 0.f, 0.f,
+ 0.f, 1.f, 0.f, 0.f,
+ 0.f, 0.f, 1.f, 0.f,
+ 0.f, 0.f, 0.f, 1.f,
+ };
+ }
+
+ static constexpr Matrix4 translate(const Vector3& v) {
+ return {
+ 1.f, 0.f, 0.f, v.x,
+ 0.f, 1.f, 0.f, v.y,
+ 0.f, 0.f, 1.f, v.z,
+ 0.f, 0.f, 0.f, 1.f,
+ };
+ }
+
+ static constexpr Matrix4 scale(float fac) {
+ return {
+ fac, 0.f, 0.f, 0.f,
+ 0.f, fac, 0.f, 0.f,
+ 0.f, 0.f, fac, 0.f,
+ 0.f, 0.f, 0.f, 1.f,
+ };
+ }
+
+ static constexpr Matrix4 scale(const 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,
+ };
+ }
+
+ static constexpr Matrix4 rot_x(float a) {
+ float c = std::cos(a);
+ float s = std::sin(a);
+ return {
+ 1.f, 0.f, 0.f, 0.f,
+ 0.f, c, -s, 0.f,
+ 0.f, s, c, 0.f,
+ 0.f, 0.f, 0.f, 1.f,
+ };
+ }
+
+ static constexpr Matrix4 rot_y(float a) {
+ float c = std::cos(a);
+ float s = std::sin(a);
+ return {
+ c, 0.f, s, 0.f,
+ 0.f, 1.f, 0.f, 0.f,
+ -s, 0.f, c, 0.f,
+ 0.f, 0.f, 0.f, 1.f,
+ };
+ }
+
+ static constexpr Matrix4 rot_z(float a) {
+ float c = std::cos(a);
+ float s = std::sin(a);
+ return {
+ c, -s, 0.f, 0.f,
+ s, c, 0.f, 0.f,
+ 0.f, 0.f, 1.f, 0.f,
+ 0.f, 0.f, 0.f, 1.f,
+ };
+ }
+
+ static constexpr Matrix4 projection(float aspect_ratio, float min_z, float max_z) {
+ return {{
+ aspect_ratio, 0.f, 0.f, 0.f,
+ 0.f, -1.f, 0.f, 0.f,
+ 0.f, 0.f, -2.f / (max_z - min_z), -(max_z + min_z) / (max_z - min_z),
+ 0.f, 0.f, -1.f, 0.f,
+ }};
+ }
+
+ std::array<float, 4 * 4> values;
+
+ constexpr Matrix4 operator+() const & {
+ return *this;
+ }
+
+ constexpr Matrix4 operator-() const & {
+ return {
+ -values[ 0], -values[ 1], -values[ 2], -values[ 3],
+ -values[ 4], -values[ 5], -values[ 6], -values[ 7],
+ -values[ 8], -values[ 9], -values[10], -values[11],
+ -values[12], -values[13], -values[14], -values[15],
+ };
+ }
+
+ constexpr Matrix4 operator+(const 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],
+ values[ 8] + m.values[ 8], values[ 9] + m.values[ 9], values[10] + m.values[10], values[11] + m.values[11],
+ values[12] + m.values[12], values[13] + m.values[13], values[14] + m.values[14], values[15] + m.values[15],
+ };
+ }
+
+ constexpr Matrix4 operator-(const Matrix4& m) const & {
+ return *this + (-m);
+ }
+
+ constexpr Matrix4 operator*(const Matrix4& m) const & {
+ Matrix4 ret;
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ ret.values[i * 4 + j] = 0.f;
+ for (int k = 0; k < 4; k++)
+ ret.values[i * 4 + j] += values[i * 4 + k] * m.values[k * 4 + j];
+ }
+ }
+ return ret;
+ }
+
+ constexpr Vector4 operator*(const 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,
+ values[ 8] * v.x + values[ 9] * v.y + values[10] * v.z + values[11] * v.w,
+ values[12] * v.x + values[13] * v.y + values[14] * v.z + values[15] * v.w,
+ };
+ }
+
+ constexpr std::array<Vector4, 4> to_vecs() const & {
+ return {{
+ { values[ 0], values[ 4], values[ 8], values[12] },
+ { values[ 1], values[ 5], values[ 9], values[13] },
+ { values[ 2], values[ 6], values[10], values[14] },
+ { values[ 3], values[ 7], values[11], values[15] },
+ }};
+ }
};
-Matrix4 operator*(float fac, Matrix4 m);
+constexpr Matrix4 operator*(float fac, const Matrix4& m) {
+ return {
+ fac * m.values[ 0], fac * m.values[ 1], fac * m.values[ 2], fac * m.values[ 3],
+ fac * m.values[ 4], fac * m.values[ 5], fac * m.values[ 6], fac * m.values[ 7],
+ fac * m.values[ 8], fac * m.values[ 9], fac * m.values[10], fac * m.values[11],
+ fac * m.values[12], fac * m.values[13], fac * m.values[14], fac * m.values[15],
+ };
+}
}
diff --git a/src/math/quat.h b/src/math/quat.h
new file mode 100644
index 0000000..763253b
--- /dev/null
+++ b/src/math/quat.h
@@ -0,0 +1,74 @@
+#ifndef MATH_QUAT_H
+#define MATH_QUAT_H
+
+#include <cmath>
+
+namespace engine::math {
+
+struct Quaternion {
+ static constexpr Quaternion zero() {
+ return {0.f, 0.f, 0.f, 0.f};
+ }
+
+ static constexpr Quaternion one() {
+ return {1.f, 0.f, 0.f, 0.f};
+ }
+
+ static constexpr Quaternion euler_zyx(float a, float b, float c) {
+ float ca = std::cos(a / 2.f), sa = std::sin(a / 2.f),
+ cb = std::cos(b / 2.f), sb = std::sin(b / 2.f),
+ cc = std::cos(c / 2.f), sc = std::sin(c / 2.f);
+ return {
+ ca * cb * cc - sa * sb * sc,
+ sa * cb * cc + ca * sb * sc,
+ ca * sb * cc - sa * cb * sc,
+ ca * cb * sc + sa * sb * cc,
+ };
+ }
+
+ float w, x, y, z;
+
+ constexpr Quaternion() {}
+ constexpr Quaternion(float w, float x, float y, float z) : w{w}, x{x}, y{y}, z{z} {}
+
+ constexpr bool operator==(const Quaternion& other) const & {
+ return w == other.w && x == other.x && y == other.y && z == other.z;
+ }
+
+ constexpr bool operator!=(const Quaternion& other) const & {
+ return !(*this == other);
+ }
+
+ constexpr Quaternion operator+() const & {
+ return *this;
+ }
+
+ constexpr Quaternion operator-() const & {
+ return { -w, -x, -y, -z };
+ }
+
+ constexpr Quaternion operator+(const Quaternion& other) const & {
+ return { w + other.w, x + other.x, y + other.y, z + other.z };
+ }
+
+ constexpr Quaternion operator-(const Quaternion& other) const & {
+ return *this + (-other);
+ }
+
+ constexpr Quaternion operator*(const Quaternion& other) const & {
+ return {
+ w * other.w - x * other.x - y * other.y - z * other.z,
+ w * other.x + x * other.w + y * other.z - z * other.y,
+ w * other.y + y * other.w + z * other.x - x * other.z,
+ w * other.z + z * other.w + x * other.y - y * other.x,
+ };
+ }
+
+ constexpr Quaternion conjugate() const & {
+ return {w, -x, -y, -z};
+ }
+};
+
+}
+
+#endif // MATH_QUAT_H
diff --git a/src/math/tform.h b/src/math/tform.h
new file mode 100644
index 0000000..2d61494
--- /dev/null
+++ b/src/math/tform.h
@@ -0,0 +1,35 @@
+#ifndef MATH_TFORM_H
+#define MATH_TFORM_H
+
+#include "math/vector.h"
+#include "math/mat4.h"
+#include "math/quat.h"
+
+namespace engine::math {
+
+class Transform {
+ public:
+ Vector3 loc;
+ Quaternion rot;
+ Vector3 scale;
+
+ constexpr Transform(Vector3 loc, Quaternion rot, Vector3 scale) : loc{loc}, rot{rot}, scale{scale} {
+ }
+
+ constexpr Transform opposite() const & {
+ return {-loc, rot.conjugate(), 1.f / scale};
+ }
+
+ constexpr Matrix4 to_mat4() const & {
+ return {
+ scale.x * (2.f * (rot.w * rot.w + rot.x * rot.x) - 1.f), scale.y * (2.f * (rot.x * rot.y - rot.w * rot.z) ), scale.z * (2.f * (rot.x * rot.z + rot.w * rot.y) ), loc.x,
+ scale.x * (2.f * (rot.x * rot.y + rot.w * rot.z) ), scale.y * (2.f * (rot.w * rot.w + rot.y * rot.y) - 1.f), scale.z * (2.f * (rot.y * rot.z - rot.w * rot.x) ), loc.y,
+ scale.x * (2.f * (rot.x * rot.z - rot.w * rot.y) ), scale.y * (2.f * (rot.y * rot.z + rot.w * rot.x) ), scale.z * (2.f * (rot.w * rot.w + rot.z * rot.z) - 1.f), loc.z,
+ 0.f, 0.f, 0.f, 1.f,
+ };
+ }
+};
+
+}
+
+#endif // MATH_TFORM_H
diff --git a/src/math/vector.cpp b/src/math/vector.cpp
deleted file mode 100644
index 306fc3d..0000000
--- a/src/math/vector.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-#include "math/vector.h"
-#include <cmath>
-
-using namespace engine::math;
-
-Vector2::Vector2() {
-}
-
-Vector2::Vector2(float x, float y) : x{x}, y{y} {
-}
-
-bool Vector2::operator==(Vector2 other) const {
- return x == other.x && y == other.y;
-}
-
-bool Vector2::operator!=(Vector2 other) const {
- return !(*this == other);
-}
-
-Vector2 Vector2::operator+() const {
- return *this;
-}
-
-Vector2 Vector2::operator-() const {
- return { -x, -y };
-}
-
-Vector2 Vector2::operator+(Vector2 other) const {
- return { x + other.x, y + other.y };
-}
-
-Vector2 Vector2::operator-(Vector2 other) const {
- return *this + (-other);
-}
-
-float Vector2::det(Vector2 other) const {
- return this->x * other.y - other.x * this->y;
-}
-
-Vector2 Vector2::round() const {
- return { std::round(x), std::round(y) };
-}
-
-Vector2 engine::math::operator*(float n, Vector2 other) {
- return { n * other.x, n * other.y };
-}
-
-Vector2 engine::math::operator*(Vector2 other, float n) {
- return n * other;
-}
-
-Vector2 engine::math::operator/(Vector2 other, float n) {
- return { other.x / n, other.y / n };
-}
-
-Vector3::Vector3() {
-}
-
-Vector3::Vector3(float x, float y, float z) : x{x}, y{y}, z{z} {
-}
-
-bool Vector3::operator==(Vector3 other) const {
- return x == other.x && y == other.y && z == other.z;
-}
-
-bool Vector3::operator!=(Vector3 other) const {
- return !(*this == other);
-}
-
-Vector3 Vector3::operator+() const {
- return *this;
-}
-
-Vector3 Vector3::operator-() const {
- return { -x, -y, -z };
-}
-
-Vector3 Vector3::operator+(Vector3 other) const {
- return { x + other.x, y + other.y, z + other.z };
-}
-
-Vector3 Vector3::operator-(Vector3 other) const {
- return *this + (-other);
-}
-
-Vector3 Vector3::round() const {
- return { std::round(x), std::round(y), std::round(z) };
-}
-
-Vector3 Vector3::cross(Vector3 other) const {
- return {
- y * other.z - z * other.y,
- z * other.x - x * other.z,
- x * other.y - y * other.x
- };
-}
-
-Vector3 engine::math::operator*(float n, Vector3 other) {
- return { n * other.x, n * other.y, n * other.z };
-}
-
-Vector3 engine::math::operator*(Vector3 other, float n) {
- return n * other;
-}
-
-Vector3 engine::math::operator/(Vector3 other, float n) {
- return { other.x / n, other.y / n, other.z / n };
-}
-
-Vector4::Vector4() {
-}
-
-Vector4::Vector4(float x, float y, float z, float w) : x{x}, y{y}, z{z}, w{w} {
-}
-
-Vector4::Vector4(float x, float y, float z) : x{x}, y{y}, z{z}, w{1.f} {
-}
-
-Vector4::Vector4(Vector3 v, float w) : x{v.x}, y{v.y}, z{v.z}, w{w} {
-}
-
-Vector4::Vector4(Vector3 v) : x{v.x}, y{v.y}, z{v.z}, w{1.f} {
-}
-
-bool Vector4::operator==(Vector4 other) const {
- return x == other.x && y == other.y && z == other.z && w == other.w;
-}
-
-bool Vector4::operator!=(Vector4 other) const {
- return !(*this == other);
-}
-
-Vector4 Vector4::operator+() const {
- return *this;
-}
-
-Vector4 Vector4::operator-() const {
- return { -x, -y, -z, -w };
-}
-
-Vector4 Vector4::operator+(Vector4 other) const {
- return { x + other.x, y + other.y, z + other.z, w + other.w };
-}
-
-Vector4 Vector4::operator-(Vector4 other) const {
- return *this + (-other);
-}
-
-Vector4 Vector4::round() const {
- return { std::round(x), std::round(y), std::round(z), std::round(w) };
-}
-
-Vector2 Vector4::xy() const {
- return { x, y };
-}
-
-Vector3 Vector4::xyz() const {
- return { x, y, z };
-}
-
-Vector4 Vector4::div_by_w() const {
- return {x / w, y / w, z / w, w};
-}
-
-Vector4 engine::math::operator*(float n, Vector4 other) {
- return { n * other.x, n * other.y, n * other.z, n * other.w };
-}
-
-Vector4 engine::math::operator*(Vector4 other, float n) {
- return n * other;
-}
-
-Vector4 engine::math::operator/(Vector4 other, float n) {
- return { other.x / n, other.y / n, other.z / n, other.w / n };
-}
diff --git a/src/math/vector.h b/src/math/vector.h
index 82e1513..b26c5fe 100644
--- a/src/math/vector.h
+++ b/src/math/vector.h
@@ -1,72 +1,222 @@
#ifndef MATH_VECTOR_H
#define MATH_VECTOR_H
+#include <cmath>
+#include "math/quat.h"
+
namespace engine::math {
-class Vector2 {
- public:
- float x, y;
-
- Vector2();
- Vector2(float x, float y);
- bool operator==(Vector2 other) const;
- bool operator!=(Vector2 other) const;
- Vector2 operator+() const;
- Vector2 operator-() const;
- Vector2 operator+(Vector2 other) const;
- Vector2 operator-(Vector2 other) const;
- float det(Vector2 other) const;
- Vector2 round() const;
+struct Vector2 {
+ float x, y;
+
+ constexpr bool operator==(const Vector2& other) const & {
+ return x == other.x && y == other.y;
+ }
+
+ constexpr bool operator!=(const Vector2& other) const & {
+ return !(*this == other);
+ }
+
+ constexpr Vector2 operator+() const & {
+ return *this;
+ }
+
+ constexpr Vector2 operator-() const & {
+ return { -x, -y };
+ }
+
+ constexpr Vector2 operator+(const Vector2& other) const & {
+ return { x + other.x, y + other.y };
+ }
+
+ constexpr Vector2 operator-(const Vector2& other) const & {
+ return *this + (-other);
+ }
+
+ constexpr float det(const Vector2& other) const & {
+ return this->x * other.y - other.x * this->y;
+ }
+
+ constexpr Vector2 round() const & {
+ return { std::round(x), std::round(y) };
+ }
+
+ constexpr Vector2 mul_term(const Vector2& other) const & {
+ return { x * other.x, y * other.y };
+ }
};
-Vector2 operator*(float n, Vector2 other);
-Vector2 operator*(Vector2 other, float n);
-Vector2 operator/(Vector2 other, float n);
-
-class Vector3 {
- public:
- float x, y, z;
-
- Vector3();
- Vector3(float x, float y, float z);
- bool operator==(Vector3 other) const;
- bool operator!=(Vector3 other) const;
- Vector3 operator+() const;
- Vector3 operator-() const;
- Vector3 operator+(Vector3 other) const;
- Vector3 operator-(Vector3 other) const;
- Vector3 round() const;
- Vector3 cross(Vector3 other) const;
+constexpr Vector2 operator*(float n, const Vector2& other) {
+ return { n * other.x, n * other.y };
+}
+
+constexpr Vector2 operator*(const Vector2& other, float n) {
+ return n * other;
+}
+
+constexpr Vector2 operator/(const Vector2& other, float n) {
+ return { other.x / n, other.y / n };
+}
+
+constexpr Vector2 operator+(const Vector2& other, float n) {
+ return { other.x + n, other.y + n };
+}
+
+constexpr Vector2 operator-(const Vector2& other, float n) {
+ return { other.x - n, other.y - n };
+}
+
+struct Vector3;
+constexpr Vector3 operator*(float n, const Vector3& other);
+constexpr Vector3 operator/(const Vector3& other, float n);
+
+struct Vector3 {
+ static constexpr Vector3 bilerp(const Vector3& v1, const Vector3& v2, const Vector3& v3, float b0, float b1) {
+ return b0 * v1 + b1 * v2 + (1.f - b0 - b1) * v3;
+ }
+
+ float x, y, z;
+
+ constexpr bool operator==(const Vector3& other) const & {
+ return x == other.x && y == other.y && z == other.z;
+ }
+
+ constexpr bool operator!=(const Vector3& other) const & {
+ return !(*this == other);
+ }
+
+ constexpr Vector3 operator+() const & {
+ return *this;
+ }
+
+ constexpr Vector3 operator-() const & {
+ return { -x, -y, -z };
+ }
+
+ constexpr Vector3 operator+(const Vector3& other) const & {
+ return { x + other.x, y + other.y, z + other.z };
+ }
+
+ constexpr Vector3 operator-(const Vector3& other) const & {
+ return *this + (-other);
+ }
+
+ constexpr Vector3 round() {
+ return { std::round(x), std::round(y), std::round(z) };
+ }
+
+ constexpr Vector3 cross(const Vector3& other) const & {
+ return {
+ y * other.z - z * other.y,
+ z * other.x - x * other.z,
+ x * other.y - y * other.x
+ };
+ }
+
+ constexpr Vector3 rot(const Quaternion& q) const & {
+ return {
+ (2.f * (q.w * q.w + q.x * q.x) - 1.f) * x + (2.f * (q.x * q.y - q.w * q.z) ) * y + (2.f * (q.x * q.z + q.w * q.y) ) * z,
+ (2.f * (q.x * q.y + q.w * q.z) ) * x + (2.f * (q.w * q.w + q.y * q.y) - 1.f) * y + (2.f * (q.y * q.z - q.w * q.x) ) * z,
+ (2.f * (q.x * q.z - q.w * q.y) ) * x + (2.f * (q.y * q.z + q.w * q.x) ) * y + (2.f * (q.w * q.w + q.z * q.z) - 1.f) * z,
+ };
+ }
+
+ constexpr float dot(const Vector3& other) const & {
+ return x * other.x + y * other.y + z * other.z;
+ }
+
+ constexpr float length_squared() const & {
+ return dot(*this);
+ }
+
+ constexpr float length() const & {
+ return std::sqrt(length_squared());
+ }
+
+ constexpr Vector3 normalize() const & {
+ return *this / length();
+ }
};
-Vector3 operator*(float n, Vector3 other);
-Vector3 operator*(Vector3 other, float n);
-Vector3 operator/(Vector3 other, float n);
-
-class Vector4 {
- public:
- float x, y, z, w;
-
- Vector4();
- Vector4(float x, float y, float z, float w);
- Vector4(float x, float y, float z);
- Vector4(Vector3 v, float w);
- Vector4(Vector3 v);
- bool operator==(Vector4 other) const;
- bool operator!=(Vector4 other) const;
- Vector4 operator+() const;
- Vector4 operator-() const;
- Vector4 operator+(Vector4 other) const;
- Vector4 operator-(Vector4 other) const;
- Vector4 round() const;
- Vector2 xy() const;
- Vector3 xyz() const;
- Vector4 div_by_w() const;
+constexpr Vector3 operator*(float n, const Vector3& other) {
+ return { n * other.x, n * other.y, n * other.z };
+}
+
+constexpr Vector3 operator*(const Vector3& other, float n) {
+ return n * other;
+}
+
+constexpr Vector3 operator/(float n, const Vector3& other) {
+ return { n / other.x, n / other.y, n / other.z };
+}
+
+constexpr Vector3 operator/(const Vector3& other, float n) {
+ return { other.x / n, other.y / n, other.z / n };
+}
+
+struct Vector4 {
+ float x, y, z, w;
+
+ constexpr Vector4() {}
+ constexpr Vector4(float x, float y, float z, float w) : x{x}, y{y}, z{z}, w{w} {}
+ constexpr Vector4(float x, float y, float z) : x{x}, y{y}, z{z}, w{1.f} {}
+ constexpr Vector4(const Vector2& v, float z, float w) : x{v.x}, y{v.y}, z{z}, w{w} {}
+ constexpr Vector4(const Vector2& v, float z) : x{v.x}, y{v.y}, z{z}, w{1.f} {}
+ constexpr Vector4(const Vector3& v, float w) : x{v.x}, y{v.y}, z{v.z}, w{w} {}
+ constexpr Vector4(const Vector3& v) : x{v.x}, y{v.y}, z{v.z}, w{1.f} {}
+
+ constexpr bool operator==(const Vector4& other) const & {
+ return x == other.x && y == other.y && z == other.z && w == other.w;
+ }
+
+ constexpr bool operator!=(const Vector4& other) const & {
+ return !(*this == other);
+ }
+
+ constexpr Vector4 operator+() const & {
+ return *this;
+ }
+
+ constexpr Vector4 operator-() const & {
+ return { -x, -y, -z, -w };
+ }
+
+ constexpr Vector4 operator+(const Vector4& other) const & {
+ return { x + other.x, y + other.y, z + other.z, w + other.w };
+ }
+
+ constexpr Vector4 operator-(const Vector4& other) const & {
+ return *this + (-other);
+ }
+
+ constexpr Vector4 round() const & {
+ return { std::round(x), std::round(y), std::round(z), std::round(w) };
+ }
+
+ constexpr Vector2 xy() const & {
+ return { x, y };
+ }
+
+ constexpr Vector3 xyz() const & {
+ return { x, y, z };
+ }
+
+ constexpr Vector4 div_by_w() const & {
+ return {x / w, y / w, z / w, w};
+ }
};
-Vector4 operator*(float n, Vector4 other);
-Vector4 operator*(Vector4 other, float n);
-Vector4 operator/(Vector4 other, float n);
+constexpr Vector4 operator*(float n, const Vector4& other) {
+ return { n * other.x, n * other.y, n * other.z, n * other.w };
+}
+
+constexpr Vector4 operator*(const Vector4& other, float n) {
+ return n * other;
+}
+
+constexpr Vector4 operator/(const Vector4& other, float n) {
+ return { other.x / n, other.y / n, other.z / n, other.w / n };
+}
}
diff --git a/src/o3d/camera.cpp b/src/o3d/camera.cpp
deleted file mode 100644
index cbb3cd2..0000000
--- a/src/o3d/camera.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "o3d/camera.h"
-#include "math/vector.h"
-
-using namespace engine::o3d;
-
-Camera::Camera(engine::math::Vector3 loc, float rot_x, float rot_y, float rot_z) : loc{loc}, rot_x{rot_x}, rot_y{rot_y}, rot_z{rot_z} {
-}
diff --git a/src/o3d/camera.h b/src/o3d/camera.h
index 5d72d29..27c31eb 100644
--- a/src/o3d/camera.h
+++ b/src/o3d/camera.h
@@ -1,19 +1,12 @@
#ifndef O3D_CAMERA_H
#define O3D_CAMERA_H
-#include "math/vector.h"
+#include "math/tform.h"
namespace engine::o3d {
-class Scene;
-
-class Camera {
- public:
- Scene* scene = nullptr;
- engine::math::Vector3 loc;
- float rot_x, rot_y, rot_z; // TODO: replace by quaternions
-
- Camera(engine::math::Vector3 loc, float rot_x, float rot_y, float rot_z);
+struct Camera {
+ engine::math::Transform transform;
};
}
diff --git a/src/o3d/deriv_vertex.cpp b/src/o3d/deriv_vertex.cpp
deleted file mode 100644
index 7123b1c..0000000
--- a/src/o3d/deriv_vertex.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "o3d/deriv_vertex.h"
-#include "math/vector.h"
-
-using namespace engine::o3d;
-
-DerivedVertex::DerivedVertex(engine::math::Vector4 vertex, float b0, float b1) : vertex{vertex}, b0{b0}, b1{b1} {
-}
-
-DerivedVertex DerivedVertex::div_by_w() const {
- return {vertex.div_by_w(), b0, b1};
-}
diff --git a/src/o3d/deriv_vertex.h b/src/o3d/deriv_vertex.h
index 7524f9b..c435a7e 100644
--- a/src/o3d/deriv_vertex.h
+++ b/src/o3d/deriv_vertex.h
@@ -5,13 +5,15 @@
namespace engine::o3d {
-class DerivedVertex {
- public:
- engine::math::Vector4 vertex;
- float b0, b1;
+using engine::math::Vector4;
- DerivedVertex(engine::math::Vector4 vertex, float b0, float b1);
- DerivedVertex div_by_w() const;
+struct DerivedVertex {
+ Vector4 vertex;
+ float b0, b1;
+
+ constexpr DerivedVertex div_by_w() const & {
+ return {vertex.div_by_w(), b0, b1};
+ }
};
}
diff --git a/src/o3d/mesh.cpp b/src/o3d/mesh.cpp
index 2dba328..60c7f8b 100644
--- a/src/o3d/mesh.cpp
+++ b/src/o3d/mesh.cpp
@@ -6,29 +6,6 @@
using namespace engine::o3d;
-// Mesh Mesh::cube() {
-// return {
-// {
-// { engine::math::Vector3(-1.f, -1.f, -1.f), {} },
-// { engine::math::Vector3(+1.f, -1.f, -1.f), {} },
-// { engine::math::Vector3(-1.f, +1.f, -1.f), {} },
-// { engine::math::Vector3(+1.f, +1.f, -1.f), {} },
-// { engine::math::Vector3(-1.f, -1.f, +1.f), {} },
-// { engine::math::Vector3(+1.f, -1.f, +1.f), {} },
-// { engine::math::Vector3(-1.f, +1.f, +1.f), {} },
-// { engine::math::Vector3(+1.f, +1.f, +1.f), {} },
-// },
-// {
-// { 0, 2, 3 }, { 0, 3, 1 }, // face 1
-// { 0, 4, 6 }, { 0, 6, 2 }, // face 2
-// { 0, 1, 5 }, { 0, 5, 4 }, // face 3
-// { 7, 6, 4 }, { 7, 4, 5 }, // face 4
-// { 7, 3, 2 }, { 7, 2, 6 }, // face 5
-// { 7, 5, 1 }, { 7, 1, 3 }, // face 6
-// }
-// };
-// }
-
Mesh Mesh::plane() {
return {
{
@@ -52,10 +29,3 @@ Mesh Mesh::plane() {
}
};
}
-
-Mesh::Mesh(std::vector<engine::math::Vector4> vertices,
- std::vector<engine::math::Vector3> normals,
- std::vector<VertexData> vertices_data,
- std::vector<std::array<std::array<std::size_t, 3>, 3>> indices)
- : vertices{vertices}, normals{normals}, vertices_data{vertices_data}, indices{indices} {
-}
diff --git a/src/o3d/mesh.h b/src/o3d/mesh.h
index 4aad0e4..1c70ca4 100644
--- a/src/o3d/mesh.h
+++ b/src/o3d/mesh.h
@@ -10,20 +10,15 @@
namespace engine::o3d {
-class Mesh {
- public:
-// static Mesh cube(); // this function should not be in this file
- static Mesh plane(); // this function should not be in this file
+using engine::math::Vector3, engine::math::Vector4;
- std::vector<engine::math::Vector4> vertices;
- std::vector<engine::math::Vector3> normals;
- std::vector<VertexData> vertices_data;
- std::vector<std::array<std::array<std::size_t, 3>, 3>> indices;
+struct Mesh {
+ static Mesh plane();
- Mesh(std::vector<engine::math::Vector4> vertices,
- std::vector<engine::math::Vector3> normals,
- std::vector<VertexData> vertices_data,
- std::vector<std::array<std::array<std::size_t, 3>, 3>> indices);
+ std::vector<Vector4> vertices;
+ std::vector<Vector3> normals;
+ std::vector<VertexData> vertices_data;
+ std::vector<std::array<std::array<std::size_t, 3>, 3>> indices;
};
}
diff --git a/src/o3d/obj3d.cpp b/src/o3d/obj3d.cpp
deleted file mode 100644
index 71fdf7d..0000000
--- a/src/o3d/obj3d.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#include "o3d/obj3d.h"
-#include "math/vector.h"
-#include "o3d/mesh.h"
-
-using namespace engine::o3d;
-
-Object3D::Object3D(Mesh mesh, engine::math::Vector3 loc, float scale, float rot_x, float rot_y, float rot_z)
- : mesh{mesh}, loc{loc}, scale{scale}, rot_x{rot_x}, rot_y{rot_y}, rot_z{rot_z} {
-}
diff --git a/src/o3d/obj3d.h b/src/o3d/obj3d.h
index 250b6bc..9f407f9 100644
--- a/src/o3d/obj3d.h
+++ b/src/o3d/obj3d.h
@@ -1,22 +1,15 @@
#ifndef O3D_OBJ3D_H
#define O3D_OBJ3D_H
-#include "math/vector.h"
+#include <type_traits>
+#include "math/tform.h"
#include "o3d/mesh.h"
namespace engine::o3d {
-class Scene;
-
-class Object3D {
- public:
- Scene* scene = nullptr;
- Mesh mesh;
- engine::math::Vector3 loc;
- float scale;
- float rot_x, rot_y, rot_z;
-
- Object3D(Mesh mesh, engine::math::Vector3 loc, float scale, float rot_x, float rot_y, float rot_z);
+struct Object3D {
+ Mesh mesh;
+ math::Transform transform;
};
}
diff --git a/src/o3d/scene.cpp b/src/o3d/scene.cpp
deleted file mode 100644
index 50f83be..0000000
--- a/src/o3d/scene.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "o3d/scene.h"
-#include <vector>
-#include "o3d/camera.h"
-#include "o3d/obj3d.h"
-
-using namespace engine::o3d;
-
-Scene::Scene(Camera camera, std::vector<Object3D> objs) : camera{camera}, objs{objs} {
- this->camera.scene = this;
- for (auto& obj : this->objs)
- obj.scene = this;
-}
diff --git a/src/o3d/scene.h b/src/o3d/scene.h
index 3759cfb..3b9131c 100644
--- a/src/o3d/scene.h
+++ b/src/o3d/scene.h
@@ -2,17 +2,15 @@
#define O3D_SCENE_H
#include <vector>
+#include <type_traits>
#include "o3d/obj3d.h"
#include "o3d/camera.h"
namespace engine::o3d {
-class Scene {
- public:
- Camera camera;
- std::vector<Object3D> objs;
-
- Scene(Camera camera, std::vector<Object3D> objs);
+struct Scene {
+ Camera camera;
+ std::vector<Object3D> objs;
};
}
diff --git a/src/o3d/tri.cpp b/src/o3d/tri.cpp
deleted file mode 100644
index 73410bf..0000000
--- a/src/o3d/tri.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "o3d/tri.h"
-#include <vector>
-#include "math/vector.h"
-#include "o3d/vertex_data.h"
-#include "o3d/deriv_vertex.h"
-#include "o3d/vertex.h"
-#include "o3d/tri_deriv.h"
-
-using namespace engine::o3d;
-
-Triangle::Triangle(Vertex vertex1, Vertex vertex2, Vertex vertex3) : vertex1{vertex1}, vertex2{vertex2}, vertex3{vertex3} {
-}
-
-TriangleDerived Triangle::to_derived() const {
- return {{vertex1.vertex, 1.f, 0.f}, {vertex2.vertex, 0.f, 1.f}, {vertex3.vertex, 0.f, 0.f}};
-}
diff --git a/src/o3d/tri.h b/src/o3d/tri.h
index 7fa37fe..4b50f91 100644
--- a/src/o3d/tri.h
+++ b/src/o3d/tri.h
@@ -3,19 +3,18 @@
#include <vector>
#include "o3d/vertex.h"
-#include "o3d/tri.h"
#include "o3d/tri_deriv.h"
namespace engine::o3d {
-class Triangle {
- public:
- Vertex vertex1;
- Vertex vertex2;
- Vertex vertex3;
+struct Triangle {
+ Vertex vertex1;
+ Vertex vertex2;
+ Vertex vertex3;
- Triangle(Vertex vertex1, Vertex vertex2, Vertex vertex3);
- TriangleDerived to_derived() const;
+ constexpr TriangleDerived to_derived() const & {
+ return {{vertex1.vertex, 1.f, 0.f}, {vertex2.vertex, 0.f, 1.f}, {vertex3.vertex, 0.f, 0.f}};
+ }
};
}
diff --git a/src/o3d/tri_deriv.cpp b/src/o3d/tri_deriv.cpp
index 81f60a0..b4184bc 100644
--- a/src/o3d/tri_deriv.cpp
+++ b/src/o3d/tri_deriv.cpp
@@ -5,10 +5,6 @@
using namespace engine::o3d;
-TriangleDerived::TriangleDerived(DerivedVertex derived_vertex1, DerivedVertex derived_vertex2, DerivedVertex derived_vertex3)
- : derived_vertex1{derived_vertex1}, derived_vertex2{derived_vertex2}, derived_vertex3{derived_vertex3} {
-}
-
#define P1_OUT 1
#define P2_OUT 2
#define P3_OUT 4
@@ -315,7 +311,3 @@ std::vector<TriangleDerived> TriangleDerived::crop_z_out(float z1, float z2) con
#undef P1_OUT
#undef P2_OUT
#undef P3_OUT
-
-TriangleDerived TriangleDerived::div_by_w() const {
- return {derived_vertex1.div_by_w(), derived_vertex2.div_by_w(), derived_vertex3.div_by_w()};
-}
diff --git a/src/o3d/tri_deriv.h b/src/o3d/tri_deriv.h
index 201539b..16a21f8 100644
--- a/src/o3d/tri_deriv.h
+++ b/src/o3d/tri_deriv.h
@@ -7,16 +7,17 @@
namespace engine::o3d {
-class TriangleDerived {
- public:
- DerivedVertex derived_vertex1;
- DerivedVertex derived_vertex2;
- DerivedVertex derived_vertex3;
+struct TriangleDerived {
+ DerivedVertex derived_vertex1;
+ DerivedVertex derived_vertex2;
+ DerivedVertex derived_vertex3;
- TriangleDerived(DerivedVertex derived_vertex1, DerivedVertex derived_vertex2, DerivedVertex derived_vertex3);
- std::vector<TriangleDerived> perspective_crop_xy_out(float x1, float x2, float y1, float y2) const;
- std::vector<TriangleDerived> crop_z_out(float z1, float z2) const;
- TriangleDerived div_by_w() const;
+ std::vector<TriangleDerived> perspective_crop_xy_out(float x1, float x2, float y1, float y2) const;
+ std::vector<TriangleDerived> crop_z_out(float z1, float z2) const;
+
+ constexpr TriangleDerived div_by_w() const & {
+ return {derived_vertex1.div_by_w(), derived_vertex2.div_by_w(), derived_vertex3.div_by_w()};
+ }
};
}
diff --git a/src/o3d/vertex.cpp b/src/o3d/vertex.cpp
deleted file mode 100644
index 5845e27..0000000
--- a/src/o3d/vertex.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#include "o3d/vertex.h"
-#include "math/vector.h"
-#include "o3d/vertex_data.h"
-
-using namespace engine::o3d;
-
-Vertex::Vertex(engine::math::Vector4 vertex, engine::math::Vector3 normal, VertexData data)
- : vertex{vertex}, normal{normal}, data{data} {
-}
diff --git a/src/o3d/vertex.h b/src/o3d/vertex.h
index 1247fc8..438f8b3 100644
--- a/src/o3d/vertex.h
+++ b/src/o3d/vertex.h
@@ -6,13 +6,12 @@
namespace engine::o3d {
-class Vertex {
- public:
- engine::math::Vector4 vertex;
- engine::math::Vector3 normal;
- VertexData data;
+using engine::math::Vector3, engine::math::Vector4;
- Vertex(engine::math::Vector4 vertex, engine::math::Vector3 normal, VertexData data);
+struct Vertex {
+ Vector4 vertex;
+ Vector3 normal;
+ VertexData data;
};
}
diff --git a/src/o3d/vertex_data.cpp b/src/o3d/vertex_data.cpp
deleted file mode 100644
index b05e382..0000000
--- a/src/o3d/vertex_data.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "o3d/vertex_data.h"
-
-using namespace engine::o3d;
-
-VertexData VertexData::lerp(const VertexData& vd1, const VertexData& vd2, float b0) {
- return {
- b0 * vd1.tx + (1.f - b0) * vd2.tx,
- b0 * vd1.ty + (1.f - b0) * vd2.ty
- };
-}
-
-VertexData VertexData::bilerp(const VertexData& vd1, const VertexData& vd2, const VertexData& vd3, float b0, float b1) {
- return {
- b0 * vd1.tx + b1 * vd2.tx + (1.f - b0 - b1) * vd3.tx,
- b0 * vd1.ty + b1 * vd2.ty + (1.f - b0 - b1) * vd3.ty
- };
-}
-
-VertexData::VertexData(float tx, float ty) : tx{tx}, ty{ty} {
-}
diff --git a/src/o3d/vertex_data.h b/src/o3d/vertex_data.h
index b8ed14c..71f42cd 100644
--- a/src/o3d/vertex_data.h
+++ b/src/o3d/vertex_data.h
@@ -3,14 +3,22 @@
namespace engine::o3d {
-class VertexData {
- public:
- static VertexData lerp(const VertexData& vd1, const VertexData& vd2, float b0);
- static VertexData bilerp(const VertexData& vd1, const VertexData& vd2, const VertexData& vd3, float b0, float b1);
+struct VertexData {
+ static constexpr VertexData lerp(const VertexData& vd1, const VertexData& vd2, float b0) {
+ return {
+ b0 * vd1.tx + (1.f - b0) * vd2.tx,
+ b0 * vd1.ty + (1.f - b0) * vd2.ty
+ };
+ }
- float tx, ty;
+ static constexpr VertexData bilerp(const VertexData& vd1, const VertexData& vd2, const VertexData& vd3, float b0, float b1) {
+ return {
+ b0 * vd1.tx + b1 * vd2.tx + (1.f - b0 - b1) * vd3.tx,
+ b0 * vd1.ty + b1 * vd2.ty + (1.f - b0 - b1) * vd3.ty
+ };
+ }
- VertexData(float tx, float ty);
+ float tx, ty;
};
}
diff --git a/src/obj_parser.cpp b/src/obj_parser.cpp
new file mode 100644
index 0000000..7791678
--- /dev/null
+++ b/src/obj_parser.cpp
@@ -0,0 +1,81 @@
+#include "obj_parser.h"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <cstddef>
+#include <array>
+#include "math/vector.h"
+#include "o3d/mesh.h"
+#include "o3d/vertex_data.h"
+
+namespace engine {
+
+namespace {
+
+std::vector<std::string> split(const std::string& s, char sep) {
+ std::vector<std::string> res;
+ std::string::size_type last_ind = 0;
+ for (std::string::size_type ind = 0; ind < s.length(); ind++) {
+ if (s[ind] == sep) {
+ res.push_back(s.substr(last_ind, ind - last_ind));
+ last_ind = ind + 1;
+ }
+ }
+ res.push_back(s.substr(last_ind));
+ return res;
+}
+
+}
+
+o3d::Mesh parse_object(const std::string& obj_path) {
+ o3d::Mesh mesh;
+ mesh.vertices_data.push_back(o3d::VertexData(0.f, 0.f));
+ std::ifstream obj_file(obj_path);
+ std::string line;
+ while (std::getline(obj_file, line)) {
+ if (line.length() == 0 || line[0] == '#')
+ continue;
+ if (line.rfind("o ", 0) == 0) {
+ std::cout << "Object: " << line.substr(2) << std::endl;
+ } else if (line.rfind("v ", 0) == 0) {
+ auto s_coords = split(line.substr(2), ' ');
+ math::Vector3 v{std::stof(s_coords[0]), std::stof(s_coords[1]), std::stof(s_coords[2])};
+ std::cout << "Vertex x: " << v.x << " y: " << v.y << " z: " << v.z << std::endl;
+ mesh.vertices.push_back(v);
+ } else if (line.rfind("vn ", 0) == 0) {
+ auto s_coords = split(line.substr(3), ' ');
+ math::Vector3 vn{std::stof(s_coords[0]), std::stof(s_coords[1]), std::stof(s_coords[2])};
+ std::cout << "Vertex normal x: " << vn.x << " y: " << vn.y << " z: " << vn.z << std::endl;
+ mesh.normals.push_back(vn);
+ } else if (line.rfind("s ", 0) == 0) {
+ auto smooth = false;
+ auto s_smooth = line.substr(2);
+ if (s_smooth == "0" || s_smooth == "off") {
+ smooth = false;
+ } else if (s_smooth == "1" || s_smooth == "on") {
+ smooth = true;
+ }
+ std::cout << "Smooth: " << std::boolalpha << smooth << std::endl;
+ } else if (line.rfind("f ", 0) == 0) {
+ std::array<std::array<std::size_t, 3>, 3> indices;
+ auto line_split = split(line.substr(2), ' ');
+ for (int i = 0; i < 3; i++) {
+ auto indices_s_group = split(line_split[i], '/');
+ indices[i][0] = std::stoi(indices_s_group[0]) - 1;
+ indices[i][1] = std::stoi(indices_s_group[2]) - 1;
+ indices[i][2] = 0;
+ }
+ std::cout << "Face:"
+ << " 1: vertex: " << indices[0][0] << " normal: " << indices[0][1]
+ << " 2: vertex: " << indices[1][0] << " normal: " << indices[1][1]
+ << " 3: vertex: " << indices[2][0] << " normal: " << indices[2][1]
+ << std::endl;
+ mesh.indices.push_back(indices);
+ }
+ }
+ return mesh;
+}
+
+}
diff --git a/src/obj_parser.h b/src/obj_parser.h
new file mode 100644
index 0000000..2a6d791
--- /dev/null
+++ b/src/obj_parser.h
@@ -0,0 +1,12 @@
+#ifndef OBJ_PARSER_H
+#define OBJ_PARSER_H
+
+#include "o3d/mesh.h"
+
+namespace engine {
+
+o3d::Mesh parse_object(const std::string& obj_path);
+
+}
+
+#endif // OBJ_PARSER_H
diff --git a/src/renderer.cpp b/src/renderer.cpp
index 1fa8799..ad67ecc 100644
--- a/src/renderer.cpp
+++ b/src/renderer.cpp
@@ -1,42 +1,64 @@
#include "renderer.h"
-#include <array>
-#include <cmath>
-#include <algorithm>
#include <memory>
+#include <array>
#include "math/vector.h"
-#include "o3d/vertex.h"
-#include "o3d/deriv_vertex.h"
#include "o3d/tri.h"
#include "o3d/tri_deriv.h"
-#include "o3d/vertex_data.h"
+#include "fb/chfb.h"
+#include "fb/pixfb.h"
using namespace engine;
+using
+ engine::math::Vector2,
+ engine::math::Vector4,
+ engine::o3d::Triangle,
+ engine::o3d::TriangleDerived,
+ engine::o3d::VertexData,
+ engine::fb::CharacterFrameBuffer,
+ engine::fb::PixelFrameBuffer;
-Renderer::Renderer(std::unique_ptr<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();
+template<typename FrameBuffer>
+template<typename FBArg>
+Renderer<FrameBuffer>::Renderer(FBArg&& fb) : fb{std::forward<FBArg>(fb)} {
+ depth_buf.resize(this->fb.width() * this->fb.height());
}
-unsigned int Renderer::height() const {
- return fb->height();
+template<typename FrameBuffer>
+void Renderer<FrameBuffer>::resize(unsigned int w, unsigned int h) {
+ fb.resize(w, h);
+ depth_buf.resize(fb.width() * fb.height());
}
-void Renderer::clear() {
+template<typename FrameBuffer>
+void Renderer<FrameBuffer>::clear() {
std::fill(depth_buf.begin(), depth_buf.end(), 1.f);
- fb->clear();
+ fb.clear();
}
enum TriangleSide { top, bottom };
-void Renderer::_draw_cropped_triangle(const o3d::Triangle& root, const o3d::TriangleDerived& triangle) {
+template<typename FrameBuffer>
+void Renderer<FrameBuffer>::draw_triangle(const Triangle& triangle) {
+ Vector2 fdim_over_2 = Vector2{static_cast<float>(fb.width()), static_cast<float>(fb.height())} / 2.f;
+ for (const auto& t1 : triangle.to_derived().crop_z_out(-1.f, 1.f)) {
+ for (auto t2 : t1.div_by_w().perspective_crop_xy_out(-1.f, 1.f, -1.f, 1.f)) {
+ auto& v1 = t2.derived_vertex1.vertex;
+ auto& v2 = t2.derived_vertex2.vertex;
+ auto& v3 = t2.derived_vertex3.vertex;
+ auto pp1 = v1.xy();
+ auto pp2 = v2.xy();
+ auto pp3 = v3.xy();
+ if ((pp2 - pp1).det(pp3 - pp1) >= 0.f) continue;
+ v1 = Vector4{(pp1 + 1.f).mul_term(fdim_over_2) - .5f, v1.z, v1.w};
+ v2 = Vector4{(pp2 + 1.f).mul_term(fdim_over_2) - .5f, v2.z, v2.w};
+ v3 = Vector4{(pp3 + 1.f).mul_term(fdim_over_2) - .5f, v3.z, v3.w};
+ _draw_cropped_triangle(triangle, t2);
+ }
+ }
+}
+
+template<typename FrameBuffer>
+void Renderer<FrameBuffer>::_draw_cropped_triangle(const Triangle& root, const TriangleDerived& triangle) {
std::array<const o3d::DerivedVertex*, 3> sorted_vs = { &triangle.derived_vertex1, &triangle.derived_vertex2, &triangle.derived_vertex3 };
{
@@ -55,13 +77,14 @@ void Renderer::_draw_cropped_triangle(const o3d::Triangle& root, const o3d::Tria
auto middle_vl = *sorted_vs[1];
const float fac = (sorted_vs[1]->vertex.y - sorted_vs[0]->vertex.y) / (sorted_vs[2]->vertex.y - sorted_vs[0]->vertex.y);
- const float fac_b0 = (1.f - fac) / sorted_vs[0]->vertex.w / ((1.f - fac) / sorted_vs[0]->vertex.w + fac / sorted_vs[2]->vertex.w);
+ const float middle_vr_vertex_w = 1.f / (1.f / sorted_vs[0]->vertex.w + fac * (1.f / sorted_vs[2]->vertex.w - 1.f / sorted_vs[0]->vertex.w));
+ const float fac_b0 = middle_vr_vertex_w * (1.f - fac) / sorted_vs[0]->vertex.w;
o3d::DerivedVertex middle_vr{
{
sorted_vs[0]->vertex.x + fac * (sorted_vs[2]->vertex.x - sorted_vs[0]->vertex.x),
sorted_vs[1]->vertex.y,
fac_b0 * sorted_vs[0]->vertex.z + (1.f - fac_b0) * sorted_vs[2]->vertex.z,
- 1.f / (1.f / sorted_vs[0]->vertex.w + fac * (1.f / sorted_vs[2]->vertex.w - 1.f / sorted_vs[0]->vertex.w))
+ middle_vr_vertex_w
},
fac_b0 * sorted_vs[0]->b0 + (1.f - fac_b0) * sorted_vs[2]->b0,
fac_b0 * sorted_vs[0]->b1 + (1.f - fac_b0) * sorted_vs[2]->b1
@@ -101,39 +124,30 @@ void Renderer::_draw_cropped_triangle(const o3d::Triangle& root, const o3d::Tria
float b_fac = 1.f / (sub_bb0 / vertex_end.vertex.w + sub_bb1 / middle_vl.vertex.w + (1.f - sub_bb0 - sub_bb1) / middle_vr.vertex.w);
float sub_b0 = b_fac * sub_bb0 / vertex_end.vertex.w;
float sub_b1 = b_fac * sub_bb1 / middle_vl.vertex.w;
- float b0 = sub_b0 * vertex_end.b0 + sub_b1 * middle_vl.b0 + (1.f - sub_b0 - sub_b1) * middle_vr.b0;
- float b1 = sub_b0 * vertex_end.b1 + sub_b1 * middle_vl.b1 + (1.f - sub_b0 - sub_b1) * middle_vr.b1;
- math::Vector3 loc{
- b0 * root.vertex1.vertex.x + b1 * root.vertex2.vertex.x + (1.f - b0 - b1) * root.vertex3.vertex.x,
- b0 * root.vertex1.vertex.y + b1 * root.vertex2.vertex.y + (1.f - b0 - b1) * root.vertex3.vertex.y,
- b0 * root.vertex1.vertex.z + b1 * root.vertex2.vertex.z + (1.f - b0 - b1) * root.vertex3.vertex.z
- };
- if (loc.z < depth_buf[x + y * fb->width()]) {
- depth_buf[x + y * fb->width()] = loc.z;
- fb->draw_point(x, y, loc, o3d::VertexData::bilerp(root.vertex1.data, root.vertex2.data, root.vertex3.data, b0, b1));
+ float loc_z = sub_b0 * vertex_end.vertex.z + sub_b1 * middle_vl.vertex.z + (1.f - sub_b0 - sub_b1) * middle_vr.vertex.z;
+ if (loc_z < depth_buf[x + y * fb.width()]) {
+ depth_buf[x + y * fb.width()] = loc_z;
+ float b0 = sub_b0 * vertex_end.b0 + sub_b1 * middle_vl.b0 + (1.f - sub_b0 - sub_b1) * middle_vr.b0;
+ float b1 = sub_b0 * vertex_end.b1 + sub_b1 * middle_vl.b1 + (1.f - sub_b0 - sub_b1) * middle_vr.b1;
+ Vector3 loc{
+ b0 * root.vertex1.vertex.x + b1 * root.vertex2.vertex.x + (1.f - b0 - b1) * root.vertex3.vertex.x,
+ b0 * root.vertex1.vertex.y + b1 * root.vertex2.vertex.y + (1.f - b0 - b1) * root.vertex3.vertex.y,
+ loc_z
+ };
+ fb.draw_point(x, y, loc,
+ VertexData::bilerp(root.vertex1.data, root.vertex2.data, root.vertex3.data, b0, b1),
+ Vector3::bilerp(root.vertex1.normal, root.vertex2.normal, root.vertex3.normal, b0, b1).normalize());
}
}
}
};
- _draw_cropped_triangle_side.operator()<TriangleSide::top>();
- _draw_cropped_triangle_side.operator()<TriangleSide::bottom>();
+ _draw_cropped_triangle_side.template operator()<TriangleSide::top>();
+ _draw_cropped_triangle_side.template operator()<TriangleSide::bottom>();
}
-void Renderer::draw_triangle(o3d::Triangle triangle) {
- for (auto t1 : triangle.to_derived().crop_z_out(-1.f, 1.f)) {
- for (auto t2 : t1.div_by_w().perspective_crop_xy_out(-1.f, 1.f, -1.f, 1.f)) {
- auto pp1 = t2.derived_vertex1.vertex.xy();
- auto pp2 = t2.derived_vertex2.vertex.xy();
- auto pp3 = t2.derived_vertex3.vertex.xy();
- if ((pp2 - pp1).det(pp3 - pp1) >= 0.f) continue;
- float fw_over_2 = static_cast<float>(fb->width()) / 2.f, fh_over_2 = static_cast<float>(fb->height()) / 2.f;
- t2.derived_vertex1.vertex.x = (t2.derived_vertex1.vertex.x + 1.f) * fw_over_2 - .5f;
- t2.derived_vertex1.vertex.y = (t2.derived_vertex1.vertex.y + 1.f) * fh_over_2 - .5f;
- t2.derived_vertex2.vertex.x = (t2.derived_vertex2.vertex.x + 1.f) * fw_over_2 - .5f;
- t2.derived_vertex2.vertex.y = (t2.derived_vertex2.vertex.y + 1.f) * fh_over_2 - .5f;
- t2.derived_vertex3.vertex.x = (t2.derived_vertex3.vertex.x + 1.f) * fw_over_2 - .5f;
- t2.derived_vertex3.vertex.y = (t2.derived_vertex3.vertex.y + 1.f) * fh_over_2 - .5f;
- _draw_cropped_triangle(triangle, t2);
- }
- }
-}
+template class Renderer<CharacterFrameBuffer>;
+template Renderer<CharacterFrameBuffer>::Renderer(CharacterFrameBuffer&&);
+template Renderer<CharacterFrameBuffer>::Renderer(const CharacterFrameBuffer&);
+template class Renderer<PixelFrameBuffer>;
+template Renderer<PixelFrameBuffer>::Renderer(PixelFrameBuffer&&);
+template Renderer<PixelFrameBuffer>::Renderer(const PixelFrameBuffer&);
diff --git a/src/renderer.h b/src/renderer.h
index 457099d..b7a3a7e 100644
--- a/src/renderer.h
+++ b/src/renderer.h
@@ -2,22 +2,33 @@
#define RENDERER_H
#include <memory>
-#include "fb/fb.h"
+#include "math/vector.h"
#include "o3d/tri.h"
#include "o3d/tri_deriv.h"
namespace engine {
+using math::Vector3, o3d::Triangle;
+
+template<typename FrameBuffer>
class Renderer {
public:
- std::unique_ptr<fb::FrameBuffer> fb;
+ FrameBuffer fb;
+
+ template<typename FBArg>
+ Renderer(FBArg&& fb);
- Renderer(std::unique_ptr<fb::FrameBuffer> fb);
void resize(unsigned int w, unsigned int h);
- unsigned int width() const;
- unsigned int height() const;
void clear();
- void draw_triangle(o3d::Triangle triangle);
+ void draw_triangle(const Triangle& triangle);
+
+ constexpr unsigned int width() const & {
+ return fb.width();
+ }
+
+ constexpr unsigned int height() const & {
+ return fb.height();
+ }
private:
std::vector<float> depth_buf;