Merge branch 'gles'
[neverball] / share / ball.c
index 4cdd5c5..b564e82 100644 (file)
@@ -18,7 +18,9 @@
 #include "vec3.h"
 #include "glext.h"
 #include "config.h"
-#include "solid_gl.h"
+#include "common.h"
+
+#include "solid_draw.h"
 
 /*---------------------------------------------------------------------------*/
 
@@ -26,35 +28,50 @@ static int has_solid = 0;
 static int has_inner = 0;
 static int has_outer = 0;
 
-static struct s_file solid;
-static struct s_file inner;
-static struct s_file outer;
+static struct s_full solid;
+static struct s_full inner;
+static struct s_full outer;
 
-#define F_PENDULUM 1
-#define F_DRAWBACK 2
-#define F_DRAWCLIP 4
-#define F_ZBUFFER  8
+#define F_PENDULUM   1
+#define F_DRAWBACK   2
+#define F_DRAWCLIP   4
+#define F_DEPTHMASK  8
+#define F_DEPTHTEST 16
 
 static int solid_flags;
 static int inner_flags;
 static int outer_flags;
 
+static float solid_alpha;
+static float inner_alpha;
+static float outer_alpha;
+
 /*---------------------------------------------------------------------------*/
 
-static int ball_flags(const struct s_file *fp)
+#define SET(B, v, b) ((v) ? ((B) | (b)) : ((B) & ~(b)))
+
+static int ball_opts(const struct s_base *base, float *alpha)
 {
-    int flags = 0;
+    int flags = F_DEPTHTEST;
     int di;
 
-    for (di = 0; di < fp->dc; ++di)
+    for (di = 0; di < base->dc; ++di)
     {
-        char *k = fp->av + fp->dv[di].ai;
-        char *v = fp->av + fp->dv[di].aj;
-
-        if (strcmp(k, "pendulum") == 0) flags |= (atoi(v) * F_PENDULUM);
-        if (strcmp(k, "drawback") == 0) flags |= (atoi(v) * F_DRAWBACK);
-        if (strcmp(k, "drawclip") == 0) flags |= (atoi(v) * F_DRAWCLIP);
-        if (strcmp(k, "zbuffer")  == 0) flags |= (atoi(v) * F_ZBUFFER);
+        char *k = base->av + base->dv[di].ai;
+        char *v = base->av + base->dv[di].aj;
+
+        if (strcmp(k, "pendulum")  == 0)
+            flags = SET(flags, atoi(v), F_PENDULUM);
+        if (strcmp(k, "drawback")  == 0)
+            flags = SET(flags, atoi(v), F_DRAWBACK);
+        if (strcmp(k, "drawclip")  == 0)
+            flags = SET(flags, atoi(v), F_DRAWCLIP);
+        if (strcmp(k, "depthmask") == 0)
+            flags = SET(flags, atoi(v), F_DEPTHMASK);
+        if (strcmp(k, "depthtest") == 0)
+            flags = SET(flags, atoi(v), F_DEPTHTEST);
+        if (strcmp(k, "alphatest") == 0)
+            sscanf(v, "%f", alpha);
     }
 
     return flags;
@@ -62,51 +79,60 @@ static int ball_flags(const struct s_file *fp)
 
 void ball_init(void)
 {
-    int T = config_get_d(CONFIG_TEXTURES);
-
-    char solid_file[PATHMAX];
-    char inner_file[PATHMAX];
-    char outer_file[PATHMAX];
-
-    config_get_s(CONFIG_BALL, solid_file, PATHMAX - 12);
-    config_get_s(CONFIG_BALL, inner_file, PATHMAX - 12);
-    config_get_s(CONFIG_BALL, outer_file, PATHMAX - 12);
-
-    strcat(solid_file, "-solid.sol");
-    strcat(inner_file, "-inner.sol");
-    strcat(outer_file, "-outer.sol");
+    char *solid_file = concat_string(config_get_s(CONFIG_BALL_FILE),
+                                     "-solid.sol", NULL);
+    char *inner_file = concat_string(config_get_s(CONFIG_BALL_FILE),
+                                     "-inner.sol", NULL);
+    char *outer_file = concat_string(config_get_s(CONFIG_BALL_FILE),
+                                     "-outer.sol", NULL);
 
     solid_flags = 0;
     inner_flags = 0;
     outer_flags = 0;
 
-    if ((has_solid = sol_load_gl(&solid, config_data(solid_file), T, 0)))
-        solid_flags = ball_flags(&solid);
+    solid_alpha = 1.0f;
+    inner_alpha = 1.0f;
+    outer_alpha = 1.0f;
+
+    if ((has_solid = sol_load_full(&solid, solid_file, 0)))
+        solid_flags = ball_opts(&solid.base, &solid_alpha);
 
-    if ((has_inner = sol_load_gl(&inner, config_data(inner_file), T, 0)))
-        inner_flags = ball_flags(&inner);
+    if ((has_inner = sol_load_full(&inner, inner_file, 0)))
+        inner_flags = ball_opts(&inner.base, &inner_alpha);
 
-    if ((has_outer = sol_load_gl(&outer, config_data(outer_file), T, 0)))
-        outer_flags = ball_flags(&outer);
+    if ((has_outer = sol_load_full(&outer, outer_file, 0)))
+        outer_flags = ball_opts(&outer.base, &outer_alpha);
+
+    free(solid_file);
+    free(inner_file);
+    free(outer_file);
 }
 
 void ball_free(void)
 {
-    if (has_outer) sol_free_gl(&outer);
-    if (has_inner) sol_free_gl(&inner);
-    if (has_solid) sol_free_gl(&solid);
+    if (has_outer) sol_free_full(&outer);
+    if (has_inner) sol_free_full(&inner);
+    if (has_solid) sol_free_full(&solid);
 
     has_solid = has_inner = has_outer = 0;
 }
 
 /*---------------------------------------------------------------------------*/
 
-static void ball_draw_solid(const float *ball_M,
-                            const float *ball_bill_M)
+static void ball_draw_solid(struct s_rend *rend,
+                            const float *ball_M,
+                            const float *ball_bill_M, float t)
 {
     if (has_solid)
     {
-        const int Z = (solid_flags & F_ZBUFFER);
+        const int mask = (solid_flags & F_DEPTHMASK);
+        const int test = (solid_flags & F_DEPTHTEST);
+
+        if (solid_alpha < 1.0f)
+        {
+            glEnable(GL_ALPHA_TEST);
+            glAlphaFunc(GL_GEQUAL, solid_alpha);
+        }
 
         glPushMatrix();
         {
@@ -116,37 +142,50 @@ static void ball_draw_solid(const float *ball_M,
 
             /* Draw the solid billboard geometry. */
 
-            if (solid.rc)
+            if (solid.base.rc)
             {
-                glDepthMask(GL_FALSE);
+                if (test == 0) glDisable(GL_DEPTH_TEST);
+                if (mask == 0) glDepthMask(GL_FALSE);
                 glDisable(GL_LIGHTING);
                 {
-                    sol_bill(&solid, ball_bill_M);
+                    sol_bill(&solid.draw, rend, ball_bill_M, t);
                 }
                 glEnable(GL_LIGHTING);
-                glDepthMask(GL_TRUE);
+                if (mask == 0) glDepthMask(GL_TRUE);
+                if (test == 0) glEnable(GL_DEPTH_TEST);
             }
 
             /* Draw the solid opaque and transparent geometry. */
 
-            sol_draw(&solid, Z);
+            sol_draw(&solid.draw, rend, mask, test);
         }
         glPopMatrix();
+
+        if (solid_alpha < 1.0f)
+            glDisable(GL_ALPHA_TEST);
     }
 }
 
-static void ball_draw_inner(const float *pend_M,
+static void ball_draw_inner(struct s_rend *rend,
+                            const float *pend_M,
                             const float *bill_M,
-                            const float *pend_bill_M)
+                            const float *pend_bill_M, float t)
 {
     if (has_inner)
     {
-        const int P = (inner_flags & F_PENDULUM);
-        const int Z = (inner_flags & F_ZBUFFER);
+        const int pend = (inner_flags & F_PENDULUM);
+        const int mask = (inner_flags & F_DEPTHMASK);
+        const int test = (inner_flags & F_DEPTHTEST);
+
+        if (inner_alpha < 1.0f)
+        {
+            glEnable(GL_ALPHA_TEST);
+            glAlphaFunc(GL_GEQUAL, inner_alpha);
+        }
 
         /* Apply the pendulum rotation. */
 
-        if (P)
+        if (pend)
         {
             glPushMatrix();
             glMultMatrixf(pend_M);
@@ -154,42 +193,55 @@ static void ball_draw_inner(const float *pend_M,
 
         /* Draw the inner opaque and transparent geometry. */
 
-        sol_draw(&inner, Z);
+        sol_draw(&inner.draw, rend, mask, test);
 
         /* Draw the inner billboard geometry. */
 
-        if (inner.rc)
+        if (inner.base.rc)
         {
-            glDepthMask(GL_FALSE);
+            if (test == 0) glDisable(GL_DEPTH_TEST);
+            if (mask == 0) glDepthMask(GL_FALSE);
             glDisable(GL_LIGHTING);
             {
-                if (P)
-                    sol_bill(&inner, pend_bill_M);
+                if (pend)
+                    sol_bill(&inner.draw, rend, pend_bill_M, t);
                 else
-                    sol_bill(&inner, bill_M);
+                    sol_bill(&inner.draw, rend, bill_M,      t);
             }
 
             glEnable(GL_LIGHTING);
-            glDepthMask(GL_TRUE);
+            if (mask == 0) glDepthMask(GL_TRUE);
+            if (test == 0) glEnable(GL_DEPTH_TEST);
         }
 
-        if (P)
+        if (pend)
             glPopMatrix();
+
+        if (inner_alpha < 1.0f)
+            glDisable(GL_ALPHA_TEST);
     }
 }
 
-static void ball_draw_outer(const float *pend_M,
+static void ball_draw_outer(struct s_rend *rend,
+                            const float *pend_M,
                             const float *bill_M,
-                            const float *pend_bill_M)
+                            const float *pend_bill_M, float t)
 {
     if (has_outer)
     {
-        const int P = (outer_flags & F_PENDULUM);
-        const int Z = (outer_flags & F_ZBUFFER);
+        const int pend = (outer_flags & F_PENDULUM);
+        const int mask = (outer_flags & F_DEPTHMASK);
+        const int test = (outer_flags & F_DEPTHTEST);
+
+        if (outer_alpha < 1.0f)
+        {
+            glEnable(GL_ALPHA_TEST);
+            glAlphaFunc(GL_GEQUAL, outer_alpha);
+        }
 
         /* Apply the pendulum rotation. */
 
-        if (P)
+        if (pend)
         {
             glPushMatrix();
             glMultMatrixf(pend_M);
@@ -197,47 +249,53 @@ static void ball_draw_outer(const float *pend_M,
 
         /* Draw the outer opaque and transparent geometry. */
 
-        sol_draw(&outer, Z);
+        sol_draw(&outer.draw, rend, mask, test);
 
         /* Draw the outer billboard geometry. */
 
-        if (outer.rc)
+        if (outer.base.rc)
         {
-            glDepthMask(GL_FALSE);
+            if (test == 0) glDisable(GL_DEPTH_TEST);
+            if (mask == 0) glDepthMask(GL_FALSE);
             glDisable(GL_LIGHTING);
             {
-                if (P)
-                    sol_bill(&outer, pend_bill_M);
+                if (pend)
+                    sol_bill(&outer.draw, rend, pend_bill_M, t);
                 else
-                    sol_bill(&outer, bill_M);
+                    sol_bill(&outer.draw, rend, bill_M,      t);
             }
             glEnable(GL_LIGHTING);
-            glDepthMask(GL_TRUE);
+            if (mask == 0) glDepthMask(GL_TRUE);
+            if (test == 0) glEnable(GL_DEPTH_TEST);
         }
 
-        if (P)
+        if (pend)
             glPopMatrix();
+
+        if (outer_alpha < 1.0f)
+            glDisable(GL_ALPHA_TEST);
     }
 }
 
 /*---------------------------------------------------------------------------*/
 
-static void ball_pass_inner(const float *ball_M,
+static void ball_pass_inner(struct s_rend *rend,
+                            const float *ball_M,
                             const float *pend_M,
                             const float *bill_M,
                             const float *ball_bill_M,
-                            const float *pend_bill_M)
+                            const float *pend_bill_M, float t)
 {
     /* Sort the inner ball using clip planes. */
 
     if      (inner_flags & F_DRAWCLIP)
     {
         glEnable(GL_CLIP_PLANE1);
-        ball_draw_inner(        pend_M, bill_M,              pend_bill_M);
+        ball_draw_inner(rend, pend_M, bill_M, pend_bill_M, t);
         glDisable(GL_CLIP_PLANE1);
-        
+
         glEnable(GL_CLIP_PLANE2);
-        ball_draw_inner(        pend_M, bill_M,              pend_bill_M);
+        ball_draw_inner(rend, pend_M, bill_M, pend_bill_M, t);
         glDisable(GL_CLIP_PLANE2);
     }
 
@@ -246,37 +304,38 @@ static void ball_pass_inner(const float *ball_M,
     else if (inner_flags & F_DRAWBACK)
     {
         glCullFace(GL_FRONT);
-        ball_draw_inner(        pend_M, bill_M,              pend_bill_M);
+        ball_draw_inner(rend, pend_M, bill_M, pend_bill_M, t);
         glCullFace(GL_BACK);
-        ball_draw_inner(        pend_M, bill_M,              pend_bill_M);
+        ball_draw_inner(rend, pend_M, bill_M, pend_bill_M, t);
     }
 
     /* Draw the inner ball normally. */
 
     else
     {
-        ball_draw_inner(        pend_M, bill_M,              pend_bill_M);
+        ball_draw_inner(rend, pend_M, bill_M, pend_bill_M, t);
     }
 }
 
-static void ball_pass_solid(const float *ball_M,
+static void ball_pass_solid(struct s_rend *rend,
+                            const float *ball_M,
                             const float *pend_M,
                             const float *bill_M,
                             const float *ball_bill_M,
-                            const float *pend_bill_M)
+                            const float *pend_bill_M, float t)
 {
     /* Sort the solid ball with the inner ball using clip planes. */
 
     if      (solid_flags & F_DRAWCLIP)
     {
         glEnable(GL_CLIP_PLANE1);
-        ball_draw_solid(ball_M,                 ball_bill_M);
+        ball_draw_solid(rend, ball_M,                 ball_bill_M, t);
         glDisable(GL_CLIP_PLANE1);
-        
-        ball_pass_inner(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M);
+
+        ball_pass_inner(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
 
         glEnable(GL_CLIP_PLANE2);
-        ball_draw_solid(ball_M,                 ball_bill_M);
+        ball_draw_solid(rend, ball_M,                 ball_bill_M, t);
         glDisable(GL_CLIP_PLANE2);
     }
 
@@ -285,40 +344,41 @@ static void ball_pass_solid(const float *ball_M,
     else if (solid_flags & F_DRAWBACK)
     {
         glCullFace(GL_FRONT);
-        ball_draw_solid(ball_M,                 ball_bill_M);
+        ball_draw_solid(rend, ball_M,                 ball_bill_M, t);
         glCullFace(GL_BACK);
-        
-        ball_pass_inner(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M);
-        ball_draw_solid(ball_M,                 ball_bill_M);
+
+        ball_pass_inner(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
+        ball_draw_solid(rend, ball_M,                 ball_bill_M, t);
     }
 
     /* Draw the solid ball after the inner ball. */
 
     else
     {
-        ball_pass_inner(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M);
-        ball_draw_solid(ball_M,                 ball_bill_M);
+        ball_pass_inner(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
+        ball_draw_solid(rend, ball_M,                 ball_bill_M, t);
     }
 }
 
-static void ball_pass_outer(const float *ball_M,
+static void ball_pass_outer(struct s_rend *rend,
+                            const float *ball_M,
                             const float *pend_M,
                             const float *bill_M,
                             const float *ball_bill_M,
-                            const float *pend_bill_M)
+                            const float *pend_bill_M, float t)
 {
     /* Sort the outer ball with the solid ball using clip planes. */
 
     if      (outer_flags & F_DRAWCLIP)
     {
         glEnable(GL_CLIP_PLANE1);
-        ball_draw_outer(        pend_M, bill_M,              pend_bill_M);
+        ball_draw_outer(rend,         pend_M, bill_M,              pend_bill_M, t);
         glDisable(GL_CLIP_PLANE1);
-        
-        ball_pass_solid(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M);
+
+        ball_pass_solid(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
 
         glEnable(GL_CLIP_PLANE2);
-        ball_draw_outer(        pend_M, bill_M,              pend_bill_M);
+        ball_draw_outer(rend,         pend_M, bill_M,              pend_bill_M, t);
         glDisable(GL_CLIP_PLANE2);
     }
 
@@ -327,27 +387,28 @@ static void ball_pass_outer(const float *ball_M,
     else if (outer_flags & F_DRAWBACK)
     {
         glCullFace(GL_FRONT);
-        ball_draw_outer(        pend_M, bill_M,              pend_bill_M);
+        ball_draw_outer(rend,         pend_M, bill_M,              pend_bill_M, t);
         glCullFace(GL_BACK);
-        
-        ball_pass_solid(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M);
-        ball_draw_outer(        pend_M, bill_M,              pend_bill_M);
+
+        ball_pass_solid(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
+        ball_draw_outer(rend,         pend_M, bill_M,              pend_bill_M, t);
     }
 
     /* Draw the outer ball after the solid ball. */
 
     else
     {
-        ball_pass_solid(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M);
-        ball_draw_outer(        pend_M, bill_M,              pend_bill_M);
+        ball_pass_solid(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
+        ball_draw_outer(rend,         pend_M, bill_M,              pend_bill_M, t);
     }
 }
 
 /*---------------------------------------------------------------------------*/
 
-void ball_draw(const float *ball_M,
+void ball_draw(struct s_rend *rend,
+               const float *ball_M,
                const float *pend_M,
-               const float *bill_M)
+               const float *bill_M, float t)
 {
     /* Compute transforms for ball and pendulum billboards. */
 
@@ -356,14 +417,13 @@ void ball_draw(const float *ball_M,
 
     m_xps(ball_T, ball_M);
     m_xps(pend_T, pend_M);
-    m_xps(pend_T, pend_M);
 
     m_mult(ball_bill_M, ball_T, bill_M);
     m_mult(pend_bill_M, pend_T, bill_M);
 
     /* Go to GREAT pains to ensure all layers are drawn back-to-front. */
 
-    ball_pass_outer(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M);
+    ball_pass_outer(rend, ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
 }
 
 /*---------------------------------------------------------------------------*/