8 void draw_mesh(struct g3d_mesh *mesh)
10 glEnableClientState(GL_VERTEX_ARRAY);
11 glEnableClientState(GL_NORMAL_ARRAY);
12 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
13 glEnableClientState(GL_COLOR_ARRAY);
15 glVertexPointer(3, GL_FLOAT, sizeof *mesh->varr, &mesh->varr->x);
16 glNormalPointer(GL_FLOAT, sizeof *mesh->varr, &mesh->varr->nx);
17 glTexCoordPointer(2, GL_FLOAT, sizeof *mesh->varr, &mesh->varr->u);
18 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof *mesh->varr, &mesh->varr->r);
21 glDrawElements(mesh->prim, mesh->icount, GL_UNSIGNED_SHORT, mesh->iarr);
23 glDrawArrays(mesh->prim, 0, mesh->vcount);
26 glDisableClientState(GL_VERTEX_ARRAY);
27 glDisableClientState(GL_NORMAL_ARRAY);
28 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
29 glDisableClientState(GL_COLOR_ARRAY);
32 void apply_mesh_xform(struct g3d_mesh *mesh, const float *xform)
35 struct g3d_vertex *v = mesh->varr;
37 for(i=0; i<mesh->vcount; i++) {
38 float x = xform[0] * v->x + xform[4] * v->y + xform[8] * v->z + xform[12];
39 float y = xform[1] * v->x + xform[5] * v->y + xform[9] * v->z + xform[13];
40 v->z = xform[2] * v->x + xform[6] * v->y + xform[10] * v->z + xform[14];
43 x = xform[0] * v->nx + xform[4] * v->ny + xform[8] * v->nz;
44 y = xform[1] * v->nx + xform[5] * v->ny + xform[9] * v->nz;
45 v->nz = xform[2] * v->nx + xform[6] * v->ny + xform[10] * v->nz;
52 int append_mesh(struct g3d_mesh *ma, struct g3d_mesh *mb)
54 int i, new_vcount, new_icount;
58 if(ma->prim != mb->prim) {
59 fprintf(stderr, "append_mesh failed, primitive mismatch\n");
63 if(ma->iarr || mb->iarr) {
65 if(indexify_mesh(ma) == -1) {
68 } else if(!mb->iarr) {
69 if(indexify_mesh(mb) == -1) {
74 new_icount = ma->icount + mb->icount;
75 if(!(iptr = realloc(ma->iarr, new_icount * sizeof *iptr))) {
76 fprintf(stderr, "append_mesh: failed to allocate combined index buffer (%d indices)\n", new_icount);
82 for(i=0; i<mb->icount; i++) {
83 *iptr++ = mb->iarr[i] + ma->vcount;
85 ma->icount = new_icount;
88 new_vcount = ma->vcount + mb->vcount;
89 if(!(tmp = realloc(ma->varr, new_vcount * sizeof *ma->varr))) {
90 fprintf(stderr, "append_mesh: failed to allocate combined vertex buffer (%d verts)\n", new_vcount);
94 memcpy(ma->varr + ma->vcount, mb->varr, mb->vcount * sizeof *ma->varr);
95 ma->vcount = new_vcount;
99 #define FEQ(a, b) ((a) - (b) < 1e-5 && (b) - (a) < 1e-5)
100 static int cmp_vertex(struct g3d_vertex *a, struct g3d_vertex *b)
102 if(!FEQ(a->x, b->x) || !FEQ(a->y, b->y) || !FEQ(a->z, b->z))
104 if(!FEQ(a->nx, b->nx) || !FEQ(a->ny, b->ny) || !FEQ(a->nz, b->nz))
106 if(!FEQ(a->u, b->u) || !FEQ(a->v, b->v))
108 if(a->r != b->r || a->g != b->g || a->b != b->b || a->a != b->a)
113 static int find_existing(struct g3d_vertex *v, struct g3d_vertex *varr, int vcount)
116 for(i=0; i<vcount; i++) {
117 if(cmp_vertex(v, varr++) == 0) {
124 int indexify_mesh(struct g3d_mesh *mesh)
126 int i, j, nfaces, max_icount, idx;
128 struct g3d_vertex *vin, *vout;
132 fprintf(stderr, "indexify_mesh failed: already indexed\n");
136 nfaces = mesh->vcount / mesh->prim;
137 max_icount = mesh->vcount;
139 if(!(mesh->iarr = malloc(max_icount * sizeof *mesh->iarr))) {
140 fprintf(stderr, "indexify_mesh failed to allocate index buffer of %d indices\n", max_icount);
144 vin = vout = mesh->varr;
147 for(i=0; i<nfaces; i++) {
148 for(j=0; j<mesh->prim; j++) {
149 if((idx = find_existing(vin, mesh->varr, out_vcount)) >= 0) {
152 *iout++ = out_vcount++;
161 /* XXX also shrink buffers? I'll just leave them to max size for now */
165 void normalize_mesh_normals(struct g3d_mesh *mesh)
168 struct g3d_vertex *v = mesh->varr;
170 for(i=0; i<mesh->vcount; i++) {
171 float mag = sqrt(v->nx * v->nx + v->ny * v->ny + v->nz * v->nz);
172 float s = (mag == 0.0f) ? 1.0f : 1.0f / mag;
181 static void sphvec(float *res, float theta, float phi, float rad)
184 res[0] = sin(theta) * sin(phi);
186 res[2] = cos(theta) * sin(phi);
189 int gen_sphere_mesh(struct g3d_mesh *mesh, float rad, int usub, int vsub)
192 int nfaces, uverts, vverts;
193 struct g3d_vertex *vptr;
196 mesh->prim = GL_QUADS;
198 if(usub < 4) usub = 4;
199 if(vsub < 2) vsub = 2;
204 mesh->vcount = uverts * vverts;
205 nfaces = usub * vsub;
206 mesh->icount = nfaces * 4;
208 if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
209 fprintf(stderr, "gen_sphere_mesh: failed to allocate vertex buffer (%d vertices)\n", mesh->vcount);
212 if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
213 fprintf(stderr, "gen_sphere_mesh: failed to allocate index buffer (%d indices)\n", mesh->icount);
219 for(i=0; i<uverts; i++) {
220 float u = (float)i / (float)(uverts - 1);
221 float theta = u * 2.0 * M_PI;
223 for(j=0; j<vverts; j++) {
224 float v = (float)j / (float)(vverts - 1);
225 float phi = v * M_PI;
226 int chess = (i & 1) == (j & 1);
228 sphvec(&vptr->x, theta, phi, rad);
230 vptr->nx = vptr->x / rad;
231 vptr->ny = vptr->y / rad;
232 vptr->nz = vptr->z / rad;
235 vptr->r = chess ? 255 : 64;
237 vptr->b = chess ? 64 : 255;
240 if(i < usub && j < vsub) {
241 int idx = i * vverts + j;
244 *iptr++ = idx + vverts + 1;
245 *iptr++ = idx + vverts;
252 int gen_plane_mesh(struct g3d_mesh *m, float width, float height, int usub, int vsub)
255 int nfaces, nverts, nidx, uverts, vverts;
256 float x, y, u, v, du, dv;
257 struct g3d_vertex *vptr;
260 if(usub < 1) usub = 1;
261 if(vsub < 1) vsub = 1;
263 nfaces = usub * vsub;
266 du = (float)width / (float)usub;
267 dv = (float)height / (float)vsub;
269 nverts = uverts * vverts;
272 if(!(m->varr = malloc(nverts * sizeof *m->varr))) {
273 fprintf(stderr, "gen_plane_mesh: failed to allocate vertex buffer (%d vertices)\n", nverts);
276 if(!(m->iarr = malloc(nidx * sizeof *m->iarr))) {
277 fprintf(stderr, "gen_plane_mesh: failed to allocate index buffer (%d indices)\n", nidx);
291 for(i=0; i<vverts; i++) {
292 y = (v - 0.5) * height;
295 for(j=0; j<uverts; j++) {
296 x = (u - 0.5) * width;
306 vptr->r = vptr->g = vptr->b = vptr->a = 255;
314 for(i=0; i<vsub; i++) {
315 for(j=0; j<usub; j++) {
316 int idx = i * uverts + j;
319 *iptr++ = idx + uverts + 1;
320 *iptr++ = idx + uverts;
326 static void torusvec(float *res, float theta, float phi, float mr, float rr)
331 rx = -cos(phi) * rr + mr;
335 res[0] = rx * sin(theta) + rz * cos(theta);
337 res[2] = -rx * cos(theta) + rz * sin(theta);
340 int gen_torus_mesh(struct g3d_mesh *mesh, float rad, float ringrad, int usub, int vsub)
343 int nfaces, uverts, vverts;
344 struct g3d_vertex *vptr;
347 mesh->prim = GL_QUADS;
349 if(usub < 4) usub = 4;
350 if(vsub < 2) vsub = 2;
355 mesh->vcount = uverts * vverts;
356 nfaces = usub * vsub;
357 mesh->icount = nfaces * 4;
359 printf("generating torus with %d faces (%d vertices)\n", nfaces, mesh->vcount);
361 if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
364 if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
370 for(i=0; i<uverts; i++) {
371 float u = (float)i / (float)(uverts - 1);
372 float theta = u * 2.0 * M_PI;
375 torusvec(rcent, theta, 0, rad, 0);
377 for(j=0; j<vverts; j++) {
378 float v = (float)j / (float)(vverts - 1);
379 float phi = v * 2.0 * M_PI;
380 int chess = (i & 1) == (j & 1);
382 torusvec(&vptr->x, theta, phi, rad, ringrad);
384 vptr->nx = (vptr->x - rcent[0]) / ringrad;
385 vptr->ny = (vptr->y - rcent[1]) / ringrad;
386 vptr->nz = (vptr->z - rcent[2]) / ringrad;
389 vptr->r = chess ? 255 : 64;
391 vptr->b = chess ? 64 : 255;
394 if(i < usub && j < vsub) {
395 int idx = i * vverts + j;
398 *iptr++ = idx + vverts + 1;
399 *iptr++ = idx + vverts;