home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Learn 3D Graphics Programming on the PC
/
Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso
/
rwwin
/
object.c1_
/
object.bin
Wrap
Text File
|
1995-11-14
|
20KB
|
613 lines
/**********************************************************************
*
* File : object.c
*
* Abstract : An implementation of a "sub-class" of RenderWare clumps
* which provides enhanced functionality such as binding a
* light to a clump which acts as the visual representation
* of a light and also stores the filename of the file from
* which the clump was loaded.
*
* This application had been written to be compatible with
* both the fixed and floating-point versions of the
* RenderWare library, i.e., it uses the macros CREAL,
* INT2REAL, RAdd, RDiv, RSub etc. If your application is
* intended for the floating-point version of the library
* only these macros are not necessary.
*
* Please note that this application is intended for
* demonstration purposes only. No support will be
* provided for this code and it comes with no warranty.
*
**********************************************************************
*
* 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) 1994, 1995 Criterion Software Ltd.
* All Rights Reserved.
*
* RenderWare is a trademark of Canon Inc.
*
**********************************************************************/
/**********************************************************************
*
* Comment:
*
* This code demonstrates the use of the user data pointer which is
* supported by most RenderWare objects. The user data pointer allows
* additional information to be stored with an object by setting the
* user data pointer to an application defined structure.
*
* The viewer manipulates two main kinds of RenderWare objects, clumps
* and lights. RenderWare lights are normally invisible but to make
* manipulation uniform between the two object types we create a clump
* to represent each light. We therefore need some mechanism to tie
* a light and the clump which represents it together (and vice-versa).
* This is one of the uses to which we put the user data to.
*
* Also, in order to give object's identifiable names and to allow us
* to save them under their original filenames we need to be able to
* store the filename of the file storing the clump. We also use the
* user-data field for this purpose.
*
* We define a structure which holds a filename string and a light
* object handle (which may be NULL if the clump does not represent
* a light). An instance of this structure is stored in the user
* data field of each clump. For lights, however, we simply store
* the handle of the clump representing the light directly in the
* user data field.
*
**********************************************************************/
/**********************************************************************
*
* Header files.
*
**********************************************************************/
/**********************************************************************
*
* Header files.
*
**********************************************************************/
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <rwlib.h>
#include <rwwin.h>
#include "common.h"
#include "object.h"
/**********************************************************************
*
* Functions.
*
**********************************************************************/
/**********************************************************************/
/*
* Read a clump from the given file. This function creates and
* initializes the user data structure of the clump.
*
* RenderWare API Equivalent: RwReadShape()
*/
RwClump *
ReadClumpObj(char *fileName)
{
ClumpUserData *userData;
RwClump *clump;
/*
* Allocate the user data for the new clump.
*/
userData = (ClumpUserData *)malloc(sizeof(ClumpUserData));
if (userData == NULL)
return NULL;
/*
* Read the clump.
*/
clump = RwReadShape(fileName);
/*
* If all went well then intialize the user data pointer and attach
* it to the clump.
*/
if (clump == NULL)
{
free((void *)userData);
return NULL;
}
else
{
/*
* This clump does not represent a light.
*/
userData->light = NULL;
strcpy(userData->fileName, fileName);
RwSetClumpData(clump, (void *)userData);
return clump;
}
}
/**********************************************************************/
/*
* Create a light of the given type. A clump is built which represents
* this light and is attached to the user data field of the light.
*
* NOTE: We return a pointer to the clump build rather than the light
* as clump's are the main object type of the viewer.
*
* RenderWare API Equivalent: RwCreateLight()
*/
RwLight *
CreateLightObj(RwLightType kind)
{
ClumpUserData *userData;
RwLight *light;
RwClump *clump;
/*
* Allocate the user data for the new clump.
*/
userData = (ClumpUserData *)malloc(sizeof(ClumpUserData));
if (userData == NULL)
return NULL;
/*
* Create the RenderWare light. The supplied vector is just a dummy
* as it will be overwritten when we copy the clump's matrix to the
* light.
*/
light = RwCreateLight(kind, CREAL(0.0), CREAL(0.0), CREAL(1.0),
CREAL(1.0));
if (light == NULL)
{
free((void *)userData);
return NULL;
}
/*
* Build the clump. For each light type the clump is unshaded, white
* wireframe so there surface conditions are set up globally.
*/
RwModelBegin();
RwClumpBegin();
/*
* We don't want the lights to take part in shading (it would
* look strange if lights illuminated themselves) so we turn
* of shading by setting diffuse and specular reflection to
* CREAL(0.0) and we ensure a nice bright white by setting
* ambient to CREAL(1.0).
*/
RwSetSurface(CREAL(1.0), CREAL(0.0), CREAL(0.0));
RwSetSurfaceColor(CREAL(1.0), CREAL(1.0), CREAL(1.0));
RwSetSurfaceGeometrySampling(rwWIREFRAME);
/*
* The RenderWare geometric primitives are designed to be
* oriented up the Y axis by default. Here, however, we
* want them point down the Z axis as the clump's local
* Z axis will be same as the light's direction. So the
* first thing we do is perform a rotation around X of
* CREAL(90.0).
*/
RwRotateCTM(CREAL(1.0), CREAL(0.0), CREAL(0.0), CREAL(90.0));
switch (kind)
{
case rwDIRECTIONAL:
/*
* The directional light is represented as a 3D
* arrow built from a cone and a cylinder. We want
* the tip of the arrow to be the origin of the
* clump (the point about which we will rotate the
* clump) so we translate down and build the arrow
* so the tip of the cone is at the origin of local
* space.
*/
RwTranslateCTM(CREAL(0.0), CREAL(-0.4), CREAL(0.0));
/*
* The arrow head.
*/
RwCone(CREAL(0.4), CREAL(0.2), 12);
/*
* We want to cap the cone. Rather than using a disc
* we will use a cylinder of zero height. This is
* a useful trick for building a circle with a hole
* in it.
*/
RwCylinder(CREAL(0.0), CREAL(0.1), CREAL(0.2), 12);
/*
* The shaft of the arrow.
*/
RwTranslateCTM(CREAL(0.0), CREAL(-0.4), CREAL(0.0));
RwCylinder(CREAL(0.4), CREAL(0.1), CREAL(0.1), 12);
/*
* Cap the shaft of the arrow with a disc. The negative
* radius looks a little odd but this is a good trick for
* flipping the polygons to point the other way, i.e.,
* to make the polygons point down rather than up.
*/
RwDisc(CREAL(0.0), CREAL(-0.1), 12);
break;
case rwPOINT:
/*
* A point light source is represented as a simple
* sphere. The origin of the sphere is the position
* of the light.
*/
RwSphere(CREAL(0.2), 3);
break;
case rwCONICAL:
/*
* A conical light source is represented as an inverse
* cone. The sharp end points in the opposite direction
* from the light vector. The tip of the cone is also the
* position of the light.The normal orientation of a cone
* is to have the base at the bottom and the tip at the
* top (in Y). We want the base at the top and the tip
* pointing down so we rotate everything 180 degrees about
* X before building the code.
*/
RwRotateCTM(CREAL(1.0), CREAL(0.0), CREAL(0.0), CREAL(180.0));
RwCone(CREAL(0.4), CREAL(0.2), 12);
/*
* Cap the cone with a disc. The negative radius looks a
* little odd but this is a good trick for flipping the
* polygons to point the other way, i.e., to make the
* polygons point down rather than up
*/
RwDisc(CREAL(0.0), CREAL(-0.2), 12);
break;
}
RwClumpEnd(&clump);
RwModelEnd();
if (clump == NULL)
{
/*
* If the clump failed for any reason cleanup and exit with
* failure.
*/
free((void *)userData);
RwDestroyLight(light);
return NULL;
}
else
{
/*
* Initialize the user data field of the clump and attach it.
* This clump has no filename as it has not been loaded from
* a file.
*/
userData->fileName[0] = '\0';
userData->light = light;
RwSetClumpData(clump, (void *)userData);
/*
* Attach the back pointer from the light to the clump.
*/
RwSetLightData(light, (void *)clump);
RwPushScratchMatrix();
/*
* Move the clump to the default position.
*/
RwTranslateMatrix(RwScratchMatrix(),
CREAL(1.0), CREAL(1.0), CREAL(1.0), rwREPLACE);
RwTransformClump(clump, RwScratchMatrix(), rwREPLACE);
RwRotateMatrix(RwScratchMatrix(), CREAL(0.0), CREAL(1.0), CREAL(0.0),
CREAL(225.0), rwREPLACE);
RwRotateMatrix(RwScratchMatrix(), CREAL(1.0), CREAL(0.0), CREAL(0.0),
CREAL(-45.0), rwPOSTCONCAT);
RwTransformClumpJoint(clump, RwScratchMatrix(), rwREPLACE);
RwGetClumpLTM(clump, RwScratchMatrix());
/*
* Make the position and/or orientation of the light match the
* clump.
*/
RwTransformLight(light, RwScratchMatrix(), rwREPLACE);
RwPopScratchMatrix();
return light;
}
}
/**********************************************************************/
/*
* Duplicate the given clump object and its associated light (if it has
* one).
*
* RenderWare API Equivalent: RwDuplicateClump(), RwDuplicateLight().
*/
RwClump *
DuplicateClumpObj(RwClump *clump)
{
ClumpUserData *userData;
ClumpUserData *newUserData;
RwClump *newClump;
RwLight *light;
RwLight *newLight;
/*
* Allocate the user data for the new clump.
*/
newUserData = (ClumpUserData *)malloc(sizeof(ClumpUserData));
if (newUserData == NULL)
return NULL;
/*
* Duplicate the clump.
*/
newClump = RwDuplicateClump(clump);
if (newClump == NULL)
{
free((void *)newUserData);
return NULL;
}
if (ISCLUMPLIGHT(clump))
{
/*
* The original clump represents a light so get the source
* light and duplicate it.
*/
light = GETCLUMPLIGHT(clump);
newLight = RwDuplicateLight(light);
if (light != NULL)
{
/*
* Initialize the user data and attach it to the clump.
*/
newUserData->fileName[0] = '\0';
newUserData->light = newLight;
RwSetClumpData(newClump, (void *)newUserData);
/*
* Set the back pointer from the light to the clump.
*/
RwSetLightData(newLight, (void *)newClump);
return newClump;
}
else
{
RwDestroyClump(clump);
free((void *)newUserData);
return NULL;
}
}
else
{
/*
* The clump does not represent a light so simply copy
* the filename across and set the user data.
*/
userData = GETCLUMPUSERDATA(clump);
strcpy(newUserData->fileName, userData->fileName);
newUserData->light = NULL;
RwSetClumpData(newClump, (void *)newUserData);
return newClump;
}
}
/**********************************************************************/
/*
* Add a clump object to the given scene. This function will also add the
* light object to the scene if the the clump represents a light.
*
* RenderWare API Equivalent: RwAddClumpToScene(), RwAddLightToScene().
*/
RwScene *
AddClumpObjToScene(RwScene *scene, RwClump *clump)
{
/*
* Add the clump to the scene.
*/
RwAddClumpToScene(scene, clump);
if (ISCLUMPLIGHT(clump))
{
/*
* If this clump represents a light then add the light to the
* scene also.
*/
RwAddLightToScene(scene, GETCLUMPLIGHT(clump));
}
return scene;
}
/**********************************************************************/
/*
* Add a light object to the given scene. This function will also add the
* clump object representing a light to the scene.
*
* RenderWare API Equivalent: RwAddLightToScene(), RwAddClumpToScene().
*/
RwScene *
AddLightObjToScene(RwScene *scene, RwLight *light)
{
RwClump *clump;
/*
* Get the clump which represents this light.
*/
clump = GETLIGHTCLUMP(light);
/*
* Add both objects to the scene.
*/
RwAddLightToScene(scene, light);
RwAddClumpToScene(scene, clump);
return scene;
}
/**********************************************************************/
/*
* Set the brightness of the given light object. This function also
* updates the visual appearance of the clump object representing the
* light to reflect the new brightness.
*
* RenderWare API Equivalent: RwSetLightBrightness().
*/
RwLight *
SetLightObjBrightness(RwLight *light, RwReal bright)
{
RwClump *clump;
/*
* Set the brightness of the light.
*/
RwSetLightBrightness(light, bright);
/*
* Update the materials of the associated clump to reflect the new
* brightness.
*/
clump = GETLIGHTCLUMP(light);
RwPushCurrentMaterial();
RwSetMaterialSurface(RwCurrentMaterial(), bright, CREAL(0.0), CREAL(0.0));
RwSetMaterialColor(RwCurrentMaterial(), CREAL(1.0), CREAL(1.0), CREAL(1.0));
RwSetMaterialGeometrySampling(RwCurrentMaterial(), rwWIREFRAME);
RwForAllPolygonsInClumpPointer(clump, (RwPolygon3dFuncPointer)RwSetPolygonMaterial,
RwCurrentMaterial());
RwPopCurrentMaterial();
return light;
}
/**********************************************************************/
/*
* Set the color of the given light object. This function also
* updates the visual appearance of the clump object representing the
* light to reflect the new color.
*
* RenderWare API Equivalent: RwSetLightColor().
*/
RwLight *
SetLightObjColor(RwLight *light, RwReal r, RwReal g, RwReal b)
{
RwClump *clump;
/*
* Set the color of the light.
*/
RwSetLightColor(light, r, g, b);
/*
* Update the materials of the associated clump to reflect the new
* brightness.
*/
clump = GETLIGHTCLUMP(light);
RwPushCurrentMaterial();
RwSetMaterialSurface(RwCurrentMaterial(), CREAL(0.70), CREAL(0.0), CREAL(0.0));
RwSetMaterialColor(RwCurrentMaterial(), r, g, b);
RwSetMaterialGeometrySampling(RwCurrentMaterial(), rwWIREFRAME);
RwForAllPolygonsInClumpPointer(clump, (RwPolygon3dFuncPointer)RwSetPolygonMaterial,
RwCurrentMaterial());
RwPopCurrentMaterial();
return light;
}
/**********************************************************************/
/*
* Turn the clump which is the visible representation of a light on or off.
* This function does not turn the light itself on or off, it only
* shows or hides the visible representation of that light.
*
* RenderWare API Equivalent: RwSetClumpState().
*/
RwLight *
SetLightObjVisibleState(RwLight *light, RwState state)
{
RwSetClumpState(GETLIGHTCLUMP(light), state);
return light;
}
/**********************************************************************/
/*
* Destory the given clump object (and its associated light if it has
* one). This function will also free the user data structure allocated
* for the clump.
*
* RenderWare API Equivalent: RwDestoryClump()
*/
void
DestroyClumpObj(RwClump *clump)
{
ClumpUserData *userData;
/*
* If this clump is a root clump and it is the representation
* of a light then we must destory the associated light and
* the user data. Otherwise all we need to do is to destroy
* the clump itself.
*/
if (RwGetClumpParent(clump) == NULL)
{
userData = GETCLUMPUSERDATA(clump);
if (userData != NULL)
{
if (userData->light != NULL)
{
/*
* If this clump represents a light blow the associated
* light away.
*/
RwDestroyLight(userData->light);
}
/*
* Free the user data.
*/
free((void *)userData);
}
}
/*
* Blow the clump away...
*/
RwDestroyClump(clump);
}
/**********************************************************************/