summaryrefslogtreecommitdiff
path: root/src/core/rasterizer.c
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-12-04 00:07:32 +0800
committerchai <chaifix@163.com>2019-12-04 00:07:32 +0800
commit2e82e2ddd0852b8063a3d6645366f53ee844e273 (patch)
tree41ec10760f2d2c9f1f782a918f48e1287da2a4b4 /src/core/rasterizer.c
+init
Diffstat (limited to 'src/core/rasterizer.c')
-rw-r--r--src/core/rasterizer.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/core/rasterizer.c b/src/core/rasterizer.c
new file mode 100644
index 0000000..0c8c6eb
--- /dev/null
+++ b/src/core/rasterizer.c
@@ -0,0 +1,180 @@
+#include "rasterizer.h"
+#include "device.h"
+#include "shader.h"
+#include "../math/math.h"
+#include "../util/assert.h"
+
+void ssrR_putline(int x0, int y0, int x1, int y1, Color color) {
+ int steep = 0;
+ if (abs(x0 - x1) < abs(y0 - y1)) {
+ swapi(x0, y0);
+ swapi(x1, y1);
+ steep = 1;
+ }
+ if (x0 > x1) {
+ swapi(x0, x1);
+ swapi(y0, y1);
+ }
+ int dx = x1 - x0;
+ int dy = y1 - y0;
+ int derror2 = abs(dy) << 1;
+ int error2 = 0;
+ int y = y0;
+ for (int x = x0; x <= x1; ++x) {
+ if (steep) {
+ ssr_putpoint(y, x, color);
+ }
+ else {
+ ssr_putpoint(x, y, color);
+ }
+ error2 += derror2;
+ if (error2 > dx) {
+ y += (y1 > y0 ? 1 : -1);
+ error2 -= (dx << 1);
+ }
+ }
+}
+
+/*使用辅助梯形计算三角形面积,《3D数学基础》P245*/
+float ssrR_area(Vec2* v1, Vec2* v2, Vec2* v3) {
+ ssr_assert(v1 && v2 && v3);
+ float area = 0.5f * ((v1->y - v2->y) * (v3->x - v2->x) + (v3->y - v2->y) * (v2->x - v1->x));
+ return area;
+}
+
+/*from https://github.com/ssloy/tinyrenderer*/
+static Vec3 s[2], u;
+bool ssrR_barycentric(Vec2* A, Vec2* B, Vec2* C, Vec2* p, Vec3* out) {
+ ssr_assert(A && B && C && p && out);
+ s[0].x = C->x - A->x; s[0].y = B->x - A->x; s[0].z = A->x - p->x;
+ s[1].x = C->y - A->y; s[1].y = B->y - A->y; s[1].z = A->y - p->y;
+ vec3_cross(&s[0], &s[1], &u);
+ if (compare(u.z, 0)) {
+ return 0;
+ } else {
+ float uz = 1.f / u.z;
+ out->x = 1 - (u.x + u.y) * uz;
+ out->y = u.y * uz;
+ out->z = u.x * uz;
+ return 1;
+ }
+}
+
+bool ssrR_ispointintriangle(Vec2* A, Vec2* B, Vec2* C, Vec2* p) {
+ ssr_assert(A && B && C && p);
+ Vec3 c; ssrR_barycentric(A, B, C, p, &c);
+ return c.x >= 0 && c.y >= 0 && c.z >= 0;
+}
+
+void ssrR_center(Vec2* A, Vec2* B, Vec2* C, Vec2* out) {
+ ssr_assert(A && B && C && out);
+ float k = 1 / 3.f;
+ out->x = k * (A->x + B->x + C->x);
+ out->y = k * (A->y + B->y + C->y);
+}
+
+/*
+** clipc 按列排放的三角形三个顶点的齐次裁剪坐标
+** program shader程序
+*/
+static Vec3 SA, SB, SC; // screen coords
+static Vec3 bcp; // 重心坐标
+void _ssrR_triangle(Vec4* CA, Vec4* CB, Vec4* CC, Vert* A, Vert* B, Vert* C, Program* program, UniformCollection* uniforms) {
+ ssr_assert(CA && CB && CC && program);
+ vec4_dividew(CA, &SA); ssrU_viewport(&SA, &SA);
+ vec4_dividew(CB, &SB); ssrU_viewport(&SB, &SB);
+ vec4_dividew(CC, &SC); ssrU_viewport(&SC, &SC);
+ /*根据屏幕空间的y值排序, A的y最小,B居中,C最大*/
+ Vec3 *sa = &SA, *sb = &SB, *sc = &SC, *tmp; Vec4* v4tmp; Vert* vtemp;
+ if (sb->y < sa->y) { sa = &SB; sb = &SA; v4tmp = CA; CA = CB; CB = v4tmp; vtemp = A; A = B; B = vtemp; }
+ if (sc->y < sb->y) { tmp = sc; sc = sb; sb = tmp; v4tmp = CC; CC = CB; CB = v4tmp; vtemp = B; B = C; C = vtemp; }
+ if (sc->y < sa->y) { tmp = sc; sc = sa; sa = tmp; v4tmp = CC; CC = CA; CA = v4tmp; vtemp = C; C = A; A = vtemp; }
+
+ float invkAC = (SC.x - SA.x) / (SC.y - SA.y + EPSILON);
+ float invkAB = (SB.x - SA.x) / (SB.y - SA.y + EPSILON);
+ float invkBC = (SC.x - SB.x) / (SC.y - SB.y + EPSILON);
+
+ int order = 1; if (((sb->y - sa->y) / (sb->x - sa->x) - invkAC) * invkAC > 0) { order = -1; }
+
+ FragmentShaderIn in = {A, B, C, 0};
+ Color color;
+ Vec2 l, r, p;
+ float depth; Vec3 cdepth = {SA.z, SB.z, SC.z};
+ float CAw = 1.f / CA->w, CBw = 1.f / CB->w, CCw = 1.f / CC->w;
+ for (p.y = sa->y; p.y <= sc->y; ++p.y) {
+ l.y = p.y;
+ r.y = p.y;
+ if (compare(SC.y, SA.y)) r.x = sc->x;
+ else r.x = sa->x + invkAC * (p.y - sa->y); /*AC*/
+ if (p.y <= sb->y) {
+ if (compare(SB.y, SA.y)) l.x = sb->x;
+ else l.x = sa->x + invkAB * (p.y - sa->y);
+ } else {
+ if (compare(SC.y, SB.y)) l.x = sc->x;
+ else l.x = sb->x + invkBC * (p.y - sb->y);
+ }
+ for (p.x = l.x; order * (r.x - p.x) >= 0; p.x += order) {
+ /*计算线性的(齐次裁剪空间)的重心坐标,分三步*/
+ if (!ssrR_barycentric(sa, sb, sc, &p, &bcp)) {
+ continue; /*discard fragment*/
+ }
+ bcp.x *= CAw; bcp.y *= CBw; bcp.z *= CCw;
+ vec3_scale(&bcp, 1.f / (bcp.x + bcp.y + bcp.z), &bcp);
+ /*depth test*/
+ depth = vec3_dot(&bcp, &cdepth) * 0.5f + 0.5f;
+ if (!ssr_testdepthf(p.x, p.y, depth)) {
+ continue; /*discard fragment*/
+ }
+ /*enter fragment shader*/
+ in.bc = &bcp;
+ program->fragmentshader(uniforms, &in, &color);
+ ssr_putpoint(p.x, p.y, color);
+ }
+ }
+}
+
+static Vec2 bboxmin, bboxmax;
+void ssrR_triangle(Vec4* CA, Vec4* CB, Vec4* CC, Vert* A, Vert* B, Vert* C, Program* program, UniformCollection* uniforms) {
+ ssr_assert(CA && CB && CC && program);
+ vec4_dividew(CA, &SA); ssrU_viewport(&SA, &SA);
+ vec4_dividew(CB, &SB); ssrU_viewport(&SB, &SB);
+ vec4_dividew(CC, &SC); ssrU_viewport(&SC, &SC);
+ bboxmin.x = min(SA.x, min(SB.x, SC.x));
+ bboxmax.x = max(SA.x, max(SB.x, SC.x));
+ bboxmin.y = min(SA.y, min(SB.y, SC.y));
+ bboxmax.y = max(SA.y, max(SB.y, SC.y));
+ float CAw = 1.f / CA->w, CBw = 1.f / CB->w, CCw = 1.f / CC->w;
+ float depth; Vec3 cdepth = { SA.z, SB.z, SC.z };
+ FragmentShaderIn in = { A, B, C, 0 };
+ Vec2 p; Color color;
+ for (p.y = bboxmin.y; p.y <= bboxmax.y; ++p.y) {
+ for (p.x = bboxmin.x; p.x <= bboxmax.x; ++p.x) {
+ /*计算线性的(齐次裁剪空间)的重心坐标,分三步*/
+ if (!ssrR_barycentric(&SA, &SB, &SC, &p, &bcp)) {
+ continue; /*discard fragment*/
+ }
+ if (bcp.x < 0 || bcp.y < 0 || bcp.z < 0) {
+ continue; /*discard fragment*/
+ }
+ bcp.x *= CAw; bcp.y *= CBw; bcp.z *= CCw;
+ vec3_scale(&bcp, 1.f / (bcp.x + bcp.y + bcp.z), &bcp);
+
+ /*深度测试*/
+ if (ssr_isenable(ENABLEMASK_DEPTHTEST)) {
+ depth = vec3_dot(&bcp, &cdepth) * 0.5f + 0.5f;
+ if (!ssr_testdepthf(p.x, p.y, depth)) {
+ continue; /*discard fragment*/
+ }
+ }
+
+ /*enter fragment shader*/
+ in.bc = &bcp;
+ bool discad = program->fragmentshader(uniforms, &in, &color);
+ if (!discad)
+ ssr_putpoint(p.x, p.y, color);
+ }
+ }
+ //ssrR_putline(SA.x, SA.y, SB.x, SB.y, 0xffff0000);
+ //ssrR_putline(SA.x, SA.y, SC.x, SC.y, 0xffff0000);
+ //ssrR_putline(SC.x, SC.y, SB.x, SB.y, 0xffff0000);
+} \ No newline at end of file