feat: texture sampling
| 11 files changed, 107 insertions(+), 21 deletions(-) | |||
|---|---|---|---|
| M | .gitattributes | +7 | -0 |
| M | assets/Default.png | +0 | -0 |
| M | assets/DuckCM.png | +0 | -0 |
| M | assets/Missing_t.png | +0 | -0 |
| M | build_win32.bat | +6 | -3 |
| M | src/draw.cpp | +14 | -8 |
| M | src/draw.h | +2 | -1 |
| M | src/mesh.cpp | +1 | -1 |
| M | src/renderer.cpp | +20 | -8 |
| A | src/texture.cpp | +41 | -0 |
| A | src/texture.h | +16 | -0 |
1@@ -2,3 +2,10 @@
2 *.bat text eol=crlf
3 *.ps1 text eol=crlf
4 *.sh text=auto eol=lf
5+
6+*.png binary
7+*.jpg binary
8+*.jpeg binary
9+*.gif binary
10+*.webp binary
11+*.ico binary
M · assets/Default.png
+0, -0M · assets/DuckCM.png
+0, -0M · assets/Missing_t.png
+0, -0M · build_win32.bat
+6, -3 1@@ -2,8 +2,9 @@ echo off
2 setlocal enabledelayedexpansion
3
4 set ROOT=%~dp0
5-::set SRC_FILES=src\renderer.cpp
6 set SRC_FILES=%ROOT%src\*.cpp
7+set STB_FILES=%ROOT%external\stb
8+set SDL_FILES=%ROOT%external\SDL\include
9
10
11 :: =====================
12@@ -66,8 +67,10 @@ if "%BUILD%"=="Release" (
13 :: === Compilation ===
14 :: ===================
15 pushd build
16-cl %CFLAGS% ^
17- /I %ROOT%external\SDL\include %SRC_FILES% ^
18+cl /D_CRT_SECURE_NO_WARNINGS ^
19+ %CFLAGS% ^
20+ /I %STB_FILES% ^
21+ /I %SDL_FILES% %SRC_FILES% ^
22 /link %LFLAGS% ^
23 shell32.lib ^
24 %ROOT%external\SDL\lib\x64\SDL2main.lib ^
M · src/draw.cpp
+14, -8 1@@ -1,6 +1,8 @@
2 #include "draw.h"
3
4 #include "globals.h"
5+#include "mesh.h"
6+#include "texture.h"
7 #include "util_math.h"
8
9 static inline u32 vec3_to_u32RGBA(vec3f &c) {
10@@ -108,6 +110,8 @@ void rasterize_triangle(ScreenTriangle *tri, Window *window) {
11 vec2f uv_over_w1 = tri->uv_over_w[1];
12 vec2f uv_over_w2 = tri->uv_over_w[2];
13
14+ Material mat = materials[tri->mat_idx];
15+
16 // bounding box (expensive fmin, fmax here I think)
17 float minX_f = fmin(v0.x, fmin(v1.x, v2.x));
18 float minY_f = fmin(v0.y, fmin(v1.y, v2.y));
19@@ -180,16 +184,18 @@ void rasterize_triangle(ScreenTriangle *tri, Window *window) {
20 float gamma = E2 * invArea;
21
22 // lerp the attribute accross the triangle's barycentric coords
23- float lerp_inv_w = alpha * inv_w0 + beta * inv_w1 + gamma * inv_w2;
24- float lerp_depth = alpha * ndc_depth0 + beta * ndc_depth1 + gamma * ndc_depth2;
25- vec2f lerp_uv = uv_over_w0 * alpha + uv_over_w1 * beta + uv_over_w2 * gamma;
26- vec3f lerped_color = alpha * c0 + beta * c1 + gamma * c2; // TODO: not needed, sample a texture by lerp_uv here
27+ float lerp_inv_w = alpha * inv_w0 + beta * inv_w1 + gamma * inv_w2;
28+ float lerp_depth = alpha * ndc_depth0 + beta * ndc_depth1 + gamma * ndc_depth2;
29+ vec2f lerp_uv = uv_over_w0 * alpha + uv_over_w1 * beta + uv_over_w2 * gamma;
30+
31+ // vec3f lerped_color = alpha * c0 + beta * c1 + gamma * c2;
32+ // vec3f color = lerped_color / lerp_inv_w;
33+ // u32 u32_color = vec3_to_u32RGBA(color);
34
35- vec3f color = lerped_color / lerp_inv_w;
36- u32 u32_color = vec3_to_u32RGBA(color);
37- vec2f uv = lerp_uv / lerp_inv_w;
38+ vec2f uv = lerp_uv / lerp_inv_w;
39+ u32 tex_rgba = sample_texture(mat.texture_img_idx, uv);
40
41- process_fragment(buffer_idx, lerp_depth, u32_color, window);
42+ process_fragment(buffer_idx, lerp_depth, tex_rgba, window);
43 }
44
45 // increment edge functions
M · src/draw.h
+2, -1 1@@ -1,8 +1,8 @@
2 #pragma once
3
4 #include "globals.h"
5-#include "util_math.h"
6 #include "renderer.h"
7+#include "util_math.h"
8
9 struct ScreenTriangle {
10 vec3f points[3];
11@@ -10,6 +10,7 @@ struct ScreenTriangle {
12 vec3f color_over_w[3];
13 float inv_w[3];
14 float ndc_depth[3];
15+ u32 mat_idx;
16 };
17
18 void clear_color_buffer(u32 color, Window *window);
M · src/mesh.cpp
+1, -1 1@@ -4,8 +4,8 @@
2 #include <stdlib.h>
3 #include <string.h>
4
5-#include "util_string.h"
6 #include "texture.h"
7+#include "util_string.h"
8
9 int current_material_idx = 0;
10 int current_texture_idx = 0;
M · src/renderer.cpp
+20, -8 1@@ -3,16 +3,13 @@
2 #include <math.h>
3 #include <stdio.h>
4
5-#include <vector>
6-
7 #include "SDL.h"
8 #include "camera.h"
9 #include "clip.h"
10 #include "draw.h"
11-#include "util_math.h"
12 #include "mesh.h"
13-
14-using std::vector;
15+#include "texture.h"
16+#include "util_math.h"
17
18 static_global Window window = {
19 .sdl_window = nullptr,
20@@ -39,11 +36,26 @@ static_global float aspect = float(window.width) / float(window.height);
21 static_global float fov_y = 59.0f * M_PI / 180.0f;
22 static_global float grid_spacing = (fmin(window.width, window.height) / 2) / 10;
23
24-// NOTE: should be like a module type thingy along with the entire pipeline?
25-static_global vector<Mesh> scene; // vertex stage input
26+static_global vector<Mesh> scene; // vertex stage input
27+
28+// should be a part of a single big scene struct
29+vector<Material> materials;
30+vector<Texture> textures;
31+
32 static_global vector<ScreenTriangle> raster_queue; // raster stage input
33
34 void initialize_scene() {
35+ Texture missing_texture = load_texture("../assets/Missing_t.png");
36+ Material missing_material = {
37+ .name = "missing_material",
38+ .ambient = vec3f(1.0f, 1.0f, 1.0f),
39+ .diffuse = vec3f(1.0f, 1.0f, 1.0f),
40+ .specular = vec3f(1.0f, 1.0f, 1.0f),
41+ .texture_img_idx = 0,
42+ };
43+ textures.push_back(missing_texture);
44+ materials.push_back(missing_material);
45+
46 Mesh plane = parse_obj("../assets/Plane.obj");
47 scene.emplace_back(plane);
48 scene.back().transform.position = {0.0, 0.0, 0.0};
49@@ -397,6 +409,7 @@ void run_pipeline(void) {
50 tri.uv_over_w[i] = cvs[i].uv * inv_w;
51 tri.color_over_w[i] = cvs[i].color * inv_w;
52 tri.ndc_depth[i] = ndc.z;
53+ tri.mat_idx = f0.mat_idx;
54 }
55 raster_queue.push_back(tri);
56 }
57@@ -419,7 +432,6 @@ void rasterize(void) {
58
59 for (int i = 0; i < raster_queue.size(); i++) {
60 ScreenTriangle &triangle = raster_queue[i];
61- // TODO: toggle primitives
62
63 // triangle primitives
64 rasterize_triangle(&triangle, &window);
A · src/texture.cpp
+41, -0 1@@ -0,0 +1,41 @@
2+#include "texture.h"
3+
4+#include "globals.h"
5+
6+#define STB_IMAGE_IMPLEMENTATION
7+#include "stb_image.h"
8+
9+Texture load_texture(const char *filename) {
10+ int width, height, channels;
11+ unsigned char *data = stbi_load(filename, &width, &height, &channels, 4);
12+
13+ if (!data) {
14+ fprintf(stderr, "Failed to load image: %s\n", filename);
15+ return textures[0]; // can see this being annoying to debug, change
16+ }
17+
18+ Texture tex;
19+ tex.width = width;
20+ tex.height = height;
21+ tex.pixels = (u32 *)malloc(sizeof(u32) * width * height);
22+ for (int y = 0; y < height; ++y) {
23+ for (int x = 0; x < width; ++x) {
24+ int pixel_idx = y * width + x;
25+ int flipped_y = height - 1 - y;
26+ u8 r = data[flipped_y * width * 4 + x * 4 + 0];
27+ u8 g = data[flipped_y * width * 4 + x * 4 + 1];
28+ u8 b = data[flipped_y * width * 4 + x * 4 + 2];
29+ u8 a = data[flipped_y * width * 4 + x * 4 + 3];
30+ tex.pixels[pixel_idx] = (r << 24) | (g << 16) | (b << 8) | a;
31+ }
32+ }
33+ stbi_image_free(data);
34+ return tex;
35+}
36+
37+u32 sample_texture(int texture_index, vec2f uv) {
38+ const Texture &tex = textures[texture_index];
39+ int x = (int)(uv.x * tex.width);
40+ int y = (int)(uv.y * tex.height);
41+ return tex.pixels[y * tex.width + x];
42+}
A · src/texture.h
+16, -0 1@@ -0,0 +1,16 @@
2+#pragma once
3+
4+#include "globals.h"
5+#include "util_math.h"
6+#include "vector"
7+
8+struct Texture {
9+ int width;
10+ int height;
11+ u32 *pixels; // sizeof(u32)[width * height]
12+};
13+
14+extern std::vector<Texture> textures;
15+
16+Texture load_texture(const char *filename);
17+u32 sample_texture(int texture_index, vec2f uv);