aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile7
-rw-r--r--main.cpp203
-rw-r--r--pixfb.cpp153
-rw-r--r--pixfb.h29
4 files changed, 378 insertions, 14 deletions
diff --git a/Makefile b/Makefile
index 4ba6469..0de5723 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
EXE=main
-OBJECT_FILES=main.o math_vector.o chfb.o obj3d.o vertex_data.o vertex.o tri_vertex.o
+OBJECT_FILES=main.o math_vector.o chfb.o pixfb.o obj3d.o vertex_data.o vertex.o tri_vertex.o
CC=g++
LD=g++
COMMON_ARGS=-Wall -Wextra
@@ -11,7 +11,7 @@ LD_ARGS=$(COMMON_ARGS) -lncurses -lSDL2
$(EXE): $(OBJECT_FILES)
$(LD) -o $@ $^ $(LD_ARGS)
-main.o: main.cpp chfb.h obj3d.h math_vector.h vertex_data.h vertex.h tri_vertex.h
+main.o: main.cpp chfb.h pixfb.h obj3d.h math_vector.h vertex_data.h vertex.h tri_vertex.h
$(CC) -o $@ -c $< $(CC_ARGS)
math_vector.o: math_vector.cpp math_vector.h
@@ -20,6 +20,9 @@ math_vector.o: math_vector.cpp math_vector.h
chfb.o: chfb.cpp chfb.h math_vector.h vertex_data.h vertex.h tri_vertex.h
$(CC) -o $@ -c $< $(CC_ARGS)
+pixfb.o: pixfb.cpp pixfb.h math_vector.h vertex_data.h vertex.h tri_vertex.h
+ $(CC) -o $@ -c $< $(CC_ARGS)
+
obj3d.o: obj3d.cpp obj3d.h math_vector.h vertex_data.h vertex.h tri_vertex.h
$(CC) -o $@ -c $< $(CC_ARGS)
diff --git a/main.cpp b/main.cpp
index eb8f117..732588a 100644
--- a/main.cpp
+++ b/main.cpp
@@ -5,6 +5,7 @@
#include <vector>
#include <SDL2/SDL.h>
#include "chfb.h"
+#include "pixfb.h"
#include "obj3d.h"
#include "math_vector.h"
#include "vertex.h"
@@ -277,21 +278,199 @@ void main_SDL() {
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT);
- std::vector<uint32_t> pixels(SCREEN_WIDTH * SCREEN_HEIGHT);
- for (int y = 0; y < SCREEN_HEIGHT; y++) {
- for (int x = 0; x < SCREEN_WIDTH; x++) {
- pixels[x + y * SCREEN_WIDTH] = ((uint32_t) (x + y * SCREEN_WIDTH) << 8) | 0xFF;
- }
- }
- SDL_UpdateTexture(texture, NULL, pixels.data(), SCREEN_WIDTH * 4);
- SDL_RenderClear(renderer);
- SDL_RenderCopy(renderer, texture, NULL, NULL);
- SDL_RenderPresent(renderer);
- SDL_UpdateWindowSurface(window);
+ PixelFrameBuffer pfb{SCREEN_WIDTH, SCREEN_HEIGHT};
+
+ MathVector3 a{0.f, 0.f, 0.f};
+ float dist = 4.f;
SDL_Event e;
bool quit = false;
while (!quit) {
- while (SDL_PollEvent(&e)) {
+ a.x += .0050f;
+ a.y += .0065f;
+ a.z += .0080f;
+
+ float rad = 5.f;
+ MathVector3 ca{std::cos(a.x), std::cos(a.y), std::cos(a.z)};
+ MathVector3 sa{std::sin(a.x), std::sin(a.y), std::sin(a.z)};
+
+ std::array<MathVector3, 3> rot_x = {{
+ { 1.f, 0.f, 0.f },
+ { 0.f, ca.x, sa.x },
+ { 0.f, -sa.x, ca.x },
+ }};
+ std::array<MathVector3, 3> rot_y = {{
+ { ca.y, 0.f, -sa.y },
+ { 0.f, 1.f, 0.f },
+ { sa.y, 0.f, ca.y },
+ }};
+ std::array<MathVector3, 3> rot_z = {{
+ { ca.z, sa.z, 0.f },
+ { -sa.z, ca.z, 0.f },
+ { 0.f, 0.f, 1.f },
+ }};
+
+ auto [e_x, e_y, e_z] = rot_x;
+ e_x = e_x.x * rot_y[0] + e_x.y * rot_y[1] + e_x.z * rot_y[2];
+ e_y = e_y.x * rot_y[0] + e_y.y * rot_y[1] + e_y.z * rot_y[2];
+ e_z = e_z.x * rot_y[0] + e_z.y * rot_y[1] + e_z.z * rot_y[2];
+ e_x = e_x.x * rot_z[0] + e_x.y * rot_z[1] + e_x.z * rot_z[2];
+ e_y = e_y.x * rot_z[0] + e_y.y * rot_z[1] + e_y.z * rot_z[2];
+ e_z = e_z.x * rot_z[0] + e_z.y * rot_z[1] + e_z.z * rot_z[2];
+
+ std::array<Object3D, 2> objs{{
+ {
+ {
+ {
+ rad * (-e_x + -e_y + -e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + -e_y + -e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + +e_y + -e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + +e_y + -e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + -e_y + +e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + -e_y + +e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + +e_y + +e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + +e_y + +e_z - .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ }
+ },
+ {
+ // face 1
+ { 0, 2, 3 },
+ { 0, 3, 1 },
+
+ // face 2
+ { 0, 4, 6 },
+ { 0, 6, 2 },
+
+ // face 3
+ { 0, 1, 5 },
+ { 0, 5, 4 },
+
+ // face 4
+ { 7, 6, 4 },
+ { 7, 4, 5 },
+
+ // face 5
+ { 7, 3, 2 },
+ { 7, 2, 6 },
+
+ // face 6
+ { 7, 5, 1 },
+ { 7, 1, 3 },
+ }
+ },
+ {
+ {
+ {
+ rad * (-e_x + -e_y + -e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + -e_y + -e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + +e_y + -e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + +e_y + -e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + -e_y + +e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + -e_y + +e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (-e_x + +e_y + +e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ },
+ {
+ rad * (+e_x + +e_y + +e_z + .5f * (e_x + e_y + e_z)) - dist * rad * MathVector3{0.f, 0.f, 1.f},
+ {}
+ }
+ },
+ {
+ // face 1
+ { 0, 2, 3 },
+ { 0, 3, 1 },
+
+ // face 2
+ { 0, 4, 6 },
+ { 0, 6, 2 },
+
+ // face 3
+ { 0, 1, 5 },
+ { 0, 5, 4 },
+
+ // face 4
+ { 7, 6, 4 },
+ { 7, 4, 5 },
+
+ // face 5
+ { 7, 3, 2 },
+ { 7, 2, 6 },
+
+ // face 6
+ { 7, 5, 1 },
+ { 7, 1, 3 },
+ }
+ }
+ }};
+ pfb.clear();
+ float min_z = 2.f, max_z = 50.f;
+ float fac_for_aspect_ratio = 2.f * static_cast<float>(pfb.height()) / static_cast<float>(pfb.width());
+ for (auto obj : objs) {
+ for (auto triangle : obj) {
+ TriangleVertex4 t{triangle};
+
+ // should be multiplied by a matrix, temporary replacement
+ t.vertex1.point.x *= fac_for_aspect_ratio;
+ t.vertex1.point.y = -t.vertex1.point.y;
+ t.vertex1.point.w = -t.vertex1.point.z;
+ t.vertex1.point.z = 2.f * (-t.vertex1.point.z - min_z) / (max_z - min_z) - 1.f;
+ t.vertex2.point.x *= fac_for_aspect_ratio;
+ t.vertex2.point.y = -t.vertex2.point.y;
+ t.vertex2.point.w = -t.vertex2.point.z;
+ t.vertex2.point.z = 2.f * (-t.vertex2.point.z - min_z) / (max_z - min_z) - 1.f;
+ t.vertex3.point.x *= fac_for_aspect_ratio;
+ t.vertex3.point.y = -t.vertex3.point.y;
+ t.vertex3.point.w = -t.vertex3.point.z;
+ t.vertex3.point.z = 2.f * (-t.vertex3.point.z - min_z) / (max_z - min_z) - 1.f;
+
+ pfb.draw_triangle(t);
+ }
+ }
+ SDL_UpdateTexture(texture, NULL, pfb.pixels(), SCREEN_WIDTH * 4);
+ SDL_RenderClear(renderer);
+ SDL_RenderCopy(renderer, texture, NULL, NULL);
+ SDL_RenderPresent(renderer);
+ SDL_UpdateWindowSurface(window);
+ while (SDL_WaitEventTimeout(&e, 10)) {
if (e.type == SDL_QUIT) {
quit = true;
}
diff --git a/pixfb.cpp b/pixfb.cpp
new file mode 100644
index 0000000..f84bf2f
--- /dev/null
+++ b/pixfb.cpp
@@ -0,0 +1,153 @@
+#include "pixfb.h"
+#include <array>
+#include <cmath>
+#include <vector>
+#include <cstdint>
+#include "math_vector.h"
+#include "vertex.h"
+#include "tri_vertex.h"
+#include "vertex_data.h"
+
+PixelFrameBuffer::PixelFrameBuffer(unsigned int w, unsigned int h) {
+ resize(w, h);
+}
+
+void PixelFrameBuffer::resize(unsigned int w, unsigned int h) {
+ this->w = w;
+ this->h = h;
+ pixels_vector.resize(w * h);
+ depth_buf.resize(w * h);
+ clear();
+}
+
+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);
+ std::fill(depth_buf.begin(), depth_buf.end(), 1.f);
+ face_ind = -1;
+}
+
+void PixelFrameBuffer::_draw_cropped_triangle(TriangleVertex3 triangle) {
+ std::array<Vertex3*, 3> sorted_vs = { &triangle.vertex1, &triangle.vertex2, &triangle.vertex3 };
+
+#define SWAP_IF_LT(X,Y) ({\
+ if (sorted_vs[X]->point.y < sorted_vs[Y]->point.y) {\
+ Vertex3* temp = sorted_vs[X];\
+ sorted_vs[X] = sorted_vs[Y];\
+ sorted_vs[Y] = temp;\
+ }\
+ })
+ SWAP_IF_LT(1, 0);
+ SWAP_IF_LT(2, 1);
+ SWAP_IF_LT(1, 0);
+#undef SWAP_IF_LT
+
+ Vertex3 middle_vl = *sorted_vs[1];
+ float fac = (sorted_vs[1]->point.y - sorted_vs[0]->point.y) / (sorted_vs[2]->point.y - sorted_vs[0]->point.y);
+ Vertex3 middle_vr{
+ {
+ sorted_vs[0]->point.x + fac * (sorted_vs[2]->point.x - sorted_vs[0]->point.x),
+ sorted_vs[1]->point.y,
+ sorted_vs[0]->point.z + fac * (sorted_vs[2]->point.z - sorted_vs[0]->point.z)
+ },
+ VertexData::lerp(sorted_vs[0]->data, sorted_vs[2]->data, fac)
+ };
+ if (middle_vr.point.x < middle_vl.point.x) {
+ Vertex3 temp = middle_vr;
+ middle_vr = middle_vl;
+ middle_vl = temp;
+ }
+
+ // top triangle
+ {
+ if (sorted_vs[0]->point.y != sorted_vs[1]->point.y) {
+ int top_y = static_cast<int>(std::floor(sorted_vs[0]->point.y + 1.f));
+ int bottom_y = static_cast<int>(std::ceil(sorted_vs[1]->point.y - 1.f));
+ for (int y = top_y; y <= bottom_y; y++) {
+ float iy = static_cast<float>(y);
+ float s = (iy - sorted_vs[0]->point.y) / (sorted_vs[1]->point.y - sorted_vs[0]->point.y);
+ float xl = sorted_vs[0]->point.x + s * (middle_vl.point.x - sorted_vs[0]->point.x);
+ float xr = sorted_vs[0]->point.x + s * (middle_vr.point.x - sorted_vs[0]->point.x);
+ int left_x = static_cast<int>(std::ceil(xl));
+ int right_x = static_cast<int>(std::ceil(xr - 1.f));
+ for (int x = left_x; x <= right_x; x++) {
+ float ix = static_cast<float>(x);
+ float t = (ix - xl) / (xr - xl);
+ // depth and vd don't take into account perspective
+ float depth = sorted_vs[0]->point.z + s * (middle_vl.point.z - sorted_vs[0]->point.z + t * (middle_vr.point.z - middle_vl.point.z));
+ // VertexData vd = VertexData::bilerp(sorted_vs[0]->data, middle_vl.data, middle_vr.data, s, t);
+ if (depth < depth_buf[x + y * w]) {
+ depth_buf[x + y * w] = depth;
+ pixels_vector[x + y * w] = face_color();
+ }
+ }
+ }
+ }
+ }
+
+ // bottom triangle
+ {
+ if (sorted_vs[1]->point.y != sorted_vs[2]->point.y) {
+ int bottom_y = static_cast<int>(std::floor(sorted_vs[2]->point.y));
+ int top_y = static_cast<int>(std::ceil(sorted_vs[1]->point.y));
+ for (int y = top_y; y <= bottom_y; y++) {
+ float iy = static_cast<float>(y);
+ float s = (iy - sorted_vs[2]->point.y) / (sorted_vs[1]->point.y - sorted_vs[2]->point.y);
+ float xl = sorted_vs[2]->point.x + s * (middle_vl.point.x - sorted_vs[2]->point.x);
+ float xr = sorted_vs[2]->point.x + s * (middle_vr.point.x - sorted_vs[2]->point.x);
+ int left_x = static_cast<int>(std::ceil(xl));
+ int right_x = static_cast<int>(std::ceil(xr - 1.f));
+ for (int x = left_x; x <= right_x; x++) {
+ float ix = static_cast<float>(x);
+ float t = (ix - xl) / (xr - xl);
+ // depth and vd don't take into account perspective
+ float depth = sorted_vs[2]->point.z + s * (middle_vl.point.z - sorted_vs[2]->point.z + t * (middle_vr.point.z - middle_vl.point.z));
+ // VertexData vd = VertexData::bilerp(sorted_vs[2]->data, middle_vl.data, middle_vr.data, s, t);
+ if (depth < depth_buf[x + y * w]) {
+ depth_buf[x + y * w] = depth;
+ pixels_vector[x + y * w] = face_color();
+ }
+ }
+ }
+ }
+ }
+}
+
+void PixelFrameBuffer::draw_triangle(TriangleVertex4 triangle) {
+ face_ind++;
+ for (auto t1 : triangle.crop_z_out(-1.f, 1.f)) {
+ for (auto t2 : t1.div_by_w().crop_xy_out(-1.f, 1.f, -1.f, 1.f)) {
+ MathVector2 pp1 = t2.vertex1.point.xy(),
+ pp2 = t2.vertex2.point.xy(),
+ pp3 = t2.vertex3.point.xy();
+ if ((pp2 - pp1).det(pp3 - pp1) >= 0.f) continue;
+ t2.vertex1.point = (t2.vertex1.point + MathVector3{1.f, 1.f, 0.f}) / 2.f;
+ t2.vertex2.point = (t2.vertex2.point + MathVector3{1.f, 1.f, 0.f}) / 2.f;
+ t2.vertex3.point = (t2.vertex3.point + MathVector3{1.f, 1.f, 0.f}) / 2.f;
+ float fw = static_cast<float>(w), fh = static_cast<float>(h);
+ t2.vertex1.point.x = t2.vertex1.point.x * fw - .5f;
+ t2.vertex1.point.y = t2.vertex1.point.y * fh - .5f;
+ t2.vertex2.point.x = t2.vertex2.point.x * fw - .5f;
+ t2.vertex2.point.y = t2.vertex2.point.y * fh - .5f;
+ t2.vertex3.point.x = t2.vertex3.point.x * fw - .5f;
+ t2.vertex3.point.y = t2.vertex3.point.y * fh - .5f;
+ _draw_cropped_triangle(t2);
+ }
+ }
+}
+
+uint32_t PixelFrameBuffer::face_color() const {
+ int n = face_ind / 2;
+ return ((n % 2 ? 0xFF000000 : 0x55000000) >> ((n % 6) / 2 * 8)) | 0xFF;
+}
diff --git a/pixfb.h b/pixfb.h
new file mode 100644
index 0000000..c54b5fb
--- /dev/null
+++ b/pixfb.h
@@ -0,0 +1,29 @@
+#ifndef PIXFB_H
+#define PIXFB_H
+
+#include <vector>
+#include <cstdint>
+#include "math_vector.h"
+#include "tri_vertex.h"
+
+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_triangle(TriangleVertex4 triangle);
+
+ private:
+ unsigned int w, h;
+ std::vector<uint32_t> pixels_vector;
+ std::vector<float> depth_buf;
+ int face_ind;
+
+ void _draw_cropped_triangle(TriangleVertex3 triangle);
+ uint32_t face_color() const;
+};
+
+#endif // PIXFB_H