//Makes a mesh ball.

#define VERTICES_NUM    1024
#define TRIS_NUM        1024

class Ball
{
    I32         vertex_count;
    I32         tri_count;
    CD3I32      v[VERTICES_NUM];
    CMeshTri    t[TRIS_NUM];

} *b;

class BallDefineStruct
{
    F64 radius      format "$DA-TRM,A=\"Radius         :%8.3f\"$\n";
    I64 n_longitude format "$DA-TRM,A=\"Longitude Faces:%5d\"$\n";
    I64 n_lattitude format "$DA-TRM,A=\"Lattitude Rings:%5d\"$\n";
};

U0 BDInit(BallDefineStruct *bd)
{
    MemSet(bd, 0, sizeof(BallDefineStruct));
    bd->n_longitude = 16;
    bd->n_lattitude = 8;
    bd->radius      = 20.0;
}

U0 BDCorrect(BallDefineStruct *bd)
{
    bd->n_longitude = (bd->n_longitude + 1) / 2;
    bd->n_lattitude = (bd->n_lattitude + 1) / 2;
}

I64 AddVertex(BallDefineStruct *, I64 x, I64 y, I64 z)
{
    I64 i;

    for (i = 0; i < b->vertex_count; i++)
        if (b->v[i].x == x && b->v[i].y == y && b->v[i].z == z)
            return i;
    i = b->vertex_count++;
    b->v[i].x = x;
    b->v[i].y = y;
    b->v[i].z = z;

    return i;
}

I64 AddTri(BallDefineStruct *, I64 c, I64 n0, I64 n1, I64 n2)
{
    I64 res = b->tri_count++;

    b->t[res].color = c;
    b->t[res].nums[0] = n0;
    b->t[res].nums[1] = n1;
    b->t[res].nums[2] = n2;

    return res;
}

U8 *Ball2CSprite()
{
//See ::/System/Gr/GrSpritePlot.ZC for how CSprite are stored.
    U8  *res = MAlloc(sizeof(CSpriteMeshU8s) +
                      b->vertex_count * sizeof(CD3I32) +
                      b->tri_count * sizeof(CMeshTri) + sprite_elem_base_sizes[SPT_END]), 
        *dst = res;
    *dst++ = SPT_MESH;
    *dst(I32 *)++ = b->vertex_count;
    *dst(I32 *)++ = b->tri_count;
    MemCopy(dst, &b->v, b->vertex_count * sizeof(CD3I32));
    dst += b->vertex_count * sizeof(CD3I32);
    MemCopy(dst, &b->t, b->tri_count * sizeof(CMeshTri));
    dst += b->tri_count * sizeof(CMeshTri);
    *dst++ = SPT_END;

    return res;
}

public U8 *BallGen()
{
    U8              *res;
    I64              i, j, n, m, c, p1, p2, p3, p4;
    BallDefineStruct bd1, bd2;
    F64              r, r1, r2, z1, z2, d_a1, d_a2;

    BDInit(&bd1);

    while (TRUE)
    {
        if (!DocForm(&bd1))
            return NULL;
        MemCopy(&bd2, &bd1, sizeof(BallDefineStruct));
        BDCorrect(&bd2);

        c = PopUpColorLighting;
        if (c < 0)
            return NULL;

        b = CAlloc(sizeof(Ball));
        r = bd2.radius;
        n = bd2.n_lattitude;
        m = bd2.n_longitude;
        d_a1 = 2 * pi / n / 4;
        d_a2 = 2 * pi / m / 2;
        for (j = -n; j < n; j++)
        {
            r1 = r * Cos( j     *d_a1);
            r2 = r * Cos((j+1)*d_a1);
            z1 = r * Sin( j     *d_a1);
            z2 = r * Sin((j+1)*d_a1);
            for (i = 0; i < m; i++)
            {
                p1 = AddVertex(&bd2, r1 * Cos((2 * i  + j)   * d_a2), r1 * Sin((2 * i + j)     * d_a2), z1);
                p2 = AddVertex(&bd2, r1 * Cos((2 * i + 2 +j) * d_a2), r1 * Sin((2 * i + 2 + j) * d_a2), z1);
                p3 = AddVertex(&bd2, r2 * Cos((2 * i + 1 +j) * d_a2), r2 * Sin((2 * i + 1 + j) * d_a2), z2);
                p4 = AddVertex(&bd2, r2 * Cos((2 * i + 3 +j) * d_a2), r2 * Sin((2 * i + 3 + j) * d_a2), z2);
                AddTri(&bd2, c, p1, p2, p3);
                AddTri(&bd2, c, p3, p2, p4);
            }
        }

        res = Ball2CSprite;
        "%h7c", '\n';
        Sprite(res, "\t\t$SP,\"<1>\",BI=%d$");
        "%h7c", '\n';
        "Vertices:%d\n", b->vertex_count;
        Free(b);
        "Do another";
        if (YorN)
            Free(res);
        else
            break;
    }

    return res;
}