-
Notifications
You must be signed in to change notification settings - Fork 1
/
graphics.cpp
149 lines (124 loc) · 3.94 KB
/
graphics.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include "graphics.h"
static bool is_back_facing(Vector3f* ndc_coords)
{
Vector3f a = ndc_coords[0];
Vector3f b = ndc_coords[1];
Vector3f c = ndc_coords[2];
float signed_area = a.x * b.y - a.y * b.x +
b.x * c.y - b.y * c.x +
c.x * a.y - c.y * a.x;
return signed_area <= 0;
}
static float interpolate_depth(float* screen_depths, Vector3f weights)
{
Vector3f screen_depth;
for (size_t i = 0; i < 3; i++)
{
screen_depth[i] = screen_depths[i];
}
return screen_depth * weights;
}
static void interpolate_varyings(shader_struct_v2f* v2f, shader_struct_v2f* ret, int sizeof_varyings, Vector3f weights, float recip_w[3])
{
int num_floats = sizeof_varyings / sizeof(float);
float* src0 = (float*)(&v2f[0]);
float* src1 = (float*)(&v2f[1]);
float* src2 = (float*)(&v2f[2]);
float* dst = (float*)ret;
float weight0 = recip_w[0] * weights.x;
float weight1 = recip_w[1] * weights.y;
float weight2 = recip_w[2] * weights.z;
float normalizer = 1 / (weight0 + weight1 + weight2);
int i;
for (i = 0; i < num_floats; i++)
{
float sum = src0[i] * weight0 + src1[i] * weight1 + src2[i] * weight2;
dst[i] = sum * normalizer;
}
}
static Vector3f barycentric(Vector2f A, Vector2f B, Vector2f C, Vector2f P)
{
Vector3f s[2];
for (int i = 2; i--; )
{
s[i][0] = C[i] - A[i];
s[i][1] = B[i] - A[i];
s[i][2] = A[i] - P[i];
}
Vector3f u = cross(s[0], s[1]);
if (std::abs(u[2]) > 1e-2)
return Vector3f(1.f - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z);
return Vector3f(-1, 1, 1);
}
static void rasterize_triangle(DrawData* draw_data, shader_struct_v2f* v2f)
{
Vector3f ndc_coords[3];
for (int i = 0; i < 3; i++) ndc_coords[i] = proj<3>(v2f[i].clip_pos / v2f[i].clip_pos[3]);
if (is_back_facing(ndc_coords)) return;
RenderBuffer* render_buffer = draw_data->render_buffer;
Vector2f screen_coords[3];
float screen_depth[3];
for (int i = 0; i < 3; i++)
{
Vector3f win_coord = viewport_transform(render_buffer->width, render_buffer->height, ndc_coords[i]);
screen_coords[i] = Vector2f(win_coord.x, win_coord.y);
screen_depth[i] = win_coord.z;
}
float recip_w[3];
/* reciprocals of w */
for (int i = 0; i < 3; i++)
{
recip_w[i] = 1 / v2f[i].clip_pos[3];
}
Vector2f bboxmin(std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
Vector2f bboxmax(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max());
Vector2f clamp(render_buffer->width - 1, render_buffer->height - 1);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
bboxmin[j] = std::max(0.f, std::min(bboxmin[j], screen_coords[i][j]));
bboxmax[j] = std::min(clamp[j], std::max(bboxmax[j], screen_coords[i][j]));
}
}
Vector2i P;
for (P.x = bboxmin.x; P.x <= bboxmax.x; P.x++)
{
for (P.y = bboxmin.y; P.y <= bboxmax.y; P.y++)
{
Vector3f barycentric_weights = barycentric(screen_coords[0], screen_coords[1], screen_coords[2], P);
if (barycentric_weights.x < 0 || barycentric_weights.y < 0 || barycentric_weights.z < 0) continue;
float frag_depth = interpolate_depth(screen_depth, barycentric_weights);
if (frag_depth > render_buffer->get_depth(P.x, P.y)) continue;
shader_struct_v2f interpolate_v2f;
interpolate_varyings(v2f, &interpolate_v2f, sizeof(shader_struct_v2f), barycentric_weights, recip_w);
// fragment shader
Color color;
bool discard = draw_data->shader->fragment(&interpolate_v2f, color);
if (!discard)
{
render_buffer->set_depth(P.x, P.y, frag_depth);
render_buffer->set_color(P.x, P.y, color);
}
}
}
}
void graphics_draw_triangle(DrawData* draw_data)
{
shader_struct_v2f v2fs[3];
for (int i = 0; i < draw_data->model->nfaces(); i++)
{
for (int j = 0; j < 3; j++)
{
shader_struct_a2v a2v;
a2v.obj_pos = draw_data->model->vert(i, j);
a2v.obj_normal = draw_data->model->normal(i, j);
a2v.uv = draw_data->model->uv(i, j);
v2fs[j] = draw_data->shader->vertex(&a2v);
}
rasterize_triangle(draw_data, v2fs);
}
}