added treestore and started a bit on the tilesets for the maze parts
[dosdemo] / src / mesh.c
index c4c8a87..88c6edc 100644 (file)
@@ -5,49 +5,59 @@
 #include "mesh.h"
 #include "3dgfx.h"
 
+void free_mesh(struct g3d_mesh *mesh)
+{
+       destroy_mesh(mesh);
+       free(mesh);
+}
+
+void destroy_mesh(struct g3d_mesh *mesh)
+{
+       free(mesh->varr);
+       free(mesh->iarr);
+}
+
 static struct {
+       int prim;
        struct g3d_vertex *varr;
        const float *xform;
 } zsort_cls;
 
 static int zsort_cmp(const void *aptr, const void *bptr)
 {
+       int i;
+       float za = 0.0f;
+       float zb = 0.0f;
        const float *m = zsort_cls.xform;
-
        const struct g3d_vertex *va = (const struct g3d_vertex*)aptr;
        const struct g3d_vertex *vb = (const struct g3d_vertex*)bptr;
 
-       float za = m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
-       float zb = m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
-
-       ++va;
-       ++vb;
-
-       za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
-       zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
-
+       for(i=0; i<zsort_cls.prim; i++) {
+               za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
+               zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
+               ++va;
+               ++vb;
+       }
        return za - zb;
 }
 
 static int zsort_indexed_cmp(const void *aptr, const void *bptr)
 {
-       const int16_t *a = (const int16_t*)aptr;
-       const int16_t *b = (const int16_t*)bptr;
+       int i;
+       float za = 0.0f;
+       float zb = 0.0f;
+       const uint16_t *a = (const uint16_t*)aptr;
+       const uint16_t *b = (const uint16_t*)bptr;
 
        const float *m = zsort_cls.xform;
 
-       const struct g3d_vertex *va = zsort_cls.varr + a[0];
-       const struct g3d_vertex *vb = zsort_cls.varr + b[0];
-
-       float za = m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
-       float zb = m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
-
-       va = zsort_cls.varr + a[2];
-       vb = zsort_cls.varr + b[2];
-
-       za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
-       zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
+       for(i=0; i<zsort_cls.prim; i++) {
+               const struct g3d_vertex *va = zsort_cls.varr + a[i];
+               const struct g3d_vertex *vb = zsort_cls.varr + b[i];
 
+               za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
+               zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
+       }
        return za - zb;
 }
 
@@ -56,6 +66,7 @@ void zsort_mesh(struct g3d_mesh *m)
 {
        zsort_cls.varr = m->varr;
        zsort_cls.xform = g3d_get_matrix(G3D_MODELVIEW, 0);
+       zsort_cls.prim = m->prim;
 
        if(m->iarr) {
                int nfaces = m->icount / m->prim;
@@ -100,7 +111,7 @@ int append_mesh(struct g3d_mesh *ma, struct g3d_mesh *mb)
 {
        int i, new_vcount, new_icount;
        void *tmp;
-       int16_t *iptr;
+       uint16_t *iptr;
 
        if(ma->prim != mb->prim) {
                fprintf(stderr, "append_mesh failed, primitive mismatch\n");
@@ -173,7 +184,7 @@ int indexify_mesh(struct g3d_mesh *mesh)
        int i, j, nfaces, max_icount, idx;
        int out_vcount = 0;
        struct g3d_vertex *vin, *vout;
-       int16_t *iout;
+       uint16_t *iout;
 
        if(mesh->iarr) {
                fprintf(stderr, "indexify_mesh failed: already indexed\n");
@@ -209,13 +220,101 @@ int indexify_mesh(struct g3d_mesh *mesh)
        return 0;
 }
 
+void normalize_mesh_normals(struct g3d_mesh *mesh)
+{
+       int i;
+       struct g3d_vertex *v = mesh->varr;
+
+       for(i=0; i<mesh->vcount; i++) {
+               float mag = sqrt(v->nx * v->nx + v->ny * v->ny + v->nz * v->nz);
+               float s = (mag == 0.0f) ? 1.0f : 1.0f / mag;
+               v->nx *= s;
+               v->ny *= s;
+               v->nz *= s;
+               ++v;
+       }
+}
+
+
+static void sphvec(float *res, float theta, float phi, float rad)
+{
+       theta = -theta;
+       res[0] = sin(theta) * sin(phi);
+       res[1] = cos(phi);
+       res[2] = cos(theta) * sin(phi);
+}
+
+int gen_sphere_mesh(struct g3d_mesh *mesh, float rad, int usub, int vsub)
+{
+       int i, j;
+       int nfaces, uverts, vverts;
+       struct g3d_vertex *vptr;
+       uint16_t *iptr;
+
+       mesh->prim = G3D_QUADS;
+
+       if(usub < 4) usub = 4;
+       if(vsub < 2) vsub = 2;
+
+       uverts = usub + 1;
+       vverts = vsub + 1;
+
+       mesh->vcount = uverts * vverts;
+       nfaces = usub * vsub;
+       mesh->icount = nfaces * 4;
+
+       if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
+               fprintf(stderr, "gen_sphere_mesh: failed to allocate vertex buffer (%d vertices)\n", mesh->vcount);
+               return -1;
+       }
+       if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
+               fprintf(stderr, "gen_sphere_mesh: failed to allocate index buffer (%d indices)\n", mesh->icount);
+               return -1;
+       }
+       vptr = mesh->varr;
+       iptr = mesh->iarr;
+
+       for(i=0; i<uverts; i++) {
+               float u = (float)i / (float)(uverts - 1);
+               float theta = u * 2.0 * M_PI;
+
+               for(j=0; j<vverts; j++) {
+                       float v = (float)j / (float)(vverts - 1);
+                       float phi = v * M_PI;
+                       int chess = (i & 1) == (j & 1);
+
+                       sphvec(&vptr->x, theta, phi, rad);
+                       vptr->w = 1.0f;
+
+                       vptr->nx = vptr->x / rad;
+                       vptr->ny = vptr->y / rad;
+                       vptr->nz = vptr->z / rad;
+                       vptr->u = u;
+                       vptr->v = v;
+                       vptr->r = chess ? 255 : 64;
+                       vptr->g = 128;
+                       vptr->b = chess ? 64 : 255;
+                       ++vptr;
+
+                       if(i < usub && j < vsub) {
+                               int idx = i * vverts + j;
+                               *iptr++ = idx;
+                               *iptr++ = idx + 1;
+                               *iptr++ = idx + vverts + 1;
+                               *iptr++ = idx + vverts;
+                       }
+               }
+       }
+       return 0;
+}
+
 int gen_plane_mesh(struct g3d_mesh *m, float width, float height, int usub, int vsub)
 {
        int i, j;
        int nfaces, nverts, nidx, uverts, vverts;
        float x, y, u, v, du, dv;
        struct g3d_vertex *vptr;
-       int16_t *iptr;
+       uint16_t *iptr;
 
        if(usub < 1) usub = 1;
        if(vsub < 1) vsub = 1;
@@ -289,7 +388,6 @@ int gen_cube_mesh(struct g3d_mesh *mesh, float sz, int sub)
        int i;
        struct g3d_mesh *m;
        struct g3d_mesh tmpmesh;
-       float xform[16];
        static float rotface[][4] = {
                {0, 0, 1, 0},
                {90, 0, 1, 0},
@@ -309,8 +407,7 @@ int gen_cube_mesh(struct g3d_mesh *mesh, float sz, int sub)
                g3d_load_identity();
                g3d_rotate(rotface[i][0], rotface[i][1], rotface[i][2], rotface[i][3]);
                g3d_translate(0, 0, sz / 2.0f);
-               g3d_get_matrix(G3D_MODELVIEW, xform);
-               apply_mesh_xform(m, xform);
+               apply_mesh_xform(m, g3d_get_matrix(G3D_MODELVIEW, 0));
                if(i > 0) {
                        if(append_mesh(mesh, m) == -1) {
                                return -1;
@@ -341,7 +438,7 @@ int gen_torus_mesh(struct g3d_mesh *mesh, float rad, float ringrad, int usub, in
        int i, j;
        int nfaces, uverts, vverts;
        struct g3d_vertex *vptr;
-       int16_t *iptr;
+       uint16_t *iptr;
 
        mesh->prim = G3D_QUADS;
 
@@ -379,6 +476,7 @@ int gen_torus_mesh(struct g3d_mesh *mesh, float rad, float ringrad, int usub, in
                        int chess = (i & 1) == (j & 1);
 
                        torusvec(&vptr->x, theta, phi, rad, ringrad);
+                       vptr->w = 1.0f;
 
                        vptr->nx = (vptr->x - rcent[0]) / ringrad;
                        vptr->ny = (vptr->y - rcent[1]) / ringrad;