diff options
author | vimene <vincent.menegaux@gmail.com> | 2024-12-31 03:40:14 +0100 |
---|---|---|
committer | vimene <vincent.menegaux@gmail.com> | 2024-12-31 03:40:14 +0100 |
commit | cc6fb8c33637566a7b116d46440e6063f016deea (patch) | |
tree | 5cc83f84525507994add57df7dd974e6611d675a | |
parent | 6b765a85cf81bf4b7162e4c9280dd4054581c611 (diff) | |
download | engine-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
36 files changed, 841 insertions, 798 deletions
@@ -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; |