foo
[regis] / x3d.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <math.h>
4 #include "x3d.h"
5 #include "fixed.h"
6 #include "sincos.h"
7 #include "regis.h"
8
9 typedef struct pvec3 {
10         int32_t x, y, z;
11 } pvec3;
12
13 typedef struct pvec2 {
14         int32_t x, y;
15 } pvec2;
16
17
18 #define MAT_STACK_SIZE  4
19
20 struct matrix {
21         int32_t m[12];
22 };
23
24 static void proc_vertex(const int32_t *vin, pvec3 *vout);
25
26 void draw_poly(int num, const pvec3 *verts, int color);
27 void draw_point(const pvec3 *v, int color);
28
29
30 static int32_t proj_fov = M_PI_X16;
31 static int32_t proj_aspect = 65536;
32 static int32_t inv_proj_aspect = 65536;
33 static int32_t proj_near = ftox16(0.5);
34 static int32_t proj_far = 500 << 16;
35 static int32_t inv_tan_half_xfov, inv_tan_half_yfov;
36
37 #define ID_INIT {65536, 0, 0, 0, 0, 65536, 0, 0, 0, 0, 65536, 0}
38
39 static struct matrix identity = { ID_INIT };
40
41 static short mtop;
42 static struct matrix mstack[MAT_STACK_SIZE] = { {ID_INIT}, {ID_INIT} };
43
44 static const int32_t *vertex_array;
45 static unsigned short vertex_count;
46
47 static uint8_t im_color_index;
48 static int32_t im_vertex[4 * 3];
49 static short im_vcount;
50 static short im_mode;
51
52
53 void x3d_projection(int fov, int32_t aspect, int32_t nearz, int32_t farz)
54 {
55         proj_fov = (M_PI_X16 * fov) / 180;
56         proj_aspect = aspect;
57         inv_proj_aspect = x16div(65536, proj_aspect);
58         proj_near = nearz;
59         proj_far = farz;
60
61         inv_tan_half_yfov = (int32_t)(65536.0 / tan(0.5 * proj_fov / 65536.0));
62         inv_tan_half_xfov = x16mul(inv_tan_half_yfov, aspect);
63 }
64
65 int x3d_push_matrix(void)
66 {
67         short newtop = mtop + 1;
68         if(newtop >= MAT_STACK_SIZE) {
69                 return -1;
70         }
71         memcpy(mstack + newtop, mstack + mtop, sizeof *mstack);
72         mtop = newtop;
73         return 0;
74 }
75
76 int x3d_pop_matrix(void)
77 {
78         if(mtop <= 0) {
79                 return -1;
80         }
81         --mtop;
82         return 0;
83 }
84
85 void x3d_load_matrix(int32_t *m)
86 {
87         memcpy(mstack[mtop].m, m, sizeof *mstack);
88 }
89
90
91 #define M(i,j)  (((i) << 2) + (j))
92 void x3d_mult_matrix(int32_t *m)
93 {
94         int i, j;
95         struct matrix tmp;
96
97         memcpy(tmp.m, mstack[mtop].m, sizeof tmp);
98
99         for(i=0; i<3; i++) {
100                 for(j=0; j<4; j++) {
101                         mstack[mtop].m[M(i, j)] =
102                                 x16mul(m[M(0, j)], tmp.m[M(i, 0)]) +
103                                 x16mul(m[M(1, j)], tmp.m[M(i, 1)]) +
104                                 x16mul(m[M(2, j)], tmp.m[M(i, 2)]);
105                 }
106                 mstack[mtop].m[M(i, 3)] += tmp.m[M(i, 3)];
107         }
108 }
109
110 void x3d_load_identity(void)
111 {
112         memcpy(mstack[mtop].m, identity.m, sizeof identity);
113 }
114
115 void x3d_translate(int32_t x, int32_t y, int32_t z)
116 {
117         int32_t m[] = ID_INIT;
118         m[3] = x;
119         m[7] = y;
120         m[11] = z;
121
122         x3d_mult_matrix(m);
123 }
124
125 void x3d_rotate(int32_t deg, int32_t x, int32_t y, int32_t z)
126 {
127         int32_t xform[] = ID_INIT;
128
129         int32_t angle = x16mul(M_PI_X16, deg) / 180;
130         int32_t sina = sin_x16(angle);
131         int32_t cosa = cos_x16(angle);
132         int32_t one_minus_cosa = 65536 - cosa;
133         int32_t nxsq = x16sq(x);
134         int32_t nysq = x16sq(y);
135         int32_t nzsq = x16sq(z);
136
137         xform[0] = nxsq + x16mul(65536 - nxsq, cosa);
138         xform[4] = x16mul(x16mul(x, y), one_minus_cosa) - x16mul(z, sina);
139         xform[8] = x16mul(x16mul(x, z), one_minus_cosa) + x16mul(y, sina);
140         xform[1] = x16mul(x16mul(x, y), one_minus_cosa) + x16mul(z, sina);
141         xform[5] = nysq + x16mul(65536 - nysq, cosa);
142         xform[9] = x16mul(x16mul(y, z), one_minus_cosa) - x16mul(x, sina);
143         xform[2] = x16mul(x16mul(x, z), one_minus_cosa) - x16mul(y, sina);
144         xform[6] = x16mul(x16mul(y, z), one_minus_cosa) + x16mul(x, sina);
145         xform[10] = nzsq + x16mul(65536 - nzsq, cosa);
146
147         x3d_mult_matrix(xform);
148 }
149
150 void x3d_scale(int32_t x, int32_t y, int32_t z)
151 {
152         int32_t m[] = ID_INIT;
153
154         m[0] = x;
155         m[5] = y;
156         m[10] = z;
157
158         x3d_mult_matrix(m);
159 }
160
161 void x3d_vertex_array(int count, const int32_t *ptr)
162 {
163         vertex_array = ptr;
164         vertex_count = count;
165 }
166
167 int x3d_draw(int prim, int vnum)
168 {
169         int i, j, pverts = prim;
170         const int32_t *vptr = vertex_array;
171         uint16_t color;
172
173         if(!vertex_array) return -1;
174
175         if(vnum > vertex_count) {
176                 vnum = vertex_count;
177         }
178
179         for(i=0; i<vnum; i+=pverts) {
180                 /* process vertices */
181                 pvec3 vpos[4];
182
183                 for(j=0; j<pverts; j++) {
184                         proc_vertex(vptr, vpos + j);
185
186                         if(vpos[j].z <= proj_near) {
187                                 goto skip_prim;
188                         }
189
190                         vptr += 3;
191                 }
192
193                 color = im_color_index;
194
195                 /* project & viewport */
196                 for(j=0; j<pverts; j++) {
197                         int32_t x, y;
198
199                         x = x16mul(vpos[j].x, inv_tan_half_xfov);
200                         x = x16div(x, vpos[j].z);
201                         vpos[j].x = (x16mul(x, inv_proj_aspect) + 65536) * (WIDTH / 2);
202
203                         y = x16mul(vpos[j].y, inv_tan_half_yfov);
204                         y = x16div(y, vpos[j].z);
205                         vpos[j].y = (65536 - y) * (HEIGHT / 2);
206                 }
207
208                 switch(pverts) {
209                 case X3D_POINTS:
210                         draw_point(vpos, color);
211                         break;
212
213                 case X3D_LINES:
214                         break;
215
216                 case X3D_TRIANGLES:
217                 case X3D_QUADS:
218                         draw_poly(pverts, vpos, im_color_index);
219                         break;
220                 }
221 skip_prim: ;
222         }
223
224         return 0;
225 }
226
227 static void proc_vertex(const int32_t *vin, pvec3 *vout)
228 {
229         int i;
230         int32_t tvert[3];
231         int32_t *mvmat = mstack[mtop].m;
232
233         /* transform vertex with current matrix */
234         for(i=0; i<3; i++) {
235                 tvert[i] = x16mul(mvmat[0], vin[0]) +
236                         x16mul(mvmat[1], vin[1]) +
237                         x16mul(mvmat[2], vin[2]) +
238                         mvmat[3];
239                 mvmat += 4;
240         }
241
242         vout->x = tvert[0];
243         vout->y = tvert[1];
244         vout->z = tvert[2];
245 }
246
247 void x3d_begin(int mode)
248 {
249         im_mode = mode;
250         im_vcount = 0;
251 }
252
253 void x3d_end(void)
254 {
255 }
256
257 void x3d_vertex(int32_t x, int32_t y, int32_t z)
258 {
259         int32_t *vptr = im_vertex + im_vcount * 3;
260         vptr[0] = x;
261         vptr[1] = y;
262         vptr[2] = z;
263
264         im_vcount = (im_vcount + 1) % im_mode;
265         if(!im_vcount) {
266                 x3d_vertex_array(im_mode, im_vertex);
267                 x3d_draw(im_mode, im_mode);
268         }
269 }
270
271 void x3d_color_index(int cidx)
272 {
273         im_color_index = cidx;
274 }
275
276
277 void draw_poly(int num, const pvec3 *verts, int color)
278 {
279         int i;
280         regis_abspos(verts[0].x >> 16, verts[0].y >> 16);
281         regis_begin_vector(REGIS_BOUNDED);
282
283         for(i=0; i<num-1; i++) {
284                 ++verts;
285                 regis_absv(verts->x >> 16, verts->y >> 16);
286         }
287         regis_end_vector();
288 }
289
290 void draw_point(const pvec3 *v, int color)
291 {
292 }