#include #include #include uchar canvas[512 * 512]; Rectangle rect; Image *img; int t; typedef struct Vec Vec; struct Vec{float x, y, z;}; Vec add(Vec a, Vec b){return (Vec){a.x+b.x, a.y+b.y, a.z+b.z};} Vec sub(Vec a, Vec b){return (Vec){a.x-b.x, a.y-b.y, a.z-b.z};} Vec mul(Vec p, float s){return (Vec){p.x*s, p.y*s, p.z*s};} Vec vabs(Vec p){if(p.x<0)p.x=-p.x; if(p.y<0)p.y=-p.y; if(p.z<0)p.z=-p.z; return p;} float dot(Vec a, Vec b){return a.x*b.x + a.y*b.y + a.z*b.z;} float mag(Vec v){return sqrt(dot(v, v));} Vec norm(Vec v){ float len; len = mag(v); return len == 0 ? (Vec){0,0,0} : (Vec){v.x/len, v.y/len, v.z/len}; } Vec cross(Vec a, Vec b){ return (Vec){ a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x, }; } struct{Vec pos, right, up, fwd;}camera; void mvcam(float x0, float y0, float z0, float x1, float y1, float z1){ camera.pos = (Vec){x0, y0, z0}; camera.fwd = norm((Vec){x1 - x0, y1 - y0, z1 - z0}); camera.right = cross((Vec){0.0, 1.0, 0.0}, camera.fwd); camera.up = cross(camera.fwd, camera.right); } float dist(Vec p){ // p = vabs(p); // return (p.x + p.y + p.z - 3.3) * 0.57735027; // return mag(p) - 0.2 + sin(t / 10.0) - 1.0; float x, y; x = sqrt(p.x * p.x + p.z * p.z) - 1.0; return sqrt(x * x + p.y * p.y) - 0.8; } void march(){ Vec p, n, lux; float d, tot; int x, y, i; uchar *out; out = canvas + 64 + 1; for(y = -32; y < 32; y++){ for(x = -32; x < 32; x++){ p = add(camera.fwd, mul(camera.right, x / 32.0)); p = add(p, mul(camera.up, y / 32.0)); n = norm(p); p = camera.pos; for(i = tot = 0.0; i < 50; i++){ tot += d = dist(p); if(tot >= 80.0 || d < 0.05f) break; p = add(p, mul(n, d)); } lux = norm(sub(camera.pos, p)); n.x = (dist((Vec){p.x + 0.05f, p.y, p.z}) - d) / 0.05f; n.y = (dist((Vec){p.x, p.y + 0.05f, p.z}) - d) / 0.05f; n.z = (dist((Vec){p.x, p.y, p.z + 0.05f}) - d) / 0.05f; d = dot(lux, n) * 255; *out++ = d < 0.0 ? 0 : d > 255.0 ? 255 : d; } out += 2; } } void marchrow(uchar *out, int y){ Vec p, n, lux; float d, tot; int x, i; for(x = -32; x < 32; x++){ p = add(camera.fwd, mul(camera.right, x / 32.0)); p = add(p, mul(camera.up, y / 32.0)); n = norm(p); p = camera.pos; for(i = tot = 0.0; i < 50; i++){ tot += d = dist(p); if(tot >= 80.0 || d < 0.05f) break; p = add(p, mul(n, d)); } lux = norm(sub(camera.pos, p)); n.x = (dist((Vec){p.x + 0.05f, p.y, p.z}) - d) / 0.05f; n.y = (dist((Vec){p.x, p.y + 0.05f, p.z}) - d) / 0.05f; n.z = (dist((Vec){p.x, p.y, p.z + 0.05f}) - d) / 0.05f; d = dot(lux, n) * 255; *out++ = d < 0.0 ? 0 : d > 255.0 ? 255 : d; } } uchar bayer[8][8] = { {0, 128, 32, 160, 8, 136, 40, 168}, {192, 64, 224, 96, 200, 72, 232, 104}, {48, 176, 16, 144, 56, 184, 24, 152}, {240, 112, 208, 80, 248, 120, 216, 88}, {12, 140, 44, 172, 4, 132, 36, 164}, {204, 76, 236, 108, 196, 68, 228, 100}, {60, 188, 28, 156, 52, 180, 20, 148}, {252, 124, 220, 92, 244, 116, 212, 84} }; void dither(void){ int i; for(i = 0; i < sizeof canvas; i++) canvas[i] = 255 + (canvas[i] < bayer[i & 7][i >> 9 & 7]); } void fill(void){ int i, j; uchar *u; u = canvas; for(j = 0; j < 127; j++){ for(i = 0; i < 128; i++){ u[513 + 513] = *u + u[513 + 513 + 513 + 513] >> 1; u[513] = *u + u[513 + 513] >> 1; u[513 + 513 + 513] = u[513 + 513] + u[513 + 513 + 513 + 513] >> 1; u += 4; } u += 3 * 512; } } Image *scanline; Rectangle scanlinerect; void quadruple(uchar *p, uchar *a, uchar *b, uchar *c, uchar *d){ uchar out[512 * 2], *o; int i; o = out; for(i = 0; i < 64; i++){ // o[0] = o[1] = o[2] = o[3] = c[i] == a[i] && c[i] != d[i] && a[i] != b[i] ? a[i] : p[i]; // o[4] = o[5] = o[6] = o[7] = a[i] == b[i] && a[i] != c[i] && b[i] != d[i] ? b[i] : p[i]; // o[512] = o[513] = o[514] = o[515] = d[i] == c[i] && d[i] != b[i] && c[i] != a[i] ? c[i] : p[i]; // o[516] = o[517] = o[518] = o[519] = b[i] == d[i] && b[i] != a[i] && d[i] != c[i] ? d[i] : p[i]; o[0] = o[1] = o[2] = o[3] = c[i] + a[i] + p[i] + p[i] >> 2; o[4] = o[5] = o[6] = o[7] = a[i] + b[i] + p[i] + p[i] >> 2; o[512] = o[513] = o[514] = o[515] = c[i] + d[i] + p[i] + p[i] >> 2; o[516] = o[517] = o[518] = o[519] = d[i] + b[i] + p[i] + p[i] >> 2; o += 8; } scanlinerect.max.y = scanlinerect.min.y + 4; loadimage(scanline, scanline->r, out, 512); draw(screen, scanlinerect, scanline, nil, ZP); scanlinerect.min.y = scanlinerect.max.y; scanlinerect.max.y = scanlinerect.min.y + 4; loadimage(scanline, scanline->r, o, 512); draw(screen, scanlinerect, scanline, nil, ZP); scanlinerect.min.y = scanlinerect.max.y; } void nuscan(void){ uchar *a, *d, *p, *t; uchar buf[(64 + 2) * 3]; Rectangle r; int i, j; scanlinerect.min.x = screen->r.min.x + screen->r.max.x - 512 >> 1; scanlinerect.max.x = scanlinerect.min.x + 512; scanlinerect.min.y = screen->r.min.y + screen->r.max.y - 512 >> 1; memset(buf, 0, sizeof buf); a = buf + 1; p = a + 64 + 2; d = p + 64 + 2; marchrow(p, -32); for(i = 1; i < 64; i++){ marchrow(d, i - 32); quadruple(p, a, p + 1, p - 1, d); t = a; a = p; p = d; d = t; } memset(d, 0, 64); quadruple(p, a, p + 1, p - 1, d); flushimage(display, 1); } void main(int, char**){ int i, j; if(initdraw(nil, nil, "③") < 0) sysfatal("initdraw: %r"); img = allocimage(display, Rect(0, 0, 512, 512), GREY8, 1, DNofill); if(img == nil) sysfatal("allocimage: %r"); scanline = allocimage(display, Rect(0, 0, 512, 1), GREY8, 1, DNofill); if(img == nil) sysfatal("allocimage: %r"); i = open("/dev/wctl", OWRITE); if(i < 0) sysfatal("open: %r"); write(i, "resize -r 0 0 9999 9999", 23); getwindow(display, Refnone); rect.min.x = screen->r.min.x + screen->r.max.x - 512 >> 1; rect.min.y = screen->r.min.y + screen->r.max.y - 512 >> 1; rect.max.x = rect.min.x + 512; rect.max.y = rect.min.y + 512; draw(screen, screen->r, display->black, nil, ZP); for(t = 0; t < 1200; t++){ mvcam(2.0, -5.5 * sin(t * 2.0 * PI / 120.0), -5.5 * cos(t * 2.0 * PI / 120.0), 0, 0, 0); nuscan(); sleep(50); } exits(nil); }