Add various versions, readme and screenshot

This commit is contained in:
tovjemam 2026-03-20 22:24:10 +01:00
parent 48819cf841
commit 58d457d332
9 changed files with 2160 additions and 0 deletions

15
README.md Normal file
View File

@ -0,0 +1,15 @@
# render
box, tree and teapot dumb software renderer
![image](res/screen-dosbox.png)
| name | lang | notes |
|---------------------|------------------------|---------------------------------------|
| `render.fcode` | Flowgorithm pseudocode | original, VT100/PPM output |
| `render.lua` | Lua | Lua port, VT100 output |
| `render_origo.lua` | Lua | unknown |
| `render_cc.lua` | Lua | ComputerCraft version, monitor output, requires processing with `convert_cc.py` and `reduce_cc.py` if too big to store on CC drive |
| `render.cpp` | C++ | C++ implementation, different structure, unknown state |
| `render_dos.c` | C | DOS, requires 32bit extender, output to VGA mode 13h (256 colors), much faster triangle rasterization alg. |

7
build_dos.bat Normal file
View File

@ -0,0 +1,7 @@
set WATCOM=c:\dev\render\wc
set EDPATH=%WATCOM%\eddat
set INCLUDE=%WATCOM%\h
set PATH=%PATH%;%WATCOM%\binnt;%WATCOM%\binw;
wcl386 -3 -fpi87 -fp3 -os -d0 -mf -bt=dos -l=stub32x -fe=render.exe render_dos.c
pause

51
convert_cc.py Normal file
View File

@ -0,0 +1,51 @@
def convert(input_filename):
with open(input_filename, "r") as f:
lines = [line.strip() for line in f if line.strip()]
# --- Step 1: Parse header ---
idx = 0
_ignored = int(lines[idx]) # First line, ignored
idx += 1
num_vertices = int(lines[idx])
idx += 1
# --- Step 2: Extract vertex data ---
vertices = []
for _ in range(num_vertices):
# Each vertex: x y z u v nx ny nz (8 numbers)
vertex = [lines[idx + i] for i in range(8)]
vertices.append(vertex)
idx += 8
# --- Step 3: Write mesh.txt ---
with open("mesh.txt", "w") as mesh_file:
mesh_file.write(str(num_vertices) + "\n")
for v in vertices:
for comp in v:
mesh_file.write(comp + "\n")
# --- Step 4: Parse texture ---
width = int(lines[idx]); idx += 1
height = int(lines[idx]); idx += 1
num_pixels = width * height
pixels = []
for _ in range(num_pixels):
r = int(lines[idx]); idx += 1
g = int(lines[idx]); idx += 1
b = int(lines[idx]); idx += 1
pixels.append((r, g, b))
# --- Step 5: Write texture.bin ---
with open("texture.bin", "wb") as tex_file:
for r, g, b in pixels:
tex_file.write(bytes([r, g, b]))
if __name__ == "__main__":
import sys
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <input_file>")
else:
convert(sys.argv[1])

20
reduce_cc.py Normal file
View File

@ -0,0 +1,20 @@
def reduce_precision(input_file, output_file):
with open(input_file, "r") as infile, open(output_file, "w") as outfile:
for line in infile:
line = line.strip()
if line: # skip empty lines
try:
num = float(line)
if num.is_integer():
outfile.write(f"{int(num)}\n")
else:
outfile.write(f"{num:.3f}\n")
except ValueError:
# If not a number, write unchanged
outfile.write(line + "\n")
if __name__ == "__main__":
input_path = "data.txt" # original file
output_path = "data2.txt" # new file
reduce_precision(input_path, output_path)

400
render.cpp Normal file
View File

@ -0,0 +1,400 @@
// render.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#pragma comment(lib,"winmm.lib")
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <Windows.h>
//#include <omp.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#define RES_WIDTH 160
#define RES_HEIGHT 120
#define RES_PIXELS (RES_WIDTH * RES_HEIGHT)
static glm::vec3 s_colorbuffer[RES_PIXELS];
static float s_depthbuffer[RES_PIXELS];
static char s_outputbuffer[5000000];
static float s_fps = 0.0f;
struct Vertex {
glm::vec3 pos;
glm::vec2 texcoord;
glm::vec3 normal;
};
struct Texture {
std::vector<glm::vec<3, uint8_t>> texels;
size_t width;
size_t height;
glm::vec3 Sample(const glm::vec2& texcoord) const {
auto idx = (int)(texcoord.x * width) + (int)((1.0f - texcoord.y) * height) * width;
const auto& t = texels[idx];
return glm::vec3((float)t.r / 255.0f, (float)t.g / 255.0f, (float)t.b / 255.0f);
}
};
static void ClearBuffers(float depth, const glm::vec3& clear_color) {
for (int i = 0; i < RES_PIXELS; ++i) {
s_colorbuffer[i] = clear_color;
s_depthbuffer[i] = depth;
}
}
using Vec3ui8 = glm::vec<3, uint8_t>;
static void OutputVT100() {
//printf("\x1b[38;2;255;255;255m\x1b[48;2;0;0;0m");
//printf("\x1b[1;1H");
//printf("\x1b[2J");
//std::cout << (char)27 << "[1;1H";
//std::string output;
//output.reserve(1000000);
int offset = 0;
//std::vector<std::ostringstream> oss;
//oss.resize(RES_HEIGHT / 2);
//output += "\x1b[38;2;255;255;255m\x1b[48;2;0;0;0m\x1b[1;1H";
Vec3ui8 prevc1(0), prevc2(0);
//#pragma omp parallel for
for (int y = 0; y <= RES_HEIGHT - 2; y += 2) {
//printf("\n");
//output += '\n';
offset += snprintf(s_outputbuffer + offset, sizeof(s_outputbuffer), "\n");
for (int x = 0; x < RES_WIDTH; ++x) {
const auto& c1 = s_colorbuffer[x + y * RES_WIDTH];
const auto& c2 = s_colorbuffer[x + (y + 1) * RES_WIDTH];
Vec3ui8 c1i = c1 * 255.0f;
Vec3ui8 c2i = c2 * 255.0f;
if (prevc1 == c1i && prevc2 == c2i) {
//offset += snprintf(s_outputbuffer + offset, sizeof(s_outputbuffer), "\xDF");
s_outputbuffer[offset++] = '\xDF';
//s_outputbuffer[offset++] = 'W';
s_outputbuffer[offset] = '\0';
}
else {
offset += snprintf(s_outputbuffer + offset, sizeof(s_outputbuffer), "\x1b[38;2;%d;%d;%dm\x1b[48;2;%d;%d;%dm\xDF", c1i.r, c1i.g, c1i.b, c2i.r, c2i.g, c2i.b);
//offset += snprintf(s_outputbuffer + offset, sizeof(s_outputbuffer), "\x1b[38;2;%d;%d;%dmW", c1i.r, c1i.g, c1i.b, c2i.r, c2i.g, c2i.b);
}
prevc1 = c1i;
prevc2 = c2i;
//printf("\x1b[38;2;%d;%d;%dm\x1b[48;2;%d;%d;%dm\xDF", c1i.r, c1i.g, c1i.b, c2i.r, c2i.g, c2i.b);
//std::ostringstream os;
//auto& os = oss[y / 2];
//os << "\x1b[38;2;" << (int)c1i.r << ";" << (int)c1i.g << ";" << (int)c1i.b << "m" << "\x1b[48;2;" << (int)c2i.r << ";" << (int)c2i.g << ";" << (int)c2i.b << "m" << "\xDF";
//output += os.str();
}
}
printf("\x1b[38;2;255;255;255m\x1b[48;2;0;0;0m");
printf("\x1b[1;1H");
printf("%s\n", s_outputbuffer);
//for (int i = 0; i < oss.size(); ++i)
// printf("%s\n", oss[i].str().c_str());
//output += "\x1b[38;2;255;255;255m\x1b[48;2;0;0;0m";
//printf("%s\n", output.c_str());
printf("\x1b[38;2;255;255;255m\x1b[48;2;0;0;0m\n");
printf("%6d %4.1f FPS ", offset, s_fps);
}
//
//// Find the closest RGBx approximation of a 24-bit RGB color, for x = 0 or 1
//glm::u8vec3 rgbx_approx(unsigned char red, unsigned char green, unsigned char blue, int x) {
// int threshold = (x + 1) * 255 / 3;
// glm::u8vec3 result;
// result.r = (red > threshold) ? 1 : 0;
// result.g = (green > threshold) ? 1 : 0;
// result.b = (blue > threshold) ? 1 : 0;
// return result;
//}
//
//// Convert a 4-bit RGBI color back to 24-bit RGB
//glm::u8vec3 rgbi_to_rgb24(int r, int g, int b, int i) {
// glm::u8vec3 result;
// result.r = ((2 * r + i) * 255) / 3;
// result.g = ((2 * g + i) * 255) / 3;
// result.b = ((2 * b + i) * 255) / 3;
// return result;
//}
//
//float color_distance(const glm::u8vec3& colorA, const glm::u8vec3& colorB) {
// int diffR = colorA.r - colorB.r;
// int diffG = colorA.g - colorB.g;
// int diffB = colorA.b - colorB.b;
// return static_cast<float>((diffR * diffR) + (diffG * diffG) + (diffB * diffB));
//}
//
//// Find the closest 4-bit RGBI approximation (by Euclidean distance) to a 24-bit RGB color
//std::pair<glm::u8vec3, int> rgbi_approx(unsigned char red, unsigned char green, unsigned char blue) {
// // Find best RGB0 and RGB1 approximations
// glm::u8vec3 rgb0 = rgbx_approx(red, green, blue, 0);
// glm::u8vec3 rgb1 = rgbx_approx(red, green, blue, 1);
//
// // Convert them back to 24-bit RGB
// glm::u8vec3 rgb24_0 = rgbi_to_rgb24(rgb0.r, rgb0.g, rgb0.b, 0);
// glm::u8vec3 rgb24_1 = rgbi_to_rgb24(rgb1.r, rgb1.g, rgb1.b, 1);
//
// // Calculate squared Euclidean distances
// float d0 = color_distance(glm::u8vec3(red, green, blue), rgb24_0);
// float d1 = color_distance(glm::u8vec3(red, green, blue), rgb24_1);
//
// if (d0 <= d1) {
// return std::make_pair(rgb0, 0);
// }
// else {
// return std::make_pair(rgb1, 1);
// }
//}
//
//
//void OutputWindows() {
// HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
//
// COORD pos;
// pos.X = 0;
// pos.Y = 0;
// SetConsoleCursorPosition(hConsole, pos);
//
// const char palette[] = ".,-~:;=!*#$@";
// int chars = sizeof(palette) - 1;
//
// for (int y = 0; y < RES_HEIGHT; ++y) {
// for (int x = 0; x < RES_WIDTH; ++x) {
// const auto& c1 = s_colorbuffer[x + y * RES_WIDTH];
// Vec3ui8 c1i = c1 * 255.0f;
//
// auto [c, i] = rgbi_approx(c1i.r, c1i.g, c1i.b);
//
// DWORD attr = 0;
// if (c.r) attr |= FOREGROUND_RED;
// if (c.g) attr |= FOREGROUND_GREEN;
// if (c.b) attr |= FOREGROUND_BLUE;
// if (i) attr |= FOREGROUND_INTENSITY;
// SetConsoleTextAttribute(hConsole, attr);
// printf("X");
//
// //float brightness = (c1.r + c1.g + c1.b) / 3.0f;
// //float b2 = glm::max(c1.r, glm::max(c1.g, c1.b));
//
// //DWORD attr = 0;
// //if (c1.r / b2 > 0.5) attr |= FOREGROUND_RED;
// //if (c1.g / b2 > 0.5) attr |= FOREGROUND_GREEN;
// //if (c1.b / b2 > 0.5) attr |= FOREGROUND_BLUE;
//
// //if (b2 > 0.5) attr |= FOREGROUND_INTENSITY;
//
// //printf("%c", palette[(int)(chars * b2)]);
//
//
// }
// printf("\n");
// }
//
//
//}
static bool ProcessVertex(const glm::vec3& pos, const glm::mat4& mvp, glm::vec2& sc, float& z) {
auto cs = mvp * glm::vec4(pos.x, pos.y, pos.z, 1.0f);
//if (cs.w < 0.0f) return true;
cs /= cs.w;
sc.x = (cs.x + 1.0f) * 0.5f * (RES_WIDTH - 1);
sc.y = (1.0f - cs.y) * 0.5f * (RES_HEIGHT - 1);
z = cs.z;
return false;
}
static bool IsRight(glm::vec2 a, glm::vec2 b, glm::vec2 c) {
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x) <= 0;
}
glm::vec3 Barycentric(glm::vec2 p, glm::vec2 a, glm::vec2 b, glm::vec2 c) {
glm::vec2 v0 = b - a, v1 = c - a, v2 = p - a;
float d00 = glm::dot(v0, v0);
float d01 = glm::dot(v0, v1);
float d11 = glm::dot(v1, v1);
float d20 = glm::dot(v2, v0);
float d21 = glm::dot(v2, v1);
float denom = d00 * d11 - d01 * d01;
float v = (d11 * d20 - d01 * d21) / denom;
float w = (d00 * d21 - d01 * d20) / denom;
float u = 1.0f - v - w;
return glm::vec3(u, v, w);
}
static void DrawTriangle(const Vertex& v0, const Vertex& v1, const Vertex& v2, const glm::mat4& mvp, const Texture& texture) {
glm::vec2 p0, p1, p2;
float z0, z1, z2;
if (ProcessVertex(v0.pos, mvp, p0, z0) || ProcessVertex(v1.pos, mvp, p1, z1) || ProcessVertex(v2.pos, mvp, p2, z2))
return;
auto aabbmin = glm::max(glm::min(glm::min(p0, p1), p2), glm::vec2(0, 0));
auto aabbmax = glm::min(glm::max(glm::max(p0, p1), p2), glm::vec2(RES_WIDTH - 1, RES_HEIGHT - 1));
int ymin = aabbmin.y;
int ymax = aabbmax.y;
//#pragma omp parallel for
for (int y = ymin; y <= ymax; y++) {
for (int x = aabbmin.x; x <= aabbmax.x; x++) {
glm::vec2 p(x, y);
if (IsRight(p0, p1, p) && IsRight(p1, p2, p) && IsRight(p2, p0, p)) {
auto w = Barycentric(p, p0, p1, p2);
auto depth = w[0] * z0 + w[1] * z1 + w[2] * z2;
int idx = p.x + p.y * RES_WIDTH;
if (depth < s_depthbuffer[idx] && depth > 0.0f) {
s_depthbuffer[idx] = depth;
auto texcoord = w[0] * v0.texcoord + w[1] * v1.texcoord + w[2] * v2.texcoord;
auto normal = w[0] * v0.normal + w[1] * v1.normal + w[2] * v2.normal;
glm::vec3 light_dir(-1, -2, -1);
float diff = glm::max(glm::dot(glm::normalize(normal), -glm::normalize(light_dir)), 0.3f);
s_colorbuffer[idx] = texture.Sample(texcoord) * diff; //glm::vec3(0, texcoord.x, texcoord.y);
//s_colorbuffer[idx] = glm::vec3(0, texcoord.x, texcoord.y);
}
}
}
}
}
int main() {
//omp_set_num_threads(4);
std::ifstream data("data.txt");
size_t waste, num_vertices;
std::vector<Vertex> vertices;
data >> waste >> num_vertices;
vertices.resize(num_vertices);
for (int i = 0; i < num_vertices; ++i) {
auto& v = vertices[i];
data >> v.pos.x >> v.pos.y >> v.pos.z >> v.texcoord.x >> v.texcoord.y >> v.normal.x >> v.normal.y >> v.normal.z;
}
Texture texture;
data >> texture.width >> texture.height;
texture.texels.resize(texture.width * texture.height);
for (int i = 0; i < texture.texels.size(); ++i) {
auto& t = texture.texels[i];
int r, g, b;
data >> r >> g >> b;
t.r = r; t.g = g; t.b = b;
}
//HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
//SetConsoleMode(hConsole, ENABLE_VIRTUAL_TERMINAL_PROCESSING);
//system(" ");
float rot = 0.0f;
int lastfpstime = 0;
int frames = 0;
while (true) {
frames++;
auto time = timeGetTime();
if (lastfpstime + 1000 < time) {
lastfpstime = time;
s_fps = frames;
frames = 0;
}
ClearBuffers(1.0f, glm::vec3(0.3f));
rot = (float)time * 0.001f;
glm::vec3 campos;
campos.x = glm::sin(rot) * 7.0f;
campos.y = 3.0f;
campos.z = glm::cos(rot) * 7.0f;
campos *= (glm::sin(rot * 0.3f) + 1.0f) * 0.5f;
//rot += glm::pi<float>() / 500.0f;
float aspect_ratio = (float)RES_WIDTH / (float)RES_HEIGHT;
auto view = glm::lookAt(campos, glm::vec3(0), glm::vec3(0, 1, 0));
auto proj = glm::perspective(glm::radians(90.0f) / aspect_ratio, aspect_ratio, 0.1f, 100.0f);
auto mvp = proj * view;
for (int i = 0; i < vertices.size(); i += 3) {
const auto& v0 = vertices[i];
const auto& v1 = vertices[i + 1];
const auto& v2 = vertices[i + 2];
DrawTriangle(v0, v1, v2, mvp, texture);
}
//for (int y = 0; y < RES_HEIGHT; ++y) {
// for (int x = 0; x < RES_WIDTH; ++x) {
// s_colorbuffer[x + RES_WIDTH * y] = glm::vec3((float)x / RES_WIDTH, (float)y / RES_HEIGHT, 0);
// }
//}
OutputVT100();
//OutputWindows();
}
}
// Run program: Ctrl + F5 or Debug > Start Without Debugging menu
// Debug program: F5 or Debug > Start Debugging menu
// Tips for Getting Started:
// 1. Use the Solution Explorer window to add/manage files
// 2. Use the Team Explorer window to connect to source control
// 3. Use the Output window to see build output and other messages
// 4. Use the Error List window to view errors
// 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project
// 6. In the future, to open this project again, go to File > Open > Project and select the .sln file

529
render.lua Normal file
View File

@ -0,0 +1,529 @@
local fps = 0
local math_floor = math.floor
local time = 0
local function ClearBuffers(meta, colorbuffer, depthbuffer, color, depth)
local i
for i = 0, meta[3] - 1 do
colorbuffer[1 + i * 3] = color[1]
colorbuffer[1 + i * 3 + 1] = color[2]
colorbuffer[1 + i * 3 + 2] = color[3]
depthbuffer[1 + i] = depth
end
end
local function DegToRad(deg)
local rad
rad = deg * 0.0174532925
return rad
end
local function Min(a, b)
local r
if a < b then
r = a
else
r = b
end
return r
end
local function Min3(a, b, c)
local r
r = Min(Min(a, b), c)
return r
end
local function Max(a, b)
local r
if a > b then
r = a
else
r = b
end
return r
end
local function Max3(a, b, c)
local r
r = Max(Max(a, b), c)
return r
end
local function IsOnRight(a, b, c)
local r
if (b[1] - a[1]) * (c[2] - a[2]) - (b[2] - a[2]) * (c[1] - a[1]) <= 0 then
r = true
else
r = false
end
return r
end
local function Distance2(a, b)
local x, y, d
x = b[1] - a[1]
y = b[2] - a[2]
d = math.sqrt(x * x + y * y)
return d
end
local function Normalize(a)
local l
l = math.sqrt(a[1] * a[1] + a[2] * a[2] + a[3] * a[3])
a[1] = a[1] / l
a[2] = a[2] / l
a[3] = a[3] / l
end
local function MapToRes(meta, a)
a[1] = a[1] / a[4]
a[2] = a[2] / a[4]
a[3] = a[3] / a[4]
a[1] = (a[1] + 1.0) * 0.5 * (meta[1] - 1)
a[2] = (1.0 - a[2]) * 0.5 * (meta[2] - 1)
end
local function Cross(result, a, b)
result[1] = a[2] * b[3] - a[3] * b[2]
result[2] = a[3] * b[1] - a[1] * b[3]
result[3] = a[1] * b[2] - a[2] * b[1]
end
local function Dot(a, b)
local result
result = a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
return result
end
local function Dot2(a, b)
local result
result = a[1] * b[1] + a[2] * b[2]
return result
end
local function VecCopy3(result, a)
result[1] = a[1]
result[2] = a[2]
result[3] = a[3]
end
local function VecSubVec3(result, a, b)
result[1] = a[1] - b[1]
result[2] = a[2] - b[2]
result[3] = a[3] - b[3]
end
local function MatMultMat(result, a, b)
result[1] = a[1] * b[1] + a[2] * b[5] + a[3] * b[9] + a[4] * b[13]
result[2] = a[1] * b[2] + a[2] * b[6] + a[3] * b[10] + a[4] * b[14]
result[3] = a[1] * b[3] + a[2] * b[7] + a[3] * b[11] + a[4] * b[15]
result[4] = a[1] * b[4] + a[2] * b[8] + a[3] * b[12] + a[4] * b[16]
result[5] = a[5] * b[1] + a[6] * b[5] + a[7] * b[9] + a[8] * b[13]
result[6] = a[5] * b[2] + a[6] * b[6] + a[7] * b[10] + a[8] * b[14]
result[7] = a[5] * b[3] + a[6] * b[7] + a[7] * b[11] + a[8] * b[15]
result[8] = a[5] * b[4] + a[6] * b[8] + a[7] * b[12] + a[8] * b[16]
result[9] = a[9] * b[1] + a[10] * b[5] + a[11] * b[9] + a[12] * b[13]
result[10] = a[9] * b[2] + a[10] * b[6] + a[11] * b[10] + a[12] * b[14]
result[11] = a[9] * b[3] + a[10] * b[7] + a[11] * b[11] + a[12] * b[15]
result[12] = a[9] * b[4] + a[10] * b[8] + a[11] * b[12] + a[12] * b[16]
result[13] = a[13] * b[1] + a[14] * b[5] + a[15] * b[9] + a[16] * b[13]
result[14] = a[13] * b[2] + a[14] * b[6] + a[15] * b[10] + a[16] * b[14]
result[15] = a[13] * b[3] + a[14] * b[7] + a[15] * b[11] + a[16] * b[15]
result[16] = a[13] * b[4] + a[14] * b[8] + a[15] * b[12] + a[16] * b[16]
end
local function MatMultVec(result, a, v)
result[1] = a[1] * v[1] + a[2] * v[2] + a[3] * v[3] + a[4] * v[4]
result[2] = a[5] * v[1] + a[6] * v[2] + a[7] * v[3] + a[8] * v[4]
result[3] = a[9] * v[1] + a[10] * v[2] + a[11] * v[3] + a[12] * v[4]
result[4] = a[13] * v[1] + a[14] * v[2] + a[15] * v[3] + a[16] * v[4]
end
local function MatMultVec3(result, a, v)
result[1] = a[1] * v[1] + a[2] * v[2] + a[3] * v[3] + a[4]
result[2] = a[5] * v[1] + a[6] * v[2] + a[7] * v[3] + a[8]
result[3] = a[9] * v[1] + a[10] * v[2] + a[11] * v[3] + a[12]
result[4] = a[13] * v[1] + a[14] * v[2] + a[15] * v[3] + a[16]
end
local function LookAt(mat, campos, targetpos, upvec)
local forward = {}
local right = {}
local up = {}
VecSubVec3(forward, targetpos, campos)
Normalize(forward)
Cross(right, forward, upvec)
Normalize(right)
Cross(up, right, forward)
mat[1] = right[1]
mat[2] = right[2]
mat[3] = right[3]
mat[4] = -Dot(right, campos)
mat[5] = up[1]
mat[6] = up[2]
mat[7] = up[3]
mat[8] = -Dot(up, campos)
mat[9] = -forward[1]
mat[10] = -forward[2]
mat[11] = -forward[3]
mat[12] = Dot(forward, campos)
mat[13] = 0.0
mat[14] = 0.0
mat[15] = 0.0
mat[16] = 1.0
end
local function Perspective(mat, fov, aspectratio, near, far)
local tanhalffovy
tanhalffovy = math.tan(fov * 0.5)
mat[1] = 1 / (aspectratio * tanhalffovy)
mat[2] = 0.0
mat[3] = 0.0
mat[4] = 0.0
mat[5] = 0.0
mat[6] = 1 / tanhalffovy
mat[7] = 0.0
mat[8] = 0.0
mat[9] = 0.0
mat[10] = 0.0
mat[11] = -(far + near) / (far - near)
mat[12] = -(2 * far * near) / (far - near)
mat[13] = 0.0
mat[14] = 0.0
mat[15] = -1.0
mat[16] = 0.0
end
local function OutputVT100(meta, colorbuffer)
print("\x1b[1;1H")
local r1, g1, b1, r2, b2, g2, width, height, idx, rowoffset
width = meta[1]
height = meta[2]
local out = {}
local pr1, pg1, pb1, pr2, pg2, pb2 = 0, 0, 0, 0, 0, 0
for y = 0, height - 2, 2 do
table.insert(out, "\n")
for x = 0, width - 1 do
idx = (x + y * width) * 3
rowoffset = width * 3
r1 = math_floor(colorbuffer[1 + idx] * 255)
g1 = math_floor(colorbuffer[1 + idx + 1] * 255)
b1 = math_floor(colorbuffer[1 + idx + 2] * 255)
r2 = math_floor(colorbuffer[1 + idx + rowoffset] * 255)
g2 = math_floor(colorbuffer[1 + idx + 1 + rowoffset] * 255)
b2 = math_floor(colorbuffer[1 + idx + 2 + rowoffset] * 255)
if r1 == pr1 and g1 == pg1 and b1 == pb1 and r2 == pr2 and g2 == pg2 and b2 == pb2 then
table.insert(out, "\xDF")
else
pr1, pg1, pb1, pr2, pg2, pb2 = r1, g1, b1, r2, g2, b2
table.insert(out, string.format("\x1b[38;2;%d;%d;%dm\x1b[48;2;%d;%d;%dm\xDF", r1, g1, b1, r2, g2, b2))
end
-- io.write("\x1b[38;2;" ..
-- r1 .. ";" .. g1 .. ";" .. b1 .. "m" .. "\x1b[48;2;" .. r2 .. ";" .. g2 .. ";" .. b2 .. "m" .. "\xDF")
end
end
io.write(table.concat(out))
io.write(string.format("\n\x1b[38;2;255;255;255m\x1b[48;2;0;0;0m%d FPS", fps))
end
local function DrawTriangle(meta, colorbuffer, depthbuffer, wp0, wp1, wp2, texture, c0, c1, c2, mvp, lightdir, n0, n1, n2)
local p0 = {}
local p1 = {}
local p2 = {}
MatMultVec3(p0, mvp, wp0)
MatMultVec3(p1, mvp, wp1)
MatMultVec3(p2, mvp, wp2)
if p0[4] ~= 0.0 and p1[4] ~= 0.0 and p2[4] ~= 0.0 then
MapToRes(meta, p0)
MapToRes(meta, p1)
MapToRes(meta, p2)
local aabbmin = {}
local aabbmax = {}
aabbmin[1] = Max(Min3(p0[1], p1[1], p2[1]), 0)
aabbmin[2] = Max(Min3(p0[2], p1[2], p2[2]), 0)
aabbmax[1] = Min(Max3(p0[1], p1[1], p2[1]), meta[1] - 1)
aabbmax[2] = Min(Max3(p0[2], p1[2], p2[2]), meta[2] - 1)
local idx, tx, ty, ti
local p = {}
local depth
local w0, w1, w2, dot00, dot01, dot11, dot20, dot21, denom, d0, d1, d2
local v0 = {}
local v1 = {}
local v2 = {}
local texcoord = {}
local normal = {}
local diff
for y = math_floor(aabbmin[2]), math_floor(aabbmax[2]) do
for x = math_floor(aabbmin[1]), math_floor(aabbmax[1]) do
p[1] = x
p[2] = y
if IsOnRight(p0, p1, p) and IsOnRight(p1, p2, p) and IsOnRight(p2, p0, p) then
v0[1] = p1[1] - p0[1]
v0[2] = p1[2] - p0[2]
v1[1] = p2[1] - p0[1]
v1[2] = p2[2] - p0[2]
v2[1] = p[1] - p0[1]
v2[2] = p[2] - p0[2]
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.0 - w1 - w2
depth = p0[3] * w0 + p1[3] * w1 + p2[3] * w2
idx = math_floor(x) + meta[1] * math_floor(y)
if depth > 0.0 and depthbuffer[1 + idx] > depth then
depthbuffer[1 + idx] = depth
idx = idx * 3
texcoord[1] = w0 * c0[1] + w1 * c1[1] + w2 * c2[1]
texcoord[2] = w0 * c0[2] + w1 * c1[2] + w2 * c2[2]
normal[1] = w0 * n0[1] + w1 * n1[1] + w2 * n2[1]
normal[2] = w0 * n0[2] + w1 * n1[2] + w2 * n2[2]
normal[3] = w0 * n0[3] + w1 * n1[3] + w2 * n2[3]
Normalize(normal)
diff = Max(0.5, Dot(normal, lightdir))
tx = math_floor(texcoord[1] * meta[4])
ty = math_floor((1 - texcoord[2]) * meta[5])
ti = (tx + ty * meta[4]) * 3
-- uz ne kokote
colorbuffer[1 + idx] = texture[1 + ti] / 255 * diff
colorbuffer[1 + idx + 1] = texture[1 + ti + 1] / 255 * diff
colorbuffer[1 + idx + 2] = texture[1 + ti + 2] / 255 * diff
OutputVT100(meta, colorbuffer)
end
end
end
end
end
end
local file = io.open("data.txt", "r")
local function Input()
return file:read("*n")
end
-- file:close() -- Close the file
-- return number
local function Main()
os.execute(" ")
local meta = {}
-- meta[1] = 175
-- meta[2] = 120
meta[1] = 175 * 2
meta[2] = 120 * 2
meta[3] = meta[1] * meta[2]
local depthbuffer = {}
local colorbuffer = {}
local background = {}
background[1] = 0.3
background[2] = 0.3
background[3] = 0.3
ClearBuffers(meta, colorbuffer, depthbuffer, background, 100.0)
local lightdir = {}
lightdir[1] = .3
lightdir[2] = 1
lightdir[3] = .4
Normalize(lightdir)
local view = {}
local proj = {}
local mvp = {}
local campos = {}
local targetpos = {}
local upvector = {}
targetpos[1] = 0
targetpos[2] = 0
targetpos[3] = 0
upvector[1] = 0
upvector[2] = 1
upvector[3] = 0
local aspectratio
aspectratio = 1.46
Perspective(proj, DegToRad(90.0) / aspectratio, aspectratio, 0.1, 50.0)
local p0 = {}
local p1 = {}
local p2 = {}
local c0 = {}
local c1 = {}
local c2 = {}
local n0 = {}
local n1 = {}
local n2 = {}
local datasize, i, vertices
datasize = Input()
vertices = Input()
local data = {}
for i = 1, datasize do
data[i] = Input()
end
print("model rdy")
meta[4] = Input()
meta[5] = Input()
local tp
tp = meta[4] * meta[5] * 3
local texture = {}
for i = 0, tp - 1 do
texture[1 + i] = Input()
end
print("textura rdy")
local temp
local i0, i1, i2
local camangle
camangle = 0
local frames = 0
local lastframereset = 0
while true do
frames = frames + 1
time = os.clock() * 1000
if time > lastframereset + 1000 then
fps = frames
frames = 0
lastframereset = time
end
ClearBuffers(meta, colorbuffer, depthbuffer, background, 100.0)
local camdis
camdis = 7.0
campos[1] = math.sin(camangle) * camdis
campos[2] = 0.8 * camdis
campos[3] = math.cos(camangle) * camdis
camangle = time * 0.0003
LookAt(view, campos, targetpos, upvector)
MatMultMat(mvp, proj, view)
for i = 0, vertices - 3, 3 do
i0 = i * 8
i1 = (i + 1) * 8
i2 = (i + 2) * 8
p0[1] = data[1 + i0]
p0[2] = data[1 + i0 + 1]
p0[3] = data[1 + i0 + 2]
p1[1] = data[1 + i1]
p1[2] = data[1 + i1 + 1]
p1[3] = data[1 + i1 + 2]
p2[1] = data[1 + i2]
p2[2] = data[1 + i2 + 1]
p2[3] = data[1 + i2 + 2]
c0[1] = data[1 + i0 + 3]
c0[2] = data[1 + i0 + 4]
c1[1] = data[1 + i1 + 3]
c1[2] = data[1 + i1 + 4]
c2[1] = data[1 + i2 + 3]
c2[2] = data[1 + i2 + 4]
n0[1] = data[1 + i0 + 5]
n0[2] = data[1 + i0 + 6]
n0[3] = data[1 + i0 + 7]
n1[1] = data[1 + i1 + 5]
n1[2] = data[1 + i1 + 6]
n1[3] = data[1 + i1 + 7]
n2[1] = data[1 + i2 + 5]
n2[2] = data[1 + i2 + 6]
n2[3] = data[1 + i2 + 7]
DrawTriangle(meta, colorbuffer, depthbuffer, p0, p1, p2, texture, c0, c1, c2, mvp, lightdir, n0, n1, n2)
end
OutputVT100(meta, colorbuffer)
end
end
Main()

616
render_cc.lua Normal file
View File

@ -0,0 +1,616 @@
local fps = 0
local math_floor = math.floor
local time = 0
local function ClearBuffers(meta, colorbuffer, depthbuffer, color, depth)
local i
for i = 0, meta[3] - 1 do
colorbuffer[1 + i * 3] = color[1]
colorbuffer[1 + i * 3 + 1] = color[2]
colorbuffer[1 + i * 3 + 2] = color[3]
depthbuffer[1 + i] = depth
end
end
local function DegToRad(deg)
local rad
rad = deg * 0.0174532925
return rad
end
local function Min(a, b)
local r
if a < b then
r = a
else
r = b
end
return r
end
local function Min3(a, b, c)
local r
r = Min(Min(a, b), c)
return r
end
local function Max(a, b)
local r
if a > b then
r = a
else
r = b
end
return r
end
local function Max3(a, b, c)
local r
r = Max(Max(a, b), c)
return r
end
local function IsOnRight(a, b, c)
local r
if (b[1] - a[1]) * (c[2] - a[2]) - (b[2] - a[2]) * (c[1] - a[1]) <= 0 then
r = true
else
r = false
end
return r
end
local function Distance2(a, b)
local x, y, d
x = b[1] - a[1]
y = b[2] - a[2]
d = math.sqrt(x * x + y * y)
return d
end
local function Normalize(a)
local l
l = math.sqrt(a[1] * a[1] + a[2] * a[2] + a[3] * a[3])
a[1] = a[1] / l
a[2] = a[2] / l
a[3] = a[3] / l
end
local function MapToRes(meta, a)
a[1] = a[1] / a[4]
a[2] = a[2] / a[4]
a[3] = a[3] / a[4]
a[1] = (a[1] + 1.0) * 0.5 * (meta[1] - 1)
a[2] = (1.0 - a[2]) * 0.5 * (meta[2] - 1)
end
local function Cross(result, a, b)
result[1] = a[2] * b[3] - a[3] * b[2]
result[2] = a[3] * b[1] - a[1] * b[3]
result[3] = a[1] * b[2] - a[2] * b[1]
end
local function Dot(a, b)
local result
result = a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
return result
end
local function Dot2(a, b)
local result
result = a[1] * b[1] + a[2] * b[2]
return result
end
local function VecCopy3(result, a)
result[1] = a[1]
result[2] = a[2]
result[3] = a[3]
end
local function VecSubVec3(result, a, b)
result[1] = a[1] - b[1]
result[2] = a[2] - b[2]
result[3] = a[3] - b[3]
end
local function MatMultMat(result, a, b)
result[1] = a[1] * b[1] + a[2] * b[5] + a[3] * b[9] + a[4] * b[13]
result[2] = a[1] * b[2] + a[2] * b[6] + a[3] * b[10] + a[4] * b[14]
result[3] = a[1] * b[3] + a[2] * b[7] + a[3] * b[11] + a[4] * b[15]
result[4] = a[1] * b[4] + a[2] * b[8] + a[3] * b[12] + a[4] * b[16]
result[5] = a[5] * b[1] + a[6] * b[5] + a[7] * b[9] + a[8] * b[13]
result[6] = a[5] * b[2] + a[6] * b[6] + a[7] * b[10] + a[8] * b[14]
result[7] = a[5] * b[3] + a[6] * b[7] + a[7] * b[11] + a[8] * b[15]
result[8] = a[5] * b[4] + a[6] * b[8] + a[7] * b[12] + a[8] * b[16]
result[9] = a[9] * b[1] + a[10] * b[5] + a[11] * b[9] + a[12] * b[13]
result[10] = a[9] * b[2] + a[10] * b[6] + a[11] * b[10] + a[12] * b[14]
result[11] = a[9] * b[3] + a[10] * b[7] + a[11] * b[11] + a[12] * b[15]
result[12] = a[9] * b[4] + a[10] * b[8] + a[11] * b[12] + a[12] * b[16]
result[13] = a[13] * b[1] + a[14] * b[5] + a[15] * b[9] + a[16] * b[13]
result[14] = a[13] * b[2] + a[14] * b[6] + a[15] * b[10] + a[16] * b[14]
result[15] = a[13] * b[3] + a[14] * b[7] + a[15] * b[11] + a[16] * b[15]
result[16] = a[13] * b[4] + a[14] * b[8] + a[15] * b[12] + a[16] * b[16]
end
local function MatMultVec(result, a, v)
result[1] = a[1] * v[1] + a[2] * v[2] + a[3] * v[3] + a[4] * v[4]
result[2] = a[5] * v[1] + a[6] * v[2] + a[7] * v[3] + a[8] * v[4]
result[3] = a[9] * v[1] + a[10] * v[2] + a[11] * v[3] + a[12] * v[4]
result[4] = a[13] * v[1] + a[14] * v[2] + a[15] * v[3] + a[16] * v[4]
end
local function MatMultVec3(result, a, v)
result[1] = a[1] * v[1] + a[2] * v[2] + a[3] * v[3] + a[4]
result[2] = a[5] * v[1] + a[6] * v[2] + a[7] * v[3] + a[8]
result[3] = a[9] * v[1] + a[10] * v[2] + a[11] * v[3] + a[12]
result[4] = a[13] * v[1] + a[14] * v[2] + a[15] * v[3] + a[16]
end
local function LookAt(mat, campos, targetpos, upvec)
local forward = {}
local right = {}
local up = {}
VecSubVec3(forward, targetpos, campos)
Normalize(forward)
Cross(right, forward, upvec)
Normalize(right)
Cross(up, right, forward)
mat[1] = right[1]
mat[2] = right[2]
mat[3] = right[3]
mat[4] = -Dot(right, campos)
mat[5] = up[1]
mat[6] = up[2]
mat[7] = up[3]
mat[8] = -Dot(up, campos)
mat[9] = -forward[1]
mat[10] = -forward[2]
mat[11] = -forward[3]
mat[12] = Dot(forward, campos)
mat[13] = 0.0
mat[14] = 0.0
mat[15] = 0.0
mat[16] = 1.0
end
local function Perspective(mat, fov, aspectratio, near, far)
local tanhalffovy
tanhalffovy = math.tan(fov * 0.5)
mat[1] = 1 / (aspectratio * tanhalffovy)
mat[2] = 0.0
mat[3] = 0.0
mat[4] = 0.0
mat[5] = 0.0
mat[6] = 1 / tanhalffovy
mat[7] = 0.0
mat[8] = 0.0
mat[9] = 0.0
mat[10] = 0.0
mat[11] = -(far + near) / (far - near)
mat[12] = -(2 * far * near) / (far - near)
mat[13] = 0.0
mat[14] = 0.0
mat[15] = -1.0
mat[16] = 0.0
end
-- local function OutputVT100(meta, colorbuffer)
-- print("\x1b[1;1H")
-- local r1, g1, b1, r2, b2, g2, width, height, idx, rowoffset
-- width = meta[1]
-- height = meta[2]
-- local out = {}
-- local pr1, pg1, pb1, pr2, pg2, pb2 = 0, 0, 0, 0, 0, 0
-- for y = 0, height - 2, 2 do
-- table.insert(out, "\n")
-- for x = 0, width - 1 do
-- idx = (x + y * width) * 3
-- rowoffset = width * 3
-- r1 = math_floor(colorbuffer[1 + idx] * 255)
-- g1 = math_floor(colorbuffer[1 + idx + 1] * 255)
-- b1 = math_floor(colorbuffer[1 + idx + 2] * 255)
-- r2 = math_floor(colorbuffer[1 + idx + rowoffset] * 255)
-- g2 = math_floor(colorbuffer[1 + idx + 1 + rowoffset] * 255)
-- b2 = math_floor(colorbuffer[1 + idx + 2 + rowoffset] * 255)
-- if r1 == pr1 and g1 == pg1 and b1 == pb1 and r2 == pr2 and g2 == pg2 and b2 == pb2 then
-- table.insert(out, "\xDF")
-- else
-- pr1, pg1, pb1, pr2, pg2, pb2 = r1, g1, b1, r2, g2, b2
-- table.insert(out, string.format("\x1b[38;2;%d;%d;%dm\x1b[48;2;%d;%d;%dm\xDF", r1, g1, b1, r2, g2, b2))
-- end
-- -- io.write("\x1b[38;2;" ..
-- -- r1 .. ";" .. g1 .. ";" .. b1 .. "m" .. "\x1b[48;2;" .. r2 .. ";" .. g2 .. ";" .. b2 .. "m" .. "\xDF")
-- end
-- end
-- io.write(table.concat(out))
-- io.write(string.format("\n\x1b[38;2;255;255;255m\x1b[48;2;0;0;0m%d FPS", fps))
-- end
local monitor = peripheral.find("monitor")
local function SetupMonitor()
monitor.setTextScale(0.5)
monitor.clear()
monitor.setPaletteColor(colors.white, 0, 0, 0 ) -- 0
monitor.setPaletteColor(colors.orange, 0, 0, 127 ) -- 1
monitor.setPaletteColor(colors.magenta, 0, 127, 0 ) -- 2
monitor.setPaletteColor(colors.lightBlue, 0, 127, 127 ) -- 3
monitor.setPaletteColor(colors.yellow, 127, 0, 0 ) -- 4
monitor.setPaletteColor(colors.lime, 127, 0, 127 ) -- 5
monitor.setPaletteColor(colors.pink, 127, 127, 0 ) -- 6
monitor.setPaletteColor(colors.gray, 127, 127, 127 ) -- 7
monitor.setPaletteColor(colors.lightGray, 127, 127, 127 ) -- 8
monitor.setPaletteColor(colors.cyan, 127, 127, 255 ) -- 9
monitor.setPaletteColor(colors.purple, 127, 255, 127 ) -- a
monitor.setPaletteColor(colors.blue, 127, 255, 255 ) -- b
monitor.setPaletteColor(colors.brown, 255, 127, 127 ) -- c
monitor.setPaletteColor(colors.green, 255, 127, 255 ) -- d
monitor.setPaletteColor(colors.red, 255, 255, 127 ) -- e
monitor.setPaletteColor(colors.black, 255, 255, 255 ) -- f
end
local function OutputCCMonitor(meta, colorbuffer)
local width = meta[1]
local height = meta[2]
local chars = {}
local fcs = {}
local bcs = {}
local hex_digits = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }
for y = 0, height - 1 do
for x = 0, width - 1 do
idx = (x + y * width) * 3
rowoffset = width * 3
local r = colorbuffer[1 + idx]
local g = colorbuffer[1 + idx + 1]
local b = colorbuffer[1 + idx + 2]
local avg = (r + g + b) / 3
local c = 0
local threshold = 1.2
if b > avg * threshold then c = c + 1 end
if g > avg * threshold then c = c + 2 end
if r > avg * threshold then c = c + 4 end
local bright_threshold = 0.5
if r > bright_threshold or g > bright_threshold or b > bright_threshold then c = c + 8 end
local xx = x + 1
local cc = hex_digits[c + 1]
chars[xx] = " "
fcs[xx] = cc
bcs[xx] = cc
end
monitor.setCursorPos(1, y + 1)
monitor.blit(table.concat(chars), table.concat(fcs), table.concat(bcs))
end
end
local function DrawTriangle(meta, colorbuffer, depthbuffer, wp0, wp1, wp2, texture, c0, c1, c2, mvp, lightdir, n0, n1, n2)
local p0 = {}
local p1 = {}
local p2 = {}
MatMultVec3(p0, mvp, wp0)
MatMultVec3(p1, mvp, wp1)
MatMultVec3(p2, mvp, wp2)
if p0[4] ~= 0.0 and p1[4] ~= 0.0 and p2[4] ~= 0.0 then
MapToRes(meta, p0)
MapToRes(meta, p1)
MapToRes(meta, p2)
local aabbmin = {}
local aabbmax = {}
aabbmin[1] = Max(Min3(p0[1], p1[1], p2[1]), 0)
aabbmin[2] = Max(Min3(p0[2], p1[2], p2[2]), 0)
aabbmax[1] = Min(Max3(p0[1], p1[1], p2[1]), meta[1] - 1)
aabbmax[2] = Min(Max3(p0[2], p1[2], p2[2]), meta[2] - 1)
local idx, tx, ty, ti
local p = {}
local depth
local w0, w1, w2, dot00, dot01, dot11, dot20, dot21, denom, d0, d1, d2
local v0 = {}
local v1 = {}
local v2 = {}
local texcoord = {}
local normal = {}
local diff
for y = math_floor(aabbmin[2]), math_floor(aabbmax[2]) do
for x = math_floor(aabbmin[1]), math_floor(aabbmax[1]) do
p[1] = x
p[2] = y
if IsOnRight(p0, p1, p) and IsOnRight(p1, p2, p) and IsOnRight(p2, p0, p) then
v0[1] = p1[1] - p0[1]
v0[2] = p1[2] - p0[2]
v1[1] = p2[1] - p0[1]
v1[2] = p2[2] - p0[2]
v2[1] = p[1] - p0[1]
v2[2] = p[2] - p0[2]
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.0 - w1 - w2
depth = p0[3] * w0 + p1[3] * w1 + p2[3] * w2
idx = math_floor(x) + meta[1] * math_floor(y)
if depth > 0.0 and depthbuffer[1 + idx] > depth then
depthbuffer[1 + idx] = depth
idx = idx * 3
texcoord[1] = w0 * c0[1] + w1 * c1[1] + w2 * c2[1]
texcoord[2] = w0 * c0[2] + w1 * c1[2] + w2 * c2[2]
normal[1] = w0 * n0[1] + w1 * n1[1] + w2 * n2[1]
normal[2] = w0 * n0[2] + w1 * n1[2] + w2 * n2[2]
normal[3] = w0 * n0[3] + w1 * n1[3] + w2 * n2[3]
Normalize(normal)
diff = Max(0.5, Dot(normal, lightdir))
tx = math_floor(texcoord[1] * meta[4])
ty = math_floor((1 - texcoord[2]) * meta[5])
ti = (tx + ty * meta[4]) * 3
-- uz ne kokote
colorbuffer[1 + idx] = texture[1 + ti] / 255 * diff
colorbuffer[1 + idx + 1] = texture[1 + ti + 1] / 255 * diff
colorbuffer[1 + idx + 2] = texture[1 + ti + 2] / 255 * diff
-- OutputVT100(meta, colorbuffer)
end
end
end
end
end
end
local file = assert(io.open("mesh.txt", "r"))
local function Input()
return tonumber(file:read())
end
-- file:close() -- Close the file
-- return number
function load_texture(filename)
local file = assert(io.open(filename, "rb"))
local data = file:read("*all")
file:close()
local tex = {}
for i = 1, #data do
tex[i] = string.byte(data, i)
end
return tex
end
local function Main()
SetupMonitor()
local meta = {}
-- meta[1] = 175
-- meta[2] = 120
meta[1] = 79
meta[2] = 38
local charaspect = 1.5
meta[3] = meta[1] * meta[2]
local depthbuffer = {}
local colorbuffer = {}
local background = {}
background[1] = 0.3
background[2] = 0.3
background[3] = 0.3
ClearBuffers(meta, colorbuffer, depthbuffer, background, 100.0)
local lightdir = {}
lightdir[1] = .3
lightdir[2] = 1
lightdir[3] = .4
Normalize(lightdir)
local view = {}
local proj = {}
local mvp = {}
local campos = {}
local targetpos = {}
local upvector = {}
targetpos[1] = 0
targetpos[2] = 0
targetpos[3] = 0
upvector[1] = 0
upvector[2] = 1
upvector[3] = 0
local aspectratio
aspectratio = (meta[1] / meta[2]) / charaspect
Perspective(proj, DegToRad(90.0) / aspectratio, aspectratio, 0.1, 50.0)
local p0 = {}
local p1 = {}
local p2 = {}
local c0 = {}
local c1 = {}
local c2 = {}
local n0 = {}
local n1 = {}
local n2 = {}
local i, vertices
vertices = Input()
local datasize = vertices * 8
local data = {}
for i = 1, datasize do
data[i] = Input()
end
print("model rdy")
meta[4] = 256 -- tex width
meta[5] = 256 -- tex height
-- local tp
-- tp = meta[4] * meta[5] * 3
-- local texture = {}
-- for i = 0, tp - 1 do
-- texture[1 + i] = Input()
-- end
local texture = load_texture("texture.bin")
print("textura rdy")
local temp
local i0, i1, i2
local camangle
camangle = 0
local frames = 0
local lastframereset = 0
while true do
frames = frames + 1
time = os.clock() * 1000
if time > lastframereset + 1000 then
fps = frames
frames = 0
lastframereset = time
end
ClearBuffers(meta, colorbuffer, depthbuffer, background, 100.0)
local camdis
camdis = 7.0
campos[1] = math.sin(camangle) * camdis
campos[2] = 0.8 * camdis
campos[3] = math.cos(camangle) * camdis
camangle = time * 0.0005
LookAt(view, campos, targetpos, upvector)
MatMultMat(mvp, proj, view)
for i = 0, vertices - 3, 3 do
i0 = i * 8
i1 = (i + 1) * 8
i2 = (i + 2) * 8
p0[1] = data[1 + i0]
p0[2] = data[1 + i0 + 1]
p0[3] = data[1 + i0 + 2]
p1[1] = data[1 + i1]
p1[2] = data[1 + i1 + 1]
p1[3] = data[1 + i1 + 2]
p2[1] = data[1 + i2]
p2[2] = data[1 + i2 + 1]
p2[3] = data[1 + i2 + 2]
c0[1] = data[1 + i0 + 3]
c0[2] = data[1 + i0 + 4]
c1[1] = data[1 + i1 + 3]
c1[2] = data[1 + i1 + 4]
c2[1] = data[1 + i2 + 3]
c2[2] = data[1 + i2 + 4]
n0[1] = data[1 + i0 + 5]
n0[2] = data[1 + i0 + 6]
n0[3] = data[1 + i0 + 7]
n1[1] = data[1 + i1 + 5]
n1[2] = data[1 + i1 + 6]
n1[3] = data[1 + i1 + 7]
n2[1] = data[1 + i2 + 5]
n2[2] = data[1 + i2 + 6]
n2[3] = data[1 + i2 + 7]
DrawTriangle(meta, colorbuffer, depthbuffer, p0, p1, p2, texture, c0, c1, c2, mvp, lightdir, n0, n1, n2)
end
OutputCCMonitor(meta, colorbuffer)
os.sleep(0.01)
end
end
Main()

522
render_origo.lua Normal file
View File

@ -0,0 +1,522 @@
local fps = 0
local function ClearBuffers(meta, colorbuffer, depthbuffer, color, depth)
local i
for i = 0, meta[3] - 1 do
colorbuffer[1 + i * 3] = color[1]
colorbuffer[1 + i * 3 + 1] = color[2]
colorbuffer[1 + i * 3 + 2] = color[3]
depthbuffer[1 + i] = depth
end
end
local function DegToRad(deg)
local rad
rad = deg * 0.0174532925
return rad
end
local function Min(a, b)
local r
if a < b then
r = a
else
r = b
end
return r
end
local function Min3(a, b, c)
local r
r = Min(Min(a, b), c)
return r
end
local function Max(a, b)
local r
if a > b then
r = a
else
r = b
end
return r
end
local function Max3(a, b, c)
local r
r = Max(Max(a, b), c)
return r
end
local function IsOnRight(a, b, c)
local r
if (b[1] - a[1]) * (c[2] - a[2]) - (b[2] - a[2]) * (c[1] - a[1]) <= 0 then
r = true
else
r = false
end
return r
end
local function Distance2(a, b)
local x, y, d
x = b[1] - a[1]
y = b[2] - a[2]
d = math.sqrt(x * x + y * y)
return d
end
local function Normalize(a)
local l
l = math.sqrt(a[1] * a[1] + a[2] * a[2] + a[3] * a[3])
a[1] = a[1] / l
a[2] = a[2] / l
a[3] = a[3] / l
end
local function MapToRes(meta, a)
a[1] = a[1] / a[4]
a[2] = a[2] / a[4]
a[3] = a[3] / a[4]
a[1] = (a[1] + 1.0) * 0.5 * (meta[1] - 1)
a[2] = (1.0 - a[2]) * 0.5 * (meta[2] - 1)
end
local function Cross(result, a, b)
result[1] = a[2] * b[3] - a[3] * b[2]
result[2] = a[3] * b[1] - a[1] * b[3]
result[3] = a[1] * b[2] - a[2] * b[1]
end
local function Dot(a, b)
local result
result = a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
return result
end
local function Dot2(a, b)
local result
result = a[1] * b[1] + a[2] * b[2]
return result
end
local function VecCopy3(result, a)
result[1] = a[1]
result[2] = a[2]
result[3] = a[3]
end
local function VecSubVec3(result, a, b)
result[1] = a[1] - b[1]
result[2] = a[2] - b[2]
result[3] = a[3] - b[3]
end
local function MatMultMat(result, a, b)
result[1] = a[1] * b[1] + a[2] * b[5] + a[3] * b[9] + a[4] * b[13]
result[2] = a[1] * b[2] + a[2] * b[6] + a[3] * b[10] + a[4] * b[14]
result[3] = a[1] * b[3] + a[2] * b[7] + a[3] * b[11] + a[4] * b[15]
result[4] = a[1] * b[4] + a[2] * b[8] + a[3] * b[12] + a[4] * b[16]
result[5] = a[5] * b[1] + a[6] * b[5] + a[7] * b[9] + a[8] * b[13]
result[6] = a[5] * b[2] + a[6] * b[6] + a[7] * b[10] + a[8] * b[14]
result[7] = a[5] * b[3] + a[6] * b[7] + a[7] * b[11] + a[8] * b[15]
result[8] = a[5] * b[4] + a[6] * b[8] + a[7] * b[12] + a[8] * b[16]
result[9] = a[9] * b[1] + a[10] * b[5] + a[11] * b[9] + a[12] * b[13]
result[10] = a[9] * b[2] + a[10] * b[6] + a[11] * b[10] + a[12] * b[14]
result[11] = a[9] * b[3] + a[10] * b[7] + a[11] * b[11] + a[12] * b[15]
result[12] = a[9] * b[4] + a[10] * b[8] + a[11] * b[12] + a[12] * b[16]
result[13] = a[13] * b[1] + a[14] * b[5] + a[15] * b[9] + a[16] * b[13]
result[14] = a[13] * b[2] + a[14] * b[6] + a[15] * b[10] + a[16] * b[14]
result[15] = a[13] * b[3] + a[14] * b[7] + a[15] * b[11] + a[16] * b[15]
result[16] = a[13] * b[4] + a[14] * b[8] + a[15] * b[12] + a[16] * b[16]
end
local function MatMultVec(result, a, v)
result[1] = a[1] * v[1] + a[2] * v[2] + a[3] * v[3] + a[4] * v[4]
result[2] = a[5] * v[1] + a[6] * v[2] + a[7] * v[3] + a[8] * v[4]
result[3] = a[9] * v[1] + a[10] * v[2] + a[11] * v[3] + a[12] * v[4]
result[4] = a[13] * v[1] + a[14] * v[2] + a[15] * v[3] + a[16] * v[4]
end
local function MatMultVec3(result, a, v)
result[1] = a[1] * v[1] + a[2] * v[2] + a[3] * v[3] + a[4]
result[2] = a[5] * v[1] + a[6] * v[2] + a[7] * v[3] + a[8]
result[3] = a[9] * v[1] + a[10] * v[2] + a[11] * v[3] + a[12]
result[4] = a[13] * v[1] + a[14] * v[2] + a[15] * v[3] + a[16]
end
local function LookAt(mat, campos, targetpos, upvec)
local forward = {}
local right = {}
local up = {}
VecSubVec3(forward, targetpos, campos)
Normalize(forward)
Cross(right, forward, upvec)
Normalize(right)
Cross(up, right, forward)
mat[1] = right[1]
mat[2] = right[2]
mat[3] = right[3]
mat[4] = -Dot(right, campos)
mat[5] = up[1]
mat[6] = up[2]
mat[7] = up[3]
mat[8] = -Dot(up, campos)
mat[9] = -forward[1]
mat[10] = -forward[2]
mat[11] = -forward[3]
mat[12] = Dot(forward, campos)
mat[13] = 0.0
mat[14] = 0.0
mat[15] = 0.0
mat[16] = 1.0
end
local function Perspective(mat, fov, aspectratio, near, far)
local tanhalffovy
tanhalffovy = math.tan(fov * 0.5)
mat[1] = 1 / (aspectratio * tanhalffovy)
mat[2] = 0.0
mat[3] = 0.0
mat[4] = 0.0
mat[5] = 0.0
mat[6] = 1 / tanhalffovy
mat[7] = 0.0
mat[8] = 0.0
mat[9] = 0.0
mat[10] = 0.0
mat[11] = -(far + near) / (far - near)
mat[12] = -(2 * far * near) / (far - near)
mat[13] = 0.0
mat[14] = 0.0
mat[15] = -1.0
mat[16] = 0.0
end
local function DrawTriangle(meta, colorbuffer, depthbuffer, wp0, wp1, wp2, texture, c0, c1, c2, mvp, lightdir, n0, n1, n2)
local p0 = {}
local p1 = {}
local p2 = {}
MatMultVec3(p0, mvp, wp0)
MatMultVec3(p1, mvp, wp1)
MatMultVec3(p2, mvp, wp2)
if p0[4] ~= 0.0 and p1[4] ~= 0.0 and p2[4] ~= 0.0 then
MapToRes(meta, p0)
MapToRes(meta, p1)
MapToRes(meta, p2)
local aabbmin = {}
local aabbmax = {}
aabbmin[1] = Max(Min3(p0[1], p1[1], p2[1]), 0)
aabbmin[2] = Max(Min3(p0[2], p1[2], p2[2]), 0)
aabbmax[1] = Min(Max3(p0[1], p1[1], p2[1]), meta[1] - 1)
aabbmax[2] = Min(Max3(p0[2], p1[2], p2[2]), meta[2] - 1)
local idx, tx, ty, ti
local p = {}
local depth
local w0, w1, w2, dot00, dot01, dot11, dot20, dot21, denom, d0, d1, d2
local v0 = {}
local v1 = {}
local v2 = {}
local texcoord = {}
local normal = {}
local diff
for x = math.floor(aabbmin[1]), math.floor(aabbmax[1]) do
for y = math.floor(aabbmin[2]), math.floor(aabbmax[2]) do
p[1] = x
p[2] = y
if IsOnRight(p0, p1, p) and IsOnRight(p1, p2, p) and IsOnRight(p2, p0, p) then
v0[1] = p1[1] - p0[1]
v0[2] = p1[2] - p0[2]
v1[1] = p2[1] - p0[1]
v1[2] = p2[2] - p0[2]
v2[1] = p[1] - p0[1]
v2[2] = p[2] - p0[2]
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.0 - w1 - w2
depth = p0[3] * w0 + p1[3] * w1 + p2[3] * w2
idx = math.floor(x) + meta[1] * math.floor(y)
if depth > 0.0 and depthbuffer[1 + idx] > depth then
depthbuffer[1 + idx] = depth
idx = idx * 3
texcoord[1] = w0 * c0[1] + w1 * c1[1] + w2 * c2[1]
texcoord[2] = w0 * c0[2] + w1 * c1[2] + w2 * c2[2]
normal[1] = w0 * n0[1] + w1 * n1[1] + w2 * n2[1]
normal[2] = w0 * n0[2] + w1 * n1[2] + w2 * n2[2]
normal[3] = w0 * n0[3] + w1 * n1[3] + w2 * n2[3]
Normalize(normal)
diff = Max(0.5, Dot(normal, lightdir))
tx = math.floor(texcoord[1] * meta[4])
ty = math.floor((1 - texcoord[2]) * meta[5])
ti = (tx + ty * meta[4]) * 3
-- uz ne kokote
colorbuffer[1 + idx] = texture[1 + ti] / 255 * diff
colorbuffer[1 + idx + 1] = texture[1 + ti + 1] / 255 * diff
colorbuffer[1 + idx + 2] = texture[1 + ti + 2] / 255 * diff
end
end
end
end
end
end
local function OutputVT100(meta, colorbuffer)
print("\x1b[1;1H")
local r1, g1, b1, r2, b2, g2, width, height, idx, rowoffset
width = meta[1]
height = meta[2]
local out = {}
local pr1, pg1, pb1, pr2, pg2, pb2 = 0, 0, 0, 0, 0, 0
for y = 0, height - 2, 2 do
table.insert(out, "\n")
for x = 0, width - 1 do
idx = (x + y * width) * 3
rowoffset = width * 3
r1 = math.floor(colorbuffer[1 + idx] * 255)
g1 = math.floor(colorbuffer[1 + idx + 1] * 255)
b1 = math.floor(colorbuffer[1 + idx + 2] * 255)
r2 = math.floor(colorbuffer[1 + idx + rowoffset] * 255)
g2 = math.floor(colorbuffer[1 + idx + 1 + rowoffset] * 255)
b2 = math.floor(colorbuffer[1 + idx + 2 + rowoffset] * 255)
if r1 == pr1 and g1 == pg1 and b1 == pb1 and r2 == pr2 and g2 == pg2 and b2 == pb2 then
table.insert(out, "\xDF")
else
pr1, pg1, pb1, pr2, pg2, pb2 = r1, g1, b1, r2, g2, b2
table.insert(out, string.format("\x1b[38;2;%d;%d;%dm\x1b[48;2;%d;%d;%dm\xDF", r1, g1, b1, r2, g2, b2))
end
-- io.write("\x1b[38;2;" ..
-- r1 .. ";" .. g1 .. ";" .. b1 .. "m" .. "\x1b[48;2;" .. r2 .. ";" .. g2 .. ";" .. b2 .. "m" .. "\xDF")
end
end
io.write(table.concat(out))
io.write(string.format("\n\x1b[38;2;255;255;255m\x1b[48;2;0;0;0m%d FPS", fps))
end
local file = io.open("data.txt", "r")
local function Input()
return file:read("*n")
end
-- file:close() -- Close the file
-- return number
local function Main()
os.execute(" ")
local meta = {}
meta[1] = 175
meta[2] = 120
meta[3] = meta[1] * meta[2]
local depthbuffer = {}
local colorbuffer = {}
local background = {}
background[1] = 0.3
background[2] = 0.3
background[3] = 0.3
ClearBuffers(meta, colorbuffer, depthbuffer, background, 100.0)
local lightdir = {}
lightdir[1] = .3
lightdir[2] = 1
lightdir[3] = .4
Normalize(lightdir)
local view = {}
local proj = {}
local mvp = {}
local campos = {}
local targetpos = {}
local upvector = {}
targetpos[1] = 0
targetpos[2] = 0
targetpos[3] = 0
upvector[1] = 0
upvector[2] = 1
upvector[3] = 0
local aspectratio
aspectratio = 1.46
Perspective(proj, DegToRad(90.0) / aspectratio, aspectratio, 0.1, 50.0)
local p0 = {}
local p1 = {}
local p2 = {}
local c0 = {}
local c1 = {}
local c2 = {}
local n0 = {}
local n1 = {}
local n2 = {}
local datasize, i, vertices
datasize = Input()
vertices = Input()
local data = {}
for i = 1, datasize do
data[i] = Input()
end
print("model rdy")
meta[4] = Input()
meta[5] = Input()
local tp
tp = meta[4] * meta[5] * 3
local texture = {}
for i = 0, tp - 1 do
texture[1 + i] = Input()
end
print("textura rdy")
local temp
local i0, i1, i2
local camangle
camangle = 0
local frames = 0
local lastframereset = 0
while true do
frames = frames + 1
local time = os.clock() * 1000
if time > lastframereset + 1000 then
fps = frames
frames = 0
lastframereset = time
end
ClearBuffers(meta, colorbuffer, depthbuffer, background, 100.0)
local camdis
camdis = 7.0
campos[1] = math.sin(camangle) * camdis
campos[2] = 0.8 * camdis
campos[3] = math.cos(camangle) * camdis
camangle = camangle + math.pi / 50
LookAt(view, campos, targetpos, upvector)
MatMultMat(mvp, proj, view)
for i = 0, vertices - 3, 3 do
i0 = i * 8
i1 = (i + 1) * 8
i2 = (i + 2) * 8
p0[1] = data[1 + i0]
p0[2] = data[1 + i0 + 1]
p0[3] = data[1 + i0 + 2]
p1[1] = data[1 + i1]
p1[2] = data[1 + i1 + 1]
p1[3] = data[1 + i1 + 2]
p2[1] = data[1 + i2]
p2[2] = data[1 + i2 + 1]
p2[3] = data[1 + i2 + 2]
c0[1] = data[1 + i0 + 3]
c0[2] = data[1 + i0 + 4]
c1[1] = data[1 + i1 + 3]
c1[2] = data[1 + i1 + 4]
c2[1] = data[1 + i2 + 3]
c2[2] = data[1 + i2 + 4]
n0[1] = data[1 + i0 + 5]
n0[2] = data[1 + i0 + 6]
n0[3] = data[1 + i0 + 7]
n1[1] = data[1 + i1 + 5]
n1[2] = data[1 + i1 + 6]
n1[3] = data[1 + i1 + 7]
n2[1] = data[1 + i2 + 5]
n2[2] = data[1 + i2 + 6]
n2[3] = data[1 + i2 + 7]
DrawTriangle(meta, colorbuffer, depthbuffer, p0, p1, p2, texture, c0, c1, c2, mvp, lightdir, n0, n1, n2)
end
OutputVT100(meta, colorbuffer)
end
end
Main()

BIN
res/screen-dosbox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB