updated URL of forum and table in readme file
[neverball] / share / solid.c
index 9b4e8c3..467da87 100644 (file)
@@ -1,4 +1,4 @@
-/*   
+/*
  * Copyright (C) 2003 Robert Kooima
  *
  * NEVERBALL is  free software; you can redistribute  it and/or modify
 
 #include "glext.h"
 #include "vec3.h"
-#include "geom.h"
-#include "image.h"
+#include "geom.h" /* Only for height constants! */
+#include "base_image.h"
 #include "solid.h"
 #include "base_config.h"
 #include "binary.h"
 
-#define MAGIC 0x4F425251  /* Neverball sol file magic number (should not change) */
-#define SOL_VERSION  1 /* Neverball sol file format version (can change)      */
+#define MAGIC       0x4c4f53af
+#define SOL_VERSION 6
 
 #define LARGE 1.0e+5f
 
@@ -68,9 +68,9 @@ static void sol_body_v(float v[3],
     }
 }
 
-static void sol_body_p(float p[3],
-                       const struct s_file *fp,
-                       const struct s_body *bp)
+void sol_body_p(float p[3],
+                const struct s_file *fp,
+                const struct s_body *bp)
 {
     float v[3];
 
@@ -92,560 +92,6 @@ static void sol_body_p(float p[3],
 
 /*---------------------------------------------------------------------------*/
 
-static int sol_enum_mtrl(const struct s_file *fp,
-                         const struct s_body *bp, int mi)
-{
-    int li, gi, c = 0;
-
-    /* Count all lump geoms with this material. */
-
-    for (li = 0; li < bp->lc; li++)
-    {
-        int g0 = fp->lv[bp->l0 + li].g0;
-        int gc = fp->lv[bp->l0 + li].gc;
-
-        for (gi = 0; gi < gc; gi++)
-            if (fp->gv[fp->iv[g0 + gi]].mi == mi)
-                c++;
-    }
-                    
-    /* Count all body geoms with this material. */
-
-    for (gi = 0; gi < bp->gc; gi++)
-        if (fp->gv[fp->iv[bp->g0 + gi]].mi == mi)
-            c++;
-
-    return c;
-}
-
-static int sol_enum_body(const struct s_file *fp,
-                           const struct s_body *bp, int fl)
-{
-    int mi, c = 0;
-
-    /* Count all geoms with this flag. */
-
-    for (mi = 0; mi < fp->mc; mi++)
-        if (fp->mv[mi].fl & fl)
-            c = c + sol_enum_mtrl(fp, bp, mi);
-
-    return c;
-}
-
-/*---------------------------------------------------------------------------*/
-
-static void sol_draw_mtrl(const struct s_file *fp, int i)
-{
-    const struct s_mtrl *mp = fp->mv + i;
-
-    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,   mp->a);
-    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,   mp->d);
-    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  mp->s);
-    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION,  mp->e);
-    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mp->h);
-
-    if (mp->fl & M_ENVIRONMENT)
-    {
-        glEnable(GL_TEXTURE_GEN_S);
-        glEnable(GL_TEXTURE_GEN_T);
-
-        glBindTexture(GL_TEXTURE_2D, mp->o);
-
-        glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
-        glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
-    }
-    else
-    {
-        glDisable(GL_TEXTURE_GEN_S);
-        glDisable(GL_TEXTURE_GEN_T);
-
-        glBindTexture(GL_TEXTURE_2D, mp->o);
-    }
-
-    if (mp->fl & M_ADDITIVE)
-        glBlendFunc(GL_ONE, GL_ONE);
-    else
-        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-}
-
-static void sol_draw_bill(const struct s_file *fp,
-                          const struct s_bill *rp, float t)
-{
-    float T  = fmodf(t, rp->t) - rp->t / 2;
-
-    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;
-
-    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;
-
-        glPushMatrix();
-        {
-            float y0 = (rp->fl & B_EDGE) ? 0 : -h / 2;
-            float y1 = (rp->fl & B_EDGE) ? h : +h / 2;
-
-            glRotatef(ry, 0.0f, 1.0f, 0.0f);
-            glRotatef(rx, 1.0f, 0.0f, 0.0f);
-            glTranslatef(0.0f, 0.0f, -rp->d);
-
-            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);
-
-            glRotatef(rz, 0.0f, 0.0f, 1.0f);
-
-            sol_draw_mtrl(fp, rp->mi);
-
-            glBegin(GL_QUADS);
-            {
-                glTexCoord2f(0.0f, 1.0f); glVertex2f(-w / 2, y0);
-                glTexCoord2f(1.0f, 1.0f); glVertex2f(+w / 2, y0);
-                glTexCoord2f(1.0f, 0.0f); glVertex2f(+w / 2, y1);
-                glTexCoord2f(0.0f, 0.0f); glVertex2f(-w / 2, y1);
-            }
-            glEnd();
-        }
-        glPopMatrix();
-    }
-}
-
-void sol_back(const struct s_file *fp, float n, float f, float t)
-{
-    int ri;
-
-    glPushAttrib(GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT);
-    {
-        /* Render all billboards in the given range. */
-
-        glDisable(GL_LIGHTING);
-        glDepthMask(GL_FALSE);
-
-        for (ri = 0; ri < fp->rc; ri++)
-            if (n <= fp->rv[ri].d && fp->rv[ri].d < f)
-                sol_draw_bill(fp, fp->rv + ri, t);
-    }
-    glPopAttrib();
-}
-
-/*---------------------------------------------------------------------------*/
-/*
- * 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_file *fp,
-                          const struct s_geom *gp, int mi)
-{
-    if (gp->mi == mi)
-    {
-        const float *ui = fp->tv[gp->ti].u;
-        const float *uj = fp->tv[gp->tj].u;
-        const float *uk = fp->tv[gp->tk].u;
-
-        const float *ni = fp->sv[gp->si].n;
-        const float *nj = fp->sv[gp->sj].n;
-        const float *nk = fp->sv[gp->sk].n;
-
-        const float *vi = fp->vv[gp->vi].p;
-        const float *vj = fp->vv[gp->vj].p;
-        const float *vk = fp->vv[gp->vk].p;
-
-        glTexCoord2fv(ui);
-        glNormal3fv(ni);
-        glVertex3fv(vi);
-
-        glTexCoord2fv(uj);
-        glNormal3fv(nj);
-        glVertex3fv(vj);
-
-        glTexCoord2fv(uk);
-        glNormal3fv(nk);
-        glVertex3fv(vk);
-    }
-}
-
-static void sol_draw_lump(const struct s_file *fp,
-                          const struct s_lump *lp, int mi)
-{
-    int i;
-
-    for (i = 0; i < lp->gc; i++)
-        sol_draw_geom(fp, fp->gv + fp->iv[lp->g0 + i], mi);
-}
-
-static void sol_draw_body(const struct s_file *fp,
-                          const struct s_body *bp, int fl)
-{
-    int mi, li, gi;
-
-    /* Iterate all materials of the correct opacity. */
-
-    for (mi = 0; mi < fp->mc; mi++)
-        if (fp->mv[mi].fl & fl)
-        {
-            if (sol_enum_mtrl(fp, bp, mi))
-            {
-                /* Set the material state. */
-
-                sol_draw_mtrl(fp, mi);
-
-                /* Render all geometry of that material. */
-
-                glBegin(GL_TRIANGLES);
-                {
-                    for (li = 0; li < bp->lc; li++)
-                        sol_draw_lump(fp, fp->lv + bp->l0 + li, mi);
-                    for (gi = 0; gi < bp->gc; gi++)
-                        sol_draw_geom(fp, fp->gv + fp->iv[bp->g0 + gi], mi);
-                }
-                glEnd();
-            }
-        }
-}
-
-static void sol_draw_list(const struct s_file *fp,
-                          const struct s_body *bp, GLuint list)
-{
-    float p[3];
-
-    sol_body_p(p, fp, bp);
-
-    glPushMatrix();
-    {
-        /* Translate a moving body. */
-
-        glTranslatef(p[0], p[1], p[2]);
-
-        /* Draw the body. */
-
-        glCallList(list);
-    }
-    glPopMatrix();
-}
-
-void sol_draw(const struct s_file *fp)
-{
-    int bi;
-
-    glPushAttrib(GL_TEXTURE_BIT      |
-                 GL_LIGHTING_BIT     |
-                 GL_COLOR_BUFFER_BIT |
-                 GL_DEPTH_BUFFER_BIT);
-    {
-        /* Render all obaque geometry into the color and depth buffers. */
-
-        for (bi = 0; bi < fp->bc; bi++)
-            if (fp->bv[bi].ol)
-                sol_draw_list(fp, fp->bv + bi, fp->bv[bi].ol);
-
-        /* Render all translucent geometry into only the color buffer. */
-
-        glDepthMask(GL_FALSE);
-
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-        for (bi = 0; bi < fp->bc; bi++)
-            if (fp->bv[bi].tl)
-                sol_draw_list(fp, fp->bv + bi, fp->bv[bi].tl);
-    }
-    glPopAttrib();
-}
-
-void sol_refl(const struct s_file *fp)
-{
-    int bi;
-
-    glPushAttrib(GL_LIGHTING_BIT);
-    {
-        /* Render all reflective geometry into the color and depth buffers. */
-
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-        for (bi = 0; bi < fp->bc; bi++)
-            if (fp->bv[bi].rl)
-                sol_draw_list(fp, fp->bv + bi, fp->bv[bi].rl);
-    }
-    glPopAttrib();
-}
-
-/*---------------------------------------------------------------------------*/
-
-static void sol_shad_geom(const struct s_file *fp,
-                          const struct s_geom *gp, int mi)
-{
-    if (gp->mi == mi)
-    {
-        const float *vi = fp->vv[gp->vi].p;
-        const float *vj = fp->vv[gp->vj].p;
-        const float *vk = fp->vv[gp->vk].p;
-
-        glTexCoord2f(vi[0], vi[2]);
-        glVertex3fv(vi);
-
-        glTexCoord2f(vj[0], vj[2]);
-        glVertex3fv(vj);
-
-        glTexCoord2f(vk[0], vk[2]);
-        glVertex3fv(vk);
-    }
-}
-
-static void sol_shad_lump(const struct s_file *fp,
-                          const struct s_lump *lp, int mi)
-{
-    int i;
-
-    for (i = 0; i < lp->gc; i++)
-        sol_shad_geom(fp, fp->gv + fp->iv[lp->g0 + i], mi);
-}
-
-static void sol_shad_body(const struct s_file *fp,
-                          const struct s_body *bp, int fl)
-{
-    int mi, li, gi;
-
-    glBegin(GL_TRIANGLES);
-    {
-        for (mi = 0; mi < fp->mc; mi++)
-            if (fp->mv[mi].fl & fl)
-            {
-                for (li = 0; li < bp->lc; li++)
-                    sol_shad_lump(fp, fp->lv + bp->l0 + li, mi);
-                for (gi = 0; gi < bp->gc; gi++)
-                    sol_shad_geom(fp, fp->gv + fp->iv[bp->g0 + gi], mi);
-            }
-    }
-    glEnd();
-}
-
-static void sol_shad_list(const struct s_file *fp,
-                          const struct s_body *bp, GLuint list)
-{
-    float p[3];
-
-    sol_body_p(p, fp, bp);
-
-    glPushMatrix();
-    {
-        /* Translate a moving body. */
-
-        glTranslatef(p[0], p[1], p[2]);
-
-        /* Translate the shadow on a moving body. */
-
-        glMatrixMode(GL_TEXTURE);
-        {
-            glPushMatrix();
-            glTranslatef(p[0], p[2], 0.0f);
-        }
-        glMatrixMode(GL_MODELVIEW);
-        
-        /* Draw the body. */
-
-        glCallList(list);
-
-        /* Pop the shadow translation. */
-
-        glMatrixMode(GL_TEXTURE);
-        {
-            glPopMatrix();
-        }
-        glMatrixMode(GL_MODELVIEW);
-    }
-    glPopMatrix();
-}
-
-void sol_shad(const struct s_file *fp)
-{
-    int bi;
-
-    glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT);
-    {
-        /* Render all shadowed geometry. */
-
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-        glDepthFunc(GL_LEQUAL);
-        glDepthMask(GL_FALSE);
-
-        for (bi = 0; bi < fp->bc; bi++)
-            if (fp->bv[bi].sl)
-                sol_shad_list(fp, fp->bv + bi, fp->bv[bi].sl);
-    }
-    glPopAttrib();
-}
-
-/*---------------------------------------------------------------------------*/
-
-static void sol_load_objects(struct s_file *fp, int s)
-{
-    int i;
-
-    for (i = 0; i < fp->bc; i++)
-    {
-        struct s_body *bp = fp->bv + i;
-
-        /* Draw all opaque geometry. */
-
-        if (sol_enum_body(fp, bp, M_OPAQUE | M_ENVIRONMENT))
-        {
-            fp->bv[i].ol = glGenLists(1);
-            
-            glNewList(fp->bv[i].ol, GL_COMPILE);
-            {
-                sol_draw_body(fp, fp->bv + i, M_OPAQUE | M_ENVIRONMENT);
-            }
-            glEndList();
-        }
-        else fp->bv[i].ol = 0;
-
-        /* Draw all translucent geometry. */
-
-        if (sol_enum_body(fp, bp, M_TRANSPARENT))
-        {
-            fp->bv[i].tl = glGenLists(1);
-
-            glNewList(fp->bv[i].tl, GL_COMPILE);
-            {
-                sol_draw_body(fp, fp->bv + i, M_TRANSPARENT);
-            }
-            glEndList();
-        }
-        else fp->bv[i].tl = 0;
-
-        /* Draw all reflective geometry. */
-
-        if (sol_enum_body(fp, bp, M_REFLECTIVE))
-        {
-            fp->bv[i].rl = glGenLists(1);
-
-            glNewList(fp->bv[i].rl, GL_COMPILE);
-            {
-                sol_draw_body(fp, fp->bv + i, M_REFLECTIVE);
-            }
-            glEndList();
-        }
-        else fp->bv[i].rl = 0;
-
-        /* Draw all shadowed geometry. */
-
-        if (s && sol_enum_body(fp, bp, M_SHADOWED))
-        {
-            fp->bv[i].sl = glGenLists(1);
-
-            glNewList(fp->bv[i].sl, GL_COMPILE);
-            {
-                sol_shad_body(fp, fp->bv + i, M_SHADOWED);
-            }
-            glEndList();
-        }
-        else fp->bv[i].sl = 0;
-    }
-}
-
-static SDL_Surface *sol_find_texture(const char *name)
-{
-    char png[MAXSTR];
-    char tga[MAXSTR];
-    char jpg[MAXSTR];
-    SDL_Surface *s;
-
-    /* Prefer a lossless copy of the texture over a lossy compression. */
-
-    strncpy(png, name, PATHMAX); strcat(png, ".png");
-    strncpy(tga, name, PATHMAX); strcat(tga, ".tga");
-    strncpy(jpg, name, PATHMAX); strcat(jpg, ".jpg");
-
-    /* Check for a PNG. */
-
-    if ((s = IMG_Load(config_data(png))))
-        return s;
-
-    /* Check for a TGA, swapping channels if found. */
-
-    if ((s = IMG_Load(config_data(tga))))
-    {
-        image_swab(s);
-        return s;
-    }
-
-    /* Check for a JPG. */
-
-    if ((s = IMG_Load(config_data(jpg))))
-        return s;
-
-    return NULL;
-}
-
-static void sol_load_textures(struct s_file *fp, int k)
-{
-    SDL_Surface *s;
-    SDL_Surface *d;
-
-    int i;
-
-    for (i = 0; i < fp->mc; i++)
-        if ((s = sol_find_texture(fp->mv[i].f)))
-        {
-            GLenum f = (s->format->BitsPerPixel == 32) ? GL_RGBA : GL_RGB;
-
-            glGenTextures(1, &fp->mv[i].o);
-            glBindTexture(GL_TEXTURE_2D, fp->mv[i].o);
-
-            if (k > 1)
-            {
-                /* Create a new buffer and copy the scaled image to it. */
-
-                if ((d = image_scale(s, k)))
-                {
-                    glTexImage2D(GL_TEXTURE_2D, 0, f, d->w, d->h, 0, f,
-                                 GL_UNSIGNED_BYTE, d->pixels);
-                    SDL_FreeSurface(d);
-                }
-            }
-            else
-                glTexImage2D(GL_TEXTURE_2D, 0, f, s->w, s->h, 0, f,
-                             GL_UNSIGNED_BYTE, s->pixels);
-
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-            /* Set the texture to clamp or repeat based on material type. */
-
-            if (fp->mv[i].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);
-            }
-
-            SDL_FreeSurface(s);
-        }
-}
-
-/*---------------------------------------------------------------------------*/
-
 static void sol_load_mtrl(FILE *fin, struct s_mtrl *mp)
 {
     get_array(fin,  mp->a, 4);
@@ -734,16 +180,19 @@ static void sol_load_body(FILE *fin, struct s_body *bp)
     get_index(fin, &bp->gc);
 }
 
-static void sol_load_coin(FILE *fin, struct s_coin *cp)
+static void sol_load_item(FILE *fin, struct s_item *hp)
 {
-    get_array(fin,  cp->p, 3);
-    get_index(fin, &cp->n);
+    get_array(fin,  hp->p, 3);
+    get_index(fin, &hp->t);
+    get_index(fin, &hp->n);
 }
 
 static void sol_load_goal(FILE *fin, struct s_goal *zp)
 {
     get_array(fin,  zp->p, 3);
     get_float(fin, &zp->r);
+    get_index(fin, &zp->s);
+    get_index(fin, &zp->c);
 }
 
 static void sol_load_swch(FILE *fin, struct s_swch *xp)
@@ -755,6 +204,7 @@ static void sol_load_swch(FILE *fin, struct s_swch *xp)
     get_float(fin, &xp->t);
     get_index(fin, &xp->f0);
     get_index(fin, &xp->f);
+    get_index(fin, &xp->i);
 }
 
 static void sol_load_bill(FILE *fin, struct s_bill *rp)
@@ -800,9 +250,11 @@ static int sol_load_file(FILE *fin, struct s_file *fp)
 
     get_index(fin, &magic);
     get_index(fin, &version);
+
     if (magic != MAGIC || version != SOL_VERSION)
         return 0;
 
+    get_index(fin, &fp->ac);
     get_index(fin, &fp->mc);
     get_index(fin, &fp->vc);
     get_index(fin, &fp->ec);
@@ -813,7 +265,7 @@ static int sol_load_file(FILE *fin, struct s_file *fp)
     get_index(fin, &fp->nc);
     get_index(fin, &fp->pc);
     get_index(fin, &fp->bc);
-    get_index(fin, &fp->cc);
+    get_index(fin, &fp->hc);
     get_index(fin, &fp->zc);
     get_index(fin, &fp->jc);
     get_index(fin, &fp->xc);
@@ -821,8 +273,9 @@ static int sol_load_file(FILE *fin, struct s_file *fp)
     get_index(fin, &fp->uc);
     get_index(fin, &fp->wc);
     get_index(fin, &fp->ic);
-    get_index(fin, &fp->ac);
 
+    if (fp->ac)
+        fp->av = (char          *) calloc(fp->ac, sizeof (char));
     if (fp->mc)
         fp->mv = (struct s_mtrl *) calloc(fp->mc, sizeof (struct s_mtrl));
     if (fp->vc)
@@ -843,8 +296,8 @@ static int sol_load_file(FILE *fin, struct s_file *fp)
         fp->pv = (struct s_path *) calloc(fp->pc, sizeof (struct s_path));
     if (fp->bc)
         fp->bv = (struct s_body *) calloc(fp->bc, sizeof (struct s_body));
-    if (fp->cc)
-        fp->cv = (struct s_coin *) calloc(fp->cc, sizeof (struct s_coin));
+    if (fp->hc)
+        fp->hv = (struct s_item *) calloc(fp->hc, sizeof (struct s_item));
     if (fp->zc)
         fp->zv = (struct s_goal *) calloc(fp->zc, sizeof (struct s_goal));
     if (fp->jc)
@@ -859,8 +312,9 @@ static int sol_load_file(FILE *fin, struct s_file *fp)
         fp->wv = (struct s_view *) calloc(fp->wc, sizeof (struct s_view));
     if (fp->ic)
         fp->iv = (int           *) calloc(fp->ic, sizeof (int));
+
     if (fp->ac)
-        fp->av = (char          *) calloc(fp->ac, sizeof (char));
+        fread(fp->av, 1, fp->ac, fin);
 
     for (i = 0; i < fp->mc; i++) sol_load_mtrl(fin, fp->mv + i);
     for (i = 0; i < fp->vc; i++) sol_load_vert(fin, fp->vv + i);
@@ -872,7 +326,7 @@ static int sol_load_file(FILE *fin, struct s_file *fp)
     for (i = 0; i < fp->nc; i++) sol_load_node(fin, fp->nv + i);
     for (i = 0; i < fp->pc; i++) sol_load_path(fin, fp->pv + i);
     for (i = 0; i < fp->bc; i++) sol_load_body(fin, fp->bv + i);
-    for (i = 0; i < fp->cc; i++) sol_load_coin(fin, fp->cv + i);
+    for (i = 0; i < fp->hc; i++) sol_load_item(fin, fp->hv + i);
     for (i = 0; i < fp->zc; i++) sol_load_goal(fin, fp->zv + i);
     for (i = 0; i < fp->jc; i++) sol_load_jump(fin, fp->jv + i);
     for (i = 0; i < fp->xc; i++) sol_load_swch(fin, fp->xv + i);
@@ -881,8 +335,50 @@ static int sol_load_file(FILE *fin, struct s_file *fp)
     for (i = 0; i < fp->wc; i++) sol_load_view(fin, fp->wv + i);
     for (i = 0; i < fp->ic; i++) get_index(fin, fp->iv + i);
 
-    if (fp->ac) fread(fp->av, 1, fp->ac, fin);
-    
+    return 1;
+}
+
+static int sol_load_head(FILE *fin, struct s_file *fp)
+{
+    int magic;
+    int version;
+
+    get_index(fin, &magic);
+    get_index(fin, &version);
+
+    if (magic != MAGIC || version != SOL_VERSION)
+        return 0;
+
+    get_index(fin, &fp->ac);
+
+#if 0
+    get_index(fin, &fp->mc);
+    get_index(fin, &fp->vc);
+    get_index(fin, &fp->ec);
+    get_index(fin, &fp->sc);
+    get_index(fin, &fp->tc);
+    get_index(fin, &fp->gc);
+    get_index(fin, &fp->lc);
+    get_index(fin, &fp->nc);
+    get_index(fin, &fp->pc);
+    get_index(fin, &fp->bc);
+    get_index(fin, &fp->hc);
+    get_index(fin, &fp->zc);
+    get_index(fin, &fp->jc);
+    get_index(fin, &fp->xc);
+    get_index(fin, &fp->rc);
+    get_index(fin, &fp->uc);
+    get_index(fin, &fp->wc);
+    get_index(fin, &fp->ic);
+#endif
+    fseek(fin, 18 * 4, SEEK_CUR);
+
+    if (fp->ac)
+    {
+        fp->av = (char *) calloc(fp->ac, sizeof (char));
+        fread(fp->av, 1, fp->ac, fin);
+    }
+
     return 1;
 }
 
@@ -899,20 +395,14 @@ int sol_load_only_file(struct s_file *fp, const char *filename)
     return res;
 }
 
-int sol_load(struct s_file *fp, const char *filename, int k, int s)
+int sol_load_only_head(struct s_file *fp, const char *filename)
 {
     FILE *fin;
     int res = 0;
 
     if ((fin = fopen(filename, FMODE_RB)))
     {
-        if (sol_load_file(fin, fp))
-       {
-           res = 1;
-           sol_load_textures(fp, k);
-            sol_load_objects (fp, s);
-       }
-
+        res = sol_load_head(fin, fp);
         fclose(fin);
     }
     return res;
@@ -1008,16 +498,19 @@ static void sol_stor_body(FILE *fout, struct s_body *bp)
     put_index(fout, &bp->gc);
 }
 
-static void sol_stor_coin(FILE *fout, struct s_coin *cp)
+static void sol_stor_item(FILE *fout, struct s_item *hp)
 {
-    put_array(fout,  cp->p, 3);
-    put_index(fout, &cp->n);
+    put_array(fout,  hp->p, 3);
+    put_index(fout, &hp->t);
+    put_index(fout, &hp->n);
 }
 
 static void sol_stor_goal(FILE *fout, struct s_goal *zp)
 {
     put_array(fout,  zp->p, 3);
     put_float(fout, &zp->r);
+    put_index(fout, &zp->s);
+    put_index(fout, &zp->c);
 }
 
 static void sol_stor_swch(FILE *fout, struct s_swch *xp)
@@ -1029,6 +522,7 @@ static void sol_stor_swch(FILE *fout, struct s_swch *xp)
     put_float(fout, &xp->t);
     put_index(fout, &xp->f0);
     put_index(fout, &xp->f);
+    put_index(fout, &xp->i);
 }
 
 static void sol_stor_bill(FILE *fout, struct s_bill *rp)
@@ -1074,7 +568,8 @@ static void sol_stor_file(FILE *fin, struct s_file *fp)
 
     put_index(fin, &magic);
     put_index(fin, &version);
-    
+
+    put_index(fin, &fp->ac);
     put_index(fin, &fp->mc);
     put_index(fin, &fp->vc);
     put_index(fin, &fp->ec);
@@ -1085,7 +580,7 @@ static void sol_stor_file(FILE *fin, struct s_file *fp)
     put_index(fin, &fp->nc);
     put_index(fin, &fp->pc);
     put_index(fin, &fp->bc);
-    put_index(fin, &fp->cc);
+    put_index(fin, &fp->hc);
     put_index(fin, &fp->zc);
     put_index(fin, &fp->jc);
     put_index(fin, &fp->xc);
@@ -1093,8 +588,8 @@ static void sol_stor_file(FILE *fin, struct s_file *fp)
     put_index(fin, &fp->uc);
     put_index(fin, &fp->wc);
     put_index(fin, &fp->ic);
-    put_index(fin, &fp->ac);
 
+    fwrite(fp->av, 1, fp->ac, fin);
     for (i = 0; i < fp->mc; i++) sol_stor_mtrl(fin, fp->mv + i);
     for (i = 0; i < fp->vc; i++) sol_stor_vert(fin, fp->vv + i);
     for (i = 0; i < fp->ec; i++) sol_stor_edge(fin, fp->ev + i);
@@ -1105,7 +600,7 @@ static void sol_stor_file(FILE *fin, struct s_file *fp)
     for (i = 0; i < fp->nc; i++) sol_stor_node(fin, fp->nv + i);
     for (i = 0; i < fp->pc; i++) sol_stor_path(fin, fp->pv + i);
     for (i = 0; i < fp->bc; i++) sol_stor_body(fin, fp->bv + i);
-    for (i = 0; i < fp->cc; i++) sol_stor_coin(fin, fp->cv + i);
+    for (i = 0; i < fp->hc; i++) sol_stor_item(fin, fp->hv + i);
     for (i = 0; i < fp->zc; i++) sol_stor_goal(fin, fp->zv + i);
     for (i = 0; i < fp->jc; i++) sol_stor_jump(fin, fp->jv + i);
     for (i = 0; i < fp->xc; i++) sol_stor_swch(fin, fp->xv + i);
@@ -1113,8 +608,6 @@ static void sol_stor_file(FILE *fin, struct s_file *fp)
     for (i = 0; i < fp->uc; i++) sol_stor_ball(fin, fp->uv + i);
     for (i = 0; i < fp->wc; i++) sol_stor_view(fin, fp->wv + i);
     for (i = 0; i < fp->ic; i++) put_index(fin, fp->iv + i);
-
-    fwrite(fp->av, 1, fp->ac, fin);
 }
 
 /*---------------------------------------------------------------------------*/
@@ -1135,24 +628,6 @@ int sol_stor(struct s_file *fp, const char *filename)
 
 void sol_free(struct s_file *fp)
 {
-    int i;
-
-    for (i = 0; i < fp->mc; i++)
-    {
-        if (glIsTexture(fp->mv[i].o))
-            glDeleteTextures(1, &fp->mv[i].o);
-    }
-
-    for (i = 0; i < fp->bc; i++)
-    {
-        if (glIsList(fp->bv[i].ol))
-            glDeleteLists(fp->bv[i].ol, 1);
-        if (glIsList(fp->bv[i].tl))
-            glDeleteLists(fp->bv[i].tl, 1);
-        if (glIsList(fp->bv[i].rl))
-            glDeleteLists(fp->bv[i].rl, 1);
-    }
-
     if (fp->mv) free(fp->mv);
     if (fp->vv) free(fp->vv);
     if (fp->ev) free(fp->ev);
@@ -1163,7 +638,7 @@ void sol_free(struct s_file *fp)
     if (fp->nv) free(fp->nv);
     if (fp->pv) free(fp->pv);
     if (fp->bv) free(fp->bv);
-    if (fp->cv) free(fp->cv);
+    if (fp->hc) free(fp->hv);
     if (fp->zv) free(fp->zv);
     if (fp->jv) free(fp->jv);
     if (fp->xv) free(fp->xv);
@@ -1366,7 +841,7 @@ static float sol_bounce(struct s_ball *up,
     v_mad(u, w, n, -wn);
     v_mad(v, v, n, -vn);
     v_mad(v, v, u, +km * dt);
-    v_mad(v, v, n, xn + yn); 
+    v_mad(v, v, n, xn + yn);
 
     v_mad(p, q, n, up->r);
 
@@ -1606,7 +1081,8 @@ static float sol_test_lump(float dt,
                            const float o[3],
                            const float w[3])
 {
-    float U[3], u, t = dt;
+    float U[3] = {0.0f, 0.0f, 0.0f}; /* init value only to avoid gcc warnings */
+    float u, t = dt;
     int i;
 
     /* Short circuit a non-solid lump. */
@@ -1626,7 +1102,7 @@ static float sol_test_lump(float dt,
                 t = u;
             }
         }
+
     /* Test all edges */
 
     if (up->r > 0.0f)
@@ -1837,36 +1313,34 @@ float sol_step(struct s_file *fp, const float *g, float dt, int ui, int *m)
 
 /*---------------------------------------------------------------------------*/
 
-int sol_coin_test(struct s_file *fp, float *p, float coin_r)
+struct s_item *sol_item_test(struct s_file *fp, float *p, float item_r)
 {
     const float *ball_p = fp->uv->p;
     const float  ball_r = fp->uv->r;
-    int ci, n;
 
-    for (ci = 0; ci < fp->cc; ci++)
+    int hi;
+
+    for (hi = 0; hi < fp->hc; hi++)
     {
         float r[3];
 
-        r[0] = ball_p[0] - fp->cv[ci].p[0];
-        r[1] = ball_p[1] - fp->cv[ci].p[1];
-        r[2] = ball_p[2] - fp->cv[ci].p[2];
+        r[0] = ball_p[0] - fp->hv[hi].p[0];
+        r[1] = ball_p[1] - fp->hv[hi].p[1];
+        r[2] = ball_p[2] - fp->hv[hi].p[2];
 
-        if (fp->cv[ci].n > 0 && v_len(r) < ball_r + coin_r)
+        if (fp->hv[hi].t != ITEM_NONE && v_len(r) < ball_r + item_r)
         {
-            p[0] = fp->cv[ci].p[0];
-            p[1] = fp->cv[ci].p[1];
-            p[2] = fp->cv[ci].p[2];
-
-            n = fp->cv[ci].n;
-            fp->cv[ci].n = 0;
+            p[0] = fp->hv[hi].p[0];
+            p[1] = fp->hv[hi].p[1];
+            p[2] = fp->hv[hi].p[2];
 
-            return n;
+            return &fp->hv[hi];
         }
     }
-    return 0;
+    return NULL;
 }
 
-int sol_goal_test(struct s_file *fp, float *p, int ui)
+struct s_goal *sol_goal_test(struct s_file *fp, float *p, int ui)
 {
     const float *ball_p = fp->uv[ui].p;
     const float  ball_r = fp->uv[ui].r;
@@ -1888,17 +1362,23 @@ int sol_goal_test(struct s_file *fp, float *p, int ui)
             p[1] = fp->zv[zi].p[1];
             p[2] = fp->zv[zi].p[2];
 
-            return 1;
+            return &fp->zv[zi];
         }
     }
-    return 0;
+    return NULL;
 }
 
 int sol_jump_test(struct s_file *fp, float *p, int ui)
+/* Test if the ball ui is inside a jump. */
+/* Return 1 if yes and fill p with the destination position. */
+/* Return 0 if no. */
+/* Return 2 if the ball is on the border of a jump. */
 {
     const float *ball_p = fp->uv[ui].p;
     const float  ball_r = fp->uv[ui].r;
     int ji;
+    float l;
+    int res = 0;
 
     for (ji = 0; ji < fp->jc; ji++)
     {
@@ -1908,26 +1388,36 @@ int sol_jump_test(struct s_file *fp, float *p, int ui)
         r[1] = ball_p[2] - fp->jv[ji].p[2];
         r[2] = 0;
 
-        if (v_len(r) < fp->jv[ji].r - ball_r &&
+        l = v_len(r) - fp->jv[ji].r;
+        if (l < 0 &&
             ball_p[1] > fp->jv[ji].p[1] &&
             ball_p[1] < fp->jv[ji].p[1] + JUMP_HEIGHT / 2)
         {
-            p[0] = fp->jv[ji].q[0] + (ball_p[0] - fp->jv[ji].p[0]);
-            p[1] = fp->jv[ji].q[1] + (ball_p[1] - fp->jv[ji].p[1]);
-            p[2] = fp->jv[ji].q[2] + (ball_p[2] - fp->jv[ji].p[2]);
+            if (l < - ball_r )
+            {
+                p[0] = fp->jv[ji].q[0] + (ball_p[0] - fp->jv[ji].p[0]);
+                p[1] = fp->jv[ji].q[1] + (ball_p[1] - fp->jv[ji].p[1]);
+                p[2] = fp->jv[ji].q[2] + (ball_p[2] - fp->jv[ji].p[2]);
 
-            return 1;
+                return 1;
+            }
+            else
+                res = 2;
         }
     }
-    return 0;
+    return res;
 }
 
-int sol_swch_test(struct s_file *fp, int flag, int ui)
+int sol_swch_test(struct s_file *fp, int ui)
+/* In the SOL fp, test and process the event the ball ui enters a switch.
+ * Return 1 if a visible switch is activated, return 0 otherwise (no switch is
+ * activated or only invisible switchs) */
 {
     const float *ball_p = fp->uv[ui].p;
     const float  ball_r = fp->uv[ui].r;
     int xi;
-    int f = 1;
+    float l;
+    int res = 0; /* result */
 
     for (xi = 0; xi < fp->xc; xi++)
     {
@@ -1941,15 +1431,20 @@ int sol_swch_test(struct s_file *fp, int flag, int ui)
             r[1] = ball_p[2] - xp->p[2];
             r[2] = 0;
 
-            if (v_len(r)  < xp->r - ball_r &&
+            l = v_len(r) - xp->r;
+            if (l < ball_r &&
                 ball_p[1] > xp->p[1] &&
                 ball_p[1] < xp->p[1] + SWCH_HEIGHT / 2)
             {
-                if (flag)
+                if (!xp->e && l < - ball_r)
                 {
                     int pi = xp->pi;
                     int pj = xp->pi;
 
+                    /* The ball enter */
+                    if (xp->t0 == 0)
+                        xp->e = 1;
+
                     /* Toggle the state, update the path. */
 
                     xp->f = xp->f ? 0 : 1;
@@ -1969,12 +1464,18 @@ int sol_swch_test(struct s_file *fp, int flag, int ui)
 
                     if (xp->f != xp->f0)
                         xp->t  = xp->t0;
+
+                    /* If visible, set the result */
+                    if (!xp->i)
+                        res = 1;
                 }
-                f = 0;
             }
+            else if (xp->e)
+                /* A ball go out */
+                xp->e = 0;
         }
     }
-    return f;
+    return res;
 }
 
 /*---------------------------------------------------------------------------*/