home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Learn 3D Graphics Programming on the PC
/
Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso
/
rwdos
/
animate.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-15
|
15KB
|
420 lines
/**********************************************************************
*
* File : animate.c
*
* Abstract : Animation handler. This module is a general animation handler
* that parses the .rwv files produced by the 3DS convertor
* and attaches the frame data to the user data field of the
* required clump(s).
*
**********************************************************************
*
* 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 ---*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "rwlib.h"
#include "animate.h"
/*--- Type Definitions ---*/
/* TyFrame: This structure is attached to the user data field of each clump
* that is being animated. It contains an RwMatrix4d for each frame of the
* animation.
*/
typedef struct {
int frames; /* Total number of frames of animation */
int current; /* Current frame being animated */
RwMatrix4d **frame; /* Array of matrices representing the frames */
} TyFrame;
/* The .rwv file contains 2 different tokens:
* 1. Frame <n> - defines the frame number for all subsequent tokens
* 2. Transform <tag> <float[12]> - defines the matrix representing the frame
* and the clump that it will be attached to.
*/
/* EnToken: Enumerated type defining the available token types */
typedef enum {
TK_NULL,
TK_FRAME,
TK_TRANSFORM,
} EnToken;
/* TyTokTransform: contains the data for a Transform token */
typedef struct {
RwInt32 tag;
float m[12];
} TyTokTransform;
/* TyToken: A single global variable of this type is declared and
* used when parsing the .rwv file.
*/
typedef struct {
union {
RwInt32 frame;
TyTokTransform transform;
} u;
} TyToken;
static TyToken tok;
/************************************************************************
*
* Function: ReadInt()
*
* Description: Read an integer value from the input stream
*
* Parameters: stream - inupt file stream
* val - location to store the value read
*
* Return Value: 0 on failure, any other value for success
*
************************************************************************/
static int
ReadInt(FILE * stream, RwInt32 *val)
{
char buffer[256];
/* Read a single string from the input stream */
while (fscanf(stream, "%250s", buffer) == 1)
{
if (buffer[0] == '#')
{
/* Its a comment. Read to the end of line and ignore */
fgets(buffer, sizeof(buffer), stream);
}
else
{
/* Convert the string into an int value */
return(sscanf(buffer, "%d", val));
}
}
/* Error reading stream */
return(0);
}
/************************************************************************
*
* Function: ReadFloat()
*
* Description: Read a floating point value from the input stream
*
* Parameters: stream - inupt file stream
* val - location to store the value read
*
* Return Value: 0 on failure, any other value for success
*
************************************************************************/
static int
ReadFloat(FILE *stream, float *val)
{
char buffer[256];
/* Read a single string from the input stream */
while (fscanf(stream, "%250s", buffer) == 1)
{
if (buffer[0] == '#')
{
/* Its a comment. Read to the end of line and ignore */
fgets(buffer, sizeof(buffer), stream);
}
else
{
/* Convert the string into a float value */
return(sscanf(buffer, "%f", val));
}
}
/* Error reading stream */
return(0);
}
/************************************************************************
*
* Function: ReadString()
*
* Description: Read a string from the input stream
*
* Parameters: stream - inupt file stream
* string - location to store the value read
*
* Return Value: 0 on failure, any other value for success
*
************************************************************************/
static int
ReadString(FILE * stream, char *string)
{
char buffer[256];
/* Read a single string from the input stream */
while (fscanf(stream, "%250s", buffer) == 1)
{
if (buffer[0] == '#')
{
/* Its a comment. Read to the end of line and ignore */
fgets(buffer, sizeof(buffer), stream);
}
else
{
/* copy the string into the variable supplied */
strcpy(string, buffer);
return(1);
}
}
return(0);
}
/************************************************************************
*
* Function: ReadToken()
*
* Description: Read a token from the input stream
*
* Parameters: stream - inupt file stream
*
* Return Value: returns the token type read. The global variable
* tok contains the token data
*
************************************************************************/
static EnToken
ReadToken(FILE *stream)
{
char string[128];
/* Read the next string from the input stream */
ReadString(stream, string);
strlwr(string);
/* Is it a frame keyword */
if (!strcmp(string, "frame"))
{
/* Yes. Read the frame number */
if (ReadInt(stream, &tok.u.frame))
return(TK_FRAME);
}
/* Is it a transform keyword */
else if (!strcmp(string, "transform"))
{
/* Yes. Read the clump tag and the transform data */
if (ReadInt(stream, &tok.u.transform.tag) &&
ReadFloat(stream, &tok.u.transform.m[0]) &&
ReadFloat(stream, &tok.u.transform.m[1]) &&
ReadFloat(stream, &tok.u.transform.m[2]) &&
ReadFloat(stream, &tok.u.transform.m[3]) &&
ReadFloat(stream, &tok.u.transform.m[4]) &&
ReadFloat(stream, &tok.u.transform.m[5]) &&
ReadFloat(stream, &tok.u.transform.m[6]) &&
ReadFloat(stream, &tok.u.transform.m[7]) &&
ReadFloat(stream, &tok.u.transform.m[8]) &&
ReadFloat(stream, &tok.u.transform.m[9]) &&
ReadFloat(stream, &tok.u.transform.m[10]) &&
ReadFloat(stream, &tok.u.transform.m[11]))
return(TK_TRANSFORM);
}
/* Couldn't read a valid toke so return error */
return (TK_NULL);
}
/************************************************************************
*
* Function: LoadAnimation()
*
* Description: Load the animation from the specified .rwv file
* and attach it to the clump.
*
* Parameters: clump - the clump to attach the animation to. This
* will usually be the parent clump of a hierarchical
* model.
* filename - the name of the .rwv file to parse
*
* Return Value: returns TRUE on success otherwise FALSE
*
************************************************************************/
int
LoadAnimation(RwClump *clump, char *filename)
{
int current_frame;
RwClump *active_clump;
TyFrame *frame;
FILE *fp;
fp = fopen(filename, "r");
if (!fp)
{
/* Can't open file - error */
return FALSE;
}
/* Keep on reading until an error occurs or we reach the end of the file */
for(;;)
{
/* Read a token fro the file */
switch (ReadToken(fp))
{
case TK_FRAME:
/* Its a frame so define the current frame of animation */
current_frame = tok.u.frame;
break;
case TK_TRANSFORM:
/* It's a transform. Find the clump to attach the transform to */
active_clump = RwFindTaggedClump(clump, tok.u.transform.tag);
if (active_clump)
{
/* Clump found. Allocate space for the frame */
frame = RwGetClumpData(active_clump);
if (!frame)
{
frame = malloc(sizeof(TyFrame));
frame->frames = 1;
frame->current = 0;
frame->frame = malloc(sizeof(RwMatrix4d *));
RwSetClumpData(active_clump, frame);
}
else
{
frame->frames = current_frame + 1;
frame->frame = realloc(frame->frame, sizeof(RwMatrix4d *) * (current_frame + 1));
}
/* Create a RenderWare matrix and initialise it with the transform values */
frame->frame[current_frame] = RwCreateMatrix();
RwSetMatrixElement(frame->frame[current_frame], 0, 0, FL2REAL(tok.u.transform.m[0]));
RwSetMatrixElement(frame->frame[current_frame], 0, 1, FL2REAL(tok.u.transform.m[1]));
RwSetMatrixElement(frame->frame[current_frame], 0, 2, FL2REAL(tok.u.transform.m[2]));
RwSetMatrixElement(frame->frame[current_frame], 0, 3, CREAL(0.0));
RwSetMatrixElement(frame->frame[current_frame], 1, 0, FL2REAL(tok.u.transform.m[3]));
RwSetMatrixElement(frame->frame[current_frame], 1, 1, FL2REAL(tok.u.transform.m[4]));
RwSetMatrixElement(frame->frame[current_frame], 1, 2, FL2REAL(tok.u.transform.m[5]));
RwSetMatrixElement(frame->frame[current_frame], 1, 3, CREAL(0.0));
RwSetMatrixElement(frame->frame[current_frame], 2, 0, FL2REAL(tok.u.transform.m[6]));
RwSetMatrixElement(frame->frame[current_frame], 2, 1, FL2REAL(tok.u.transform.m[7]));
RwSetMatrixElement(frame->frame[current_frame], 2, 2, FL2REAL(tok.u.transform.m[8]));
RwSetMatrixElement(frame->frame[current_frame], 2, 3, CREAL(0.0));
RwSetMatrixElement(frame->frame[current_frame], 3, 0, FL2REAL(tok.u.transform.m[9]));
RwSetMatrixElement(frame->frame[current_frame], 3, 1, FL2REAL(tok.u.transform.m[10]));
RwSetMatrixElement(frame->frame[current_frame], 3, 2, FL2REAL(tok.u.transform.m[11]));
RwSetMatrixElement(frame->frame[current_frame], 3, 3, CREAL(1.0));
}
break;
default:
/* Not a valid token. Its probably the end of the file so just
shutup and return success */
fclose(fp);
return TRUE;
}
}
}
/************************************************************************
*
* Function: DestroyCallback()
*
* Description: Function called for each clump in the hierarchy to
* return all frame data back to the system.
*
* Parameters: clump - The clump to remove the frame data from.
*
* Return Value: returns the clump passed in
* (required for RwForAllClumps...)
*
************************************************************************/
RwClump *DestroyCallback(RwClump *clump)
{
TyFrame *frame;
int i;
/* Retrieve the frame data for the clump and free it up if it exists */
frame = RwGetClumpData(clump);
if (frame)
{
if (frame->frame)
{
for (i = 0; i < frame->frames; i++)
{
/* Destroy the RenderWare matrix objects */
RwDestroyMatrix(frame->frame[i]);
}
free(frame->frame);
}
free(frame);
}
return(clump);
}
/************************************************************************
*
* Function: DestroyAnimation()
*
* Description: Detach the animation data from a clump and
* return all allocated memory back to the system
*
* Parameters: clump - The clump to remove the frame data from.
*
* Return Value: None
*
************************************************************************/
void DestroyAnimation(RwClump *clump)
{
RwForAllClumpsInHierarchy(clump, DestroyCallback);
}
/************************************************************************
*
* Function: AnimateClump()
*
* Description: Animate the clump. For this example we just advance
* to the next frame of animation and cycle back to the
* start once we reach the end.
*
* Parameters: clump - The clump to advance.
*
* Return Value: the clump passed in. This allows the function to be
* called by RwForAllClumps... functions
*
************************************************************************/
RwClump *AnimateClump(RwClump *clump)
{
TyFrame *clump_frame;
int current_frame;
/* Get the frame data */
clump_frame = (TyFrame *)RwGetClumpData(clump);
if (clump_frame)
{
/* We've got the frame data so advance the clump to the next frame */
current_frame = clump_frame->current % clump_frame->frames;
/* And apply the transform to the clump */
RwTransformClump(clump, clump_frame->frame[current_frame], rwREPLACE);
clump_frame->current++;
}
return(clump);
}