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 >
C/C++ Source or Header  |  1995-02-15  |  15KB  |  420 lines

  1. /**********************************************************************
  2.  *
  3.  * File :     animate.c
  4.  *
  5.  * Abstract : Animation handler. This module is a general animation handler
  6.  *            that parses the .rwv files produced by the 3DS convertor
  7.  *            and attaches the frame data to the user data field of the
  8.  *            required clump(s).
  9.  *
  10.  **********************************************************************
  11.  *
  12.  * This file is a product of Criterion Software Ltd.
  13.  *
  14.  * This file is provided as is with no warranties of any kind and is
  15.  * provided without any obligation on Criterion Software Ltd. or
  16.  * Canon Inc. to assist in its use or modification.
  17.  *
  18.  * Criterion Software Ltd. will not, under any
  19.  * circumstances, be liable for any lost revenue or other damages arising
  20.  * from the use of this file.
  21.  *
  22.  * Copyright (c) 1995 Criterion Software Ltd.
  23.  * All Rights Reserved.
  24.  *
  25.  * RenderWare is a trademark of Canon Inc.
  26.  *
  27.  ************************************************************************/
  28.  
  29. /*--- Include Files ---*/
  30.  
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33. #include <string.h>
  34. #include <ctype.h>
  35.  
  36. #include "rwlib.h"
  37. #include "animate.h"
  38.  
  39. /*--- Type Definitions ---*/
  40.  
  41. /* TyFrame: This structure is attached to the user data field of each clump
  42.  * that is being animated. It contains an RwMatrix4d for each frame of the 
  43.  * animation.
  44.  */
  45.  
  46. typedef struct {
  47.     int frames;             /* Total number of frames of animation */
  48.     int current;            /* Current frame being animated */
  49.     RwMatrix4d **frame;     /* Array of matrices representing the frames */
  50. } TyFrame;
  51.  
  52.  
  53. /* The .rwv file contains 2 different tokens:
  54.  * 1. Frame <n> - defines the frame number for all subsequent tokens
  55.  * 2. Transform <tag> <float[12]> - defines the matrix representing the frame
  56.  *                                  and the clump that it will be attached to.
  57.  */
  58.  
  59. /* EnToken: Enumerated type defining the available token types */
  60.  
  61. typedef enum {
  62.     TK_NULL,
  63.     TK_FRAME,
  64.     TK_TRANSFORM,
  65. } EnToken;
  66.  
  67. /* TyTokTransform: contains the data for a Transform token */
  68.  
  69. typedef struct {
  70.     RwInt32     tag;
  71.     float       m[12];
  72. } TyTokTransform;
  73.  
  74. /* TyToken: A single global variable of this type is declared and 
  75.  * used when parsing the .rwv file.
  76.  */
  77. typedef struct {
  78.   union {
  79.     RwInt32        frame;
  80.     TyTokTransform transform;
  81.   } u;
  82. } TyToken;
  83.  
  84. static TyToken tok;
  85.  
  86. /************************************************************************
  87.  *
  88.  *      Function:       ReadInt()
  89.  *                      
  90.  *      Description:    Read an integer value from the input stream
  91.  *
  92.  *      Parameters:     stream - inupt file stream
  93.  *                      val - location to store the value read
  94.  *
  95.  *      Return Value:   0 on failure, any other value for success
  96.  *
  97.  ************************************************************************/
  98. static int
  99. ReadInt(FILE * stream, RwInt32 *val)
  100. {
  101.     char buffer[256];
  102.  
  103.     /* Read a single string from the input stream */
  104.     while (fscanf(stream, "%250s", buffer) == 1)
  105.     {
  106.         if (buffer[0] == '#')
  107.         {
  108.             /* Its a comment. Read to the end of line and ignore */ 
  109.             fgets(buffer, sizeof(buffer), stream);
  110.         }
  111.         else
  112.         {
  113.             /* Convert the string into an int value */
  114.             return(sscanf(buffer, "%d", val));
  115.         }
  116.     }
  117.     /* Error reading stream */
  118.     return(0);
  119. }
  120. /************************************************************************
  121.  *
  122.  *      Function:       ReadFloat()
  123.  *                      
  124.  *      Description:    Read a floating point value from the input stream
  125.  *
  126.  *      Parameters:     stream - inupt file stream
  127.  *                      val - location to store the value read
  128.  *
  129.  *      Return Value:   0 on failure, any other value for success
  130.  *
  131.  ************************************************************************/
  132. static int
  133. ReadFloat(FILE *stream, float *val)
  134. {
  135.     char buffer[256];
  136.  
  137.     /* Read a single string from the input stream */
  138.     while (fscanf(stream, "%250s", buffer) == 1)
  139.     {
  140.         if (buffer[0] == '#')
  141.         {
  142.             /* Its a comment. Read to the end of line and ignore */ 
  143.             fgets(buffer, sizeof(buffer), stream);
  144.         }
  145.         else
  146.         {
  147.             /* Convert the string into a float value */
  148.             return(sscanf(buffer, "%f", val));
  149.         }
  150.     }
  151.     /* Error reading stream */
  152.     return(0);
  153. }
  154. /************************************************************************
  155.  *
  156.  *      Function:       ReadString()
  157.  *                      
  158.  *      Description:    Read a string from the input stream
  159.  *
  160.  *      Parameters:     stream - inupt file stream
  161.  *                      string - location to store the value read
  162.  *
  163.  *      Return Value:   0 on failure, any other value for success
  164.  *
  165.  ************************************************************************/
  166. static int
  167. ReadString(FILE * stream, char *string)
  168. {
  169.     char buffer[256];
  170.  
  171.    /* Read a single string from the input stream */
  172.    while (fscanf(stream, "%250s", buffer) == 1)
  173.     {
  174.         if (buffer[0] == '#')
  175.         {
  176.             /* Its a comment. Read to the end of line and ignore */ 
  177.             fgets(buffer, sizeof(buffer), stream);
  178.         }
  179.         else
  180.         {
  181.             /* copy the string into the variable supplied */
  182.             strcpy(string, buffer);
  183.             return(1);
  184.         }
  185.     }
  186.     return(0);
  187. }
  188.  
  189. /************************************************************************
  190.  *
  191.  *      Function:       ReadToken()
  192.  *                      
  193.  *      Description:    Read a token from the input stream
  194.  *
  195.  *      Parameters:     stream - inupt file stream
  196.  *
  197.  *      Return Value:   returns the token type read. The global variable
  198.  *                      tok contains the token data
  199.  *
  200.  ************************************************************************/
  201. static EnToken 
  202. ReadToken(FILE *stream)
  203. {
  204.     char string[128];
  205.  
  206.     /* Read the next string from the input stream */
  207.     ReadString(stream, string);
  208.  
  209.     strlwr(string);
  210.  
  211.     /* Is it a frame keyword */
  212.     if (!strcmp(string, "frame"))
  213.     {
  214.         /* Yes. Read the frame number */
  215.         if (ReadInt(stream, &tok.u.frame))
  216.             return(TK_FRAME);
  217.     }
  218.  
  219.     /* Is it a transform keyword */
  220.     else if (!strcmp(string, "transform"))
  221.     {
  222.         /* Yes. Read the clump tag and the transform data */
  223.         if (ReadInt(stream, &tok.u.transform.tag) &&
  224.             ReadFloat(stream, &tok.u.transform.m[0]) &&
  225.             ReadFloat(stream, &tok.u.transform.m[1]) &&
  226.             ReadFloat(stream, &tok.u.transform.m[2]) &&
  227.             ReadFloat(stream, &tok.u.transform.m[3]) &&
  228.             ReadFloat(stream, &tok.u.transform.m[4]) &&
  229.             ReadFloat(stream, &tok.u.transform.m[5]) &&
  230.             ReadFloat(stream, &tok.u.transform.m[6]) &&
  231.             ReadFloat(stream, &tok.u.transform.m[7]) &&
  232.             ReadFloat(stream, &tok.u.transform.m[8]) &&
  233.             ReadFloat(stream, &tok.u.transform.m[9]) &&
  234.             ReadFloat(stream, &tok.u.transform.m[10]) &&
  235.             ReadFloat(stream, &tok.u.transform.m[11]))
  236.             return(TK_TRANSFORM);
  237.     }
  238.  
  239.     /* Couldn't read a valid toke so return error */
  240.     return (TK_NULL);
  241. }
  242.  
  243. /************************************************************************
  244.  *
  245.  *      Function:       LoadAnimation()
  246.  *                      
  247.  *      Description:    Load the animation from the specified .rwv file
  248.  *                      and attach it to the clump.
  249.  *
  250.  *      Parameters:     clump - the clump to attach the animation to. This
  251.  *                      will usually be the parent clump of a hierarchical
  252.  *                      model.
  253.  *                      filename - the name of the .rwv file to parse
  254.  *
  255.  *      Return Value:   returns TRUE on success otherwise FALSE
  256.  *
  257.  ************************************************************************/
  258. int 
  259. LoadAnimation(RwClump *clump, char *filename)
  260. {
  261.     int current_frame;
  262.     RwClump *active_clump;
  263.     TyFrame *frame;
  264.     FILE *fp;
  265.  
  266.     fp = fopen(filename, "r");
  267.     if (!fp) 
  268.     {
  269.         /* Can't open file - error */
  270.        return FALSE;
  271.     }
  272.  
  273.     /* Keep on reading until an error occurs or we reach the end of the file */
  274.  
  275.     for(;;)
  276.     {
  277.         /* Read a token fro the file */
  278.         switch (ReadToken(fp))
  279.         {
  280.             case TK_FRAME:
  281.                 /* Its a frame so define the current frame of animation */
  282.                 current_frame = tok.u.frame;
  283.                 break;
  284.             case TK_TRANSFORM:
  285.                 /* It's a transform. Find the clump to attach the transform to */
  286.                 active_clump = RwFindTaggedClump(clump, tok.u.transform.tag);
  287.                 if (active_clump)
  288.                 {
  289.                     /* Clump found. Allocate space for the frame */
  290.                     frame = RwGetClumpData(active_clump);
  291.                     if (!frame)
  292.                     {
  293.                             frame = malloc(sizeof(TyFrame));
  294.                             frame->frames = 1;
  295.                             frame->current = 0;
  296.                             frame->frame = malloc(sizeof(RwMatrix4d *));
  297.                             RwSetClumpData(active_clump, frame);
  298.                     }
  299.                     else
  300.                     {
  301.                             frame->frames = current_frame + 1;
  302.                             frame->frame = realloc(frame->frame, sizeof(RwMatrix4d *) * (current_frame + 1));
  303.                     }
  304.                     /* Create a RenderWare matrix and initialise it with the transform values */
  305.                     frame->frame[current_frame] = RwCreateMatrix();
  306.                     RwSetMatrixElement(frame->frame[current_frame], 0, 0, FL2REAL(tok.u.transform.m[0]));
  307.                     RwSetMatrixElement(frame->frame[current_frame], 0, 1, FL2REAL(tok.u.transform.m[1]));
  308.                     RwSetMatrixElement(frame->frame[current_frame], 0, 2, FL2REAL(tok.u.transform.m[2]));
  309.                     RwSetMatrixElement(frame->frame[current_frame], 0, 3, CREAL(0.0));
  310.                     RwSetMatrixElement(frame->frame[current_frame], 1, 0, FL2REAL(tok.u.transform.m[3]));
  311.                     RwSetMatrixElement(frame->frame[current_frame], 1, 1, FL2REAL(tok.u.transform.m[4]));
  312.                     RwSetMatrixElement(frame->frame[current_frame], 1, 2, FL2REAL(tok.u.transform.m[5]));
  313.                     RwSetMatrixElement(frame->frame[current_frame], 1, 3, CREAL(0.0));
  314.                     RwSetMatrixElement(frame->frame[current_frame], 2, 0, FL2REAL(tok.u.transform.m[6]));
  315.                     RwSetMatrixElement(frame->frame[current_frame], 2, 1, FL2REAL(tok.u.transform.m[7]));
  316.                     RwSetMatrixElement(frame->frame[current_frame], 2, 2, FL2REAL(tok.u.transform.m[8]));
  317.                     RwSetMatrixElement(frame->frame[current_frame], 2, 3, CREAL(0.0));
  318.                     RwSetMatrixElement(frame->frame[current_frame], 3, 0, FL2REAL(tok.u.transform.m[9]));
  319.                     RwSetMatrixElement(frame->frame[current_frame], 3, 1, FL2REAL(tok.u.transform.m[10]));
  320.                     RwSetMatrixElement(frame->frame[current_frame], 3, 2, FL2REAL(tok.u.transform.m[11]));
  321.                     RwSetMatrixElement(frame->frame[current_frame], 3, 3, CREAL(1.0));
  322.                 }
  323.                 break;
  324.             default:
  325.                 /* Not a valid token. Its probably the end of the file so just 
  326.                    shutup and return success */
  327.                 fclose(fp);
  328.                 return TRUE;
  329.          }
  330.     }
  331. }
  332.  
  333. /************************************************************************
  334.  *
  335.  *      Function:       DestroyCallback()
  336.  *                      
  337.  *      Description:    Function called for each clump in the hierarchy to 
  338.  *                      return all frame data back to the system.
  339.  *
  340.  *      Parameters:     clump - The clump to remove the frame data from.
  341.  *
  342.  *      Return Value:   returns the clump passed in 
  343.  *                      (required for RwForAllClumps...)
  344.  *
  345.  ************************************************************************/
  346. RwClump *DestroyCallback(RwClump *clump)
  347. {
  348.     TyFrame *frame;
  349.     int i;
  350.  
  351.     /* Retrieve the frame data for the clump and free it up if it exists */
  352.     frame = RwGetClumpData(clump);
  353.     if (frame)
  354.     {
  355.         if (frame->frame)
  356.         {
  357.             for (i = 0; i < frame->frames; i++)
  358.             {
  359.                 /* Destroy the RenderWare matrix objects */
  360.                 RwDestroyMatrix(frame->frame[i]);
  361.             }
  362.             free(frame->frame);
  363.         }
  364.         free(frame);
  365.     }
  366.     return(clump);
  367. }
  368.  
  369. /************************************************************************
  370.  *
  371.  *      Function:       DestroyAnimation()
  372.  *                      
  373.  *      Description:    Detach the animation data from a clump and
  374.  *                      return all allocated memory back to the system
  375.  *
  376.  *      Parameters:     clump - The clump to remove the frame data from.
  377.  *
  378.  *      Return Value:   None
  379.  *
  380.  ************************************************************************/
  381. void DestroyAnimation(RwClump *clump)
  382. {
  383.     RwForAllClumpsInHierarchy(clump, DestroyCallback);
  384. }
  385.  
  386. /************************************************************************
  387.  *
  388.  *      Function:       AnimateClump()
  389.  *                      
  390.  *      Description:    Animate the clump. For this example we just advance
  391.  *                      to the next frame of animation and cycle back to the
  392.  *                      start once we reach the end.
  393.  *
  394.  *      Parameters:     clump - The clump to advance.
  395.  *
  396.  *      Return Value:   the clump passed in. This allows the function to be
  397.  *                      called by RwForAllClumps... functions
  398.  *
  399.  ************************************************************************/
  400. RwClump *AnimateClump(RwClump *clump)
  401. {
  402.     TyFrame *clump_frame;
  403.     int current_frame;
  404.  
  405.     /* Get the frame data */
  406.     clump_frame = (TyFrame *)RwGetClumpData(clump);
  407.  
  408.     if (clump_frame)
  409.     {
  410.        /* We've got the frame data so advance the clump to the next frame */
  411.        current_frame = clump_frame->current % clump_frame->frames;
  412.        
  413.        /* And apply the transform to the clump */
  414.        RwTransformClump(clump, clump_frame->frame[current_frame], rwREPLACE);
  415.        clump_frame->current++;
  416.     }
  417.     return(clump);
  418. }
  419.  
  420.