Correct logic of BSP back/front tests
[neverball] / share / ball.c
index 8f1e215..9e0bdeb 100644 (file)
@@ -40,11 +40,15 @@ 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_file *fp, float *alpha)
 {
     int flags = F_DEPTHTEST;
     int di;
@@ -64,6 +68,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;
@@ -89,14 +95,18 @@ void ball_init(void)
     inner_flags = 0;
     outer_flags = 0;
 
+    solid_alpha = 1.0f;
+    inner_alpha = 1.0f;
+    outer_alpha = 1.0f;
+
     if ((has_solid = sol_load_gl(&solid, config_data(solid_file), T, 0)))
-        solid_flags = ball_flags(&solid);
+        solid_flags = ball_opts(&solid, &solid_alpha);
 
     if ((has_inner = sol_load_gl(&inner, config_data(inner_file), T, 0)))
-        inner_flags = ball_flags(&inner);
+        inner_flags = ball_opts(&inner, &inner_alpha);
 
     if ((has_outer = sol_load_gl(&outer, config_data(outer_file), T, 0)))
-        outer_flags = ball_flags(&outer);
+        outer_flags = ball_opts(&outer, &outer_alpha);
 }
 
 void ball_free(void)
@@ -111,13 +121,19 @@ void ball_free(void)
 /*---------------------------------------------------------------------------*/
 
 static void ball_draw_solid(const float *ball_M,
-                            const float *ball_bill_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. */
@@ -129,13 +145,13 @@ static void ball_draw_solid(const float *ball_M,
             if (solid.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, ball_bill_M, t);
                 }
                 glEnable(GL_LIGHTING);
-                glDepthMask(GL_TRUE);
+                if (mask == 0) glDepthMask(GL_TRUE);
                 if (test == 0) glEnable(GL_DEPTH_TEST);
             }
 
@@ -144,12 +160,15 @@ static void ball_draw_solid(const float *ball_M,
             sol_draw(&solid, mask, test);
         }
         glPopMatrix();
+
+        if (solid_alpha < 1.0f)
+            glDisable(GL_ALPHA_TEST);
     }
 }
 
 static void ball_draw_inner(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 +176,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)
@@ -174,28 +199,31 @@ static void ball_draw_inner(const float *pend_M,
         if (inner.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, pend_bill_M, t);
                 else
-                    sol_bill(&inner, bill_M);
+                    sol_bill(&inner, 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,
                             const float *bill_M,
-                            const float *pend_bill_M)
+                            const float *pend_bill_M, float t)
 {
     if (has_outer)
     {
@@ -203,7 +231,13 @@ static void ball_draw_outer(const float *pend_M,
         const int mask = (outer_flags & F_DEPTHMASK);
         const int test = (outer_flags & F_DEPTHTEST);
 
-        /* Apply the pendulum rotation. */
+        if (outer_alpha < 1.0f)
+        {
+            glEnable(GL_ALPHA_TEST);
+            glAlphaFunc(GL_GEQUAL, outer_alpha);
+        }
+
+       /* Apply the pendulum rotation. */
 
         if (pend)
         {
@@ -220,21 +254,24 @@ static void ball_draw_outer(const float *pend_M,
         if (outer.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, pend_bill_M, t);
                 else
-                    sol_bill(&outer, bill_M);
+                    sol_bill(&outer, 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);
     }
 }
 
@@ -244,18 +281,18 @@ static void ball_pass_inner(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(        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(        pend_M, bill_M,              pend_bill_M, t);
         glDisable(GL_CLIP_PLANE2);
     }
 
@@ -264,16 +301,16 @@ 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(        pend_M, bill_M,              pend_bill_M, t);
         glCullFace(GL_BACK);
-        ball_draw_inner(        pend_M, bill_M,              pend_bill_M);
+        ball_draw_inner(        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(        pend_M, bill_M,              pend_bill_M, t);
     }
 }
 
@@ -281,20 +318,20 @@ static void ball_pass_solid(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(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(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(ball_M,                 ball_bill_M, t);
         glDisable(GL_CLIP_PLANE2);
     }
 
@@ -303,19 +340,19 @@ 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(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(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
+        ball_draw_solid(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(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
+        ball_draw_solid(ball_M,                 ball_bill_M, t);
     }
 }
 
@@ -323,20 +360,20 @@ static void ball_pass_outer(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(        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(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(        pend_M, bill_M,              pend_bill_M, t);
         glDisable(GL_CLIP_PLANE2);
     }
 
@@ -345,19 +382,19 @@ 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(        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(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
+        ball_draw_outer(        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(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
+        ball_draw_outer(        pend_M, bill_M,              pend_bill_M, t);
     }
 }
 
@@ -365,7 +402,7 @@ static void ball_pass_outer(const float *ball_M,
 
 void ball_draw(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. */
 
@@ -381,7 +418,7 @@ void ball_draw(const float *ball_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(ball_M, pend_M, bill_M, ball_bill_M, pend_bill_M, t);
 }
 
 /*---------------------------------------------------------------------------*/