Group key config symbols together
[neverball] / share / part.c
index 7d6727b..2bb2a26 100644 (file)
@@ -1,4 +1,4 @@
-/*   
+/*
  * Copyright (C) 2003 Robert Kooima
  *
  * NEVERBALL is  free software; you can redistribute  it and/or modify
@@ -36,9 +36,14 @@ struct part
 
 static struct part part_coin[PART_MAX_COIN];
 static struct part part_goal[PART_MAX_GOAL];
-static GLuint      part_text;
+static struct part part_jump[PART_MAX_JUMP];
+static GLuint      part_text_star;
+static GLuint      part_text_squiggle;
 static GLuint      part_list;
 
+static float goal_height;
+static float jump_height;
+
 /*---------------------------------------------------------------------------*/
 
 #define PI 3.1415927f
@@ -50,45 +55,74 @@ static float rnd(float l, float h)
 
 /*---------------------------------------------------------------------------*/
 
-static GLfloat gcoltab[] = {0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f};
-
-void part_reset(float h)
+void part_reset(float zh, float jh)
 {
     int i;
 
+    goal_height = zh;
+    jump_height = jh;
+
+    for (i = 0; i < PART_MAX_COIN; i++)
+        part_coin[i].t = 0.0f;
+
     for (i = 0; i < PART_MAX_GOAL; i++)
     {
         float t = rnd(+0.1f,      +1.0f);
         float a = rnd(-1.0f * PI, +1.0f * PI);
         float w = rnd(-2.0f * PI, +2.0f * PI);
-       int k = i % 6;
 
         part_goal[i].t = t;
         part_goal[i].a = V_DEG(a);
         part_goal[i].w = V_DEG(w);
 
-        part_goal[i].c[0] = gcoltab[k];
-        part_goal[i].c[1] = gcoltab[k+1];
-        part_goal[i].c[2] = gcoltab[k+2];
+        part_goal[i].c[0] = 1.0f;
+        part_goal[i].c[1] = 1.0f;
+        part_goal[i].c[2] = 0.0f;
 
         part_goal[i].p[0] = fsinf(a);
-        part_goal[i].p[1] = (1.f - t) * h;
+        part_goal[i].p[1] = (1.f - t) * goal_height;
         part_goal[i].p[2] = fcosf(a);
 
         part_goal[i].v[0] = 0.f;
         part_goal[i].v[1] = 0.f;
         part_goal[i].v[2] = 0.f;
+    }
+
+    for (i = 0; i < PART_MAX_JUMP; i++)
+    {
+        float t = rnd(+0.1f,      +1.0f);
+        float a = rnd(-1.0f * PI, +1.0f * PI);
+        float w = rnd(+0.5f,      +2.5f);
+
+        float vy = rnd(+0.025f, +0.25f);
 
-        part_coin[i].t    = 0.0f;
+        part_jump[i].t = t;
+        part_jump[i].a = V_DEG(a);
+        part_jump[i].w = w;
+
+        part_jump[i].c[0] = 1.0f;
+        part_jump[i].c[1] = 1.0f;
+        part_jump[i].c[2] = 1.0f;
+
+        part_jump[i].p[0] = fsinf(a);
+        part_jump[i].p[1] = (1.f - t) * jump_height;
+        part_jump[i].p[2] = fcosf(a);
+
+        part_jump[i].v[0] = 0.f;
+        part_jump[i].v[1] = vy;
+        part_jump[i].v[2] = 0.f;
     }
 }
 
-void part_init(float h)
+void part_init(float zh, float jh)
 {
     memset(part_coin, 0, PART_MAX_COIN * sizeof (struct part));
     memset(part_goal, 0, PART_MAX_GOAL * sizeof (struct part));
+    memset(part_jump, 0, PART_MAX_JUMP * sizeof (struct part));
+
+    part_text_star     = make_image_from_file(IMG_PART_STAR);
+    part_text_squiggle = make_image_from_file(IMG_PART_SQUIGGLE);
 
-    part_text = make_image_from_file(NULL, NULL, NULL, NULL, IMG_PART);
     part_list = glGenLists(1);
 
     glNewList(part_list, GL_COMPILE);
@@ -111,7 +145,7 @@ void part_init(float h)
     }
     glEndList();
 
-    part_reset(h);
+    part_reset(zh, jh);
 }
 
 void part_free(void)
@@ -119,8 +153,11 @@ void part_free(void)
     if (glIsList(part_list))
         glDeleteLists(part_list, 1);
 
-    if (glIsTexture(part_text))
-        glDeleteTextures(1, &part_text);
+    if (glIsTexture(part_text_star))
+        glDeleteTextures(1, &part_text_star);
+
+    if (glIsTexture(part_text_squiggle))
+        glDeleteTextures(1, &part_text_squiggle);
 }
 
 /*---------------------------------------------------------------------------*/
@@ -193,79 +230,101 @@ static void part_spin(struct part *part, int n, const float *g, float dt)
 
 void part_step(const float *g, float dt)
 {
+    int i;
+
     part_fall(part_coin, PART_MAX_COIN, g, dt);
 
     if (g[1] > 0.f)
         part_fall(part_goal, PART_MAX_GOAL, g, dt);
     else
         part_spin(part_goal, PART_MAX_GOAL, g, dt);
+
+    for (i = 0; i < PART_MAX_JUMP; i++)
+    {
+        part_jump[i].p[1] += part_jump[i].v[1] * dt;
+
+        if (part_jump[i].p[1] > jump_height)
+            part_jump[i].p[1] = 0.0f;
+    }
 }
 
 /*---------------------------------------------------------------------------*/
 
-static void part_draw(const float p[3], const float c[3],
-                      float a, float r, float rx, float ry, float rz)
+static void part_draw(const float *M,
+                      const float *p, float r, float rz, float s)
 {
     glPushMatrix();
     {
         glTranslatef(r * p[0], p[1], r * p[2]);
-        glRotatef(ry, 0.f, 1.f, 0.f);
-        glRotatef(rx, 1.f, 0.f, 0.f);
+        glMultMatrixf(M);
         glRotatef(rz, 0.f, 0.f, 1.f);
-
-        glColor4f(c[0], c[1], c[2], a);
+        glScalef(s, s, 1.0f);
 
         glCallList(part_list);
     }
     glPopMatrix();
 }
 
-void part_draw_coin(float rx, float ry)
+void part_draw_coin(const float *M, float t)
 {
-    float r = (float) SDL_GetTicks() / 1000.f;
     int i;
 
-    glPushAttrib(GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT);
-    {
-        glDisable(GL_LIGHTING);
-        glEnable(GL_COLOR_MATERIAL);
-
-        glDepthMask(GL_FALSE);
-        glBindTexture(GL_TEXTURE_2D, part_text);
-
-        for (i = 0; i < PART_MAX_COIN; i++)
-            if (part_coin[i].t > 0.f)
-                part_draw(part_coin[i].p,
-                          part_coin[i].c,
-                          part_coin[i].t,
-                          1.f, rx, ry, r * part_coin[i].w);
-    }
-    glPopAttrib();
+    glBindTexture(GL_TEXTURE_2D, part_text_star);
+
+    for (i = 0; i < PART_MAX_COIN; i++)
+        if (part_coin[i].t > 0.f)
+        {
+            glColor4f(part_coin[i].c[0],
+                      part_coin[i].c[1],
+                      part_coin[i].c[2],
+                      part_coin[i].t);
+
+            part_draw(M, part_coin[i].p, 1.0f, t * part_coin[i].w, 1.0f);
+        }
 }
 
-void part_draw_goal(float rx, float ry, float radius, float a, int spe)
+void part_draw_goal(const float *M, float radius, float a, float t)
 {
-    float r = (float) SDL_GetTicks() / 1000.f;
     int i;
-    GLfloat yel[3] = {1.0f, 1.0f, 0.0f};
 
-    glPushAttrib(GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT);
+    glBindTexture(GL_TEXTURE_2D, part_text_star);
+
+    glColor4f(1.0f, 1.0f, 0.0f, a);
+
+    for (i = 0; i < PART_MAX_GOAL; i++)
+        if (part_goal[i].t > 0.0f)
+            part_draw(M, part_goal[i].p, radius - 0.05f,
+                      t * part_goal[i].w, 1.0f);
+}
+
+void part_draw_jump(const float *M, float radius, float a, float t)
+{
+    int i;
+
+    glBindTexture(GL_TEXTURE_2D, part_text_squiggle);
+
+    for (i = 0; i < PART_MAX_JUMP; i++)
     {
-        glDisable(GL_LIGHTING);
+        glColor4f(part_jump[i].c[0],
+                  part_jump[i].c[1],
+                  part_jump[i].c[2],
+                  1.0f - part_jump[i].p[1] / jump_height);
+
+        /*
+         * X is the current time since some Epoch, Y is the time it
+         * takes for a squiggle to grow to its full size and then
+         * shrink again.  F is the current scale of the squiggle in
+         * the interval [0.0, 1.0].  The ratio is offset by 0.5 to
+         * have F = 1.0 when X = 0.0.
+         */
 
-        glEnable(GL_COLOR_MATERIAL);
+#define F(x, y) fabsf(fsinf(((x) / (y) + 0.5f) * PI))
 
-        glDepthMask(GL_FALSE);
-        glBindTexture(GL_TEXTURE_2D, part_text);
+        part_draw(M, part_jump[i].p, radius - 0.05f,
+                  0.0f, F(t, part_jump[i].w));
 
-        for (i = 0; i < PART_MAX_GOAL; i++)
-            if (part_goal[i].t > 0.f)
-                part_draw(part_goal[i].p,
-                          spe ? part_goal[i].c : yel,
-                         a,
-                          radius - 0.05f, rx, ry, r * part_goal[i].w);
+#undef F
     }
-    glPopAttrib();
 }
 
 /*---------------------------------------------------------------------------*/