gba-trycatch
view src/x3d.c @ 14:c398d834d64a
fixed the rendering bugs
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 23 Jun 2014 10:33:24 +0300 |
parents | 2070a81127f2 |
children | b755fb002f17 |
line source
1 #include "config.h"
2 #include <stdio.h>
3 #include <string.h>
4 #include <math.h>
5 #include "x3d.h"
6 #include "fixed.h"
7 #include "sincos.h"
8 #include "logger.h"
9 #include "polyfill.h"
10 #include "gbasys.h"
12 int dbg_fill_dump;
14 #define MAT_STACK_SIZE 4
16 struct matrix {
17 int32_t m[12];
18 };
20 static void proc_vertex(const int32_t *vin, const int32_t *cin, pvec3 *vout, pvec3 *cout);
21 static int dump_frame(struct pixel_buffer *frame);
24 static int32_t proj_fov = M_PI_X16;
25 static int32_t proj_aspect = 65536;
26 static int32_t inv_proj_aspect = 65536;
27 static int32_t proj_near = ftox16(0.5);
28 static int32_t proj_far = 500 << 16;
29 static int32_t inv_tan_half_xfov, inv_tan_half_yfov;
31 #define ID_INIT {65536, 0, 0, 0, 0, 65536, 0, 0, 0, 0, 65536, 0}
33 static struct matrix identity = { ID_INIT };
35 static short mtop;
36 static struct matrix mstack[MAT_STACK_SIZE] = { {ID_INIT}, {ID_INIT} };
38 static const int32_t *vertex_array;
39 static unsigned short vertex_count;
40 static const int32_t *color_array;
41 static unsigned short color_count;
43 static int32_t im_color[3];
44 static uint8_t im_color_index;
46 void x3d_projection(int fov, int32_t aspect, int32_t nearz, int32_t farz)
47 {
48 proj_fov = (M_PI_X16 * fov) / 180;
49 proj_aspect = aspect;
50 inv_proj_aspect = x16div(65536, proj_aspect);
51 proj_near = nearz;
52 proj_far = farz;
54 inv_tan_half_yfov = (int32_t)(65536.0 / tan(0.5 * proj_fov / 65536.0));
55 inv_tan_half_xfov = x16mul(inv_tan_half_yfov, aspect);
56 }
58 int x3d_push_matrix(void)
59 {
60 short newtop = mtop + 1;
61 if(newtop >= MAT_STACK_SIZE) {
62 return -1;
63 }
64 memcpy(mstack + newtop, mstack + mtop, sizeof *mstack);
65 mtop = newtop;
66 return 0;
67 }
69 int x3d_pop_matrix(void)
70 {
71 if(mtop <= 0) {
72 return -1;
73 }
74 --mtop;
75 return 0;
76 }
78 void x3d_load_matrix(int32_t *m)
79 {
80 memcpy(mstack[mtop].m, m, sizeof *mstack);
81 }
84 #define M(i,j) (((i) << 2) + (j))
85 void x3d_mult_matrix(int32_t *m)
86 {
87 int i, j;
88 struct matrix tmp;
90 memcpy(tmp.m, mstack[mtop].m, sizeof tmp);
92 for(i=0; i<3; i++) {
93 for(j=0; j<4; j++) {
94 mstack[mtop].m[M(i, j)] =
95 x16mul(m[M(0, j)], tmp.m[M(i, 0)]) +
96 x16mul(m[M(1, j)], tmp.m[M(i, 1)]) +
97 x16mul(m[M(2, j)], tmp.m[M(i, 2)]);
98 }
99 mstack[mtop].m[M(i, 3)] += tmp.m[M(i, 3)];
100 }
101 }
103 void x3d_load_identity(void)
104 {
105 memcpy(mstack[mtop].m, identity.m, sizeof identity);
106 }
108 void x3d_translate(int32_t x, int32_t y, int32_t z)
109 {
110 int32_t m[] = ID_INIT;
111 m[3] = x;
112 m[7] = y;
113 m[11] = z;
115 x3d_mult_matrix(m);
116 }
118 void x3d_rotate(int32_t deg, int32_t x, int32_t y, int32_t z)
119 {
120 int32_t xform[] = ID_INIT;
122 int32_t angle = x16mul(M_PI_X16, deg) / 180;
123 int32_t sina = sin_x16(angle);
124 int32_t cosa = cos_x16(angle);
125 int32_t one_minus_cosa = 65536 - cosa;
126 int32_t nxsq = x16sq(x);
127 int32_t nysq = x16sq(y);
128 int32_t nzsq = x16sq(z);
130 xform[0] = nxsq + x16mul(65536 - nxsq, cosa);
131 xform[4] = x16mul(x16mul(x, y), one_minus_cosa) - x16mul(z, sina);
132 xform[8] = x16mul(x16mul(x, z), one_minus_cosa) + x16mul(y, sina);
133 xform[1] = x16mul(x16mul(x, y), one_minus_cosa) + x16mul(z, sina);
134 xform[5] = nysq + x16mul(65536 - nysq, cosa);
135 xform[9] = x16mul(x16mul(y, z), one_minus_cosa) - x16mul(x, sina);
136 xform[2] = x16mul(x16mul(x, z), one_minus_cosa) - x16mul(y, sina);
137 xform[6] = x16mul(x16mul(y, z), one_minus_cosa) + x16mul(x, sina);
138 xform[10] = nzsq + x16mul(65536 - nzsq, cosa);
140 x3d_mult_matrix(xform);
141 }
143 void x3d_scale(int32_t x, int32_t y, int32_t z)
144 {
145 int32_t m[] = ID_INIT;
147 m[0] = x;
148 m[5] = y;
149 m[10] = z;
151 x3d_mult_matrix(m);
152 }
154 void x3d_vertex_array(int count, const int32_t *ptr)
155 {
156 vertex_array = ptr;
157 vertex_count = count;
158 }
160 void x3d_color_array(int count, const int32_t *ptr)
161 {
162 color_array = ptr;
163 color_count = count;
164 }
166 int x3d_draw(int prim, int vnum)
167 {
168 int i, j, pverts = prim;
169 const int32_t *vptr = vertex_array;
170 const int32_t *cptr = color_array;
171 #ifndef PALMODE
172 short cr, cg, cb;
173 #endif
174 uint16_t color;
176 if(!vertex_array) return -1;
178 if(vnum > vertex_count) {
179 logmsg(LOG_DBG, "%s called with vnum=%d, but current vertex array has %d vertices\n",
180 __FUNCTION__, vnum, vertex_count);
181 vnum = vertex_count;
182 }
183 if(color_array && vnum > color_count) {
184 logmsg(LOG_DBG, "%s called with vnum=%d, but current color array has %d elements\n",
185 __FUNCTION__, vnum, color_count);
186 vnum = color_count;
187 }
189 for(i=0; i<vnum; i+=pverts) {
190 /* process vertices */
191 pvec3 vpos[4];
192 pvec3 col[4];
194 for(j=0; j<pverts; j++) {
195 proc_vertex(vptr, cptr, vpos + j, col + j);
197 if(vpos[j].z <= proj_near) {
198 goto skip_prim;
199 }
201 vptr += 3;
202 if(cptr) cptr += 3;
203 }
205 #ifdef PALMODE
206 color = im_color_index;
207 #else
208 cr = col[0].x >> 8;
209 cg = col[0].y >> 8;
210 cb = col[0].z >> 8;
212 if(cr > 255) cr = 255;
213 if(cg > 255) cg = 255;
214 if(cb > 255) cb = 255;
216 color = RGB(cr, cg, cb);
217 #endif
219 /* project & viewport */
220 for(j=0; j<pverts; j++) {
221 int32_t x, y;
223 x = x16mul(vpos[j].x, inv_tan_half_xfov);
224 x = x16div(x, vpos[j].z);
225 vpos[j].x = (x16mul(x, inv_proj_aspect) + 65536) * (WIDTH / 2);
227 y = x16mul(vpos[j].y, inv_tan_half_yfov);
228 y = x16div(y, vpos[j].z);
229 vpos[j].y = (65536 - y) * (HEIGHT / 2);
230 }
232 switch(pverts) {
233 case X3D_POINTS:
234 draw_point(vpos, color);
235 break;
237 case X3D_LINES:
238 break;
240 case X3D_TRIANGLES:
241 case X3D_QUADS:
242 draw_poly(pverts, vpos, color);
243 if(dbg_fill_dump) {
244 dump_frame(back_buffer);
245 }
246 break;
247 }
248 skip_prim: ;
249 }
251 dbg_fill_dump = 0;
252 return 0;
253 }
255 static void proc_vertex(const int32_t *vin, const int32_t *cin, pvec3 *vout, pvec3 *cout)
256 {
257 int i;
258 int32_t tvert[3];
259 int32_t *mvmat = mstack[mtop].m;
261 /* transform vertex with current matrix */
262 for(i=0; i<3; i++) {
263 tvert[i] = x16mul(mvmat[0], vin[0]) +
264 x16mul(mvmat[1], vin[1]) +
265 x16mul(mvmat[2], vin[2]) +
266 mvmat[3];
267 mvmat += 4;
268 }
270 vout->x = tvert[0];
271 vout->y = tvert[1];
272 vout->z = tvert[2];
273 /*logmsg(LOG_DBG, "%s: (%g %g %g) -> (%g %g %g)\n", __FUNCTION__,
274 x16tof(vin[0]), x16tof(vin[1]), x16tof(vin[2]),
275 x16tof(vout->x), x16tof(vout->y), x16tof(vout->z));*/
277 if(color_array) {
278 cout->x = cin[0];
279 cout->y = cin[1];
280 cout->z = cin[2];
281 } else {
282 cout->x = im_color[0];
283 cout->y = im_color[1];
284 cout->z = im_color[2];
285 }
286 }
288 void x3d_color_index(int cidx)
289 {
290 im_color_index = cidx;
291 }
293 void x3d_color(int32_t r, int32_t g, int32_t b)
294 {
295 im_color[0] = r;
296 im_color[1] = g;
297 im_color[2] = b;
298 }
300 static int dump_frame(struct pixel_buffer *frame)
301 {
302 static int frameno;
303 char buf[128];
304 FILE *fp;
305 int i, npix;
306 uint16_t *ptr = frame->pixels;
308 sprintf(buf, "dump%03d.ppm", ++frameno);
310 if(!(fp = fopen(buf, "wb"))) {
311 fprintf(stderr, "failed to dump file: %s\n", buf);
312 return -1;
313 }
315 fprintf(fp, "P6\n%d %d\n255\n", frame->x, frame->y);
317 npix = frame->x * frame->y;
318 for(i=0; i<npix; i++) {
319 uint16_t pixel = *ptr++;
320 fputc(GET_R(pixel), fp);
321 fputc(GET_G(pixel), fp);
322 fputc(GET_B(pixel), fp);
323 }
324 fclose(fp);
325 return 0;
326 }