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_hmap;
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_hmap[((((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 int vox_view(int32_t x, int32_t y, int h, int32_t angle)
111 vox_valid &= ~SLICELEN;
116 void vox_proj(int fov, int znear, int zfar)
122 vox_nslices = vox_zfar - vox_znear;
124 if(!(vox_slicelen = iwram_sbrk(vox_nslices * sizeof *vox_slicelen))) {
125 panic(get_pc(), "vox_proj: failed to allocate slice length table (%d)\n", vox_nslices);
127 if(!(projlut = iwram_sbrk(vox_nslices * sizeof *projlut))) {
128 panic(get_pc(), "vox_framebuf: failed to allocate projection table (%d)\n", vox_nslices);
132 vox_valid &= ~SLICELEN;
136 * calculate extents of horizontal equidistant line from the viewer based on fov
137 * for each column step along this line and compute height for each pixel
138 * fill the visible (top) part of each column
141 void vox_render(void)
147 for(i=0; i<vox_nslices; i++) {
157 memset(vox_coltop, 0, FBWIDTH * sizeof *vox_coltop);
159 if(!(vox_valid & SLICELEN)) {
160 float theta = (float)vox_fov * M_PI / 360.0f; /* half angle */
161 for(i=0; i<vox_nslices; i++) {
162 vox_slicelen[i] = (int32_t)((vox_znear + i) * tan(theta) * 4.0f * 65536.0f);
163 projlut[i] = (HSCALE << 8) / (vox_znear + i);
165 vox_valid |= SLICELEN;
170 void vox_render_slice(int n)
172 int i, j, hval, last_hval, colstart, colheight, col, z, offs, last_offs = -1;
173 int32_t x, y, len, xstep, ystep;
174 uint8_t color, last_col;
177 struct vox_object *obj;
181 len = vox_slicelen[n] >> 8;
182 xstep = (((COS(vox_angle) >> 4) * len) >> 4) / (FBWIDTH / 2);
183 ystep = (((SIN(vox_angle) >> 4) * len) >> 4) / (FBWIDTH / 2);
185 x = vox_x - SIN(vox_angle) * z - xstep * (FBWIDTH / 4);
186 y = vox_y + COS(vox_angle) * z - ystep * (FBWIDTH / 4);
188 /*proj = (HSCALE << 8) / (vox_znear + n);*/
190 for(i=0; i<FBWIDTH/2; i++) {
192 offs = (((y >> 16) & YMASK) << XSHIFT) + ((x >> 16) & XMASK);
193 if(offs == last_offs) {
197 hval = vox_hmap[offs] - vox_vheight;
198 hval = ((hval * projlut[n]) >> 8) + vox_horizon;
199 if(hval > FBHEIGHT) hval = FBHEIGHT;
200 color = vox_color[offs];
205 if(hval >= vox_coltop[col]) {
206 colstart = FBHEIGHT - hval;
207 colheight = hval - vox_coltop[col];
208 fbptr = vox_fb + colstart * (FBPITCH / 2) + i;
210 for(j=0; j<colheight; j++) {
211 *fbptr = color | ((uint16_t)color << 8);
212 fbptr += FBPITCH / 2;
214 vox_coltop[col] = hval;
216 /* check to see if there's an object here */
217 if(color >= CMAP_SPAWN0) {
218 int idx = color - CMAP_SPAWN0;
219 obj = (struct vox_object*)((char*)vox_obj + (idx << OBJ_STRIDE_SHIFT));
222 obj->scale = projlut[n];
231 void vox_sky_solid(uint8_t color)
236 for(i=0; i<FBWIDTH / 2; i++) {
238 colheight = FBHEIGHT - vox_coltop[i << 1];
240 for(j=0; j<colheight; j++) {
241 *fbptr = color | ((uint16_t)color << 8);
242 fbptr += FBPITCH / 2;
248 void vox_sky_grad(uint8_t chor, uint8_t ctop)
250 int i, j, colheight, t;
251 int d = FBHEIGHT - vox_horizon;
252 uint8_t grad[FBHEIGHT];
257 grad[i] = XLERP(ctop, chor, t, 16);
259 for(i=d; i<FBHEIGHT; i++) {
263 for(i=0; i<FBWIDTH / 2; i++) {
265 colheight = FBHEIGHT - vox_coltop[i << 1];
267 for(j=0; j<colheight; j++) {
268 *fbptr = grad[j] | ((uint16_t)grad[j] << 8);
269 fbptr += FBPITCH / 2;
274 void vox_objects(struct vox_object *ptr, int count, int stride)
277 struct vox_object *obj;
279 if(stride != 1 << OBJ_STRIDE_SHIFT) {
280 panic(get_pc(), "optimization requires %d byte vox obj (got %d)",
281 1 << OBJ_STRIDE_SHIFT, stride);
286 vox_obj_stride = stride;
289 for(i=0; i<count; i++) {
290 obj->offs = obj->y * XSZ + obj->x;
291 obj = (struct vox_object*)((char*)obj + stride);
295 int vox_height(int x, int y)
300 int vox_check_vis(int32_t x0, int32_t y0, int32_t x1, int32_t y1)