cubes.c (4505B)
1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <event.h> 5 #include <geometry.h> 6 7 /* 8 * given 640 resolution and 80 digrees FoV, 9 * single pixel will be 0.125 digrees wide. 10 * 360/.125 = 2880 - amount of pixels needed 11 * for full circle. 12 * Small enough amount to precompute all possible 13 * angles for every possible direction 14 */ 15 16 #define OTSize (64 * 64 * 64) 17 18 #define CSWidth 640 19 #define CSHeight 640 20 #define CSSize (CSWidth * CSHeight) 21 22 u32int otree[OTSize]; 23 u32int imgbuf[CSSize]; 24 25 Image *img; 26 vlong n; 27 char *s; 28 29 typedef struct Raydef Raydef; 30 struct Raydef { 31 double O[3]; 32 double D[3]; 33 }; 34 35 typedef struct Boxdef Boxdef; 36 struct Boxdef { 37 double min[3]; 38 double max[3]; 39 }; 40 41 Boxdef box = {{0,0,0}, {1,1,1}}; 42 Raydef view = {{10,20,30}, {-1,-2,-3}}; 43 44 Raydef 45 raynorm(Raydef r) 46 { 47 double d = r.D[0] * r.D[0] + r.D[1] * r.D[1] + r.D[2] * r.D[2]; 48 if (d != 0) { 49 r.D[0] /= d; 50 r.D[1] /= d; 51 r.D[2] /= d; 52 } 53 return r; 54 } 55 56 /* 57 * Ray is O + Dt, where O is origin and D is direction 58 * Box is defined by 2 boundary points, M, N (min and max) 59 * which translates into 6 planes: 60 * x = Nx; x = Mx; y = Ny; y = My; z = Nz; z = Mz 61 * Intersections of ray and planes: 62 * Tn = (Bn - On)/Dn; where B (as in boundary) is either M or N, 63 * and n stands for axis (x,y,z) 64 * (beware division by zero!) 65 * 66 */ 67 68 Raydef 69 intersectX(Raydef ray, double X) 70 { 71 Raydef ref; 72 double t; 73 if (ray.D[0] >= X) { 74 Raydef ret = { 75 {Inf(ray.D[0]), Inf(ray.D[1]), Inf(ray.D[2])}, 76 {ray.D[0], ray.D[1], ray.D[2]}, 77 }; 78 return ret; 79 } 80 t = (X-ray.O[0]) / ray.D[0]; 81 ref.O[0] = X; 82 ref.O[1] = ray.O[1] + ray.D[1] * t; 83 ref.O[2] = ray.O[2] + ray.D[2] * t; 84 ref.D[0] = -ray.D[0]; 85 ref.D[1] = ray.D[1]; 86 ref.D[2] = ray.D[2]; 87 return ref; 88 } 89 90 Raydef 91 intersectY(Raydef ray, double Y) 92 { 93 Raydef ref; 94 double t; 95 if (ray.D[1] >= Y) { 96 Raydef ret = { 97 {Inf(ray.D[0]), Inf(ray.D[1]), Inf(ray.D[2])}, 98 {ray.D[0], ray.D[1], ray.D[2]}, 99 }; 100 return ret; 101 } 102 t = (Y-ray.O[1]) / ray.D[1]; 103 ref.O[0] = ray.O[0] + ray.D[0] * t; 104 ref.O[1] = Y; 105 ref.O[2] = ray.O[2] + ray.D[2] * t; 106 ref.D[0] = ray.D[0]; 107 ref.D[1] = -ray.D[1]; 108 ref.D[2] = ray.D[2]; 109 return ref; 110 } 111 112 Raydef 113 intersectZ(Raydef ray, double Z) 114 { 115 Raydef ref; 116 double t; 117 if (ray.D[2] >= Z) { 118 Raydef ret = { 119 {Inf(ray.D[0]), Inf(ray.D[1]), Inf(ray.D[2])}, 120 {ray.D[0], ray.D[1], ray.D[2]}, 121 }; 122 return ret; 123 } 124 t = (Z-ray.O[0]) / ray.D[0]; 125 ref.O[0] = ray.O[0] + ray.D[0] * t; 126 ref.O[1] = ray.O[1] + ray.D[1] * t; 127 ref.O[2] = Z; 128 ref.D[0] = ray.D[0]; 129 ref.D[1] = ray.D[1]; 130 ref.D[2] = -ray.D[2]; 131 return ref; 132 } 133 134 void 135 vrender(void) 136 { 137 int i, j, x, y; 138 double X, Y; 139 for (i = 0, y = 0; y < CSHeight; y++) { 140 Y = (double)(y) / CSHeight; 141 for (x = 0; x < CSWidth; x++, i++) { 142 X = (double)(x) / CSWidth; 143 // TODO: generate camera ray properly 144 Raydef r = { 145 .O {10, 10, 10}, 146 .D {-1 + X * 2, 1 - Y * 2, 2} 147 }; 148 Raydef ref[6]; 149 ref[0] = intersectX(r, 0); 150 ref[1] = intersectY(r, 0); 151 ref[2] = intersectZ(r, 0); 152 153 ref[3] = intersectX(r, 0); 154 ref[4] = intersectY(r, 0); 155 ref[5] = intersectZ(r, 0); 156 157 Raydef one; // = infray 158 for (j = 0; j < 6; j++) { 159 // check boundary; 160 if ((ref[j].O[0] < 0) || (ref[j].O[1] < 0) || (ref[j].O[2] < 0)) 161 continue; 162 // todo check distance; 163 one = ref[j]; 164 } 165 if (isInf(ref[0].O[0], 0) != 0) imgbuf[i] = 0x004f7fff; 166 else { 167 double d = sqrt((ref[0].D[1] * ref[0].D[1]) 168 / (ref[0].D[0] * ref[0].D[0] + ref[0].D[2] * ref[0].D[2])); 169 int br = 0xff * d; 170 imgbuf[i] = (br << 16) + (br << 8) + (br); 171 } 172 } 173 } 174 } 175 176 void 177 redraw(Image *) 178 { 179 draw(screen, screen->r, display->white, nil, ZP); 180 draw(screen, screen->r, img, nil, ZP); 181 182 string(screen, screen->r.min, display->white, ZP, font, s); 183 } 184 185 void 186 eresized(int new) 187 { 188 if(new && getwindow(display, Refnone) < 0) 189 sysfatal("can't reattach to window"); 190 redraw(screen); 191 } 192 193 void 194 main(void) 195 { 196 view = raynorm(view); 197 srand(nsec()); 198 s = smprint("render time %lld nsec", n); 199 initdraw(nil, 0, "cubes"); 200 img = allocimage(display, Rect(0, 0, CSWidth, CSHeight), XRGB32, 0, DRed); 201 202 n = nsec(); vrender(); n = nsec() - n; 203 s = smprint("render time %lld nsec", n); 204 loadimage(img, img->r, (uchar *)imgbuf, CSSize * 4); 205 redraw(img); 206 207 Event e; 208 einit(Emouse); 209 int timer = etimer(0, 500); 210 for(;;) { 211 int key = event(&e); 212 if (key == timer) { 213 n = nsec(); vrender(); n = nsec() - n; 214 free(s); s = smprint("render time %lld nsec", n); 215 loadimage(img, img->r, (uchar *)imgbuf, CSSize * 4); 216 redraw(img); 217 } 218 } 219 }