#include "u.h" #include "libc.h" #include #include #include #include typedef char i8; typedef unsigned char u8; typedef short i16; typedef unsigned short u16; typedef int i32; typedef unsigned int u32; #define WIDTH 320 #define HEIGHT 200 #define ASPECT ((float)WIDTH/HEIGHT) typedef struct Canvas Canvas; struct Canvas { u8 *fb; int w, h; }; Keyboardctl *kbctl; Mousectl *mctl; int running; Canvas *canvas; Image *img; typedef struct Color { u8 b, g, r, x; } Color; typedef struct vec3 { float x, y, z; } vec3; typedef struct vec2 { float x, y; } vec2; typedef struct quat { float x, y, z, w; } quat; float dot2(vec2 a, vec2 b) { return a.x*b.x + a.y*b.y; } float norm2sq(vec2 v) { return dot2(v, v); } float norm2(vec2 v) { return sqrt(norm2sq(v)); } vec2 scalev2(vec2 v, float r) { vec2 u = {v.x*r, v.y*r}; return u; } vec2 addv2(vec2 v, vec2 u) { vec2 w = {v.x+u.x, v.y+u.y}; return w; } vec2 subv2(vec2 v, vec2 u) { vec2 w = {v.x-u.x, v.y-u.y}; return w; } float dot3(vec3 a, vec3 b) { return a.x*b.x + a.y*b.y + a.z*b.z; } float norm3sq(vec3 v) { return dot3(v, v); } float norm3(vec3 v) { return sqrt(norm3sq(v)); } vec3 scalev3(vec3 v, float r) { vec3 u = {v.x*r, v.y*r, v.z*r}; return u; } vec3 addv3(vec3 v, vec3 u) { vec3 w = {v.x+u.x, v.y+u.y, v.z+u.z}; return w; } vec3 subv3(vec3 v, vec3 u) { vec3 w = {v.x-u.x, v.y-u.y, v.z-u.z}; return w; } vec3 normalize(vec3 v) { float l = norm3(v); return l ? scalev3(v, 1.0f/l) : (vec3){1.0f, 0.0f, 0.0f}; } quat conj(quat q) { return (quat){-q.x, -q.y, -q.z, q.w}; } quat rotq(vec3 axis, float angle) { angle *= 0.5f; axis = normalize(axis); float s = sin(angle); float c = cos(angle); return (quat){axis.x*s, axis.y*s, axis.z*s, c}; } quat mulq(quat q, quat p) { return (quat){ q.w*p.x + q.x*p.w + q.y*p.z - q.z*p.y, q.w*p.y + q.y*p.w + q.z*p.x - q.x*p.z, q.w*p.z + q.z*p.w + q.x*p.y - q.y*p.x, q.w*p.w - q.x*p.x - q.y*p.y - q.z*p.z }; } vec3 qxform(quat q, vec3 v) { quat p = {v.x, v.y, v.z, 0.0f}; p = mulq(q, mulq(p, conj(q))); return (vec3){p.x, p.y, p.z}; } float clamp(float r, float low, float high) { return r < low ? low : r > high ? high : r; } float min(float a, float b) { return a < b ? a : b; } float max(float a, float b) { return a > b ? a : b; } #define MIN_DIST 0.00001f #define MAX_DIST 100.0f float sdSphere(vec3 p, float r){ return norm3(p) - r; } float sdCircle(vec2 p, float r){ return norm2(p) - r; } float sdTorus(vec3 p, float r1, float r2) { vec2 t = {p.x, p.y}; vec2 q = {norm2(t)-r1, p.z}; return sdCircle(q, r2); } vec3 ldir; vec3 color; quat rot; float timer; float sdf(vec3 p) { /* float s = sdSphere(p, 0.5f); vec3 xx = { 1.3f, 0.0f, 0.0f }; float s2 = sdSphere(subv3(p,xx), 0.5f); return min(s, s2); */ float s = sdSphere(p, 0.5f); float t = sdTorus(qxform(rot, p), 1.0f, 0.2f); return min(s, t); } void setupScene(void) { vec3 axis = {1.0f, 1.0f, 0.0f}; rot = rotq(axis, timer); // ldir = (vec3){ -0.4, -0.7, -0.5 }; // ldir = (vec3){ -sin(timer), cos(timer), -0.7 }; ldir = (vec3){ cos(timer), 0.4f, sin(timer) }; ldir = normalize(ldir); color = (vec3){ 0.0f, 0.47f, 0.94f }; // color = (vec3){ 1.0f, 1.0f, 1.0f }; // color = (vec3){ 0.8f, 0.8f, 0.8f }; } vec3 ndx = { 0.001f, 0.0f, 0.0f }; vec3 ndy = { 0.0f, 0.001f, 0.0f }; vec3 ndz = { 0.0f, 0.0f, 0.001f }; vec3 normal(vec3 p) { vec3 tmp = { sdf(addv3(p, ndx)), sdf(addv3(p, ndy)), sdf(addv3(p, ndz)) }; float d = sdf(p); vec3 d3 = { d, d, d }; return normalize(subv3(tmp, d3)); } Color shade(float x, float y) { x = (x*2.0f - 1.0f)*ASPECT; y = -y*2.0f + 1.0f; vec3 ro = { 0.0f, 0.0f, -2.0f }; vec3 rd = { x, y, 1.0f }; rd = normalize(rd); float d = 0.0f; vec3 p = ro; for(int i = 0; i < 100; i++){ d = sdf(p); p = addv3(p, scalev3(rd, d)); if(d < MIN_DIST || d > MAX_DIST) break; } vec3 c = { 0.0f, 0.0f, 0.0f }; if(d < MAX_DIST){ vec3 n = normal(p); float l = clamp(dot3(ldir, n), 0.0f, 1.0f); // l += 0.3f; l = clamp(l+0.3f, 0.0f, 1.0f); c = scalev3(color, l); }else{ c = (vec3){ 0.0f, 0.0f, 0.0f }; } c.x = clamp(c.x, 0.0f, 1.0f); c.y = clamp(c.y, 0.0f, 1.0f); c.z = clamp(c.z, 0.0f, 1.0f); return (Color){ c.z*255, c.y*255, c.x*255, 0 }; } Canvas* makecanvas(int w, int h) { Canvas *canv; canv = malloc(sizeof(*canv) + w*h*(4)); canv->w = w; canv->h = h; canv->fb = ((u8*)canv + sizeof(*canv)); return canv; } void drawframe(Canvas *canv) { Color c; int x, y; u8 *p; for(y = 0; y < canv->h; y++) for(x = 0; x < canv->w; x++){ p = &canv->fb[(y*canv->w + x)*4]; c = shade((float)x/canv->w, (float)y/canv->h); p[3] = c.r; p[2] = c.g; p[1] = c.b; p[0] = 255; } } void drawwindow(Canvas *canvas) { drawframe(canvas); loadimage(img, Rect(0, 0, canvas->w, canvas->h), canvas->fb, canvas->w*canvas->h*4); draw(screen, screen->r, img, nil, ZP); flushimage(display, 1); } void init(void) { canvas = makecanvas(WIDTH, HEIGHT); img = allocimage(display, Rect(0, 0, canvas->w, canvas->h), RGBA32, 0, DRed); } void kbthread(void*) { Rune r; for(;;){ r = recvul(kbctl->c); switch(r){ case L'q': case Kdel: threadexitsall(nil); default: ; } } } void mthread(void*) { Mouse m; for(;;){ recv(mctl->c, &m); } } void resthread(void*) { for(;;){ recvul(mctl->resizec); if(getwindow(display, Refnone) < 0) sysfatal("resize failed: %r"); drawwindow(canvas); } } void resize(int x, int y) { int fd; fd = open("/dev/wctl", OWRITE); if(fd >= 0){ fprint(fd, "resize -dx %d -dy %d", x+8, y+8); close(fd); } } void threadmain(int /*argc*/, char */*argv*/[]) { newwindow(nil); resize(WIDTH, HEIGHT); if(initdraw(nil, nil, "march") < 0) sysfatal("initdraw: %r"); kbctl = initkeyboard("/dev/cons"); if(kbctl == nil) sysfatal("initkeyboard: %r"); mctl = initmouse("/dev/mouse", screen); if(mctl == nil) sysfatal("initmouse: %r"); threadcreate(kbthread, nil, mainstacksize); threadcreate(mthread, nil, mainstacksize); threadcreate(resthread, nil, mainstacksize); init(); while(1){ setupScene(); drawwindow(canvas); timer += 0.1f; yield(); } }