8 void init_g3dmtl(struct g3d_material *mtl)
11 mtl->r = mtl->g = mtl->b = mtl->a = 1.0f;
12 mtl->sr = mtl->sg = mtl->sb = 0.0f;
14 /*mtl->texmap = mtl->envmap = 0;*/
17 int init_mesh(struct g3d_mesh *mesh, int prim, int num_verts, int num_idx)
22 if(!(mesh->varr = malloc(num_verts * sizeof *mesh->varr))) {
29 if(!(mesh->iarr = malloc(num_idx * prim * sizeof *mesh->iarr))) {
36 mesh->vcount = num_verts;
37 mesh->icount = num_idx;
42 void free_mesh(struct g3d_mesh *mesh)
48 void destroy_mesh(struct g3d_mesh *mesh)
57 int copy_mesh(struct g3d_mesh *dest, struct g3d_mesh *src)
59 dest->prim = src->prim;
61 if(!(dest->varr = malloc(src->vcount * sizeof *src->varr))) {
64 memcpy(dest->varr, src->varr, src->vcount * sizeof *src->varr);
66 dest->vcount = src->vcount;
68 if(!(dest->iarr = malloc(src->icount * sizeof *src->iarr))) {
73 memcpy(dest->iarr, src->iarr, src->icount * sizeof *src->iarr);
75 dest->icount = src->icount;
81 struct g3d_vertex *varr;
85 static int zsort_cmp(const void *aptr, const void *bptr)
90 const float *m = zsort_cls.xform;
91 const struct g3d_vertex *va = (const struct g3d_vertex*)aptr;
92 const struct g3d_vertex *vb = (const struct g3d_vertex*)bptr;
94 for(i=0; i<zsort_cls.prim; i++) {
95 za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
96 zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
105 static int zsort_indexed_cmp(const void *aptr, const void *bptr)
110 const uint16_t *a = (const uint16_t*)aptr;
111 const uint16_t *b = (const uint16_t*)bptr;
113 const float *m = zsort_cls.xform;
115 for(i=0; i<zsort_cls.prim; i++) {
116 const struct g3d_vertex *va = zsort_cls.varr + a[i];
117 const struct g3d_vertex *vb = zsort_cls.varr + b[i];
119 za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
120 zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
128 void zsort_mesh(struct g3d_mesh *m)
130 zsort_cls.varr = m->varr;
131 zsort_cls.xform = g3d_get_matrix(G3D_MODELVIEW, 0);
132 zsort_cls.prim = m->prim;
135 int nfaces = m->icount / m->prim;
136 qsort(m->iarr, nfaces, m->prim * sizeof *m->iarr, zsort_indexed_cmp);
138 int nfaces = m->vcount / m->prim;
139 qsort(m->varr, nfaces, m->prim * sizeof *m->varr, zsort_cmp);
144 void draw_mesh(struct g3d_mesh *mesh)
146 struct g3d_material *mtl;
148 if((mtl = mesh->mtl)) {
149 g3d_mtl_diffuse(mtl->r);
150 g3d_mtl_specular(mtl->sr);
151 g3d_mtl_shininess(mtl->shin);
154 g3d_enable(G3D_TEXTURE_2D);
155 g3d_set_texture(mtl->texmap->width, mtl->texmap->height, mtl->texmap->pixels);
160 g3d_draw_indexed(mesh->prim, mesh->varr, mesh->vcount, mesh->iarr, mesh->icount);
162 g3d_draw(mesh->prim, mesh->varr, mesh->vcount);
167 g3d_disable(G3D_TEXTURE_2D);
172 void apply_mesh_xform(struct g3d_mesh *mesh, const float *xform)
175 struct g3d_vertex *v = mesh->varr;
177 for(i=0; i<mesh->vcount; i++) {
178 float x = xform[0] * v->x + xform[4] * v->y + xform[8] * v->z + xform[12];
179 float y = xform[1] * v->x + xform[5] * v->y + xform[9] * v->z + xform[13];
180 v->z = xform[2] * v->x + xform[6] * v->y + xform[10] * v->z + xform[14];
183 x = xform[0] * v->nx + xform[4] * v->ny + xform[8] * v->nz;
184 y = xform[1] * v->nx + xform[5] * v->ny + xform[9] * v->nz;
185 v->nz = xform[2] * v->nx + xform[6] * v->ny + xform[10] * v->nz;
192 int append_mesh(struct g3d_mesh *ma, struct g3d_mesh *mb)
194 int i, new_vcount, new_icount;
198 if(ma->prim != mb->prim) {
199 fprintf(stderr, "append_mesh failed, primitive mismatch\n");
203 if(ma->iarr || mb->iarr) {
205 if(indexify_mesh(ma) == -1) {
208 } else if(!mb->iarr) {
209 if(indexify_mesh(mb) == -1) {
214 new_icount = ma->icount + mb->icount;
215 if(!(iptr = realloc(ma->iarr, new_icount * sizeof *iptr))) {
216 fprintf(stderr, "append_mesh: failed to allocate combined index buffer (%d indices)\n", new_icount);
222 for(i=0; i<mb->icount; i++) {
223 *iptr++ = mb->iarr[i] + ma->vcount;
225 ma->icount = new_icount;
228 new_vcount = ma->vcount + mb->vcount;
229 if(!(tmp = realloc(ma->varr, new_vcount * sizeof *ma->varr))) {
230 fprintf(stderr, "append_mesh: failed to allocate combined vertex buffer (%d verts)\n", new_vcount);
234 memcpy(ma->varr + ma->vcount, mb->varr, mb->vcount * sizeof *ma->varr);
235 ma->vcount = new_vcount;
239 #define FEQ(a, b) ((a) - (b) < 1e-5 && (b) - (a) < 1e-5)
240 static int cmp_vertex(struct g3d_vertex *a, struct g3d_vertex *b)
242 if(!FEQ(a->x, b->x) || !FEQ(a->y, b->y) || !FEQ(a->z, b->z) || !FEQ(a->w, b->w))
244 if(!FEQ(a->nx, b->nx) || !FEQ(a->ny, b->ny) || !FEQ(a->nz, b->nz))
246 if(!FEQ(a->u, b->u) || !FEQ(a->v, b->v))
248 if(a->l != b->l || a->a != b->a)
253 static int find_existing(struct g3d_vertex *v, struct g3d_vertex *varr, int vcount)
256 for(i=0; i<vcount; i++) {
257 if(cmp_vertex(v, varr++) == 0) {
264 int indexify_mesh(struct g3d_mesh *mesh)
266 int i, j, nfaces, max_icount, idx;
268 struct g3d_vertex *vin, *vout;
272 fprintf(stderr, "indexify_mesh failed: already indexed\n");
276 nfaces = mesh->vcount / mesh->prim;
277 max_icount = mesh->vcount;
279 if(!(mesh->iarr = malloc(max_icount * sizeof *mesh->iarr))) {
280 fprintf(stderr, "indexify_mesh failed to allocate index buffer of %d indices\n", max_icount);
284 vin = vout = mesh->varr;
287 for(i=0; i<nfaces; i++) {
288 for(j=0; j<mesh->prim; j++) {
289 if((idx = find_existing(vin, mesh->varr, out_vcount)) >= 0) {
292 *iout++ = out_vcount++;
301 /* XXX also shrink buffers? I'll just leave them to max size for now */
305 void normalize_mesh_normals(struct g3d_mesh *mesh)
308 struct g3d_vertex *v = mesh->varr;
310 for(i=0; i<mesh->vcount; i++) {
311 float mag = sqrt(v->nx * v->nx + v->ny * v->ny + v->nz * v->nz);
312 float s = (mag == 0.0f) ? 1.0f : 1.0f / mag;
321 void calc_mesh_centroid(struct g3d_mesh *mesh, float *cent)
324 float s = 1.0f / (float)mesh->vcount;
325 cent[0] = cent[1] = cent[2] = 0.0f;
327 for(i=0; i<mesh->vcount; i++) {
328 cent[0] += mesh->varr[i].x;
329 cent[1] += mesh->varr[i].y;
330 cent[2] += mesh->varr[i].z;
337 static void sphvec(float *res, float theta, float phi, float rad)
340 res[0] = sin(theta) * sin(phi);
342 res[2] = cos(theta) * sin(phi);
345 int gen_sphere_mesh(struct g3d_mesh *mesh, float rad, int usub, int vsub)
348 int nfaces, uverts, vverts;
349 struct g3d_vertex *vptr;
352 init_mesh(mesh, G3D_QUADS, 0, 0);
354 if(usub < 4) usub = 4;
355 if(vsub < 2) vsub = 2;
360 mesh->vcount = uverts * vverts;
361 nfaces = usub * vsub;
362 mesh->icount = nfaces * 4;
364 if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
365 fprintf(stderr, "gen_sphere_mesh: failed to allocate vertex buffer (%d vertices)\n", mesh->vcount);
368 if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
369 fprintf(stderr, "gen_sphere_mesh: failed to allocate index buffer (%d indices)\n", mesh->icount);
375 for(i=0; i<uverts; i++) {
376 float u = (float)i / (float)(uverts - 1);
377 float theta = u * 2.0 * M_PI;
379 for(j=0; j<vverts; j++) {
380 float v = (float)j / (float)(vverts - 1);
381 float phi = v * M_PI;
382 int chess = (i & 1) == (j & 1);
384 sphvec(&vptr->x, theta, phi, rad);
387 vptr->nx = vptr->x / rad;
388 vptr->ny = vptr->y / rad;
389 vptr->nz = vptr->z / rad;
392 vptr->l = chess ? 255 : 64;
395 if(i < usub && j < vsub) {
396 int idx = i * vverts + j;
399 *iptr++ = idx + vverts + 1;
400 *iptr++ = idx + vverts;
407 int gen_plane_mesh(struct g3d_mesh *m, float width, float height, int usub, int vsub)
410 int nfaces, nverts, nidx, uverts, vverts;
411 float x, y, u, v, du, dv;
412 struct g3d_vertex *vptr;
415 init_mesh(m, G3D_QUADS, 0, 0);
417 if(usub < 1) usub = 1;
418 if(vsub < 1) vsub = 1;
420 nfaces = usub * vsub;
423 du = 1.0f / (float)usub;
424 dv = 1.0f / (float)vsub;
426 nverts = uverts * vverts;
429 if(!(m->varr = malloc(nverts * sizeof *m->varr))) {
430 fprintf(stderr, "gen_plane_mesh: failed to allocate vertex buffer (%d vertices)\n", nverts);
433 if(!(m->iarr = malloc(nidx * sizeof *m->iarr))) {
434 fprintf(stderr, "gen_plane_mesh: failed to allocate index buffer (%d indices)\n", nidx);
447 for(i=0; i<vverts; i++) {
448 y = (v - 0.5) * height;
451 for(j=0; j<uverts; j++) {
452 x = (u - 0.5) * width;
463 vptr->l = vptr->a = 255;
471 for(i=0; i<vsub; i++) {
472 for(j=0; j<usub; j++) {
473 int idx = i * uverts + j;
476 *iptr++ = idx + uverts + 1;
477 *iptr++ = idx + uverts;
483 int gen_cube_mesh(struct g3d_mesh *mesh, float sz, int sub)
488 struct g3d_mesh tmpmesh;
489 static float rotface[][4] = {
501 g3d_matrix_mode(G3D_MODELVIEW);
505 m = i > 0 ? &tmpmesh : mesh;
506 if(gen_plane_mesh(m, sz, sz, sub, sub) == -1)
509 g3d_rotate(rotface[i][0], rotface[i][1], rotface[i][2], rotface[i][3]);
510 g3d_translate(0, 0, offs / 2.0f);
511 apply_mesh_xform(m, g3d_get_matrix(G3D_MODELVIEW, 0));
513 if(append_mesh(mesh, m) == -1) {
523 static void torusvec(float *res, float theta, float phi, float mr, float rr)
528 rx = -cos(phi) * rr + mr;
532 res[0] = rx * sin(theta) + rz * cos(theta);
534 res[2] = -rx * cos(theta) + rz * sin(theta);
537 int gen_torus_mesh(struct g3d_mesh *mesh, float rad, float ringrad, int usub, int vsub)
540 int nfaces, uverts, vverts;
541 struct g3d_vertex *vptr;
544 init_mesh(mesh, G3D_QUADS, 0, 0);
546 if(usub < 4) usub = 4;
547 if(vsub < 2) vsub = 2;
552 mesh->vcount = uverts * vverts;
553 nfaces = usub * vsub;
554 mesh->icount = nfaces * 4;
556 printf("generating torus with %d faces (%d vertices)\n", nfaces, mesh->vcount);
558 if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
561 if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
567 for(i=0; i<uverts; i++) {
568 float u = (float)i / (float)(uverts - 1);
569 float theta = u * 2.0 * M_PI;
572 torusvec(rcent, theta, 0, rad, 0);
574 for(j=0; j<vverts; j++) {
575 float v = (float)j / (float)(vverts - 1);
576 float phi = v * 2.0 * M_PI;
577 int chess = (i & 1) == (j & 1);
579 torusvec(&vptr->x, theta, phi, rad, ringrad);
582 vptr->nx = (vptr->x - rcent[0]) / ringrad;
583 vptr->ny = (vptr->y - rcent[1]) / ringrad;
584 vptr->nz = (vptr->z - rcent[2]) / ringrad;
587 vptr->l = chess ? 255 : 64;
590 if(i < usub && j < vsub) {
591 int idx = i * vverts + j;
594 *iptr++ = idx + vverts + 1;
595 *iptr++ = idx + vverts;