11 /* hardcoded dimensions for the GBA */
24 #define OBJ_STRIDE_SHIFT 5
28 #define XLERP(a, b, t, fp) \
29 ((((a) << (fp)) + ((b) - (a)) * (t)) >> fp)
35 static unsigned char *vox_height;
36 static unsigned char *vox_color;
38 static uint16_t *vox_fb;
39 static int *vox_coltop;
40 static int vox_horizon;
42 static int32_t vox_x, vox_y, vox_angle;
43 static int vox_vheight;
45 static int vox_fov, vox_znear, vox_zfar;
46 static int vox_nslices;
47 static int32_t *vox_slicelen;
49 static unsigned int vox_valid;
51 static struct vox_object *vox_obj;
52 static int vox_num_obj, vox_obj_stride;
56 int vox_init(int xsz, int ysz, uint8_t *himg, uint8_t *cimg)
58 assert(xsz == XSZ && ysz == YSZ);
66 vox_x = vox_y = vox_angle = 0;
68 vox_znear = vox_zfar = 0;
79 void vox_destroy(void)
81 /* XXX we rely on the screen to clear up any allocated IWRAM */
85 vox_height[((((y) >> 16) & YMASK) << XSHIFT) + (((x) >> 16) & XMASK)]
87 vox_color[((((y) >> 16) & YMASK) << XSHIFT) + (((x) >> 16) & XMASK)]
89 void vox_framebuf(int xres, int yres, void *fb, int horizon)
92 if(!(vox_coltop = iwram_sbrk(xres * sizeof *vox_coltop))) {
93 panic(get_pc(), "vox_framebuf: failed to allocate column table (%d)\n", xres);
97 vox_horizon = horizon >= 0 ? horizon : (FBHEIGHT >> 1);
100 void vox_view(int32_t x, int32_t y, int h, int32_t angle)
111 vox_valid &= ~SLICELEN;
114 void vox_proj(int fov, int znear, int zfar)
120 vox_nslices = vox_zfar - vox_znear;
122 if(!(vox_slicelen = iwram_sbrk(vox_nslices * sizeof *vox_slicelen))) {
123 panic(get_pc(), "vox_proj: failed to allocate slice length table (%d)\n", vox_nslices);
125 if(!(projlut = iwram_sbrk(vox_nslices * sizeof *projlut))) {
126 panic(get_pc(), "vox_framebuf: failed to allocate projection table (%d)\n", vox_nslices);
130 vox_valid &= ~SLICELEN;
134 * calculate extents of horizontal equidistant line from the viewer based on fov
135 * for each column step along this line and compute height for each pixel
136 * fill the visible (top) part of each column
139 void vox_render(void)
145 for(i=0; i<vox_nslices; i++) {
155 memset(vox_coltop, 0, FBWIDTH * sizeof *vox_coltop);
157 if(!(vox_valid & SLICELEN)) {
158 float theta = (float)vox_fov * M_PI / 360.0f; /* half angle */
159 for(i=0; i<vox_nslices; i++) {
160 vox_slicelen[i] = (int32_t)((vox_znear + i) * tan(theta) * 4.0f * 65536.0f);
161 projlut[i] = (HSCALE << 8) / (vox_znear + i);
163 vox_valid |= SLICELEN;
168 void vox_render_slice(int n)
170 int i, j, hval, last_hval, colstart, colheight, col, z, offs, last_offs = -1;
171 int32_t x, y, len, xstep, ystep;
172 uint8_t color, last_col;
175 struct vox_object *obj;
179 len = vox_slicelen[n] >> 8;
180 xstep = (((COS(vox_angle) >> 4) * len) >> 4) / (FBWIDTH / 2);
181 ystep = (((SIN(vox_angle) >> 4) * len) >> 4) / (FBWIDTH / 2);
183 x = vox_x - SIN(vox_angle) * z - xstep * (FBWIDTH / 4);
184 y = vox_y + COS(vox_angle) * z - ystep * (FBWIDTH / 4);
186 /*proj = (HSCALE << 8) / (vox_znear + n);*/
188 for(i=0; i<FBWIDTH/2; i++) {
190 offs = (((y >> 16) & YMASK) << XSHIFT) + ((x >> 16) & XMASK);
191 if(offs == last_offs) {
195 hval = vox_height[offs] - vox_vheight;
196 hval = ((hval * projlut[n]) >> 8) + vox_horizon;
197 if(hval > FBHEIGHT) hval = FBHEIGHT;
198 color = vox_color[offs];
203 if(hval >= vox_coltop[col]) {
204 colstart = FBHEIGHT - hval;
205 colheight = hval - vox_coltop[col];
206 fbptr = vox_fb + colstart * (FBPITCH / 2) + i;
208 for(j=0; j<colheight; j++) {
209 *fbptr = color | ((uint16_t)color << 8);
210 fbptr += FBPITCH / 2;
212 vox_coltop[col] = hval;
214 /* check to see if there's an object here */
215 if(color >= CMAP_SPAWN0) {
216 int idx = color - CMAP_SPAWN0;
217 obj = (struct vox_object*)((char*)vox_obj + (idx << OBJ_STRIDE_SHIFT));
220 obj->scale = projlut[n];
229 void vox_sky_solid(uint8_t color)
234 for(i=0; i<FBWIDTH / 2; i++) {
236 colheight = FBHEIGHT - vox_coltop[i << 1];
238 for(j=0; j<colheight; j++) {
239 *fbptr = color | ((uint16_t)color << 8);
240 fbptr += FBPITCH / 2;
246 void vox_sky_grad(uint8_t chor, uint8_t ctop)
248 int i, j, colheight, t;
249 int d = FBHEIGHT - vox_horizon;
250 uint8_t grad[FBHEIGHT];
255 grad[i] = XLERP(ctop, chor, t, 16);
257 for(i=d; i<FBHEIGHT; i++) {
261 for(i=0; i<FBWIDTH / 2; i++) {
263 colheight = FBHEIGHT - vox_coltop[i << 1];
265 for(j=0; j<colheight; j++) {
266 *fbptr = grad[j] | ((uint16_t)grad[j] << 8);
267 fbptr += FBPITCH / 2;
272 void vox_objects(struct vox_object *ptr, int count, int stride)
275 struct vox_object *obj;
277 if(stride != 1 << OBJ_STRIDE_SHIFT) {
278 panic(get_pc(), "optimization requires %d byte vox obj (got %d)",
279 1 << OBJ_STRIDE_SHIFT, stride);
284 vox_obj_stride = stride;
287 for(i=0; i<count; i++) {
288 obj->offs = obj->y * XSZ + obj->x;
289 obj = (struct vox_object*)((char*)obj + stride);