Merge branch 'gles'
[neverball] / share / ball.c
index 8f1e215..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,9 +28,9 @@ 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
@@ -40,19 +42,23 @@ static int solid_flags;
 static int inner_flags;
 static int outer_flags;
 
+static float solid_alpha;
+static float inner_alpha;
+static float outer_alpha;
+
 /*---------------------------------------------------------------------------*/
 
 #define SET(B, v, b) ((v) ? ((B) | (b)) : ((B) & ~(b)))
 
-static int ball_flags(const struct s_file *fp)
+static int ball_opts(const struct s_base *base, float *alpha)
 {
     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;
+        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);
@@ -64,6 +70,8 @@ static int ball_flags(const struct s_file *fp)
             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;
@@ -71,53 +79,61 @@ 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_full(&inner, inner_file, 0)))
+        inner_flags = ball_opts(&inner.base, &inner_alpha);
 
-    if ((has_inner = sol_load_gl(&inner, config_data(inner_file), T, 0)))
-        inner_flags = ball_flags(&inner);
+    if ((has_outer = sol_load_full(&outer, outer_file, 0)))
+        outer_flags = ball_opts(&outer.base, &outer_alpha);
 
-    if ((has_outer = sol_load_gl(&outer, config_data(outer_file), T, 0)))
-        outer_flags = ball_flags(&outer);
+    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 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();
         {
             /* Apply the ball rotation. */
@@ -126,30 +142,34 @@ static void ball_draw_solid(const float *ball_M,
 
             /* Draw the solid billboard geometry. */
 
-            if (solid.rc)
+            if (solid.base.rc)
             {
                 if (test == 0) glDisable(GL_DEPTH_TEST);
-                glDepthMask(GL_FALSE);
+                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, mask, test);
+            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)
     {
@@ -157,6 +177,12 @@ static void ball_draw_inner(const float *pend_M,
         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 (pend)
@@ -167,35 +193,39 @@ static void ball_draw_inner(const float *pend_M,
 
         /* Draw the inner opaque and transparent geometry. */
 
-        sol_draw(&inner, mask, test);
+        sol_draw(&inner.draw, rend, mask, test);
 
         /* Draw the inner billboard geometry. */
 
-        if (inner.rc)
+        if (inner.base.rc)
         {
             if (test == 0) glDisable(GL_DEPTH_TEST);
-            glDepthMask(GL_FALSE);
+            if (mask == 0) glDepthMask(GL_FALSE);
             glDisable(GL_LIGHTING);
             {
                 if (pend)
-                    sol_bill(&inner, pend_bill_M);
+                    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 (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)
     {
@@ -203,6 +233,12 @@ static void ball_draw_outer(const float *pend_M,
         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 (pend)
@@ -213,49 +249,53 @@ static void ball_draw_outer(const float *pend_M,
 
         /* Draw the outer opaque and transparent geometry. */
 
-        sol_draw(&outer, mask, test);
+        sol_draw(&outer.draw, rend, mask, test);
 
         /* Draw the outer billboard geometry. */
 
-        if (outer.rc)
+        if (outer.base.rc)
         {
             if (test == 0) glDisable(GL_DEPTH_TEST);
-            glDepthMask(GL_FALSE);
+            if (mask == 0) glDepthMask(GL_FALSE);
             glDisable(GL_LIGHTING);
             {
                 if (pend)
-                    sol_bill(&outer, pend_bill_M);
+                    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 (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);
     }
 
@@ -264,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);
     }
 
@@ -303,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);
     }
 
@@ -345,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. */
 
@@ -374,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);
 }
 
 /*---------------------------------------------------------------------------*/