/**********************************************************************
 *
 * File :     man.c
 *
 * Abstract : This is the module of the cyberstreet demo that handles 
 *            the animated figure seen walking in the pool room.
 *
 **********************************************************************
 *
 * This file is a product of Criterion Software Ltd.
 *
 * This file is provided as is with no warranties of any kind and is
 * provided without any obligation on Criterion Software Ltd. or
 * Canon Inc. to assist in its use or modification.
 *
 * Criterion Software Ltd. will not, under any
 * circumstances, be liable for any lost revenue or other damages arising
 * from the use of this file.
 *
 * Copyright (c) 1995 Criterion Software Ltd.
 * All Rights Reserved.
 *
 * RenderWare is a trademark of Canon Inc.
 *
 ************************************************************************/


/**********************************************************************
 *
 * Include Files
 *
 **********************************************************************/

/* Standard include files */

#include "global.h"
#include "animate.h"

/*--- Macros and Magic Number definitions */

#define MAN_HEIGHT      CREAL(0.12)  /* Absolute height to position the man's
                                        origin */

#define MAN_SCALE       CREAL(0.8)   /* Scale factor to apply to man */
#define MAN_RADIUS      CREAL(0.6)   /* Radius of circle that man walks 
                                        around */

#define MAN_CENTRE_X    CREAL(5.0)   /* Centre of circle */
#define MAN_CENTRE_Y    MAN_HEIGHT  
#define MAN_CENTRE_Z    CREAL(5.0)  

#define MAN_ROTATE      CREAL(3.0)   /* Man moves 3 degrees round circle 
                                        every frame */

/*--- Structure Definitions ---*/

/* Man: This structure defines the walking Man figure */

typedef struct 
{
    RwClump *cpMan;       /* The RenderWare clump object for the man */
    RwV3d vCentre;        /* The centre of the circle that the man walks 
                             around */
    RwMatrix4d *mpPos;    /* The absolute position matrix for the man */
    RwMatrix4d *mpRot;    /* The increment that is added to mpPos each 
                             frame */
} Man;

/*--- Global Variables ---*/

static Man mGMan;                /* The man in the Pool Room */

/*--- Function Definitions ---*/

/************************************************************************
 *
 *      Function:       ManSetup()
 *                      
 *      Description:    Initialise the global Man data structure
 *
 *      Return Value:   TRUE on success, FALSE on failure
 *
 ************************************************************************/
int ManSetup(void)
{
    /* Read the RenderWare script file */

    if (!(mGMan.cpMan = RwReadShape("chappy.rwx"))) 
    {
        /* Error - Failed to load RenderWare script file */
        return FALSE;
    }

    /* Add the man to the poolroom scene */

    RwAddClumpToScene(spGPoolScene, mGMan.cpMan);

    /* Load the animation data file */

    if (!(LoadAnimation(mGMan.cpMan, ".\\chappy.rwv"))) 
    {
        /* Error - failed to load animation */
        return FALSE;
    }

    /* Create the incremental rotation matrix. This matrix is postconcated
       to the absolute position matrix on each frame to advance the position
       of the man */

    if (!(mGMan.mpRot = RwCreateMatrix())) 
    {
        /* Error - failed to create RenderWare matrix object */
        return FALSE;
    }
    RwRotateMatrix(mGMan.mpRot, CREAL(0.0), CREAL(1.0), CREAL(0.0), 
                   MAN_ROTATE, rwREPLACE);


    if (!(mGMan.mpPos = RwCreateMatrix())) 
    {
        /* Error - failed to create RenderWare matrix object */
        return FALSE;
    }
    RwIdentityMatrix(mGMan.mpPos);

    mGMan.vCentre.x = MAN_CENTRE_X;
    mGMan.vCentre.y = MAN_CENTRE_Y;
    mGMan.vCentre.z = MAN_CENTRE_Z;

    return TRUE;
}

/************************************************************************
 *
 *      Function:       ManDestroy()
 *                      
 *      Description:    Destroy the global Man data structure
 *
 ************************************************************************/
void ManDestroy(void)
{
    DestroyAnimation(mGMan.cpMan);  /* Destroy animation data attached to 
                                       clump */
    RwDestroyClump(mGMan.cpMan);    /* Destroy RenderWare clump object */

    RwDestroyMatrix(mGMan.mpRot);     /* Destroy RenderWare matrices */
    RwDestroyMatrix(mGMan.mpPos);

}

/************************************************************************
 *
 *      Function:       ManUpdate()
 *                      
 *      Description:    Called every frame to update the mans position
 *
 ************************************************************************/
void ManUpdate(void)
{
    RwV3d vPos;

    /* Apply the next frame of animation */

    RwForAllClumpsInHierarchy(mGMan.cpMan, AnimateClump);

    /* Postconcat the incremental rotation onto the absolute position */

    RwTransformMatrix(mGMan.mpPos, mGMan.mpRot, rwPOSTCONCAT);

    /* Ensure the matrix stays orthonormal. */

    RwOrthoNormalizeMatrix(mGMan.mpPos, mGMan.mpPos);

    RwCopyMatrix(mGMan.mpPos, RwScratchMatrix());
    RwScaleMatrix(RwScratchMatrix(),
           MAN_SCALE, MAN_SCALE, MAN_SCALE, rwPOSTCONCAT);
    RwTransformClumpJoint(mGMan.cpMan, RwScratchMatrix(), rwREPLACE);

    /* Set up default radius vector */
    vPos.x = -MAN_RADIUS;
    vPos.y = CREAL(0.0);
    vPos.z = CREAL(0.0);

    /* Rotate the vector by the absolute rotation matrix */

    RwTransformVector(&vPos, mGMan.mpPos);

    /* and add the vector to the circle's centre to get the absolute
       position for the man */

    RwAddVector(&vPos, &mGMan.vCentre, &vPos);

    /* Build a translation matrix to move the Man to this position */

    RwTranslateMatrix(RwScratchMatrix(),
                      vPos.x, vPos.y, vPos.z,rwREPLACE);

    /* and apply the matrix to the Man's clump */    

    RwTransformClump(mGMan.cpMan, RwScratchMatrix(), rwREPLACE);
}

