//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;
}