Converted the SOL renderer to use VBOs.
authorrlk <rlk@78b8d119-cf0a-0410-b17c-f493084dd1d7>
Sat, 26 Mar 2011 19:03:53 +0000 (19:03 +0000)
committerrlk <rlk@78b8d119-cf0a-0410-b17c-f493084dd1d7>
Sat, 26 Mar 2011 19:03:53 +0000 (19:03 +0000)
Multitexture shadow is not yet implemented.

git-svn-id: https://s.snth.net/svn/neverball/branches/gles@3531 78b8d119-cf0a-0410-b17c-f493084dd1d7

Makefile
ball/game_draw.c
share/solid_draw.c
share/solid_draw.h

index ab192c9..9d4103f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -321,7 +321,6 @@ BALL_DEPS := $(BALL_OBJS:.o=.d)
 PUTT_DEPS := $(PUTT_OBJS:.o=.d)
 MAPC_DEPS := $(MAPC_OBJS:.o=.d)
 
-#MAPS := $(shell find data/map-medium -name "*.map" \! -name "*.autosave.map")
 MAPS := $(shell find data -name "*.map" \! -name "*.autosave.map")
 SOLS := $(MAPS:%.map=%.sol)
 
@@ -333,7 +332,8 @@ DESKTOPS := $(basename $(wildcard dist/*.desktop.in))
        $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) -MM -MP -MF $*.d -MT "$@" $<
        $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) -o $@ -c $<
 
-%.sol : %.map $(MAPC_TARG)
+#%.sol : %.map $(MAPC_TARG)
+%.sol : %.map
        $(MAPC) $< data
 
 %.desktop : %.desktop.in
index 7d039fc..10109a6 100644 (file)
@@ -483,7 +483,6 @@ void game_draw(const struct game_draw *gd, int pose, float t)
         {
             float T[16], U[16], M[16], v[3];
 
-
             /* Compute direct and reflected view bases. */
 
             v[0] = +view->p[0];
index fbe649b..ca3cb95 100644 (file)
 
 /*---------------------------------------------------------------------------*/
 
-static int sol_enum_mtrl(const struct s_base *base,
-                         const struct b_body *bp, int mi)
+static float sol_transform(const struct s_vary *vary,
+                           const struct v_body *bp, float *p, float *r)
 {
-    int li, gi, c = 0;
+    float a, e[4];
 
-    /* Count all lump geoms with this material. */
+    sol_body_p(p, vary, bp->pi, bp->t);
+    sol_body_e(e, vary, bp, 0);
 
-    for (li = 0; li < bp->lc; li++)
-    {
-        int g0 = base->lv[bp->l0 + li].g0;
-        int gc = base->lv[bp->l0 + li].gc;
+    q_as_axisangle(e, r, &a);
 
-        for (gi = 0; gi < gc; gi++)
-            if (base->gv[base->iv[g0 + gi]].mi == mi)
-                c++;
-    }
-
-    /* Count all body geoms with this material. */
+    return V_DEG(a);
+}
 
-    for (gi = 0; gi < bp->gc; gi++)
-        if (base->gv[base->iv[bp->g0 + gi]].mi == mi)
-            c++;
+/*---------------------------------------------------------------------------*/
 
-    return c;
+void sol_back(const struct s_draw *draw, float n, float f, float t)
+{
 }
 
-static int sol_enum_body(const struct s_base *base,
-                         const struct b_body *bp, int fl)
-{
-    int mi, c = 0;
+/*---------------------------------------------------------------------------*/
 
-    /* Count all geoms with this flag. */
+void sol_bill(const struct s_draw *draw, const float *M, float t)
+{
+}
 
-    for (mi = 0; mi < base->mc; mi++)
-        if (base->mv[mi].fl & fl)
-            c = c + sol_enum_mtrl(base, bp, mi);
+/*---------------------------------------------------------------------------*/
 
-    return c;
+void sol_shad(const struct s_draw *draw, int ui)
+{
 }
 
 /*---------------------------------------------------------------------------*/
@@ -95,14 +86,18 @@ static struct d_mtrl default_draw_mtrl =
     &default_base_mtrl, 0
 };
 
-static const struct d_mtrl *sol_draw_mtrl(const struct s_draw *draw,
-                                          const struct d_mtrl *mp_draw,
-                                          const struct d_mtrl *mq_draw)
+static const struct d_mtrl *sol_apply_mtrl(const struct d_mtrl *mp_draw,
+                                           const struct d_mtrl *mq_draw)
 {
     const struct b_mtrl *mp_base = mp_draw->base;
     const struct b_mtrl *mq_base = mq_draw->base;
 
-    /* Change material properties only as needed. */
+    /* Bind the texture. */
+
+    if (mp_draw->o != mq_draw->o)
+        glBindTexture(GL_TEXTURE_2D, mp_draw->o);
+
+    /* Set material properties. */
 
     if (!color_cmp(mp_base->a, mq_base->a))
         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,   mp_base->a);
@@ -115,11 +110,6 @@ static const struct d_mtrl *sol_draw_mtrl(const struct s_draw *draw,
     if (tobyte(mp_base->h[0]) != tobyte(mq_base->h[0]))
         glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mp_base->h);
 
-    /* Bind the texture. */
-
-    if (mp_draw->o != mq_draw->o)
-        glBindTexture(GL_TEXTURE_2D, mp_draw->o);
-
     /* Enable environment mapping. */
 
     if ((mp_base->fl & M_ENVIRONMENT) && !(mq_base->fl & M_ENVIRONMENT))
@@ -181,599 +171,324 @@ static const struct d_mtrl *sol_draw_mtrl(const struct s_draw *draw,
     return mp_draw;
 }
 
-static const struct d_mtrl *sol_back_bill(const struct s_draw *draw,
-                                           const struct b_bill *rp,
-                                           const struct d_mtrl *mp,
-                                           float t)
+static GLuint sol_find_texture(const char *name)
 {
-    float T = (rp->t > 0.0f) ? (fmodf(t, rp->t) - rp->t / 2) : 0.0f;
-
-    float w = rp->w[0] + rp->w[1] * T + rp->w[2] * T * T;
-    float h = rp->h[0] + rp->h[1] * T + rp->h[2] * T * T;
+    char png[MAXSTR];
+    char jpg[MAXSTR];
 
-    if (w > 0 && h > 0)
-    {
-        float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * T * T;
-        float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * T * T;
-        float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * T * T;
+    GLuint o;
 
-        glPushMatrix();
-        {
-            float y0 = (rp->fl & B_EDGE) ? 0 : -h / 2;
-            float y1 = (rp->fl & B_EDGE) ? h : +h / 2;
+    /* Prefer a lossless copy of the texture over a lossy compression. */
 
-            glRotatef(ry, 0.0f, 1.0f, 0.0f);
-            glRotatef(rx, 1.0f, 0.0f, 0.0f);
-            glTranslatef(0.0f, 0.0f, -rp->d);
+    strncpy(png, name, PATHMAX); strcat(png, ".png");
+    strncpy(jpg, name, PATHMAX); strcat(jpg, ".jpg");
 
-            if (rp->fl & B_FLAT)
-            {
-                glRotatef(-rx - 90.0f, 1.0f, 0.0f, 0.0f);
-                glRotatef(-ry,         0.0f, 0.0f, 1.0f);
-            }
-            if (rp->fl & B_EDGE)
-                glRotatef(-rx,         1.0f, 0.0f, 0.0f);
+    /* Check for a PNG. */
 
-            glRotatef(rz, 0.0f, 0.0f, 1.0f);
+    if ((o = make_image_from_file(png)))
+        return o;
 
-            mp = sol_draw_mtrl(draw, draw->mv + rp->mi, mp);
+    /* Check for a JPG. */
 
-            glBegin(GL_QUADS);
-            {
-                glTexCoord2f(0.0f, 0.0f); glVertex2f(-w / 2, y0);
-                glTexCoord2f(1.0f, 0.0f); glVertex2f(+w / 2, y0);
-                glTexCoord2f(1.0f, 1.0f); glVertex2f(+w / 2, y1);
-                glTexCoord2f(0.0f, 1.0f); glVertex2f(-w / 2, y1);
-            }
-            glEnd();
-        }
-        glPopMatrix();
-    }
+    if ((o = make_image_from_file(jpg)))
+        return o;
 
-    return mp;
+    return 0;
 }
 
-/*---------------------------------------------------------------------------*/
-
-void sol_back(const struct s_draw *draw, float n, float f, float t)
+static void sol_load_mtrl(struct d_mtrl *mp,
+                    const struct b_mtrl *mq,
+                          struct s_draw *draw)
 {
-    const struct d_mtrl *mp = &default_draw_mtrl;
-
-    int ri;
-
-    /* Render all billboards in the given range. */
+    mp->base = mq;
 
-    if (draw && draw->base)
+    if ((mp->o = sol_find_texture(_(mq->f))))
     {
-        glDisable(GL_LIGHTING);
-        glDepthMask(GL_FALSE);
-        {
-            for (ri = 0; ri < draw->base->rc; ri++)
-                if (n <= draw->base->rv[ri].d && draw->base->rv[ri].d < f)
-                    mp = sol_back_bill(draw, draw->base->rv + ri, mp, t);
+        /* Set the texture to clamp or repeat based on material type. */
 
-            mp = sol_draw_mtrl(draw, &default_draw_mtrl, mp);
+        if (mq->fl & M_CLAMPED)
+        {
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+        }
+        else
+        {
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
         }
-        glDepthMask(GL_TRUE);
-        glEnable(GL_LIGHTING);
+
+        if (mq->fl & M_REFLECTIVE)
+            draw->reflective = 1;
     }
 }
 
-/*---------------------------------------------------------------------------*/
-/*
- * The  following code  renders a  body in  a  ludicrously inefficient
- * manner.  It iterates the materials and scans the data structure for
- * geometry using each.  This  has the effect of absolutely minimizing
- * material  changes,  texture  bindings,  and  Begin/End  pairs,  but
- * maximizing trips through the data.
- *
- * However, this  is only done once  for each level.   The results are
- * stored in display lists.  Thus, it is well worth it.
- */
-
-static void sol_draw_geom(const struct s_base *base,
-                          const struct b_geom *gp, int mi)
+static void sol_free_mtrl(struct d_mtrl *mp)
 {
-    if (gp->mi == mi)
-    {
-        const struct b_offs *op = base->ov + gp->oi;
-        const struct b_offs *oq = base->ov + gp->oj;
-        const struct b_offs *or = base->ov + gp->ok;
-
-        const float *u0 = base->tv[op->ti].u;
-        const float *u1 = base->tv[oq->ti].u;
-        const float *u2 = base->tv[or->ti].u;
-
-        const float *n0 = base->sv[op->si].n;
-        const float *n1 = base->sv[oq->si].n;
-        const float *n2 = base->sv[or->si].n;
-
-        const float *p0 = base->vv[op->vi].p;
-        const float *p1 = base->vv[oq->vi].p;
-        const float *p2 = base->vv[or->vi].p;
-
-        glTexCoord2fv(u0);
-        glNormal3fv(n0);
-        glVertex3fv(p0);
-
-        glTexCoord2fv(u1);
-        glNormal3fv(n1);
-        glVertex3fv(p1);
-
-        glTexCoord2fv(u2);
-        glNormal3fv(n2);
-        glVertex3fv(p2);
-    }
+    if (glIsTexture(mp->o))
+        glDeleteTextures(1, &mp->o);
 }
 
-static void sol_draw_lump(const struct s_base *base,
-                          const struct b_lump *lp, int mi)
+static int sol_test_mtrl(const struct d_mtrl *mp, int f0, int f1)
 {
-    int i;
+    /* Test whether the material flags exclude f0 and include f1. */
 
-    for (i = 0; i < lp->gc; i++)
-        sol_draw_geom(base, base->gv + base->iv[lp->g0 + i], mi);
+    return ((mp->base->fl & f1) == f1 &&
+            (mp->base->fl & f0) ==  0);
 }
 
-static const struct d_mtrl *sol_draw_body(const struct s_draw *draw,
-                                          const struct b_body *bp,
-                                          const struct d_mtrl *mp,
-                                          int fl, int decal)
-{
-    const struct s_base *base = draw->base;
-
-    int mi, li, gi;
+/*---------------------------------------------------------------------------*/
 
-    /* Iterate all materials of the correct opacity. */
+static int sol_count_geom(const struct s_base *base, int g0, int gc, int mi)
+{
+    int gi, c = 0;
 
-    for (mi = 0; mi < draw->mc; mi++)
-    {
-        struct d_mtrl *mq = draw->mv + mi;
+    /* The arguments g0 and gc specify a range of the index array. These     */
+    /* indices refer to geoms. Determine how many of these geoms use the     */
+    /* given material                                                        */
 
-        if ((mq->base->fl & fl) && (mq->base->fl & M_DECAL) == decal)
-        {
-            if (sol_enum_mtrl(draw->base, bp, mi))
-            {
-                /* Set the material state. */
-
-                mp = sol_draw_mtrl(draw, mq, mp);
-
-                /* Render all geometry of that material. */
-
-                glBegin(GL_TRIANGLES);
-                {
-                    for (li = 0; li < bp->lc; li++)
-                        sol_draw_lump(draw->base,
-                                      base->lv + bp->l0 + li,
-                                      mi);
-                    for (gi = 0; gi < bp->gc; gi++)
-                        sol_draw_geom(draw->base,
-                                      base->gv + base->iv[bp->g0 + gi],
-                                      mi);
-                }
-                glEnd();
-            }
-        }
-    }
+    for (gi = 0; gi < gc; gi++)
+        if (base->gv[base->iv[g0 + gi]].mi == mi)
+            c++;
 
-    return mp;
+    return c;
 }
 
-static void sol_draw_list(const struct s_vary *vary,
-                          const struct v_body *bp, GLuint list)
+static int sol_count_body(const struct b_body *bp,
+                          const struct s_base *base, int mi)
 {
-    float p[3], e[4], u[3], a;
-
-    sol_body_p(p, vary, bp->pi, bp->t);
-    sol_body_e(e, vary, bp, 0);
+    int li, c = 0;
 
-    q_as_axisangle(e, u, &a);
-    a = V_DEG(a);
+    /* Count all lump geoms with the given material. */
 
-    glPushMatrix();
-    {
-        /* Translate and rotate a moving body. */
+    for (li = 0; li < bp->lc; li++)
+        c += sol_count_geom(base, base->lv[bp->l0 + li].g0,
+                                  base->lv[bp->l0 + li].gc, mi);
 
-        glTranslatef(p[0], p[1], p[2]);
-        glRotatef(a, u[0], u[1], u[2]);
+    /* Count all body geoms with the given material. */
 
-        /* Draw the body. */
+    c += sol_count_geom(base, bp->g0, bp->gc, mi);
 
-        glCallList(list);
-    }
-    glPopMatrix();
+    return c;
 }
 
-void sol_draw(const struct s_draw *draw, int depthmask, int depthtest)
+/*---------------------------------------------------------------------------*/
+
+static void sol_mesh_vert(struct d_vert *vp,
+                    const struct s_base *base, int oi)
 {
-    int bi;
+    /* Gather all vertex attributes for the given offs. */
 
-    /* Render all opaque geometry into the color and depth buffers. */
+    const struct b_texc *tq = base->tv + base->ov[oi].ti;
+    const struct b_side *sq = base->sv + base->ov[oi].si;
+    const struct b_vert *vq = base->vv + base->ov[oi].vi;
 
-    for (bi = 0; bi < draw->bc; bi++)
-        if (draw->bv[bi].ol)
-            sol_draw_list(draw->vary, draw->vary->bv + bi, draw->bv[bi].ol);
+    vp->p[0] = vq->p[0];
+    vp->p[1] = vq->p[1];
+    vp->p[2] = vq->p[2];
 
-    /* Render all translucent geometry into only the color buffer. */
+    vp->n[0] = sq->n[0];
+    vp->n[1] = sq->n[1];
+    vp->n[2] = sq->n[2];
 
-    if (depthtest == 0) glDisable(GL_DEPTH_TEST);
-    if (depthmask == 0) glDepthMask(GL_FALSE);
-    {
-        for (bi = 0; bi < draw->bc; bi++)
-            if (draw->bv[bi].tl)
-                sol_draw_list(draw->vary, draw->vary->bv + bi, draw->bv[bi].tl);
-    }
-    if (depthmask == 0) glDepthMask(GL_TRUE);
-    if (depthtest == 0) glEnable(GL_DEPTH_TEST);
+    vp->t[0] = tq->u[0];
+    vp->t[1] = tq->u[1];
 }
 
-void sol_bill(const struct s_draw *draw, const float *M, float t)
+static void sol_mesh_geom(struct d_vert *vv,   int *vn,
+                          struct d_geom *gv,   int *gn,
+                    const struct s_base *base, int *iv, int g0, int gc, int mi)
 {
-    const struct d_mtrl *mp = &default_draw_mtrl;
+    int gi;
 
-    int ri;
+    /* Insert all geoms with material mi into the vertex and element data. */
 
-    for (ri = 0; ri < draw->base->rc; ++ri)
+    for (gi = 0; gi < gc; gi++)
     {
-        const struct b_bill *rp = draw->base->rv + ri;
-
-        float T = rp->t * t;
-        float S = fsinf(T);
-
-        float w  = rp->w [0] + rp->w [1] * T + rp->w [2] * S;
-        float h  = rp->h [0] + rp->h [1] * T + rp->h [2] * S;
-        float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * S;
-        float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * S;
-        float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * S;
-
-        mp = sol_draw_mtrl(draw, draw->mv + rp->mi, mp);
+        const struct b_geom *gq = base->gv + base->iv[g0 + gi];
 
-        glPushMatrix();
+        if (gq->mi == mi)
         {
-            glTranslatef(rp->p[0], rp->p[1], rp->p[2]);
-
-            if (M && ((rp->fl & B_NOFACE) == 0)) glMultMatrixf(M);
+            /* Insert a d_vert into the VBO data for each referenced b_off. */
 
-            if (fabsf(rx) > 0.0f) glRotatef(rx, 1.0f, 0.0f, 0.0f);
-            if (fabsf(ry) > 0.0f) glRotatef(ry, 0.0f, 1.0f, 0.0f);
-            if (fabsf(rz) > 0.0f) glRotatef(rz, 0.0f, 0.0f, 1.0f);
-
-            glBegin(GL_QUADS);
+            if (iv[gq->oi] == -1)
             {
-                glTexCoord2f(0.0f, 0.0f); glVertex2f(-w / 2, -h / 2);
-                glTexCoord2f(1.0f, 0.0f); glVertex2f(+w / 2, -h / 2);
-                glTexCoord2f(1.0f, 1.0f); glVertex2f(+w / 2, +h / 2);
-                glTexCoord2f(0.0f, 1.0f); glVertex2f(-w / 2, +h / 2);
+                iv[gq->oi] = *vn;
+                sol_mesh_vert(vv + (*vn)++, base, gq->oi);
+            }
+            if (iv[gq->oj] == -1)
+            {
+                iv[gq->oj] = *vn;
+                sol_mesh_vert(vv + (*vn)++, base, gq->oj);
+            }
+            if (iv[gq->ok] == -1)
+            {
+                iv[gq->ok] = *vn;
+                sol_mesh_vert(vv + (*vn)++, base, gq->ok);
             }
-            glEnd();
-        }
-        glPopMatrix();
-    }
-
-    mp = sol_draw_mtrl(draw, &default_draw_mtrl, mp);
-}
-
-void sol_refl(const struct s_draw *draw)
-{
-    int bi;
-
-    /* Render all reflective geometry into the color and depth buffers. */
-
-    for (bi = 0; bi < draw->bc; bi++)
-        if (draw->bv[bi].rl)
-            sol_draw_list(draw->vary, draw->vary->bv + bi, draw->bv[bi].rl);
-}
-
-/*---------------------------------------------------------------------------*/
-
-static void sol_shad_geom(const struct s_base *base,
-                          const struct b_geom *gp, int mi)
-{
-    if (gp->mi == mi)
-    {
-        const float *v0 = base->vv[base->ov[gp->oi].vi].p;
-        const float *v1 = base->vv[base->ov[gp->oj].vi].p;
-        const float *v2 = base->vv[base->ov[gp->ok].vi].p;
-
-        glVertex3fv(v0);
-        glVertex3fv(v1);
-        glVertex3fv(v2);
-    }
-}
-
-static void sol_shad_lump(const struct s_base *base,
-                          const struct b_lump *lp, int mi)
-{
-    int i;
-
-    for (i = 0; i < lp->gc; i++)
-        sol_shad_geom(base, base->gv + base->iv[lp->g0 + i], mi);
-}
-
-static void sol_shad_body(const struct s_base *base,
-                          const struct b_body *bp,
-                          int fl, int decal)
-{
-    int mi, li, gi;
 
-    if (decal)
-    {
-        glEnable(GL_POLYGON_OFFSET_FILL);
-        glPolygonOffset(-1.0f, -2.0f);
-    }
+            /* Populate the EBO data using remapped b_off indices. */
 
-    glBegin(GL_TRIANGLES);
-    {
-        for (mi = 0; mi < base->mc; mi++)
-        {
-            struct b_mtrl *mp = base->mv + mi;
+            gv[*gn].i = iv[gq->oi];
+            gv[*gn].j = iv[gq->oj];
+            gv[*gn].k = iv[gq->ok];
 
-            if ((mp->fl & fl) && (mp->fl & M_DECAL) == decal)
-            {
-                for (li = 0; li < bp->lc; li++)
-                    sol_shad_lump(base, base->lv + bp->l0 + li, mi);
-                for (gi = 0; gi < bp->gc; gi++)
-                    sol_shad_geom(base, base->gv + base->iv[bp->g0 + gi], mi);
-            }
+            (*gn)++;
         }
     }
-    glEnd();
-
-    if (decal)
-        glDisable(GL_POLYGON_OFFSET_FILL);
 }
 
-static void sol_shad_list(const struct s_vary *vary,
-                          const struct v_ball *up,
-                          const struct v_body *bp, GLuint list)
+static void sol_load_mesh(struct d_mesh *mp,
+                    const struct b_body *bp,
+                    const struct s_draw *draw, int mi)
 {
-    float p[3], e[4], u[3], a;
-    float d[3];
+    const size_t vs = sizeof (struct d_vert);
+    const size_t gs = sizeof (struct d_geom);
 
-    float X[] = { 1.0f, 0.0f, 0.0f, 0.0f };
-    float Y[] = { 0.0f, 1.0f, 0.0f, 0.0f };
-    float Z[] = { 0.0f, 0.0f, 1.0f, 0.0f };
+    struct d_vert *vv = 0;
+    struct d_geom *gv = 0;
+    int           *iv = 0;
 
-    sol_body_p(p, vary, bp->pi, bp->t);
-    sol_body_e(e, vary, bp, 0);
+    int oc = draw->base->oc;
+    int vn = 0;
+    int gn = 0;
 
-    v_sub(d, up->p, p);
+    const int gc = sol_count_body(bp, draw->base, mi);
 
-    Y[3] = 0.5f - v_dot(Y, d);
+    /* Get temporary storage for vertex and element array creation. */
 
-    if (e[0] != 1.0f)
+    if ((vv = (struct d_vert *) calloc(oc, vs)) &&
+        (gv = (struct d_geom *) calloc(gc, gs)) &&
+        (iv = (int           *) calloc(oc, sizeof (int))))
     {
-        q_as_axisangle(e, u, &a);
-        a = V_DEG(a);
+        int li, i;
 
-        q_conj(e, e);
+        /* Initialize the index remapping. */
 
-        q_rot(X, e, X);
-        q_rot(Y, e, Y);
-        q_rot(Z, e, Z);
-    }
-    else
-    {
-        u[0] = 0.0f;
-        u[1] = 0.0f;
-        u[2] = 0.0f;
+        for (i = 0; i < oc; ++i) iv[i] = -1;
 
-        a = 0.0f;
-    }
+        /* Include all matching lump geoms in the arrays. */
 
-    glTexGenfv(GL_S, GL_OBJECT_PLANE, X);
-    glTexGenfv(GL_T, GL_OBJECT_PLANE, Z);
+        for (li = 0; li < bp->lc; li++)
+            sol_mesh_geom(vv, &vn, gv, &gn, draw->base, iv,
+                          draw->base->lv[bp->l0 + li].g0,
+                          draw->base->lv[bp->l0 + li].gc, mi);
 
-    /* Translate the shadow on a moving body. */
+        /* Include all matching body geoms in the arrays. */
 
-    glMatrixMode(GL_TEXTURE);
-    {
-        float k = 0.25f / up->r;
+        sol_mesh_geom(vv, &vn, gv, &gn, draw->base, iv, bp->g0, bp->gc, mi);
 
-        glPushMatrix();
-        glTranslatef(0.5f - k * d[0],
-                     0.5f - k * d[2], 0.0f);
-        glScalef(k, k, 0.0f);
-    }
-    glMatrixMode(GL_MODELVIEW);
+        /* Initialize buffer objects for all data. */
 
-    /* Set up shadow clipping. */
+        glGenBuffers(1, &mp->vbo);
+        glBindBuffer(GL_ARRAY_BUFFER,         mp->vbo);
+        glBufferData(GL_ARRAY_BUFFER,         vn * vs, vv, GL_STATIC_DRAW);
+        glBindBuffer(GL_ARRAY_BUFFER,         0);
 
-    if (glActiveTextureARB_)
-    {
-        glActiveTextureARB_(GL_TEXTURE1_ARB);
-        glTexGenfv(GL_S, GL_OBJECT_PLANE, Y);
-        glActiveTextureARB_(GL_TEXTURE0_ARB);
-    }
+        glGenBuffers(1, &mp->ebo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mp->ebo);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, gn * gs, gv, GL_STATIC_DRAW);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 
-    /* Draw the body. */
-
-    glPushMatrix();
-    {
-        glTranslatef(p[0], p[1], p[2]);
-        glRotatef(a, u[0], u[1], u[2]);
-
-        glCallList(list);
+        mp->mp  = draw->mv + mi;
+        mp->ebc = gn * 3;
     }
-    glPopMatrix();
-
-    /* Pop the shadow translation. */
 
-    glMatrixMode(GL_TEXTURE);
-    {
-        glPopMatrix();
-    }
-    glMatrixMode(GL_MODELVIEW);
+    free(iv);
+    free(gv);
+    free(vv);
 }
 
-void sol_shad(const struct s_draw *draw, int ui)
+static void sol_free_mesh(struct d_mesh *mp)
 {
-    int bi;
-
-    /* Render all shadowed geometry. */
-
-    glDepthMask(GL_FALSE);
-    {
-        for (bi = 0; bi < draw->bc; bi++)
-            if (draw->bv[bi].sl)
-                sol_shad_list(draw->vary,
-                              draw->vary->uv + ui,
-                              draw->vary->bv + bi, draw->bv[bi].sl);
-    }
-    glDepthMask(GL_TRUE);
+    if (glIsBuffer(mp->ebo))
+        glDeleteBuffers(1, &mp->ebo);
+    if (glIsBuffer(mp->vbo))
+        glDeleteBuffers(1, &mp->vbo);
 }
 
-/*---------------------------------------------------------------------------*/
-
-static void sol_load_objects(struct s_draw *draw, int s)
+static const struct d_mtrl *sol_draw_mesh(const struct d_mesh *mp,
+                                          const struct d_mtrl *mq,
+                                          int f0, int f1)
 {
-    int i;
-
-    /* Here we sort geometry into display lists by material type. */
+    /* If this mesh has material matching the given flags... */
 
-    for (i = 0; i < draw->bc; i++)
+    if (sol_test_mtrl(mp->mp, f0, f1))
     {
-        struct d_body *bp = draw->bv + i;
+        const size_t vs =   sizeof (struct d_vert);
+        const size_t po = offsetof (struct d_vert, p);
+        const size_t no = offsetof (struct d_vert, n);
+        const size_t to = offsetof (struct d_vert, t);
 
-        int on = sol_enum_body(draw->base, bp->base, M_OPAQUE);
-        int tn = sol_enum_body(draw->base, bp->base, M_TRANSPARENT);
-        int rn = sol_enum_body(draw->base, bp->base, M_REFLECTIVE);
-        int dn = sol_enum_body(draw->base, bp->base, M_DECAL);
-        int sn = sol_enum_body(draw->base, bp->base, M_SHADOWED);
+        /* Apply the material state. */
 
-        /* Draw all opaque geometry, decals last. */
+        mq = sol_apply_mtrl(mp->mp, mq);
 
-        if (on)
-        {
-            bp->ol = glGenLists(1);
+        /* Bind the mesh data. */
 
-            glNewList(bp->ol, GL_COMPILE);
-            {
-                const struct d_mtrl *mp = &default_draw_mtrl;
-
-                mp = sol_draw_body(draw, bp->base, mp, M_OPAQUE, 0);
-                mp = sol_draw_body(draw, bp->base, mp, M_OPAQUE, M_DECAL);
-                mp = sol_draw_mtrl(draw, &default_draw_mtrl, mp);
-            }
-            glEndList();
-        }
-        else bp->ol = 0;
+        glBindBuffer(GL_ARRAY_BUFFER,         mp->vbo);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mp->ebo);
 
-        /* Draw all translucent geometry, decals first. */
+        glVertexPointer  (3, GL_FLOAT, vs, (GLvoid *) po);
+        glNormalPointer  (   GL_FLOAT, vs, (GLvoid *) no);
+        glTexCoordPointer(2, GL_FLOAT, vs, (GLvoid *) to);
 
-        if (tn)
-        {
-            bp->tl = glGenLists(1);
+        /* Draw the mesh. */
 
-            glNewList(bp->tl, GL_COMPILE);
-            {
-                const struct d_mtrl *mp = &default_draw_mtrl;
+        glDrawElements(GL_TRIANGLES, mp->ebc, GL_UNSIGNED_SHORT, 0);
+    }
 
-                mp = sol_draw_body(draw, bp->base, mp, M_TRANSPARENT, M_DECAL);
-                mp = sol_draw_body(draw, bp->base, mp, M_TRANSPARENT, 0);
-                mp = sol_draw_mtrl(draw, &default_draw_mtrl, mp);
-            }
-            glEndList();
-        }
-        else bp->tl = 0;
+    return mq;
+}
 
-        /* Draw all reflective geometry. */
+/*---------------------------------------------------------------------------*/
 
-        if (rn)
-        {
-            bp->rl = glGenLists(1);
+static void sol_load_body(struct d_body *bp,
+                    const struct b_body *bq,
+                    const struct s_draw *draw)
+{
+    int mi;
 
-            glNewList(bp->rl, GL_COMPILE);
-            {
-                const struct d_mtrl *mp = &default_draw_mtrl;
+    bp->base = bq;
+    bp->mc   =  0;
 
-                mp = sol_draw_body(draw, bp->base, mp, M_REFLECTIVE, 0);
-                mp = sol_draw_mtrl(draw, &default_draw_mtrl, mp);
-            }
-            glEndList();
+    /* Determine how many materials this body uses. */
 
-            draw->reflective = 1;
-        }
-        else bp->rl = 0;
+    for (mi = 0; mi < draw->mc; ++mi)
+        if (sol_count_body(bq, draw->base, mi))
+            bp->mc++;
 
-        /* Draw all shadowed geometry. */
+    /* Allocate and initialize a mesh for each material. */
 
-        if (s && (on || rn || sn))
-        {
-            bp->sl = glGenLists(1);
+    if ((bp->mv = (struct d_mesh *) calloc(bp->mc, sizeof (struct d_mesh))))
+    {
+        int mj = 0;
 
-            glNewList(bp->sl, GL_COMPILE);
-            {
-                if (on) sol_shad_body(draw->base, bp->base, M_OPAQUE, 0);
-                if (rn) sol_shad_body(draw->base, bp->base, M_REFLECTIVE, 0);
-                if (dn) sol_shad_body(draw->base, bp->base, M_OPAQUE, M_DECAL);
-                if (sn)
-                {
-                    /* Transparent shadowed geometry hack. */
-
-                    if (dn)
-                        sol_shad_body(draw->base, bp->base, M_SHADOWED, M_DECAL);
-
-                    sol_shad_body(draw->base, bp->base, M_SHADOWED, 0);
-                }
-            }
-            glEndList();
-        }
-        else bp->sl = 0;
+        for (mi = 0; mi < draw->mc; ++mi)
+            if (sol_count_body(bq, draw->base, mi))
+                sol_load_mesh(bp->mv + mj++, bq, draw, mi);
     }
 }
 
-static GLuint sol_find_texture(const char *name)
+static void sol_free_body(struct d_body *bp)
 {
-    char png[MAXSTR];
-    char jpg[MAXSTR];
+    int mi;
 
-    GLuint o;
-
-    /* Prefer a lossless copy of the texture over a lossy compression. */
-
-    strncpy(png, name, PATHMAX); strcat(png, ".png");
-    strncpy(jpg, name, PATHMAX); strcat(jpg, ".jpg");
-
-    /* Check for a PNG. */
-
-    if ((o = make_image_from_file(png)))
-        return o;
+    for (mi = 0; mi < bp->mc; ++mi)
+        sol_free_mesh(bp->mv + mi);
 
-    /* Check for a JPG. */
-
-    if ((o = make_image_from_file(jpg)))
-        return o;
-
-    return 0;
+    free(bp->mv);
 }
 
-static void sol_load_textures(struct s_draw *draw)
+static const struct d_mtrl *sol_draw_body(const struct d_body *bp,
+                                          const struct d_mtrl *mq,
+                                          int f0, int f1)
 {
     int i;
 
-    /* Load the image referenced by each material. */
+    for (i = 0; i < bp->mc; ++i)
+        mq = sol_draw_mesh(bp->mv + i, mq, f0, f1);
 
-    for (i = 0; i < draw->mc; i++)
-    {
-        struct d_mtrl *mp = draw->mv + i;
-
-        if ((mp->o = sol_find_texture(_(mp->base->f))))
-        {
-            /* Set the texture to clamp or repeat based on material type. */
-
-            if (mp->base->fl & M_CLAMPED)
-            {
-                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
-                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-            }
-            else
-            {
-                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-            }
-        }
-    }
+    return mq;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -782,42 +497,37 @@ int sol_load_draw(struct s_draw *draw, const struct s_vary *vary, int s)
 {
     int i;
 
-    memset(draw, 0, sizeof (*draw));
+    memset(draw, 0, sizeof (struct s_draw));
 
     draw->vary = vary;
-    draw->base = draw->vary->base;
+    draw->base = vary->base;
+
+    /* Initialize all materials for this file. */
 
     if (draw->base->mc)
     {
-        draw->mv = calloc(draw->base->mc, sizeof (*draw->mv));
-        draw->mc = draw->base->mc;
-
-        for (i = 0; i < draw->base->mc; i++)
+        if ((draw->mv = calloc(draw->base->mc, sizeof (*draw->mv))))
         {
-            struct d_mtrl *mp = draw->mv + i;
-            struct b_mtrl *mq = draw->base->mv + i;
+            draw->mc = draw->base->mc;
 
-            mp->base = mq;
+            for (i = 0; i < draw->mc; i++)
+                sol_load_mtrl(draw->mv + i, draw->base->mv + i, draw);
         }
     }
 
+    /* Initialize all bodies for this file. */
+
     if (draw->base->bc)
     {
-        draw->bv = calloc(draw->base->bc, sizeof (*draw->bv));
-        draw->bc = draw->base->bc;
-
-        for (i = 0; i < draw->base->bc; i++)
+        if ((draw->bv = calloc(draw->base->bc, sizeof (*draw->bv))))
         {
-            struct d_body *bp = draw->bv + i;
-            struct b_body *bq = draw->base->bv + i;
+            draw->bc = draw->base->bc;
 
-            bp->base = bq;
+            for (i = 0; i < draw->bc; i++)
+                sol_load_body(draw->bv + i, draw->base->bv + i, draw);
         }
     }
 
-    sol_load_textures(draw);
-    sol_load_objects (draw, s);
-
     return 1;
 }
 
@@ -825,28 +535,97 @@ void sol_free_draw(struct s_draw *draw)
 {
     int i;
 
+    for (i = 0; i < draw->bc; i++)
+        sol_free_body(draw->bv + i);
     for (i = 0; i < draw->mc; i++)
+        sol_free_mtrl(draw->mv + i);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static const struct d_mtrl *sol_draw_all(const struct s_draw *draw,
+                                         const struct d_mtrl *mq,
+                                         int f0, int f1)
+{
+    float p[3];
+    float v[3];
+    float a;
+
+    int bi;
+
+    /* Draw all meshes of all bodies matching the given material flags. */
+
+    for (bi = 0; bi < draw->bc; ++bi)
     {
-        if (glIsTexture(draw->mv[i].o))
-            glDeleteTextures(1, &draw->mv[i].o);
+        glPushMatrix();
+        {
+            a  = sol_transform(draw->vary, draw->vary->bv + bi, p, v);
+
+            glTranslatef(p[0], p[1], p[2]);
+            glRotatef(a, v[0], v[1], v[2]);
+
+            mq = sol_draw_body(draw->bv + bi, mq, f0, f1);
+        }
+        glPopMatrix();
     }
+    return mq;
+}
 
-    for (i = 0; i < draw->bc; i++)
+void sol_draw(const struct s_draw *draw, int mask, int test)
+{
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glEnableClientState(GL_NORMAL_ARRAY);
+    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     {
-        if (glIsList(draw->bv[i].ol))
-            glDeleteLists(draw->bv[i].ol, 1);
-        if (glIsList(draw->bv[i].tl))
-            glDeleteLists(draw->bv[i].tl, 1);
-        if (glIsList(draw->bv[i].rl))
-            glDeleteLists(draw->bv[i].rl, 1);
-        if (glIsList(draw->bv[i].sl))
-            glDeleteLists(draw->bv[i].sl, 1);
+        const struct d_mtrl *mq = &default_draw_mtrl;
+
+        /* Render all opaque geometry. */
+
+        mq = sol_draw_all(draw, mq, M_TRANSPARENT | M_REFLECTIVE, 0);
+
+        /* Render all transparent geometry. */
+
+        if (!test) glDisable(GL_DEPTH_TEST);
+        if (!mask) glDepthMask(GL_FALSE);
+        {
+            sol_draw_all(draw, mq, M_REFLECTIVE, M_TRANSPARENT);
+        }
+        if (!mask) glDepthMask(GL_TRUE);
+        if (!test) glEnable(GL_DEPTH_TEST);
+
+        mq = sol_apply_mtrl(&default_draw_mtrl, mq);
+
+        /* Revert the buffer object state. */
+
+        glBindBuffer(GL_ARRAY_BUFFER,         0);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
     }
+    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+    glDisableClientState(GL_NORMAL_ARRAY);
+    glDisableClientState(GL_VERTEX_ARRAY);
+}
+
+void sol_refl(const struct s_draw *draw)
+{
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glEnableClientState(GL_NORMAL_ARRAY);
+    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+    {
+        const struct d_mtrl *mq = &default_draw_mtrl;
+
+        /* Render all reflective geometry. */
 
-    free(draw->mv);
-    free(draw->bv);
+        mq = sol_draw_all(draw, mq, 0, M_REFLECTIVE);
+        mq = sol_apply_mtrl(&default_draw_mtrl, mq);
 
-    memset(draw, 0, sizeof (*draw));
+        /* Revert the buffer object state. */
+
+        glBindBuffer(GL_ARRAY_BUFFER,         0);
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    }
+    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+    glDisableClientState(GL_NORMAL_ARRAY);
+    glDisableClientState(GL_VERTEX_ARRAY);
 }
 
 /*---------------------------------------------------------------------------*/
index 30d1583..eb03e49 100644 (file)
 
 /*---------------------------------------------------------------------------*/
 
+struct d_vert
+{
+    float p[3];
+    float n[3];
+    float t[2];
+};
+
+struct d_geom
+{
+    GLushort i;
+    GLushort j;
+    GLushort k;
+};
+
+/*---------------------------------------------------------------------------*/
+
 struct d_mtrl
 {
     const struct b_mtrl *base;
@@ -31,14 +47,22 @@ struct d_mtrl
     GLuint o;                                  /* OpenGL texture object      */
 };
 
+struct d_mesh
+{
+    const struct d_mtrl *mp;
+
+    GLuint vbo;                                /* Vertex  buffer object      */
+    GLuint ebo;                                /* Element buffer object      */
+    GLuint ebc;                                /* Element buffer count       */
+};
+
 struct d_body
 {
     const struct b_body *base;
 
-    GLuint ol;                                 /* opaque geometry list       */
-    GLuint tl;                                 /* transparent geometry list  */
-    GLuint rl;                                 /* reflective geometry list   */
-    GLuint sl;                                 /* shadowed geometry list     */
+    int mc;
+
+    struct d_mesh *mv;
 };
 
 struct s_draw