This commit is contained in:
zbyv 2026-03-19 12:09:03 +01:00
commit 44d2b8e350
5 changed files with 219901 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
.cache/
.vscode/
build/
wc/
*.exe
*.o
*.ppm

4
build-dos.sh Normal file
View File

@ -0,0 +1,4 @@
#!/bin/bash
WATCOM=/home/zbyv/render/wc EDPATH=/home/zbyv/render/wc/eddat INCLUDE=/home/zbyv/render/wc/h PATH=/home/zbyv/render/wc/binl:/home/zbyv/render/wc/binw:$PATH ./wc/binl/wcl386 -3 -fpi87 -fp3 -os -d0 -mf -bt=dos -l=stub32x -fe=render.exe render_dos.c

218764
data.txt Normal file

File diff suppressed because it is too large Load Diff

519
render.fcode Normal file
View File

@ -0,0 +1,519 @@
Function ClearBuffers(Integer Array meta, Real Array colorbuffer, Real Array depthbuffer, Real Array color, Real depth)
Declare Integer i
For i = 0 to meta[2] - 1
Assign colorbuffer[i * 3] = color[0]
Assign colorbuffer[i * 3 + 1] = color[1]
Assign colorbuffer[i * 3 + 2] = color[2]
Assign depthbuffer[i] = depth
End
End
Function DegToRad(Real deg)
Declare Real rad
Assign rad = deg * 0.0174532925
Return Real rad
Function Min(Real a, Real b)
Declare Real r
If a < b
Assign r = a
False:
Assign r = b
End
Return Real r
Function Min3(Real a, Real b, Real c)
Declare Real r
Assign r = Min(Min(a, b), c)
Return Real r
Function Max(Real a, Real b)
Declare Real r
If a > b
Assign r = a
False:
Assign r = b
End
Return Real r
Function Max3(Real a, Real b, Real c)
Declare Real r
Assign r = Max(Max(a, b), c)
Return Real r
Function IsOnRight(Real Array a, Real Array b, Real Array c)
Declare Boolean r
If (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]) <= 0
Assign r = true
False:
Assign r= false
End
Return Boolean r
Function Distance2(Real Array a, Real Array b)
Declare Real x, y, d
Assign x = b[0] - a[0]
Assign y = b[1] - a[1]
Assign d = sqrt(x * x + y * y)
Return Real d
Function Normalize(Real Array a)
Declare Real l
Assign l = sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2])
Assign a[0] = a[0] / l
Assign a[1] = a[1] / l
Assign a[2] = a[2] / l
End
Function MapToRes(Integer Array meta, Real Array a)
Assign a[0] = a[0] / a[3]
Assign a[1] = a[1] / a[3]
Assign a[2] = a[2] / a[3]
Assign a[0] = (a[0] + 1.0) * 0.5 * (meta[0] - 1)
Assign a[1] = (1.0 - a[1]) * 0.5 * (meta[1] - 1)
End
Function Cross(Real Array result, Real Array a, Real Array b)
Assign result[0] = a[1] * b[2] - a[2] * b[1]
Assign result[1] = a[2] * b[0] - a[0] * b[2]
Assign result[2] = a[0] * b[1] - a[1] * b[0]
End
Function Dot(Real Array a, Real Array b)
Declare Real result
Assign result = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
Return Real result
Function Dot2(Real Array a, Real Array b)
Declare Real result
Assign result = a[0] * b[0] + a[1] * b[1]
Return Real result
Function VecCopy3(Real Array result, Real Array a)
Assign result[0] = a[0]
Assign result[1] = a[1]
Assign result[2] = a[2]
End
Function VecSubVec3(Real Array result, Real Array a, Real Array b)
Assign result[0] = a[0] - b[0]
Assign result[1] = a[1] - b[1]
Assign result[2] = a[2] - b[2]
End
Function MatMultMat(Real Array result, Real Array a, Real Array b)
Assign result[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12]
Assign result[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13]
Assign result[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14]
Assign result[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15]
Assign result[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12]
Assign result[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13]
Assign result[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14]
Assign result[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15]
Assign result[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12]
Assign result[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13]
Assign result[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14]
Assign result[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15]
Assign result[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12]
Assign result[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13]
Assign result[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14]
Assign result[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15]
End
Function MatMultVec(Real Array result, Real Array a, Real Array v)
Assign result[0] = a[0] * v[0] + a[1] * v[1] + a[2] * v[2] + a[3] * v[3]
Assign result[1] = a[4] * v[0] + a[5] * v[1] + a[6] * v[2] + a[7] * v[3]
Assign result[2] = a[8] * v[0] + a[9] * v[1] + a[10] * v[2] + a[11] * v[3]
Assign result[3] = a[12] * v[0] + a[13] * v[1] + a[14] * v[2] + a[15] * v[3]
End
Function MatMultVec3(Real Array result, Real Array a, Real Array v)
Assign result[0] = a[0] * v[0] + a[1] * v[1] + a[2] * v[2] + a[3]
Assign result[1] = a[4] * v[0] + a[5] * v[1] + a[6] * v[2] + a[7]
Assign result[2] = a[8] * v[0] + a[9] * v[1] + a[10] * v[2] + a[11]
Assign result[3] = a[12] * v[0] + a[13] * v[1] + a[14] * v[2] + a[15]
End
Function LookAt(Real Array mat, Real Array campos, Real Array targetpos, Real Array upvec)
Declare Real Array forward[3]
Declare Real Array right[3]
Declare Real Array up[3]
Call VecSubVec3(forward, targetpos, campos)
Call Normalize(forward)
Call Cross(right, forward, upvec)
Call Normalize(right)
Call Cross(up, right, forward)
Assign mat[0] = right[0]
Assign mat[1] = right[1]
Assign mat[2] = right[2]
Assign mat[3] = -Dot(right, campos)
Assign mat[4] = up[0]
Assign mat[5] = up[1]
Assign mat[6] = up[2]
Assign mat[7] = -Dot(up, campos)
Assign mat[8] = -forward[0]
Assign mat[9] = -forward[1]
Assign mat[10] = -forward[2]
Assign mat[11] = Dot(forward, campos)
Assign mat[12] = 0.0
Assign mat[13] = 0.0
Assign mat[14] = 0.0
Assign mat[15] = 1.0
End
Function Perspective(Real Array mat, Real fov, Real aspectratio, Real near, Real far)
Declare Real tanhalffovy
Assign tanhalffovy = tan(fov * 0.5)
Assign mat[0] = 1 / (aspectratio * tanhalffovy)
Assign mat[1] = 0.0
Assign mat[2] = 0.0
Assign mat[3] = 0.0
Assign mat[4] = 0.0
Assign mat[5] = 1 / tanhalffovy
Assign mat[6] = 0.0
Assign mat[7] = 0.0
Assign mat[8] = 0.0
Assign mat[9] = 0.0
Assign mat[10] = -(far + near) / (far - near)
Assign mat[11] = -(2 * far * near) / (far - near)
Assign mat[12] = 0.0
Assign mat[13] = 0.0
Assign mat[14] = -1.0
Assign mat[15] = 0.0
End
Function DrawTriangle(Integer Array meta, Real Array colorbuffer, Real Array depthbuffer, Real Array wp0, Real Array wp1, Real Array wp2, Integer Array texture, Real Array c0, Real Array c1, Real Array c2, Real Array mvp, Real Array lightdir, Real Array n0, Real Array n1, Real Array n2)
Declare Real Array p0[4]
Declare Real Array p1[4]
Declare Real Array p2[4]
Call MatMultVec3(p0, mvp, wp0)
Call MatMultVec3(p1, mvp, wp1)
Call MatMultVec3(p2, mvp, wp2)
If p0[3] != 0.0 && p1[3] != 0.0 && p2[3] != 0.0
Call MapToRes(meta, p0)
Call MapToRes(meta, p1)
Call MapToRes(meta, p2)
Declare Real Array aabbmin[2]
Declare Real Array aabbmax[2]
Assign aabbmin[0] = Max(Min3(p0[0], p1[0], p2[0]), 0)
Assign aabbmin[1] = Max(Min3(p0[1], p1[1], p2[1]), 0)
Assign aabbmax[0] = Min(Max3(p0[0], p1[0], p2[0]), meta[0] - 1)
Assign aabbmax[1] = Min(Max3(p0[1], p1[1], p2[1]), meta[1] - 1)
Declare Integer x, y, idx, tx, ty, ti
Declare Real Array p[2]
Declare Real depth
Declare Real w0, w1, w2, dot00, dot01, dot11, dot20, dot21, denom, d0, d1, d2
Declare Real Array v0[2]
Declare Real Array v1[2]
Declare Real Array v2[2]
Declare Real Array texcoord[2]
... Output p0[2]
... Output p1[2]
... Output p2[2]
Declare Real Array normal[3]
Declare Real diff
For x = aabbmin[0] to aabbmax[0]
For y = aabbmin[1] to aabbmax[1]
Assign p[0] = x
Assign p[1] = y
... x >= 0 && x < meta[0] && y >= 0 && y < meta[1] &&
If IsOnRight(p0, p1, p) && IsOnRight(p1, p2, p) && IsOnRight(p2, p0, p)
Assign v0[0] = p1[0] - p0[0]
Assign v0[1] = p1[1] - p0[1]
Assign v1[0] = p2[0] - p0[0]
Assign v1[1] = p2[1] - p0[1]
Assign v2[0] = p[0] - p0[0]
Assign v2[1] = p[1] - p0[1]
Assign dot00 = Dot2(v0, v0)
Assign dot01 = Dot2(v0, v1)
Assign dot11 = Dot2(v1, v1)
Assign dot20 = Dot2(v2, v0)
Assign dot21 = Dot2(v2, v1)
Assign denom = dot00 * dot11 - dot01 * dot01
Assign w1 = (dot11 * dot20 - dot01 * dot21) / denom
Assign w2 = (dot00 * dot21 - dot01 * dot20) / denom
Assign w0 = 1.0 - w1 - w2
Assign depth = p0[2] * w0 + p1[2] * w1 + p2[2] * w2
Assign idx = x + meta[0] * y
If depth > 0.0 && depthbuffer[idx] > depth
Assign depthbuffer[idx] = depth
Assign idx = idx * 3
Assign texcoord[0] = w0 * c0[0] + w1 * c1[0] + w2 * c2[0]
Assign texcoord[1] = w0 * c0[1] + w1 * c1[1] + w2 * c2[1]
Assign normal[0] = w0 * n0[0] + w1 * n1[0] + w2 * n2[0]
Assign normal[1] = w0 * n0[1] + w1 * n1[1] + w2 * n2[1]
Assign normal[2] = w0 * n0[2] + w1 * n1[2] + w2 * n2[2]
Call Normalize(normal)
Assign diff = Max(0.5, Dot(normal, lightdir))
Assign tx = texcoord[0] * meta[3]
Assign ty = (1 - texcoord[1]) * meta[4]
Assign ti = (tx + ty * meta[3]) * 3
Assign colorbuffer[idx] = texture[ti] / 255 * diff
Assign colorbuffer[idx + 1] = texture[ti + 1] / 255 * diff
Assign colorbuffer[idx + 2] = texture[ti + 2] / 255 * diff
End
End
End
End
End
End
Function OutputPPM(Integer Array meta, Real Array colorbuffer)
Output "P3"
Output meta[0] & " " & meta[1]
Output 255
Declare Integer i, numpixels
Assign numpixels = meta[2]
For i = 0 to (numpixels - 1) * 3 step 3
Output Int(colorbuffer[i] * 255) & " " ...
Output Int(colorbuffer[i + 1] * 255) & " " ...
Output Int(colorbuffer[i + 2] * 255) & " " ...
End
End
Function OutputVT100(Integer Array meta, Real Array colorbuffer)
Output ToChar(27)&"[1;1H"
Declare Integer r1, g1, b1, r2, b2, g2, x, y, width, height, idx, rowoffset
... Assign iterations = (meta[2] / 2 - 1) * 3
Assign width = meta[0]
Assign height = meta[1]
For y = 0 to height - 2 step 2
Output ""
For x = 0 to width - 1
Assign idx = (x + y * width) * 3
Assign rowoffset = width * 3
Assign r1 = colorbuffer[idx] * 255
Assign g1 = colorbuffer[idx + 1] * 255
Assign b1 = colorbuffer[idx + 2] * 255
Assign r2 = colorbuffer[idx + rowoffset] * 255
Assign g2 = colorbuffer[idx + 1 + rowoffset] * 255
Assign b2 = colorbuffer[idx + 2 + rowoffset] * 255
Output ToChar(27) & "[38;2;" & r1 & ";" & g1 & ";" & b1 & "m" & ToChar(27) & "[48;2;" & r2 &";" & g2 & ";" & b2 & "m" & "▀" ...
End
End
End
Function DumpMat(Real Array mat)
Declare Integer i
For i = 0 to 15
Output mat[i] & " "
If i % 4 == 3
Output ""
End
End
End
Function Main
Declare Integer Array meta[5]
Assign meta[0] = 175
Assign meta[1] = 120
... Assign meta[0] = 1280
... Assign meta[1] = 720
Assign meta[2] = meta[0] * meta[1]
Declare Real Array depthbuffer[meta[2]]
Declare Real Array colorbuffer[meta[2] * 3]
Declare Real Array background[3]
Assign background[0] = 0.3
Assign background[1] = 0.3
Assign background[2] = 0.3
Call ClearBuffers(meta, colorbuffer, depthbuffer, background, 100.0)
Declare Real Array lightdir[3]
Assign lightdir[0] = .3
Assign lightdir[1] = 1
Assign lightdir[2] = .4
Call Normalize(lightdir)
Declare Real Array view[16]
Declare Real Array proj[16]
Declare Real Array mvp[16]
Declare Real Array campos[3]
Declare Real Array targetpos[3]
Declare Real Array upvector[3]
Assign targetpos[0] = 0
Assign targetpos[1] = 0
Assign targetpos[2] = 0
Assign upvector[0] = 0
Assign upvector[1] = 1
Assign upvector[2] = 0
... Call DumpMat(view)
Declare Real aspectratio
Assign aspectratio = 1.46
... meta[0] / meta[1]
Call Perspective(proj, DegToRad(90.0) / aspectratio, aspectratio, 0.1, 50.0)
Declare Real Array p0[3]
Declare Real Array p1[3]
Declare Real Array p2[3]
Declare Real Array c0[2]
Declare Real Array c1[2]
Declare Real Array c2[2]
Declare Real Array n0[3]
Declare Real Array n1[3]
Declare Real Array n2[3]
Declare Integer datasize, i, vertices
Input datasize
Input vertices
Declare Real Array data[datasize]
For i = 0 to datasize - 1
Input data[i]
End
Output "model rdy"
Input meta[3]
Input meta[4]
Declare Integer tp
Assign tp = meta[3] * meta[4] * 3
Declare Integer Array texture[tp]
For i = 0 to tp - 1
Input texture[i]
End
Output "textura rdy"
Declare Integer temp
Declare Integer i0, i1, i2
Declare Real camangle
Assign camangle = 0
While true
Call ClearBuffers(meta, colorbuffer, depthbuffer, background, 100.0)
Declare Real camdis
Assign camdis = 7.0
Assign campos[0] = sin(camangle) * camdis
Assign campos[1] = 0.8 * camdis
... 10 * camdis
Assign campos[2] = cos(camangle) * camdis
Assign camangle = camangle + pi / 5
Call LookAt(view, campos, targetpos, upvector)
Call MatMultMat(mvp, proj, view)
For i = 0 to vertices - 3 step 3
... For temp = 0 to vertices - 3 step 3
... Assign i = vertices - 3 - temp
Assign i0 = i * 8
Assign i1 = (i + 1) * 8
Assign i2 = (i + 2) * 8
Assign p0[0] = data[i0]
Assign p0[1] = data[i0 + 1]
Assign p0[2] = data[i0 + 2]
Assign p1[0] = data[i1]
Assign p1[1] = data[i1 + 1]
Assign p1[2] = data[i1 + 2]
Assign p2[0] = data[i2]
Assign p2[1] = data[i2 + 1]
Assign p2[2] = data[i2 + 2]
... Assign c0[0] = data[i * 8 + 5] * 0.5 + 0.5
... Assign c0[1] = data[i * 8 + 6] * 0.5 + 0.5
... Assign c0[2] = data[i * 8 + 7] * 0.5 + 0.5
Assign c0[0] = data[i0 + 3]
Assign c0[1] = data[i0 + 4]
Assign c1[0] = data[i1 + 3]
Assign c1[1] = data[i1 + 4]
Assign c2[0] = data[i2 + 3]
Assign c2[1] = data[i2 + 4]
Assign n0[0] = data[i0 + 5]
Assign n0[1] = data[i0 + 6]
Assign n0[2] = data[i0 + 7]
Assign n1[0] = data[i1 + 5]
Assign n1[1] = data[i1 + 6]
Assign n1[2] = data[i1 + 7]
Assign n2[0] = data[i2 + 5]
Assign n2[1] = data[i2 + 6]
Assign n2[2] = data[i2 + 7]
Call DrawTriangle(meta, colorbuffer, depthbuffer, p0, p1, p2, texture, c0, c1, c2, mvp, lightdir, n0, n1, n2)
... Output i
End
... Call OutputPPM(meta, colorbuffer)
Call OutputVT100(meta, colorbuffer)
End
End

607
render_dos.c Normal file
View File

@ -0,0 +1,607 @@
#include <math.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <dos.h>
#include <i86.h>
#include <conio.h>
#include <string.h>
struct Context
{
int width, height;
int tex_w, tex_h;
uint8_t *backbuffer;
uint8_t *colorbuffer;
float *depthbuffer;
};
static uint8_t *vga = (uint8_t *)0xA0000;
static const uint8_t bayer8x8[] = {
0, 32, 8, 40, 2, 34, 10, 42,
48, 16, 56, 24, 50, 18, 58, 26,
12, 44, 4, 36, 14, 46, 6, 38,
60, 28, 52, 20, 62, 30, 54, 22,
3, 35, 11, 43, 1, 33, 9, 41,
51, 19, 59, 27, 49, 17, 57, 25,
15, 47, 7, 39, 13, 45, 5, 37,
63, 31, 55, 23, 61, 29, 53, 21
};
static void SetMode(unsigned char mode) {
union REGS regs;
regs.w.ax = mode;
int386(0x10, &regs, &regs);
}
static void SetPalette(int i, unsigned char r, unsigned char g, unsigned char b) {
outp(0x3C8, i);
outp(0x3C9, r);
outp(0x3C9, g);
outp(0x3C9, b);
}
static void InitPalette(void)
{
int i, r, g, b;
for (i = 0; i < 256; ++i)
{
r = (i >> 6) & 3;
r = (r << 4) | (r << 2) | r;
g = (i >> 3) & 7;
g = (g << 3) | g;
b = i & 7;
b = (b << 3) | b;
/* RRGGGBBB */
// SetPalette(i, (((i >> 6) & 3) << 4) | 15, (((i >> 3) & 7) << 3) | 7, ((i & 7) << 3) | 7);
SetPalette(i, r, g, b);
}
}
static void SetPixel(struct Context *ctx, int x, int y, float c[])
{
int r, g, b;
uint8_t color;
uint8_t bayerval;
r = c[0] * (4 * 64);
g = c[1] * (8 * 64);
b = c[2] * (8 * 64);
bayerval = bayer8x8[(x & 7) + (y & 7) * 8];
r += bayerval;
g += bayerval;
b += bayerval;
r >>= 6;
g >>= 6;
b >>= 6;
if (r > 3) r = 3;
if (g > 7) g = 7;
if (b > 7) b = 7;
color = (r << 6) | (g << 3) | b;
ctx->colorbuffer[x + y * 320] = color;
}
static void ClearDepth(struct Context *ctx, float depth)
{
int i;
int pixels = ctx->width * ctx->height;
for (i = 0; i < pixels; ++i)
{
ctx->depthbuffer[i] = depth;
}
}
static float DegToRad(float deg)
{
return deg * 0.0174532925f;
}
static float Min(float a, float b)
{
return a < b ? a : b;
}
static float Min3(float a, float b, float c)
{
return Min(Min(a, b), c);
}
static float Max(float a, float b)
{
return a > b ? a : b;
}
static float Max3(float a, float b, float c)
{
return Max(Max(a, b), c);
}
static int IsOnRight(float a[], float b[], float c[])
{
return ((b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]) <= 0.0f);
}
static float Distance2(float a[], float b[])
{
float x, y, d;
x = b[0] - a[0];
y = b[1] - a[1];
return sqrt(x * x + y * y);
}
static void Normalize(float a[])
{
float l = sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]);
a[0] = a[0] / l;
a[1] = a[1] / l;
a[2] = a[2] / l;
}
static void MapToRes(struct Context *ctx, float a[])
{
a[0] = a[0] / a[3];
a[1] = a[1] / a[3];
a[2] = a[2] / a[3];
a[0] = (a[0] + 1.0) * 0.5 * (ctx->width - 1);
a[1] = (1.0 - a[1]) * 0.5 * (ctx->height - 1);
}
static void Cross(float result[], float a[], float b[])
{
result[0] = a[1] * b[2] - a[2] * b[1];
result[1] = a[2] * b[0] - a[0] * b[2];
result[2] = a[0] * b[1] - a[1] * b[0];
}
static float Dot(float a[], float b[])
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
static float Dot2(float a[], float b[])
{
return a[0] * b[0] + a[1] * b[1];
}
static void VecCopy3(float result[], float a[])
{
result[0] = a[0];
result[1] = a[1];
result[2] = a[2];
}
static void VecSubVec3(float result[], float a[], float b[])
{
result[0] = a[0] - b[0];
result[1] = a[1] - b[1];
result[2] = a[2] - b[2];
};
static void MatMultMat(float result[], float a[], float b[])
{
result[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12];
result[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13];
result[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14];
result[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15];
result[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12];
result[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13];
result[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14];
result[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15];
result[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12];
result[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13];
result[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14];
result[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15];
result[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12];
result[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13];
result[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14];
result[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15];
}
static void MatMultVec(float result[], float a[], float v[])
{
result[0] = a[0] * v[0] + a[1] * v[1] + a[2] * v[2] + a[3] * v[3];
result[1] = a[4] * v[0] + a[5] * v[1] + a[6] * v[2] + a[7] * v[3];
result[2] = a[8] * v[0] + a[9] * v[1] + a[10] * v[2] + a[11] * v[3];
result[3] = a[12] * v[0] + a[13] * v[1] + a[14] * v[2] + a[15] * v[3];
}
static void MatMultVec3(float result[], float a[], float v[])
{
result[0] = a[0] * v[0] + a[1] * v[1] + a[2] * v[2] + a[3];
result[1] = a[4] * v[0] + a[5] * v[1] + a[6] * v[2] + a[7];
result[2] = a[8] * v[0] + a[9] * v[1] + a[10] * v[2] + a[11];
result[3] = a[12] * v[0] + a[13] * v[1] + a[14] * v[2] + a[15];
}
static void LookAt(float mat[], float campos[], float targetpos[], float upvec[])
{
float forward[3];
float right[3];
float up[3];
VecSubVec3(forward, targetpos, campos);
Normalize(forward);
Cross(right, forward, upvec);
Normalize(right);
Cross(up, right, forward);
mat[0] = right[0];
mat[1] = right[1];
mat[2] = right[2];
mat[3] = -Dot(right, campos);
mat[4] = up[0];
mat[5] = up[1];
mat[6] = up[2];
mat[7] = -Dot(up, campos);
mat[8] = -forward[0];
mat[9] = -forward[1];
mat[10] = -forward[2];
mat[11] = Dot(forward, campos);
mat[12] = 0.0f;
mat[13] = 0.0f;
mat[14] = 0.0f;
mat[15] = 1.0f;
}
static void Perspective(float mat[], float fov, float aspectratio, float nearp, float farp)
{
float tanhalffovy = tan(fov * 0.5f);
mat[0] = 1.0f / (aspectratio * tanhalffovy);
mat[1] = 0.0f;
mat[2] = 0.0f;
mat[3] = 0.0f;
mat[4] = 0.0f;
mat[5] = 1.0f / tanhalffovy;
mat[6] = 0.0f;
mat[7] = 0.0f;
mat[8] = 0.0f;
mat[9] = 0.0f;
mat[10] = -(farp + nearp) / (farp - nearp);
mat[11] = -(2 * farp * nearp) / (farp - nearp) ;
mat[12] = 0.0f;
mat[13] = 0.0f;
mat[14] = -1.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[])
{
float p0[4], p1[4], p2[4];
MatMultVec3(p0, mvp, wp0);
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 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);
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)
{
p[0] = x;
p[1] = y;
if (!IsOnRight(p0, p1, p) || !IsOnRight(p1, p2, p) || !IsOnRight(p2, p0, p))
continue;
idx = x + ctx->width * y;
v0[0] = p1[0] - p0[0];
v0[1] = p1[1] - p0[1];
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);
dot01 = Dot2(v0, v1);
dot11 = Dot2(v1, v1);
dot20 = Dot2(v2, v0);
dot21 = Dot2(v2, v1);
denom = dot00 * dot11 - dot01 * dot01;
w1 = (dot11 * dot20 - dot01 * dot21) / denom;
w2 = (dot00 * dot21 - dot01 * dot20) / denom;
w0 = 1.0f - w1 - w2;
depth = p0[2] * w0 + p1[2] * w1 + p2[2] * w2;
if (depth > 0.0 && ctx->depthbuffer[idx] > depth)
{
ctx->depthbuffer[idx] = depth;
idx = idx * 3;
texcoord[0] = w0 * c0[0] + w1 * c1[0] + w2 * c2[0];
texcoord[1] = w0 * c0[1] + w1 * c1[1] + w2 * c2[1];
normal[0] = w0 * n0[0] + w1 * n1[0] + w2 * n2[0];
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);
}
}
}
}
}
// 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)
{
if (ctx->colorbuffer != vga)
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)
{
void *mem = malloc(n);
if (!mem)
{
fprintf(stderr, "cannot alloc %d bytes!\n", (int)n);
exit(1);
}
return mem;
}
int main(int argc, char **argv)
{
struct Context ctx;
// float bg[] = { 0.25f, 0.25f, 0.25f };
float lightdir[] = { 0.3f, 1.0f, 0.4f };
float view[16];
float proj[16];
float mvp[16];
float campos[3];
float targetpos[] = { 0.0f, 0.0f, 0.0f };
float upvector[] = { 0.0f, 1.0f, 0.0f };
float aspectratio = 1.46;
float p0[3], p1[3], p2[3];
float c0[3], c1[3], c2[3];
float n0[3], n1[3], n2[3];
int datasize, i, vertices, tp;
float *data;
uint8_t *texture;
int temp, i0, i1, i2;
float camangle;
FILE *in = stdin;
FILE *out = stdout;
// getch();
// SetMode(0x3);
// return 0;
if (argc > 1)
{
in = fopen(argv[1], "r");
if (!in)
{
fprintf(stderr, "cannot open for reading: %s\n", argv[1]);
exit(2);
}
}
if (argc > 2)
{
out = fopen(argv[2], "w");
if (!out)
{
fprintf(stderr, "cannot open for writing: %s\n", argv[2]);
exit(2);
}
}
ctx.width = 320;
ctx.height = 200;
ctx.backbuffer = MyMalloc(320 * 240);
ctx.depthbuffer = MyMalloc(sizeof(float) * ctx.width * ctx.height);
ctx.colorbuffer = ctx.backbuffer;
Normalize(lightdir);
Perspective(proj, DegToRad(90.0f) / aspectratio, aspectratio, 0.1f, 50.0f);
fscanf(in, "%d\n%d\n", &datasize, &vertices);
data = MyMalloc(sizeof(float) * datasize);
for (i = 0; i < datasize; ++i)
{
fscanf(in, "%f\n", &data[i]);
}
fprintf(stderr, "model rdy\n");
fscanf(in, "%d\n%d\n", &ctx.tex_w, &ctx.tex_h);
tp = ctx.tex_w * ctx.tex_h * 3;
texture = MyMalloc(tp);
for (i = 0; i < tp; ++i)
{
int v;
fscanf(in, "%d\n", &v);
texture[i] = v;
}
fprintf(stderr, "textura rdy\n");
camangle = 0.0f;
SetMode(0x13);
InitPalette();
for (;;)
{
const float camdis = 7.0f;
ClearDepth(&ctx, 100.0);
memset(ctx.colorbuffer, 82, 320*240);
campos[0] = sin(camangle) * camdis;
campos[1] = 0.8f * camdis;
campos[2] = cos(camangle) * camdis;
camangle = camangle + 3.14f * 0.005f;
LookAt(view, campos, targetpos, upvector);
MatMultMat(mvp, proj, view);
for (i = 0; i < vertices; i += 3)
{
i0 = i * 8;
i1 = (i + 1) * 8;
i2 = (i + 2) * 8;
p0[0] = data[i0];
p0[1] = data[i0 + 1];
p0[2] = data[i0 + 2];
p1[0] = data[i1];
p1[1] = data[i1 + 1];
p1[2] = data[i1 + 2];
p2[0] = data[i2];
p2[1] = data[i2 + 1];
p2[2] = data[i2 + 2];
c0[0] = data[i0 + 3];
c0[1] = data[i0 + 4];
c1[0] = data[i1 + 3];
c1[1] = data[i1 + 4];
c2[0] = data[i2 + 3];
c2[1] = data[i2 + 4];
n0[0] = data[i0 + 5];
n0[1] = data[i0 + 6];
n0[2] = data[i0 + 7];
n1[0] = data[i1 + 5];
n1[1] = data[i1 + 6];
n1[2] = data[i1 + 7];
n2[0] = data[i2 + 5];
n2[1] = data[i2 + 6];
n2[2] = data[i2 + 7];
DrawTriangle(&ctx, p0, p1, p2, texture, c0, c1, c2, mvp, lightdir, n0, n1, n2);
}
// OutputPPM(out, &ctx);
// OutputVT100(out, &ctx);
OutputVGA(&ctx);
}
return 0;
}