home *** CD-ROM | disk | FTP | other *** search
/ Learn 3D Graphics Programming on the PC / Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso / rwwin / xbject.c_ / xbject.bin
Text File  |  1995-11-14  |  22KB  |  664 lines

  1. /**********************************************************************
  2.  *
  3.  * File :     object.c
  4.  *
  5.  * Abstract : An implementation of a "sub-class" of RenderWare clumps
  6.  *            which provides enhanced functionality such as binding a
  7.  *            light to a clump which acts as the visual representation
  8.  *            of a light and also stores the filename of the file from
  9.  *            which the clump was loaded.
  10.  *
  11.  *            This application had been written to be compatible with
  12.  *            both the fixed and floating-point versions of the
  13.  *            RenderWare library, i.e., it uses the macros CREAL,
  14.  *            INT2REAL, RAdd, RDiv, RSub etc. If your application is
  15.  *            intended for the floating-point version of the library
  16.  *            only these macros are not necessary.
  17.  *
  18.  *            Please note that this application is intended for
  19.  *            demonstration purposes only. No support will be
  20.  *            provided for this code and it comes with no warranty.
  21.  *
  22.  **********************************************************************
  23.  *
  24.  * This file is a product of Criterion Software Ltd.
  25.  *
  26.  * This file is provided as is with no warranties of any kind and is
  27.  * provided without any obligation on Criterion Software Ltd. or
  28.  * Canon Inc. to assist in its use or modification.
  29.  *
  30.  * Criterion Software Ltd. will not, under any
  31.  * circumstances, be liable for any lost revenue or other damages arising
  32.  * from the use of this file.
  33.  *
  34.  * Copyright (c) 1994, 1995 Criterion Software Ltd.
  35.  * All Rights Reserved.
  36.  *
  37.  * RenderWare is a trademark of Canon Inc.
  38.  *
  39.  **********************************************************************/
  40.  
  41. /**********************************************************************
  42.  *
  43.  * Comment:
  44.  *
  45.  * This code demonstrates the use of the user data pointer which is
  46.  * supported by most RenderWare objects. The user data pointer allows
  47.  * additional information to be stored with an object by setting the
  48.  * user data pointer to an application defined structure.
  49.  *
  50.  * The viewer manipulates two main kinds of RenderWare objects, clumps
  51.  * and lights. RenderWare lights are normally invisible but to make
  52.  * manipulation uniform between the two object types we create a clump
  53.  * to represent each light. We therefore need some mechanism to tie
  54.  * a light and the clump which represents it together (and vice-versa).
  55.  * This is one of the uses to which we put the user data to.
  56.  *
  57.  * Also, in order to give object's identifiable names and to allow us
  58.  * to save them under their original filenames we need to be able to
  59.  * store the filename of the file storing the clump. We also use the
  60.  * user-data field for this purpose.
  61.  *
  62.  * We define a structure which holds a filename string and a light
  63.  * object handle (which may be NULL if the clump does not represent
  64.  * a light). An instance of this structure is stored in the user
  65.  * data field of each clump. For lights, however, we simply store
  66.  * the handle of the clump representing the light directly in the
  67.  * user data field.
  68.  *
  69.  **********************************************************************/
  70.  
  71. /**********************************************************************
  72.  *
  73.  * Header files.
  74.  *
  75.  **********************************************************************/
  76.  
  77. /**********************************************************************
  78.  *
  79.  * Header files.
  80.  *
  81.  **********************************************************************/
  82.  
  83. #include <windows.h>
  84. #include <stdlib.h>
  85. #include <string.h>
  86.  
  87. #include <rwlib.h>
  88. #include <rwwin.h>
  89.  
  90. #include "common.h"
  91. #include "object.h"
  92.  
  93. /**********************************************************************
  94.  *
  95.  * Functions.
  96.  *
  97.  **********************************************************************/
  98.  
  99. /**********************************************************************/
  100.  
  101. /*
  102.  * Read a clump from the given file. This function creates and
  103.  * initializes the user data structure of the clump.
  104.  *
  105.  * RenderWare API Equivalent: RwReadShape()
  106.  */
  107. RwClump *
  108. ReadClumpObj(char *fileName)
  109. {
  110.     ClumpUserData *userData;
  111.     RwClump       *clump;
  112.  
  113.     /*
  114.      * Allocate the user data for the new clump.
  115.      */
  116.     userData = (ClumpUserData *)malloc(sizeof(ClumpUserData));
  117.     if (userData == NULL)
  118.         return NULL;
  119.         
  120.     /*
  121.      * Read the clump.
  122.      */
  123.     clump = RwReadShape(fileName);
  124.     
  125.     /*
  126.      * If all went well then intialize the user data pointer and attach
  127.      * it to the clump.
  128.      */
  129.     if (clump == NULL)
  130.     {
  131.         free((void *)userData);
  132.         return NULL;
  133.     }
  134.     else
  135.     {
  136.         /*
  137.          * This clump does not represent a light.
  138.          */
  139.         userData->light = NULL;
  140.         userData->datatype = rfIsClump;
  141.         strcpy(userData->fileName, fileName);
  142.         RwSetClumpData(clump, (void *)userData);
  143.         return clump;
  144.     }
  145. }
  146.  
  147. /**********************************************************************/
  148.  
  149. /*
  150.  * Create a sprite from the bitmap contained in the given file.
  151.  *
  152.  * RenderWare API Equivalent: RwCreateSprite()
  153.  */
  154. RwClump *CreateSpriteObj(char *fileName)
  155. {
  156.     ClumpUserData *userData;
  157.     RwClump       *clump;
  158.  
  159.     /*
  160.      * Allocate the user data for the new clump.
  161.      */
  162.     userData = (ClumpUserData *)malloc(sizeof(ClumpUserData));
  163.     if (userData == NULL)
  164.         return NULL;
  165.         
  166.     /*
  167.      * Read the clump.
  168.      */
  169.     clump = RwCreateSprite(RwGetNamedTexture(fileName));
  170.     
  171.     /*
  172.      * If all went well then intialize the user data pointer and attach
  173.      * it to the clump.
  174.      */
  175.     if (clump == NULL)
  176.     {
  177.         free((void *)userData);
  178.         return NULL;
  179.     }
  180.     else
  181.     {
  182.         /*
  183.          * This clump does not represent a light.
  184.          */
  185.         userData->light = NULL;
  186.         userData->datatype = rfIsSprite;
  187.         strcpy(userData->fileName, fileName);
  188.         RwSetClumpData(clump, (void *)userData);
  189.         return clump;
  190.     }
  191. }
  192.  
  193. /**********************************************************************/
  194.  
  195. /*
  196.  * Create a light of the given type. A clump is built which represents
  197.  * this light and is attached to the user data field of the light.
  198.  *
  199.  * NOTE: We return a pointer to the clump build rather than the light
  200.  * as clump's are the main object type of the viewer.
  201.  *
  202.  * RenderWare API Equivalent: RwCreateLight()
  203.  */
  204. RwLight *
  205. CreateLightObj(RwLightType kind)
  206. {
  207.     ClumpUserData *userData;
  208.     RwLight       *light;
  209.     RwClump       *clump;
  210.     
  211.     /*
  212.      * Allocate the user data for the new clump.
  213.      */
  214.     userData = (ClumpUserData *)malloc(sizeof(ClumpUserData));
  215.     if (userData == NULL)
  216.         return NULL;
  217.         
  218.     /*
  219.      * Create the RenderWare light. The supplied vector is just a dummy
  220.      * as it will be overwritten when we copy the clump's matrix to the
  221.      * light.
  222.      */
  223.     light = RwCreateLight(kind, CREAL(0.0), CREAL(0.0), CREAL(1.0),
  224.                           CREAL(1.0));
  225.     if (light == NULL)
  226.     {
  227.         free((void *)userData);
  228.         return NULL;
  229.     }
  230.     
  231.     /*
  232.      * Build the clump. For each light type the clump is unshaded, white
  233.      * wireframe so there surface conditions are set up globally.
  234.      */
  235.     RwModelBegin();
  236.         RwClumpBegin();
  237.             /*
  238.              * We don't want the lights to take part in shading (it would
  239.              * look strange if lights illuminated themselves) so we turn
  240.              * of shading by setting diffuse and specular reflection to
  241.              * CREAL(0.0) and we ensure a nice bright white by setting
  242.              * ambient to CREAL(1.0).
  243.              */
  244.             //RwSetSurface(CREAL(1.0), CREAL(0.0), CREAL(0.0));
  245.             RwSetSurface(CREAL(0.0), CREAL(0.0), CREAL(0.0));
  246.             RwSetSurfaceColor(CREAL(1.0), CREAL(1.0), CREAL(1.0));
  247.             RwSetSurfaceGeometrySampling(rwWIREFRAME);
  248.             
  249.             /*
  250.              * The RenderWare geometric primitives are designed to be
  251.              * oriented up the Y axis by default. Here, however, we
  252.              * want them point down the Z axis as the clump's local
  253.              * Z axis will be same as the light's direction. So the
  254.              * first thing we do is perform a rotation around X of
  255.              * CREAL(90.0).
  256.              */     
  257.             RwRotateCTM(CREAL(1.0), CREAL(0.0), CREAL(0.0), CREAL(90.0));
  258.  
  259.             switch (kind)
  260.             {
  261.                 case rwDIRECTIONAL:
  262.                     /*
  263.                      * The directional light is represented as a 3D
  264.                      * arrow built from a cone and a cylinder. We want
  265.                      * the tip of the arrow to be the origin of the
  266.                      * clump (the point about which we will rotate the
  267.                      * clump) so we translate down and build the arrow
  268.                      * so the tip of the cone is at the origin of local
  269.                      * space.
  270.                      */
  271.                     RwTranslateCTM(CREAL(0.0), CREAL(-0.4), CREAL(0.0));
  272.                     
  273.                     /*
  274.                      * The arrow head.
  275.                      */
  276.                     RwCone(CREAL(0.4), CREAL(0.2), 12);
  277.                     
  278.                     /*
  279.                      * We want to cap the cone. Rather than using a disc
  280.                      * we will use a cylinder of zero height. This is 
  281.                      * a useful trick for building a circle with a hole
  282.                      * in it.
  283.                      */
  284.                     RwCylinder(CREAL(0.0), CREAL(0.1), CREAL(0.2), 12);
  285.                     
  286.                     /*
  287.                      * The shaft of the arrow.
  288.                      */
  289.                     RwTranslateCTM(CREAL(0.0), CREAL(-0.4), CREAL(0.0));
  290.                     RwCylinder(CREAL(0.4), CREAL(0.1), CREAL(0.1), 12);
  291.                     
  292.                     /*
  293.                      * Cap the shaft of the arrow with a disc. The negative
  294.                      * radius looks a little odd but this is a good trick for
  295.                      * flipping the polygons to point the other way, i.e., 
  296.                      * to make the polygons point down rather than up.
  297.                      */
  298.                     RwDisc(CREAL(0.0), CREAL(-0.1), 12);
  299.                     
  300.                     break;
  301.                     
  302.                 case rwPOINT:
  303.                     /*
  304.                      * A point light source is represented as a simple
  305.                      * sphere. The origin of the sphere is the position
  306.                      * of the light.
  307.                      */
  308.                     RwSphere(CREAL(0.2), 3);
  309.                     
  310.                     break;
  311.                     
  312.                 case rwCONICAL:
  313.                     /*
  314.                      * A conical light source is represented as an inverse
  315.                      * cone. The sharp end points in the opposite direction
  316.                      * from the light vector. The tip of the cone is also the
  317.                      * position of the light.The normal orientation of a cone
  318.                      * is to have the base at the bottom and the tip at the
  319.                      * top (in Y). We want the base at the top and the tip
  320.                      * pointing down so we rotate everything 180 degrees about
  321.                      * X before building the code.
  322.                      */
  323.                     RwRotateCTM(CREAL(1.0), CREAL(0.0), CREAL(0.0), CREAL(180.0));
  324.                     RwCone(CREAL(0.4), CREAL(0.2), 12);
  325.                     
  326.                     /*
  327.                      * Cap the cone with a disc. The negative radius looks a
  328.                      * little odd but this is a good trick for flipping the
  329.                      * polygons to point the other way, i.e., to make the
  330.                      * polygons point down rather than up
  331.                      */
  332.                     RwDisc(CREAL(0.0), CREAL(-0.2), 12);
  333.                     
  334.                     break;
  335.             }
  336.         
  337.         RwClumpEnd(&clump);
  338.     RwModelEnd();
  339.     
  340.     if (clump == NULL)
  341.     {
  342.         /*
  343.          * If the clump failed for any reason cleanup and exit with
  344.          * failure.
  345.          */
  346.         free((void *)userData);
  347.         RwDestroyLight(light);
  348.         return NULL;
  349.     }
  350.     else
  351.     {
  352.         /*
  353.          * Initialize the user data field of the clump and attach it.
  354.          * This clump has no filename as it has not been loaded from
  355.          * a file.
  356.          */
  357.         userData->fileName[0] = '\0';
  358.         userData->light       = light;
  359.         userData->datatype    = rfIsLight;
  360.         RwSetClumpData(clump, (void *)userData);
  361.         
  362.         /*
  363.          * Attach the back pointer from the light to the clump.
  364.          */
  365.         RwSetLightData(light, (void *)clump);
  366.         
  367.         RwPushScratchMatrix();
  368.             /*
  369.              * Move the clump to the default position.
  370.              */
  371.             RwTranslateMatrix(RwScratchMatrix(),
  372.                               CREAL(1.0), CREAL(1.0), CREAL(1.0), rwREPLACE);
  373.             RwTransformClump(clump, RwScratchMatrix(), rwREPLACE);
  374.             RwRotateMatrix(RwScratchMatrix(), CREAL(0.0), CREAL(1.0), CREAL(0.0),
  375.                            CREAL(225.0), rwREPLACE);
  376.             RwRotateMatrix(RwScratchMatrix(), CREAL(1.0), CREAL(0.0), CREAL(0.0),
  377.                            CREAL(-45.0), rwPOSTCONCAT);
  378.             RwTransformClumpJoint(clump, RwScratchMatrix(), rwREPLACE);
  379.             RwGetClumpLTM(clump, RwScratchMatrix());
  380.     
  381.             /*
  382.              * Make the position and/or orientation of the light match the
  383.              * clump.
  384.              */
  385.             RwTransformLight(light, RwScratchMatrix(), rwREPLACE);
  386.         RwPopScratchMatrix();
  387.     
  388.         return light;
  389.     }
  390. }
  391.  
  392. /**********************************************************************/
  393.  
  394. /*
  395.  * Duplicate the given clump object and its associated light (if it has
  396.  * one).
  397.  *
  398.  * RenderWare API Equivalent: RwDuplicateClump(), RwDuplicateLight().
  399.  */
  400. RwClump *
  401. DuplicateClumpObj(RwClump *clump)
  402. {
  403.     ClumpUserData *userData;
  404.     ClumpUserData *newUserData;
  405.     RwClump       *newClump;
  406.     RwLight       *light;
  407.     RwLight       *newLight;
  408.     
  409.     /*
  410.      * Allocate the user data for the new clump.
  411.      */
  412.     newUserData = (ClumpUserData *)malloc(sizeof(ClumpUserData));
  413.     if (newUserData == NULL)
  414.         return NULL;
  415.         
  416.     /*
  417.      * Duplicate the clump.
  418.      */
  419.     newClump = RwDuplicateClump(clump);
  420.     if (newClump == NULL)
  421.     {
  422.         free((void *)newUserData);
  423.         return NULL;
  424.     }
  425.  
  426.     if (ISCLUMPLIGHT(clump))
  427.     {
  428.         /*
  429.          * The original clump represents a light so get the source
  430.          * light and duplicate it.
  431.          */
  432.         light = GETCLUMPLIGHT(clump);
  433.         newLight = RwDuplicateLight(light);
  434.         if (light != NULL)
  435.         {
  436.             /*
  437.              * Initialize the user data and attach it to the clump.
  438.              */
  439.             newUserData->fileName[0] = '\0';
  440.             newUserData->light = newLight;
  441.             newUserData->datatype = rfIsLight;
  442.             RwSetClumpData(newClump, (void *)newUserData);
  443.             
  444.             /*
  445.              * Set the back pointer from the light to the clump.
  446.              */
  447.             RwSetLightData(newLight, (void *)newClump);
  448.             
  449.             return newClump;
  450.         }
  451.         else
  452.         {
  453.             RwDestroyClump(clump);
  454.             free((void *)newUserData);
  455.             return NULL;
  456.         }
  457.     }
  458.     else
  459.     {
  460.         /*
  461.          * The clump does not represent a light so simply copy
  462.          * the filename across and set the user data.
  463.          */
  464.         userData = GETCLUMPUSERDATA(clump);
  465.         strcpy(newUserData->fileName, userData->fileName);
  466.         newUserData->light = NULL;
  467.         newUserData->datatype = rfIsClump;
  468.         RwSetClumpData(newClump, (void *)newUserData);
  469.         
  470.         return newClump;
  471.     }    
  472. }
  473.  
  474. /**********************************************************************/
  475.  
  476. /*
  477.  * Add a clump object to the given scene. This function will also add the
  478.  * light object to the scene if the the clump represents a light.
  479.  *
  480.  * RenderWare API Equivalent: RwAddClumpToScene(), RwAddLightToScene().
  481.  */
  482. RwScene *
  483. AddClumpObjToScene(RwScene *scene, RwClump *clump)
  484. {
  485.     /*
  486.      * Add the clump to the scene.
  487.      */
  488.     RwAddClumpToScene(scene, clump);
  489.     
  490.     if (ISCLUMPLIGHT(clump))
  491.     {    
  492.         /*
  493.          * If this clump represents a light then add the light to the
  494.          * scene also.
  495.          */
  496.         RwAddLightToScene(scene, GETCLUMPLIGHT(clump));
  497.     }
  498.     
  499.     return scene;
  500. }
  501.  
  502. /**********************************************************************/
  503.  
  504. /*
  505.  * Add a light object to the given scene. This function will also add the
  506.  * clump object representing a light to the scene.
  507.  *
  508.  * RenderWare API Equivalent: RwAddLightToScene(), RwAddClumpToScene().
  509.  */
  510. RwScene *
  511. AddLightObjToScene(RwScene *scene, RwLight *light)
  512. {
  513.     RwClump *clump;
  514.     
  515.     /*
  516.      * Get the clump which represents this light.
  517.      */
  518.     clump = GETLIGHTCLUMP(light);
  519.     
  520.     /*
  521.      * Add both objects to the scene.
  522.      */
  523.     RwAddLightToScene(scene, light);
  524.     RwAddClumpToScene(scene, clump);
  525.     
  526.     return scene;
  527. }
  528.  
  529. /**********************************************************************/
  530.  
  531. /*
  532.  * Set the brightness of the given light object. This function also
  533.  * updates the visual appearance of the clump object representing the
  534.  * light to reflect the new brightness.
  535.  *
  536.  * RenderWare API Equivalent: RwSetLightBrightness().
  537.  */
  538. RwLight *
  539. SetLightObjBrightness(RwLight *light, RwReal bright)
  540. {
  541.     RwClump *clump;
  542.  
  543.     /*
  544.      * Set the brightness of the light.
  545.      */
  546.     RwSetLightBrightness(light, bright);
  547.  
  548.     /*
  549.      * Update the materials of the associated clump to reflect the new
  550.      * brightness.
  551.      */
  552.     clump = GETLIGHTCLUMP(light);
  553.     RwPushCurrentMaterial();
  554.         RwSetMaterialSurface(RwCurrentMaterial(), bright, CREAL(0.0), CREAL(0.0));
  555.         RwSetMaterialColor(RwCurrentMaterial(), CREAL(1.0), CREAL(1.0), CREAL(1.0));
  556.         RwSetMaterialGeometrySampling(RwCurrentMaterial(), rwWIREFRAME);
  557.         RwForAllPolygonsInClumpPointer(clump, (RwPolygon3dFuncPointer)RwSetPolygonMaterial,
  558.                                        RwCurrentMaterial());
  559.     RwPopCurrentMaterial();
  560.     
  561.     return light;
  562. }
  563.  
  564. /**********************************************************************/
  565.  
  566. /*
  567.  * Set the color of the given light object. This function also
  568.  * updates the visual appearance of the clump object representing the
  569.  * light to reflect the new color.
  570.  *
  571.  * RenderWare API Equivalent: RwSetLightColor().
  572.  */
  573. RwLight *
  574. SetLightObjColor(RwLight *light, RwReal r, RwReal g, RwReal b)
  575. {
  576.     RwClump *clump;
  577.  
  578.     /*
  579.      * Set the color of the light.
  580.      */
  581.     RwSetLightColor(light, r, g, b);
  582.  
  583.     /*
  584.      * Update the materials of the associated clump to reflect the new
  585.      * brightness.
  586.      */
  587.     clump = GETLIGHTCLUMP(light);
  588.     RwPushCurrentMaterial();
  589.         RwSetMaterialSurface(RwCurrentMaterial(), CREAL(0.70), CREAL(0.0), CREAL(0.0));
  590.         RwSetMaterialColor(RwCurrentMaterial(), r, g, b);
  591.         RwSetMaterialGeometrySampling(RwCurrentMaterial(), rwWIREFRAME);
  592.         RwForAllPolygonsInClumpPointer(clump, (RwPolygon3dFuncPointer)RwSetPolygonMaterial,
  593.                                        RwCurrentMaterial());
  594.     RwPopCurrentMaterial();
  595.     
  596.     return light;
  597. }
  598.  
  599. /**********************************************************************/
  600.  
  601. /*
  602.  * Turn the clump which is the visible representation of a light on or off.
  603.  * This function does not turn the light itself on or off, it only
  604.  * shows or hides the visible representation of that light.
  605.  *
  606.  * RenderWare API Equivalent: RwSetClumpState().
  607.  */
  608. RwLight *
  609. SetLightObjVisibleState(RwLight *light, RwState state)
  610. {
  611.     RwSetClumpState(GETLIGHTCLUMP(light), state);
  612.     
  613.     return light;
  614. }
  615.  
  616. /**********************************************************************/
  617.  
  618. /*
  619.  * Destory the given clump object (and its associated light if it has
  620.  * one). This function will also free the user data structure allocated
  621.  * for the clump.
  622.  *
  623.  * RenderWare API Equivalent: RwDestoryClump()
  624.  */
  625. void
  626. DestroyClumpObj(RwClump *clump)
  627. {
  628.     ClumpUserData *userData;
  629.     
  630.     /*
  631.      * If this clump is a root clump and it is the representation
  632.      * of a light then we must destory the associated light and
  633.      * the user data. Otherwise all we need to do is to destroy
  634.      * the clump itself.
  635.      */
  636.     if (RwGetClumpParent(clump) == NULL)
  637.     { 
  638.         userData = GETCLUMPUSERDATA(clump);
  639.         if (userData != NULL)
  640.         {
  641.             if (userData->light != NULL)
  642.             {
  643.                 /*
  644.                  * If this clump represents a light blow the associated
  645.                  * light away.
  646.                  */
  647.                 RwDestroyLight(userData->light);
  648.             }
  649.  
  650.             /*
  651.              * Free the user data.
  652.              */
  653.             free((void *)userData);
  654.         }
  655.     }
  656.     
  657.     /*
  658.      * Blow the clump away...
  659.      */
  660.     RwDestroyClump(clump);
  661. }
  662.  
  663. /**********************************************************************/
  664.