//Makes a mesh man.

#define VERTICES_NUM    1024
#define TRIS_NUM        1024

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

} *m;

class ManDefineStruct
{
    F64 head_rad        format "$DA-TRM,A=\"Head Radius                :%8.3f\"$\n";

    F64 torso_len       format "$DA-TRM,A=\"Torso Length               :%8.3f\"$\n";
    F64 arm_len         format "$DA-TRM,A=\"Arm Length                 :%8.3f\"$\n";
    F64 hand_len        format "$DA-TRM,A=\"Hand Length                :%8.3f\"$\n";
    F64 leg_len         format "$DA-TRM,A=\"Leg Length                 :%8.3f\"$\n";
    F64 foot_len        format "$DA-TRM,A=\"Foot Length                :%8.3f\"$\n";
    F64 torso_width     format "$DA-TRM,A=\"Torso Width                :%8.3f\"$\n";
    F64 torso_depth     format "$DA-TRM,A=\"Torso Depth                :%8.3f\"$\n";
    F64 arm_rad         format "$DA-TRM,A=\"Arm Radius                 :%8.3f\"$\n";
    F64 hand_rad        format "$DA-TRM,A=\"Hand Radius                :%8.3f\"$\n";
    F64 leg_rad         format "$DA-TRM,A=\"Leg Radius                 :%8.3f\"$\n";
    F64 foot_rad        format "$DA-TRM,A=\"Foot Radius                :%8.3f\"$\n\n";

    F64 r_shoulder_a1   format "$DA-TRM,A=\"R.Shoulder Front/Back Angle:%8.3f\"$\n";
    F64 l_shoulder_a1   format "$DA-TRM,A=\"L.Shoulder Front/Back Angle:%8.3f\"$\n";
    F64 r_hip_a1        format "$DA-TRM,A=\"R.Hip Front/Back Angle     :%8.3f\"$\n";
    F64 l_hip_a1        format "$DA-TRM,A=\"L.Hip Front/Back Angle     :%8.3f\"$\n";

    F64 r_shoulder_a2   format "$DA-TRM,A=\"R.Shoulder Side Angle      :%8.3f\"$\n";
    F64 l_shoulder_a2   format "$DA-TRM,A=\"L.Shoulder Side Angle      :%8.3f\"$\n";
    F64 r_hip_a2        format "$DA-TRM,A=\"R.Hip Side Angle           :%8.3f\"$\n";
    F64 l_hip_a2        format "$DA-TRM,A=\"L.Hip Side Angle           :%8.3f\"$\n";

    F64 r_elbow_a       format "$DA-TRM,A=\"R.Elbow Angle              :%8.3f\"$\n";
    F64 l_elbow_a       format "$DA-TRM,A=\"L.Elbow Angle              :%8.3f\"$\n";
    F64 r_knee_a        format "$DA-TRM,A=\"R.Knee Angle               :%8.3f\"$\n";
    F64 l_knee_a        format "$DA-TRM,A=\"L.Knee Angle               :%8.3f\"$\n";

    F64 r_wrist_a       format "$DA-TRM,A=\"R.Wrist Angle              :%8.3f\"$\n";
    F64 l_wrist_a       format "$DA-TRM,A=\"L.Wrist Angle              :%8.3f\"$\n";
    F64 r_ankle_a       format "$DA-TRM,A=\"R.Ankle Angle              :%8.3f\"$\n";
    F64 l_ankle_a       format "$DA-TRM,A=\"L.Ankle Angle              :%8.3f\"$\n";

};

U0 MDInit(ManDefineStruct *md)
{
    MemSet(md,0,sizeof(ManDefineStruct));

    md->head_rad    = 5.0;

    md->torso_len   = 35.0;
    md->arm_len     = 30.0;
    md->hand_len    = 8.0;
    md->leg_len     = 32.0;
    md->foot_len    = 16.0;
    md->torso_width = 20.0;
    md->torso_depth = 10.0;
    md->arm_rad     = 3.5;
    md->hand_rad    = 2.0;
    md->leg_rad     = 4.0;
    md->foot_rad    = 3.0;

    md->r_shoulder_a1   = 30;
    md->l_shoulder_a1   = -30;
    md->r_hip_a1        = -45;
    md->l_hip_a1        = 45;

    md->r_shoulder_a2   = 10;
    md->l_shoulder_a2   = 10;
    md->r_hip_a2        = -5;
    md->l_hip_a2        = -5;

    md->r_elbow_a   = 30;
    md->l_elbow_a   = 0;
    md->r_knee_a    = 0;
    md->l_knee_a    = 30;

    md->r_wrist_a = 0;
    md->l_wrist_a = 0;
    md->r_ankle_a = 0;
    md->l_ankle_a = 0;
}

U0 MDCorrect(ManDefineStruct *md)
{
    md->r_ankle_a       = -md->r_ankle_a;
    md->l_ankle_a       = -md->l_ankle_a;
    md->r_knee_a        = -md->r_knee_a;
    md->l_knee_a        = -md->l_knee_a;
    md->r_hip_a2        = -md->r_hip_a2;
    md->r_shoulder_a2   = -md->r_shoulder_a2;
    md->r_ankle_a += 90;
    md->l_ankle_a += 90;

    md->foot_len -= md->leg_rad;

    md->r_elbow_a += md->r_shoulder_a1;
    md->l_elbow_a += md->l_shoulder_a1;
    md->r_knee_a += md->r_hip_a1;
    md->l_knee_a += md->l_hip_a1;

    md->r_wrist_a += md->r_elbow_a;
    md->l_wrist_a += md->l_elbow_a;
    md->r_ankle_a += md->r_knee_a;
    md->l_ankle_a += md->l_knee_a;
}

I64 AddVertex(ManDefineStruct *md, I64 x, I64 y, I64 z)
{
    I64 res = m->vertex_count++;

    m->v[res].x = -x;
    m->v[res].y = -y - md->leg_len - md->foot_rad * 2;
    m->v[res].z = -z;

    return res;
}

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

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

    return res;
}

U0 AddBox(ManDefineStruct *md, I64 c,
          I64 x1, I64 y1, I64 z1, F64 w, F64 h, F64 d, F64 h2, F64 h3, F64 az, F64 ay, F64 ax, I64 *ox, I64 *oy, I64 *oz)
{
    I64 *r;
    I64  p1a, p2a, p3a, p4a;
    I64  p1b, p2b, p3b, p4b;
    I64  wx = w / 2, wy = 0, wz = 0, hx = 0, hy = h, hz = 0, h2x = 0, h2y = h2, h2z = 0, 
         h3x = 0, h3y = h3, h3z = 0, dx = 0, dy = 0, dz = d / 2;

    r = Mat4x4IdentNew;
    Mat4x4RotZ(r, az * pi / 180.0);
    Mat4x4RotY(r, ay * pi / 180.0);
    Mat4x4RotX(r, ax * pi / 180.0);
    Mat4x4MulXYZ(r, &wx, &wy, &wz);
    Mat4x4MulXYZ(r, &hx, &hy, &hz);
    Mat4x4MulXYZ(r, &h2x, &h2y, &h2z);
    Mat4x4MulXYZ(r, &h3x, &h3y, &h3z);
    Mat4x4MulXYZ(r, &dx, &dy, &dz);

    p1a = AddVertex(md, x1 + dx - wx + h2x, y1 + dy - wy + h2y, z1 + dz - wz + h2z);
    p2a = AddVertex(md, x1 + dx + wx + h2x, y1 + dy + wy + h2y, z1 + dz + wz + h2z);
    p3a = AddVertex(md, x1 + dx + hx - wx,  y1 + dy + hy - wy,  z1 + dz + hz - wz);
    p4a = AddVertex(md, x1 + dx + hx + wx,  y1 + dy + hy + wy,  z1 + dz + hz + wz);
    AddTri(md, c, p1a, p2a, p3a);
    AddTri(md, c, p4a, p3a, p2a);

    p1b = AddVertex(md, x1 - dx - wx + h2x, y1 - dy - wy + h2y, z1 - dz - wz + h2z);
    p2b = AddVertex(md, x1 - dx + wx + h2x, y1 - dy + wy + h2y, z1 - dz + wz + h2z);
    p3b = AddVertex(md, x1 - dx + hx - wx,  y1 - dy + hy - wy,  z1 - dz + hz - wz);
    p4b = AddVertex(md, x1 - dx + hx + wx,  y1 - dy + hy + wy,  z1 - dz + hz + wz);
    AddTri(md, c, p1b, p2b, p3b);
    AddTri(md, c, p4b, p3b, p2b);

    AddTri(md, c, p1a, p2a, p1b);
    AddTri(md, c, p2b, p1b, p2a);
    AddTri(md, c, p3a, p4a, p3b);
    AddTri(md, c, p4b, p3b, p4a);
    AddTri(md, c, p1a, p3a, p1b);
    AddTri(md, c, p3b, p1b, p3a);
    AddTri(md, c, p2a, p4a, p2b);
    AddTri(md, c, p4b, p2b, p4a);

    *ox = x1 + hx - h3x;
    *oy = y1 + hy - h3y;
    *oz = z1 + hz - h3z;

    Free(r);
}

U8 *Man2CSprite()
{
//See ::/System/Gr/GrSpritePlot.CC for how CSprite are stored.
    U8 *res = MAlloc(sizeof(CSpriteMeshU8s) +
                     m->vertex_count * sizeof(CD3I32) + m->tri_count * sizeof(CMeshTri) + sprite_elem_base_sizes[SPT_END]), 
        *dst = res;

    *dst++ = SPT_MESH;
    *dst(I32 *)++ = m->vertex_count;
    *dst(I32 *)++ = m->tri_count;
    MemCopy(dst, &m->v, m->vertex_count * sizeof(CD3I32));
    dst += m->vertex_count * sizeof(CD3I32);
    MemCopy(dst, &m->t, m->tri_count * sizeof(CMeshTri));
    dst += m->tri_count * sizeof(CMeshTri);
    *dst++ = SPT_END;

    return res;
}

public U8 *ManGen()
{
    U8              *res;
    I64              x, y, z, c1, c2, c3, c4;
    ManDefineStruct  md1, md2;

    MDInit(&md1);

    while (TRUE)
    {
        if (!DocForm(&md1))
            return NULL;
        MemCopy(&md2, &md1, sizeof(ManDefineStruct));
        MDCorrect(&md2);

        c1 = PopUpColorLighting("$BK,1$Shirt$BK,0$\n");
        if (c1 < 0)
            return NULL;
        c2 = PopUpColorLighting("$BK,1$Pants$BK,0$\n");
        if (c2 < 0)
            return NULL;
        c3 = PopUpColorLighting("$BK,1$Skin$BK,0$\n");
        if (c3 < 0)
            return NULL;
        c4 = PopUpColorLighting("$BK,1$Shoes$BK,0$\n");
        if (c4 < 0)
            return NULL;

        m = CAlloc(sizeof(Man));

        //Head
        AddBox(&md2, c3, 0, md2.torso_len+md2.head_rad * 2, 0,
                md2.head_rad * 2, -md2.head_rad * 2, md2.head_rad * 2, 0, 0,  0, 0, 0, &x, &y, &z);

        //Torso
        AddBox(&md2, c1, 0, md2.torso_len, 0, md2.torso_width, -md2.torso_len, md2.torso_depth, 0, 0,  0, 0, 0, &x, &y, &z);

        //Right Arm
        AddBox(&md2, c1, -md2.torso_width / 2 - md2.arm_rad, md2.torso_len - md2.arm_rad, 0, 
                md2.arm_rad * 2, -md2.arm_len / 2, md2.arm_rad * 2, md2.arm_rad, 0, 
                md2.r_shoulder_a2, 0, md2.r_shoulder_a1, &x, &y, &z);

        AddBox(&md2, c3, x, y, z, 
                md2.arm_rad * 2, -md2.arm_len / 2, md2.arm_rad * 2, 0, 0, 
                md2.r_shoulder_a2, 0, md2.r_elbow_a, &x, &y, &z);

        AddBox(&md2, c3, x, y, z, 
                md2.arm_rad * 2, -md2.hand_len, md2.hand_rad * 2, 0, 0, 
                md2.r_shoulder_a2, 0, md2.r_wrist_a, &x, &y, &z);

        //Left Arm
        AddBox(&md2, c1, md2.torso_width / 2 + md2.arm_rad, md2.torso_len - md2.arm_rad, 0, 
                md2.arm_rad * 2, -md2.arm_len / 2, md2.arm_rad * 2, md2.arm_rad, 0, 
                md2.l_shoulder_a2, 0, md2.l_shoulder_a1, &x, &y, &z);

        AddBox(&md2, c3, x, y, z, 
                md2.arm_rad * 2, -md2.arm_len / 2, md2.arm_rad * 2, 0, 0, 
                md2.l_shoulder_a2, 0, md2.l_elbow_a, &x, &y, &z);

        AddBox(&md2, c3, x, y, z, 
                md2.arm_rad * 2, -md2.hand_len, md2.hand_rad * 2, 0, 0, 
                md2.l_shoulder_a2, 0, md2.l_wrist_a, &x, &y, &z);

        //Right Leg
        AddBox(&md2, c2, -md2.torso_width / 2 + md2.leg_rad, 0, 0, 
                md2.leg_rad * 2, -md2.leg_len / 2, md2.leg_rad * 2, 0, 0, 
                md2.r_hip_a2, 0, md2.r_hip_a1, &x, &y, &z);

        AddBox(&md2, c3, x, y, z, 
                md2.leg_rad * 2, -md2.leg_len / 2, md2.leg_rad * 2, 0, md2.foot_rad, 
                md2.r_hip_a2, 0, md2.r_knee_a, &x, &y, &z);

        AddBox(&md2, c4, x, y, z, 
                md2.leg_rad * 2, -md2.foot_len, md2.foot_rad * 2, md2.leg_rad, 0, 
                md2.r_hip_a2, 0, md2.r_ankle_a, &x, &y, &z);

        //Left Leg
        AddBox(&md2, c2, md2.torso_width / 2 - md2.leg_rad, 0, 0, 
                md2.leg_rad * 2, -md2.leg_len / 2, md2.leg_rad * 2, 0, 0, 
                md2.l_hip_a2, 0, md2.l_hip_a1, &x, &y, &z);

        AddBox(&md2, c3, x, y, z, 
                md2.leg_rad * 2, -md2.leg_len / 2, md2.leg_rad * 2, 0, md2.foot_rad, 
                md2.l_hip_a2, 0, md2.l_knee_a, &x, &y, &z);

        AddBox(&md2, c4, x, y, z, 
                md2.leg_rad * 2, -md2.foot_len, md2.foot_rad * 2, md2.leg_rad, 0, 
                md2.l_hip_a2, 0, md2.l_ankle_a, &x, &y, &z);

        res = Man2CSprite;
        "%h7c", '\n';
        Sprite(res, "\t\t$SP,\"<1>\",BI=%d$");
        "%h7c", '\n';
        Free(m);
        "Do another";
        if (YorN)
            Free(res);
        else
            break;
    }
    return res;
}