dos - faster rasterization

This commit is contained in:
zbyv 2026-03-19 23:36:54 +01:00
parent 44d2b8e350
commit 48819cf841

View File

@ -15,6 +15,8 @@ struct Context
uint8_t *backbuffer; uint8_t *backbuffer;
uint8_t *colorbuffer; uint8_t *colorbuffer;
float *depthbuffer; float *depthbuffer;
uint8_t *texture;
float lightdir[3];
}; };
static uint8_t *vga = (uint8_t *)0xA0000; static uint8_t *vga = (uint8_t *)0xA0000;
@ -154,8 +156,8 @@ static void MapToRes(struct Context *ctx, float a[])
a[1] = a[1] / a[3]; a[1] = a[1] / a[3];
a[2] = a[2] / a[3]; a[2] = a[2] / a[3];
a[0] = (a[0] + 1.0) * 0.5 * (ctx->width - 1); a[0] = (a[0] + 1.0f) * 0.5f * (ctx->width - 1);
a[1] = (1.0 - a[1]) * 0.5 * (ctx->height - 1); a[1] = (1.0f - a[1]) * 0.5f * (ctx->height - 1);
} }
static void Cross(float result[], float a[], float b[]) static void Cross(float result[], float a[], float b[])
@ -279,154 +281,255 @@ static void Perspective(float mat[], float fov, float aspectratio, float nearp,
mat[15] = 0.0f; mat[15] = 0.0f;
} }
static void DrawTriangle(struct Context *ctx, float wp0[], float wp1[], float wp2[], uint8_t texture[], float c0[], float c1[], float c2[], float mvp[], float lightdir[], float n0[], float n1[], float n2[]) struct ScrVertex
{ {
float p0[4], p1[4], p2[4]; float x, y;
float t[2];
MatMultVec3(p0, mvp, wp0); float n[3];
MatMultVec3(p1, mvp, wp1);
MatMultVec3(p2, mvp, wp2);
if (p0[3] != 0.0f && p1[3] != 0.0f && p2[3] != 0.0f)
{
int x, y, idx, tx, ty, ti;
float p[2];
float depth; float depth;
float w0, w1, w2, dot00, dot01, dot11, dot20, dot21, denom, d0, d1, d2; };
float v0[2], v1[2], v2[2];
float texcoord[2];
float normal[3];
float diff;
int aabbmin[2], aabbmax[2];
float c[3];
MapToRes(ctx, p0); static void FillScanLine(struct Context *ctx, const struct ScrVertex *v0, const struct ScrVertex *v1)
MapToRes(ctx, p1);
MapToRes(ctx, p2);
aabbmin[0] = Max(Min3(p0[0], p1[0], p2[0]), 0.0f);
aabbmin[1] = Max(Min3(p0[1], p1[1], p2[1]), 0.0f);
aabbmax[0] = Min(Max3(p0[0], p1[0], p2[0]), ctx->width - 1);
aabbmax[1] = Min(Max3(p0[1], p1[1], p2[1]), ctx->height - 1);
for (y = aabbmin[1]; y <= aabbmax[1]; ++y)
{ {
for (x = aabbmin[0]; x <= aabbmax[0]; ++x) int x, y, start, end, t0x, t0y, t1x, t1y, tx, ty;
{ float c[3], n[3], depth, *depthbuf, xdiff, depthdiff, tdiff[2], ndiff[3], diffuse;
p[0] = x; uint8_t *texel;
p[1] = y;
if (!IsOnRight(p0, p1, p) || !IsOnRight(p1, p2, p) || !IsOnRight(p2, p0, p))
start = v0->x;
if (start < 0)
start = 0;
end = v1->x;
if (end > ctx->width)
end = ctx->width;
y = v0->y;
xdiff = v1->x - v0->x;
depthdiff = v1->depth - v0->depth;
tdiff[0] = v1->t[0] - v0->t[0];
tdiff[1] = v1->t[1] - v0->t[1];
ndiff[0] = v1->n[0] - v0->n[0];
ndiff[1] = v1->n[1] - v0->n[1];
ndiff[2] = v1->n[2] - v0->n[2];
for (x = start; x < end; ++x)
{
float t = ((float)x - v0->x) / xdiff;
depth = v0->depth + t * depthdiff;
depthbuf = &ctx->depthbuffer[x + y * ctx->width];
if (*depthbuf < depth)
continue; continue;
idx = x + ctx->width * y; *depthbuf = depth;
v0[0] = p1[0] - p0[0]; tx = (v0->t[0] + t * tdiff[0]) * ctx->tex_w;
v0[1] = p1[1] - p0[1]; ty = (1.0f - (v0->t[1] + t * tdiff[1])) * ctx->tex_h;
v1[0] = p2[0] - p0[0];
v1[1] = p2[1] - p0[1];
v2[0] = p[0] - p0[0];
v2[1] = p[1] - p0[1];
dot00 = Dot2(v0, v0); if (tx < 0)
dot01 = Dot2(v0, v1); tx = 0;
dot11 = Dot2(v1, v1); else if (tx >= ctx->width)
dot20 = Dot2(v2, v0); tx = ctx->width - 1;
dot21 = Dot2(v2, v1);
denom = dot00 * dot11 - dot01 * dot01; if (ty < 0)
w1 = (dot11 * dot20 - dot01 * dot21) / denom; ty = 0;
w2 = (dot00 * dot21 - dot01 * dot20) / denom; else if (ty >= ctx->height)
w0 = 1.0f - w1 - w2; ty = ctx->height - 1;
depth = p0[2] * w0 + p1[2] * w1 + p2[2] * w2; n[0] = v0->n[0] + t * ndiff[0];
n[1] = v0->n[1] + t * ndiff[1];
n[2] = v0->n[2] + t * ndiff[2];
if (depth > 0.0 && ctx->depthbuffer[idx] > depth) Normalize(n);
{ diffuse = Max(0.5, Dot(n, ctx->lightdir));
ctx->depthbuffer[idx] = depth;
idx = idx * 3;
texcoord[0] = w0 * c0[0] + w1 * c1[0] + w2 * c2[0]; texel = &ctx->texture[(tx + ty * ctx->tex_w) * 3];
texcoord[1] = w0 * c0[1] + w1 * c1[1] + w2 * c2[1]; c[0] = texel[0] / 255.0f * diffuse;
c[1] = texel[1] / 255.0f * diffuse;
normal[0] = w0 * n0[0] + w1 * n1[0] + w2 * n2[0]; c[2] = texel[2] / 255.0f * diffuse;
normal[1] = w0 * n0[1] + w1 * n1[1] + w2 * n2[1];
normal[2] = w0 * n0[2] + w1 * n1[2] + w2 * n2[2];
Normalize(normal);
diff = Max(0.5, Dot(normal, lightdir));
tx = texcoord[0] * ctx->tex_w;
ty = (1 - texcoord[1]) * ctx->tex_h;
ti = (tx + ty * ctx->tex_w) * 3;
c[0] = texture[ti] / 255.0f * diff;
c[1] = texture[ti + 1] / 255.0f * diff;
c[2] = texture[ti + 2] / 255.0f * diff;
SetPixel(ctx, x, y, c); SetPixel(ctx, x, y, c);
} }
} }
static void SortByY(struct ScrVertex** s)
{
struct ScrVertex* temp;
if (s[0]->y > s[1]->y)
{
temp = s[0];
s[0] = s[1];
s[1] = temp;
}
if (s[1]->y > s[2]->y)
{
temp = s[1];
s[1] = s[2];
s[2] = temp;
}
if (s[0]->y > s[1]->y)
{
temp = s[0];
s[0] = s[1];
s[1] = temp;
}
}
static void DebugDrawPoint(struct Context *ctx, int x, int y)
{
float c[] = { 1.0f, 0.0f, 0.0f };
if (x < 0 || x >= ctx->width || y < 0 || y >= ctx->height)
return;
SetPixel(ctx, x, y, c);
}
static void LerpScrVertex(const struct ScrVertex *a, const struct ScrVertex *b, struct ScrVertex *res, float t)
{
res->x = a->x + (b->x - a->x) * t;
res->y = a->y + (b->y - a->y) * t;
res->t[0] = a->t[0] + (b->t[0] - a->t[0]) * t;
res->t[1] = a->t[1] + (b->t[1] - a->t[1]) * t;
res->n[0] = a->n[0] + (b->n[0] - a->n[0]) * t;
res->n[1] = a->n[1] + (b->n[1] - a->n[1]) * t;
res->n[2] = a->n[2] + (b->n[2] - a->n[2]) * t;
res->depth = a->depth + (b->depth - a->depth) * t;
}
static void DrawTriangle(struct Context *ctx, float wp0[], float wp1[], float wp2[], float c0[], float c1[], float c2[], float mvp[], float n0[], float n1[], float n2[])
{
float p[3][4];
struct ScrVertex v[3], nv, *s[4], *tempv;
int i;
float nf;
MatMultVec3(p[0], mvp, wp0);
MatMultVec3(p[1], mvp, wp1);
MatMultVec3(p[2], mvp, wp2);
for (i = 0; i < 3; ++i)
{
if (p[i][3] == 0.0f)
return;
MapToRes(ctx, p[i]);
v[i].x = p[i][0];
v[i].y = p[i][1];
v[i].depth = p[i][2];
}
v[0].t[0] = c0[0];
v[0].t[1] = c0[1];
v[1].t[0] = c1[0];
v[1].t[1] = c1[1];
v[2].t[0] = c2[0];
v[2].t[1] = c2[1];
v[0].n[0] = n0[0];
v[0].n[1] = n0[1];
v[0].n[2] = n0[2];
v[1].n[0] = n1[0];
v[1].n[1] = n1[1];
v[1].n[2] = n1[2];
v[2].n[0] = n2[0];
v[2].n[1] = n2[1];
v[2].n[2] = n2[2];
if (IsOnRight(p[0], p[2], p[1]))
return; /* backface cull */
s[0] = &v[0];
s[1] = &v[1];
s[2] = &v[2];
s[3] = &nv;
SortByY(s);
nf = (s[1]->y - s[0]->y) / (s[2]->y - s[0]->y);
LerpScrVertex(s[0], s[2], &nv, nf);
nv.y = s[1]->y;
if (s[3]->x < s[1]->x)
{
tempv = s[1];
s[1] = s[3];
s[3] = tempv;
}
// for (i = 0; i < 4; ++i)
// {
// DebugDrawPoint(ctx, s[i]->x, s[i]->y);
// }
if (s[0]->y != s[1]->y)
{
int start, end, sc_y;
start = s[0]->y;
if (start < 0)
start = 0;
end = s[1]->y + 1;
if (end > ctx->height)
end = ctx->height;
for (sc_y = start; sc_y < end; sc_y++)
{
struct ScrVertex scv[2];
float t = ((float)sc_y - s[0]->y) / (s[1]->y - s[0]->y);
LerpScrVertex(s[0], s[1], &scv[0], t);
LerpScrVertex(s[0], s[3], &scv[1], t);
scv[0].y = sc_y;
FillScanLine(ctx, &scv[0], &scv[1]);
}
}
if (s[1]->y != s[2]->y)
{
int start, end, sc_y;
start = s[3]->y + 1;
if (start < 0)
start = 0;
end = s[2]->y + 1;
if (end > ctx->height)
end = ctx->height;
for (sc_y = start; sc_y < end; sc_y++)
{
struct ScrVertex scv[2];
float t = ((float)sc_y - s[3]->y) / (s[2]->y - s[3]->y);
LerpScrVertex(s[1], s[2], &scv[0], t);
LerpScrVertex(s[3], s[2], &scv[1], t);
scv[0].y = sc_y;
FillScanLine(ctx, &scv[0], &scv[1]);
} }
} }
} }
// static void OutputPPM(FILE *file, struct Context *ctx)
// {
// int i, numpixels;
// fprintf(file, "P3\n%d\n%d\n255\n", ctx->width, ctx->height);
// numpixels = ctx->width * ctx->height;
// for (i = 0; i < numpixels * 3; ++i)
// {
// fprintf(file, "%d ", (int)(ctx->colorbuffer[i] * 255.0f));
// }
// fprintf(file, "\n");
// }
// static void OutputVT100(FILE* out, const struct Context *ctx)
// {
// int r1, g1, b1, r2, b2, g2, x, y, idx, rowoffset;
// fprintf(out, "\x1b[1;1H\n");
// for (y = 0; y <= ctx->height - 2; y += 2)
// {
// fprintf(out, "\n");
// for (x = 0; x < ctx->width; ++x)
// {
// idx = (x + y * ctx->width) * 3;
// rowoffset = ctx->width * 3;
// r1 = ctx->colorbuffer[idx] * 255;
// g1 = ctx->colorbuffer[idx + 1] * 255;
// b1 = ctx->colorbuffer[idx + 2] * 255;
// r2 = ctx->colorbuffer[idx + rowoffset] * 255;
// g2 = ctx->colorbuffer[idx + 1 + rowoffset] * 255;
// b2 = ctx->colorbuffer[idx + 2 + rowoffset] * 255;
// fprintf(out, "\x1b[38;2;%d;%d;%dm\x1b[48;2;%d;%d;%dm▀", r1, g1, b1, r2, g2, b2);
// }
// }
// }
static void OutputVGA(const struct Context *ctx) static void OutputVGA(const struct Context *ctx)
{ {
if (ctx->colorbuffer != vga) if (ctx->colorbuffer != vga)
memcpy(vga, ctx->colorbuffer, 320 * 200); memcpy(vga, ctx->colorbuffer, 320 * 200);
} }
// Function DumpMat(Real Array mat)
// Declare Integer i
// For i = 0 to 15
// Output mat[i] & " "
// If i % 4 == 3
// Output ""
// End
// End
// End
static void *MyMalloc(size_t n) static void *MyMalloc(size_t n)
{ {
void *mem = malloc(n); void *mem = malloc(n);
@ -443,9 +546,6 @@ int main(int argc, char **argv)
{ {
struct Context ctx; struct Context ctx;
// float bg[] = { 0.25f, 0.25f, 0.25f };
float lightdir[] = { 0.3f, 1.0f, 0.4f };
float view[16]; float view[16];
float proj[16]; float proj[16];
float mvp[16]; float mvp[16];
@ -454,7 +554,7 @@ int main(int argc, char **argv)
float targetpos[] = { 0.0f, 0.0f, 0.0f }; float targetpos[] = { 0.0f, 0.0f, 0.0f };
float upvector[] = { 0.0f, 1.0f, 0.0f }; float upvector[] = { 0.0f, 1.0f, 0.0f };
float aspectratio = 1.46; float aspectratio = 1.3f;
float p0[3], p1[3], p2[3]; float p0[3], p1[3], p2[3];
float c0[3], c1[3], c2[3]; float c0[3], c1[3], c2[3];
@ -462,7 +562,6 @@ int main(int argc, char **argv)
int datasize, i, vertices, tp; int datasize, i, vertices, tp;
float *data; float *data;
uint8_t *texture;
int temp, i0, i1, i2; int temp, i0, i1, i2;
float camangle; float camangle;
@ -470,11 +569,6 @@ int main(int argc, char **argv)
FILE *in = stdin; FILE *in = stdin;
FILE *out = stdout; FILE *out = stdout;
// getch();
// SetMode(0x3);
// return 0;
if (argc > 1) if (argc > 1)
{ {
in = fopen(argv[1], "r"); in = fopen(argv[1], "r");
@ -503,7 +597,10 @@ int main(int argc, char **argv)
ctx.colorbuffer = ctx.backbuffer; ctx.colorbuffer = ctx.backbuffer;
Normalize(lightdir); ctx.lightdir[0] = 0.3f;
ctx.lightdir[1] = 1.0f;
ctx.lightdir[2] = 0.4f;
Normalize(ctx.lightdir);
Perspective(proj, DegToRad(90.0f) / aspectratio, aspectratio, 0.1f, 50.0f); Perspective(proj, DegToRad(90.0f) / aspectratio, aspectratio, 0.1f, 50.0f);
@ -520,13 +617,13 @@ int main(int argc, char **argv)
fscanf(in, "%d\n%d\n", &ctx.tex_w, &ctx.tex_h); fscanf(in, "%d\n%d\n", &ctx.tex_w, &ctx.tex_h);
tp = ctx.tex_w * ctx.tex_h * 3; tp = ctx.tex_w * ctx.tex_h * 3;
texture = MyMalloc(tp); ctx.texture = MyMalloc(tp);
for (i = 0; i < tp; ++i) for (i = 0; i < tp; ++i)
{ {
int v; int v;
fscanf(in, "%d\n", &v); fscanf(in, "%d\n", &v);
texture[i] = v; ctx.texture[i] = v;
} }
fprintf(stderr, "textura rdy\n"); fprintf(stderr, "textura rdy\n");
@ -592,16 +689,12 @@ int main(int argc, char **argv)
n2[1] = data[i2 + 6]; n2[1] = data[i2 + 6];
n2[2] = data[i2 + 7]; n2[2] = data[i2 + 7];
DrawTriangle(&ctx, p0, p1, p2, texture, c0, c1, c2, mvp, lightdir, n0, n1, n2); DrawTriangle(&ctx, p0, p1, p2, c0, c1, c2, mvp, n0, n1, n2);
} }
// OutputPPM(out, &ctx);
// OutputVT100(out, &ctx);
OutputVGA(&ctx); OutputVGA(&ctx);
} }
return 0; return 0;
} }