This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/ww3d2/part_ldr.cpp

1835 lines
50 KiB
C++

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : WW3D *
* *
* $Archive:: /VSS_Sync/ww3d2/part_ldr.cpp $*
* *
* Author:: Patrick Smith
* *
* $Modtime:: 10/26/01 2:57p $*
* *
* $Revision:: 11 $*
* *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "part_ldr.h"
#include "part_emt.h"
#include "w3derr.h"
#include "chunkio.h"
#include "win.h" // for lstrcpy, can this be improved?
#include "assetmgr.h"
#include "texture.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(pointer) \
{ \
if (pointer) { \
delete pointer; \
pointer = 0; \
} \
}
#endif //SAFE_DELETE
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(pointer) \
if (pointer) { \
delete [] pointer; \
pointer = 0; \
} \
#endif //SAFE_DELETE
///////////////////////////////////////////////////////////////////////////////////
//
// Global variable initialization
//
ParticleEmitterLoaderClass _ParticleEmitterLoader;
// This array is declared in "W3D_File.H"
const char *EMITTER_TYPE_NAMES[EMITTER_TYPEID_COUNT] =
{
"Default"
};
///////////////////////////////////////////////////////////////////////////////////
//
// ParticleEmitterDefClass
//
ParticleEmitterDefClass::ParticleEmitterDefClass (void)
: m_pName (NULL),
m_Version (0L),
m_pUserString (NULL),
m_iUserType (EMITTER_TYPEID_DEFAULT),
m_InitialOrientationRandom (0),
m_pCreationVolume (NULL),
m_pVelocityRandomizer (NULL)
{
::memset (&m_Info, 0, sizeof (m_Info));
::memset (&m_InfoV2, 0, sizeof (m_InfoV2));
::memset (&m_ColorKeyframes, 0, sizeof (m_ColorKeyframes));
::memset (&m_OpacityKeyframes, 0, sizeof (m_OpacityKeyframes));
::memset (&m_SizeKeyframes, 0, sizeof (m_SizeKeyframes));
::memset (&m_RotationKeyframes, 0, sizeof (m_RotationKeyframes));
::memset (&m_FrameKeyframes, 0, sizeof (m_FrameKeyframes));
::memset (&m_BlurTimeKeyframes, 0, sizeof (m_BlurTimeKeyframes));
::memset (&m_LineProperties, 0, sizeof (m_LineProperties));
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// ParticleEmitterDefClass
//
ParticleEmitterDefClass::ParticleEmitterDefClass (const ParticleEmitterDefClass &src)
: m_pName (NULL),
m_Version (0L),
m_pUserString (NULL),
m_iUserType (EMITTER_TYPEID_DEFAULT),
m_InitialOrientationRandom (src.m_InitialOrientationRandom),
m_pCreationVolume (NULL),
m_pVelocityRandomizer (NULL)
{
::memset (&m_Info, 0, sizeof (m_Info));
::memset (&m_InfoV2, 0, sizeof (m_InfoV2));
::memset (&m_ColorKeyframes, 0, sizeof (m_ColorKeyframes));
::memset (&m_OpacityKeyframes, 0, sizeof (m_OpacityKeyframes));
::memset (&m_SizeKeyframes, 0, sizeof (m_SizeKeyframes));
::memset (&m_RotationKeyframes, 0, sizeof (m_RotationKeyframes));
::memset (&m_FrameKeyframes, 0, sizeof (m_FrameKeyframes));
::memset (&m_BlurTimeKeyframes, 0, sizeof (m_BlurTimeKeyframes));
::memset (&m_LineProperties, 0, sizeof (m_LineProperties));
(*this) = src;
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// ~ParticleEmitterDefClass
//
ParticleEmitterDefClass::~ParticleEmitterDefClass (void)
{
// Free the name buffer if necessary
if (m_pName != NULL) {
// free() is used because the buffer was allocated with ::_strdup().
::free (m_pName);
m_pName = NULL;
}
// Free the user-string buffer if necessary
if (m_pUserString != NULL) {
// free() is used because the buffer was allocated with ::malloc() or ::_strdup().
::free (m_pUserString);
m_pUserString = NULL;
}
Free_Props ();
SAFE_DELETE (m_pCreationVolume);
SAFE_DELETE (m_pVelocityRandomizer);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// ParticleEmitterDefClass
//
const ParticleEmitterDefClass &
ParticleEmitterDefClass::operator= (const ParticleEmitterDefClass &src)
{
//
// Copy the user structures
//
Set_Name (src.Get_Name ());
Set_User_String (src.Get_User_String ());
Set_User_Type (src.Get_User_Type ());
m_Version = src.m_Version;
//
// Copy the information structures
//
::memcpy (&m_Info, &src.m_Info, sizeof (m_Info));
::memcpy (&m_InfoV2, &src.m_InfoV2, sizeof (m_InfoV2));
::memcpy (&m_LineProperties, &src.m_LineProperties, sizeof(m_LineProperties));
//
// Copy the keyframes
//
Free_Props ();
::Copy_Emitter_Property_Struct (m_ColorKeyframes, src.m_ColorKeyframes);
::Copy_Emitter_Property_Struct (m_OpacityKeyframes, src.m_OpacityKeyframes);
::Copy_Emitter_Property_Struct (m_SizeKeyframes, src.m_SizeKeyframes);
::Copy_Emitter_Property_Struct (m_RotationKeyframes, src.m_RotationKeyframes);
::Copy_Emitter_Property_Struct (m_FrameKeyframes, src.m_FrameKeyframes);
::Copy_Emitter_Property_Struct (m_BlurTimeKeyframes, src.m_BlurTimeKeyframes);
m_InitialOrientationRandom = src.m_InitialOrientationRandom;
//
// Create the randomizers
//
SAFE_DELETE (m_pCreationVolume);
SAFE_DELETE (m_pVelocityRandomizer);
m_pCreationVolume = Create_Randomizer (m_InfoV2.CreationVolume);
m_pVelocityRandomizer = Create_Randomizer (m_InfoV2.VelRandom);
return (*this);
}
///////////////////////////////////////////////////////////////////////////////////
//
// Free_Props
//
void
ParticleEmitterDefClass::Free_Props (void)
{
m_ColorKeyframes.NumKeyFrames = 0;
m_OpacityKeyframes.NumKeyFrames = 0;
m_SizeKeyframes.NumKeyFrames = 0;
m_RotationKeyframes.NumKeyFrames = 0;
m_FrameKeyframes.NumKeyFrames = 0;
m_BlurTimeKeyframes.NumKeyFrames = 0;
SAFE_DELETE_ARRAY (m_ColorKeyframes.KeyTimes);
SAFE_DELETE_ARRAY (m_ColorKeyframes.Values);
SAFE_DELETE_ARRAY (m_OpacityKeyframes.KeyTimes);
SAFE_DELETE_ARRAY (m_OpacityKeyframes.Values);
SAFE_DELETE_ARRAY (m_SizeKeyframes.KeyTimes);
SAFE_DELETE_ARRAY (m_SizeKeyframes.Values);
SAFE_DELETE_ARRAY (m_RotationKeyframes.KeyTimes);
SAFE_DELETE_ARRAY (m_RotationKeyframes.Values);
SAFE_DELETE_ARRAY (m_FrameKeyframes.KeyTimes);
SAFE_DELETE_ARRAY (m_FrameKeyframes.Values);
SAFE_DELETE_ARRAY (m_BlurTimeKeyframes.KeyTimes);
SAFE_DELETE_ARRAY (m_BlurTimeKeyframes.Values);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Set_Velocity_Random
//
void
ParticleEmitterDefClass::Set_Velocity_Random (Vector3Randomizer *randomizer)
{
SAFE_DELETE (m_pVelocityRandomizer);
m_pVelocityRandomizer = randomizer;
//
// Ensure our persistent structure is up-to-date so it will save correctly
//
if (m_pVelocityRandomizer != NULL) {
Initialize_Randomizer_Struct (*m_pVelocityRandomizer, m_InfoV2.VelRandom);
}
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Set_Creation_Volume
//
void
ParticleEmitterDefClass::Set_Creation_Volume (Vector3Randomizer *randomizer)
{
SAFE_DELETE (m_pCreationVolume);
m_pCreationVolume = randomizer;
//
// Ensure our persistent structure is up-to-date so it will save correctly
//
if (m_pCreationVolume != NULL) {
Initialize_Randomizer_Struct (*m_pCreationVolume, m_InfoV2.CreationVolume);
}
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Set_User_String
//
void
ParticleEmitterDefClass::Set_User_String (const char *pstring)
{
SAFE_FREE (m_pUserString);
m_pUserString = ::_strdup (pstring);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Set_Name
//
void
ParticleEmitterDefClass::Set_Name (const char *pname)
{
SAFE_FREE (m_pName);
m_pName = ::_strdup (pname);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Set_Texture_Filename
//
void
ParticleEmitterDefClass::Set_Texture_Filename (const char *pname)
{
::lstrcpy (m_Info.TextureFilename, pname);
Normalize_Filename ();
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Normalize_Filename
//
void
ParticleEmitterDefClass::Normalize_Filename (void)
{
TCHAR path[MAX_PATH];
::lstrcpy (path, m_Info.TextureFilename);
// Find the last occurance of the directory deliminator
LPCTSTR filename = ::strrchr (path, '\\');
if (filename != NULL) {
// Increment past the directory deliminator
filename ++;
// Now copy the filename protion of the path to the structure
::lstrcpy (m_Info.TextureFilename, filename);
}
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Load
//
WW3DErrorType
ParticleEmitterDefClass::Load_W3D (ChunkLoadClass &chunk_load)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
Initialize_To_Ver2 ();
// Attempt to read the different sections of the emitter definition
if ((Read_Header (chunk_load) == WW3D_ERROR_OK) &&
(Read_User_Data (chunk_load) == WW3D_ERROR_OK) &&
(Read_Info (chunk_load) == WW3D_ERROR_OK)) {
if (m_Version > 0x00010000) {
//
// Read the version 2.0 structures from the chunk
//
if ((Read_InfoV2 (chunk_load) == WW3D_ERROR_OK) &&
(Read_Props (chunk_load) == WW3D_ERROR_OK)) {
// Success!
ret_val = WW3D_ERROR_OK;
}
} else {
// Make sure the data fits version 2
Convert_To_Ver2 ();
ret_val = WW3D_ERROR_OK;
}
}
// (gth) Handle all future additions to the particle emitter file format
// in the typical chunk fashion.
while (chunk_load.Open_Chunk() && ret_val == WW3D_ERROR_OK) {
switch (chunk_load.Cur_Chunk_ID())
{
case W3D_CHUNK_EMITTER_LINE_PROPERTIES:
ret_val = Read_Line_Properties(chunk_load);
break;
case W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES:
ret_val = Read_Rotation_Keyframes(chunk_load);
break;
case W3D_CHUNK_EMITTER_FRAME_KEYFRAMES:
ret_val = Read_Frame_Keyframes(chunk_load);
break;
case W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES:
ret_val = Read_Blur_Time_Keyframes(chunk_load);
break;
default:
WWDEBUG_SAY(("Unhandled Chunk! File: %s Line: %d\r\n",__FILE__,__LINE__));
break;
}
chunk_load.Close_Chunk();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Initialize_To_Ver2
//
void
ParticleEmitterDefClass::Initialize_To_Ver2 (void)
{
::memset (&m_Info, 0, sizeof (m_Info));
::memset (&m_InfoV2, 0, sizeof (m_InfoV2));
//
// Set the version 2 values using defaults from version 1
//
m_InfoV2.BurstSize = 1;
m_InfoV2.OutwardVel = 0;
m_InfoV2.VelInherit = 0;
W3dUtilityClass::Convert_Shader (ShaderClass::_PresetAdditiveSpriteShader, &m_InfoV2.Shader);
m_InfoV2.CreationVolume.ClassID = Vector3Randomizer::CLASSID_SOLIDBOX;
m_InfoV2.CreationVolume.Value1 = 0;
m_InfoV2.CreationVolume.Value2 = 0;
m_InfoV2.CreationVolume.Value3 = 0;
m_InfoV2.VelRandom.ClassID = Vector3Randomizer::CLASSID_SOLIDBOX;
m_InfoV2.VelRandom.Value1 = 0;
m_InfoV2.VelRandom.Value2 = 0;
m_InfoV2.VelRandom.Value3 = 0;
Free_Props ();
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Convert_To_Ver2
//
void
ParticleEmitterDefClass::Convert_To_Ver2 (void)
{
if (m_Version < 0x00020000) {
m_InfoV2.BurstSize = 1;
m_InfoV2.OutwardVel = 0;
m_InfoV2.VelInherit = 0;
//
// Determine which shader to use...
//
ShaderClass shader = ShaderClass::_PresetAdditiveSpriteShader;
TextureClass *ptexture = WW3DAssetManager::Get_Instance ()->Get_Texture (m_Info.TextureFilename);
if (ptexture != NULL) {
// If texture has an alpha channel do alpha blending instead of additive
// (which is the default for point groups):
// SurfaceClass::SurfaceDescription surf_desc;
// ::ZeroMemory(&surf_desc, sizeof(SurfaceClass::SurfaceDescription));
// ptexture->Get_Level_Description(surf_desc);
// if (Has_Alpha(surf_desc.Format)) {
if (Has_Alpha(ptexture->Get_Texture_Format())) {
shader = ShaderClass::_PresetAlphaSpriteShader;
}
ptexture->Release_Ref();
}
W3dUtilityClass::Convert_Shader (shader, &m_InfoV2.Shader);
//
// Convert the randomziers
//
m_InfoV2.CreationVolume.ClassID = Vector3Randomizer::CLASSID_SOLIDBOX;
m_InfoV2.CreationVolume.Value1 = m_Info.PositionRandom / 1000.0f;
m_InfoV2.CreationVolume.Value2 = m_Info.PositionRandom / 1000.0f;
m_InfoV2.CreationVolume.Value3 = m_Info.PositionRandom / 1000.0f;
m_InfoV2.VelRandom.ClassID = Vector3Randomizer::CLASSID_SOLIDBOX;
m_InfoV2.VelRandom.Value1 = m_Info.VelocityRandom;
m_InfoV2.VelRandom.Value2 = m_Info.VelocityRandom;
m_InfoV2.VelRandom.Value3 = m_Info.VelocityRandom;
//
// Recreate the randomizers
//
SAFE_DELETE (m_pCreationVolume);
SAFE_DELETE (m_pVelocityRandomizer);
m_pCreationVolume = Create_Randomizer (m_InfoV2.CreationVolume);
m_pVelocityRandomizer = Create_Randomizer (m_InfoV2.VelRandom);
//
// Convert the colors, opacities, and sizes
//
Free_Props ();
m_ColorKeyframes.Start = RGBA_TO_VECTOR3 (m_Info.StartColor);
m_ColorKeyframes.Rand = Vector3 (0, 0, 0);
m_ColorKeyframes.NumKeyFrames = 1;
m_ColorKeyframes.KeyTimes = new float(m_Info.FadeTime);
m_ColorKeyframes.Values = new Vector3(RGBA_TO_VECTOR3 (m_Info.EndColor));
m_OpacityKeyframes.Start = ((float)(m_Info.StartColor.A)) / 255;
m_OpacityKeyframes.Rand = 0;
m_OpacityKeyframes.NumKeyFrames = 1;
m_OpacityKeyframes.KeyTimes = new float(m_Info.FadeTime);
m_OpacityKeyframes.Values = new float(((float)(m_Info.EndColor.A)) / 255);
m_SizeKeyframes.Start = m_Info.StartSize;
m_SizeKeyframes.Rand = 0;
m_SizeKeyframes.NumKeyFrames = 0;
}
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Read_Header
//
WW3DErrorType
ParticleEmitterDefClass::Read_Header (ChunkLoadClass &chunk_load)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
// Is this the header chunk?
if (chunk_load.Open_Chunk () &&
(chunk_load.Cur_Chunk_ID () == W3D_CHUNK_EMITTER_HEADER)) {
W3dEmitterHeaderStruct header = { 0 };
if (chunk_load.Read (&header, sizeof (header)) == sizeof (header)) {
// Copy the name from the header structure
m_pName = ::_strdup (header.Name);
m_Version = header.Version;
// Success!
ret_val = WW3D_ERROR_OK;
}
// Close the chunk, so the next read will be successful.
chunk_load.Close_Chunk ();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Read_User_Data
//
WW3DErrorType
ParticleEmitterDefClass::Read_User_Data (ChunkLoadClass &chunk_load)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
// Is this the user chunk?
if (chunk_load.Open_Chunk () &&
(chunk_load.Cur_Chunk_ID () == W3D_CHUNK_EMITTER_USER_DATA)) {
W3dEmitterUserInfoStruct user_info = { 0 };
if (chunk_load.Read (&user_info, sizeof (user_info)) == sizeof (user_info)) {
// Assume success from here on out
ret_val = WW3D_ERROR_OK;
// Record the user information into our member data
m_iUserType = user_info.Type;
// Should we read the user string from the file?
if (user_info.SizeofStringParam > 0) {
m_pUserString = (char *)::malloc (sizeof (char) * (user_info.SizeofStringParam+1));
m_pUserString[0] = 0;
// Attempt to read the user-string from the chunk
if (chunk_load.Read (m_pUserString, user_info.SizeofStringParam) != user_info.SizeofStringParam) {
ret_val = WW3D_ERROR_LOAD_FAILED;
}
}
}
// Close the chunk, so the next read will be successful.
chunk_load.Close_Chunk ();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Read_Info
//
WW3DErrorType
ParticleEmitterDefClass::Read_Info (ChunkLoadClass &chunk_load)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
// Is this the user chunk?
if (chunk_load.Open_Chunk () &&
(chunk_load.Cur_Chunk_ID () == W3D_CHUNK_EMITTER_INFO)) {
// Read the chunk straight into our member structure
::memset (&m_Info, 0, sizeof (m_Info));
if (chunk_load.Read (&m_Info, sizeof (m_Info)) == sizeof (m_Info)) {
// Success!
ret_val = WW3D_ERROR_OK;
}
// Close the chunk, so the next read will be successful.
chunk_load.Close_Chunk ();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Create_Randomizer
//
Vector3Randomizer *
ParticleEmitterDefClass::Create_Randomizer (W3dVolumeRandomizerStruct &info)
{
Vector3Randomizer *randomizer = NULL;
switch (info.ClassID)
{
case Vector3Randomizer::CLASSID_SOLIDBOX:
randomizer = new Vector3SolidBoxRandomizer (Vector3 (info.Value1, info.Value2, info.Value3));
break;
case Vector3Randomizer::CLASSID_SOLIDSPHERE:
randomizer = new Vector3SolidSphereRandomizer (info.Value1);
break;
case Vector3Randomizer::CLASSID_HOLLOWSPHERE:
randomizer = new Vector3HollowSphereRandomizer (info.Value1);
break;
case Vector3Randomizer::CLASSID_SOLIDCYLINDER:
randomizer = new Vector3SolidCylinderRandomizer (info.Value1, info.Value2);
break;
}
return randomizer;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Initialize_Randomizer_Struct
//
void
ParticleEmitterDefClass::Initialize_Randomizer_Struct
(
const Vector3Randomizer & randomizer,
W3dVolumeRandomizerStruct & info
)
{
info.ClassID = randomizer.Class_ID ();
switch (randomizer.Class_ID ())
{
case Vector3Randomizer::CLASSID_SOLIDBOX:
{
Vector3 extents = ((Vector3SolidBoxRandomizer &)randomizer).Get_Extents ();
info.Value1 = extents.X;
info.Value2 = extents.Y;
info.Value3 = extents.Z;
}
break;
case Vector3Randomizer::CLASSID_SOLIDSPHERE:
info.Value1 = ((Vector3SolidSphereRandomizer &)randomizer).Get_Radius ();
break;
case Vector3Randomizer::CLASSID_HOLLOWSPHERE:
info.Value1 = ((Vector3HollowSphereRandomizer &)randomizer).Get_Radius ();
break;
case Vector3Randomizer::CLASSID_SOLIDCYLINDER:
info.Value1 = ((Vector3SolidCylinderRandomizer &)randomizer).Get_Height ();
info.Value2 = ((Vector3SolidCylinderRandomizer &)randomizer).Get_Radius ();
break;
}
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Read_InfoV2
//
WW3DErrorType
ParticleEmitterDefClass::Read_InfoV2 (ChunkLoadClass &chunk_load)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
// Is this the user chunk?
if (chunk_load.Open_Chunk () &&
(chunk_load.Cur_Chunk_ID () == W3D_CHUNK_EMITTER_INFOV2)) {
// Read the chunk straight into our member structure
::memset (&m_InfoV2, 0, sizeof (m_InfoV2));
if (chunk_load.Read (&m_InfoV2, sizeof (m_InfoV2)) == sizeof (m_InfoV2)) {
//
// Recreate the randomizers
//
SAFE_DELETE (m_pCreationVolume);
SAFE_DELETE (m_pVelocityRandomizer);
m_pCreationVolume = Create_Randomizer (m_InfoV2.CreationVolume);
m_pVelocityRandomizer = Create_Randomizer (m_InfoV2.VelRandom);
// Success!
ret_val = WW3D_ERROR_OK;
}
// Close the chunk, so the next read will be successful.
chunk_load.Close_Chunk ();
}
// Return the WW3DErrorClass::ErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Read_Props
//
WW3DErrorType
ParticleEmitterDefClass::Read_Props (ChunkLoadClass &chunk_load)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
Free_Props ();
// Is this the user chunk?
if (chunk_load.Open_Chunk () &&
(chunk_load.Cur_Chunk_ID () == W3D_CHUNK_EMITTER_PROPS)) {
W3dEmitterPropertyStruct info = { 0 };
if (chunk_load.Read (&info, sizeof (info)) == sizeof (info)) {
unsigned int index=0;
//ParticlePropertyStruct<Vector3>
m_ColorKeyframes.NumKeyFrames = info.ColorKeyframes - 1;
m_OpacityKeyframes.NumKeyFrames = info.OpacityKeyframes - 1;
m_SizeKeyframes.NumKeyFrames = info.SizeKeyframes - 1;
m_ColorKeyframes.Rand = RGBA_TO_VECTOR3 (info.ColorRandom);
m_OpacityKeyframes.Rand = info.OpacityRandom;
m_SizeKeyframes.Rand = info.SizeRandom;
//
// Allocate the array of color keyframes
//
if (m_ColorKeyframes.NumKeyFrames > 0) {
m_ColorKeyframes.KeyTimes = new float[m_ColorKeyframes.NumKeyFrames];
m_ColorKeyframes.Values = new Vector3[m_ColorKeyframes.NumKeyFrames];
}
//
// Allocate the array of opacity keyframes
//
if (m_OpacityKeyframes.NumKeyFrames > 0) {
m_OpacityKeyframes.KeyTimes = new float[m_OpacityKeyframes.NumKeyFrames];
m_OpacityKeyframes.Values = new float[m_OpacityKeyframes.NumKeyFrames];
}
//
// Allocate the array of size keyframes
//
if (m_SizeKeyframes.NumKeyFrames > 0) {
m_SizeKeyframes.KeyTimes = new float[m_SizeKeyframes.NumKeyFrames];
m_SizeKeyframes.Values = new float[m_SizeKeyframes.NumKeyFrames];
}
//
// Read the color keyframes from the chunk
//
Read_Color_Keyframe (chunk_load, NULL, &m_ColorKeyframes.Start);
for (index = 0; index < m_ColorKeyframes.NumKeyFrames; index ++) {
Read_Color_Keyframe (chunk_load,
&m_ColorKeyframes.KeyTimes[index],
&m_ColorKeyframes.Values[index]);
}
//
// If the last keyframe is 'black' and we are using a color randomizer,
// then make sure the last color is less then 0 so any randomized color
// will end up as black
//
int last_keyframe = (m_ColorKeyframes.NumKeyFrames - 1);
if ( last_keyframe > 0 &&
m_ColorKeyframes.Values[last_keyframe].X == 0 &&
m_ColorKeyframes.Values[last_keyframe].Y == 0 &&
m_ColorKeyframes.Values[last_keyframe].Z == 0 &&
(m_ColorKeyframes.Rand.X > 0 || m_ColorKeyframes.Rand.Y > 0 || m_ColorKeyframes.Rand.Z > 0))
{
m_ColorKeyframes.Values[last_keyframe].X = -m_ColorKeyframes.Rand.X;
m_ColorKeyframes.Values[last_keyframe].Y = -m_ColorKeyframes.Rand.Y;
m_ColorKeyframes.Values[last_keyframe].Z = -m_ColorKeyframes.Rand.Z;
}
//
// Read the opacity keyframes from the chunk
//
Read_Opacity_Keyframe (chunk_load, NULL, &m_OpacityKeyframes.Start);
for (index = 0; index < m_OpacityKeyframes.NumKeyFrames; index ++) {
Read_Opacity_Keyframe (chunk_load,
&m_OpacityKeyframes.KeyTimes[index],
&m_OpacityKeyframes.Values[index]);
}
//
// Read the size keyframes from the chunk
//
Read_Size_Keyframe (chunk_load, NULL, &m_SizeKeyframes.Start);
for (index = 0; index < m_SizeKeyframes.NumKeyFrames; index ++) {
Read_Size_Keyframe (chunk_load,
&m_SizeKeyframes.KeyTimes[index],
&m_SizeKeyframes.Values[index]);
}
// Success!
ret_val = WW3D_ERROR_OK;
}
// Close the chunk, so the next read will be successful.
chunk_load.Close_Chunk ();
}
// Return the WW3DErrorClass::ErrorType return code
return ret_val;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Read_Color_Keyframe
//
bool
ParticleEmitterDefClass::Read_Color_Keyframe
(
ChunkLoadClass & chunk_load,
float * key_time,
Vector3 * value
)
{
bool retval = false;
//
// Read the color key frame from the chunk
//
W3dEmitterColorKeyframeStruct key_frame = { 0 };
if (chunk_load.Read (&key_frame, sizeof (key_frame)) == sizeof (key_frame)) {
// Pass the key time to the caller
if (key_time != NULL) {
(*key_time) = key_frame.Time;
}
// Pass the oclor back to the caller
if (value != NULL) {
(*value) = RGBA_TO_VECTOR3 (key_frame.Color);
}
// Success!
retval = true;
}
return retval;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Read_Opacity_Keyframe
//
bool
ParticleEmitterDefClass::Read_Opacity_Keyframe
(
ChunkLoadClass & chunk_load,
float * key_time,
float * value
)
{
bool retval = false;
//
// Read the key frame from the chunk
//
W3dEmitterOpacityKeyframeStruct key_frame = { 0 };
if (chunk_load.Read (&key_frame, sizeof (key_frame)) == sizeof (key_frame)) {
// Pass the key time to the caller
if (key_time != NULL) {
(*key_time) = key_frame.Time;
}
// Pass the value back to the caller
if (value != NULL) {
(*value) = key_frame.Opacity;
}
// Success!
retval = true;
}
return retval;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Read_Size_Keyframe
//
bool
ParticleEmitterDefClass::Read_Size_Keyframe
(
ChunkLoadClass & chunk_load,
float * key_time,
float * value
)
{
bool retval = false;
//
// Read the key frame from the chunk
//
W3dEmitterSizeKeyframeStruct key_frame = { 0 };
if (chunk_load.Read (&key_frame, sizeof (key_frame)) == sizeof (key_frame)) {
// Pass the key time to the caller
if (key_time != NULL) {
(*key_time) = key_frame.Time;
}
// Pass the value back to the caller
if (value != NULL) {
(*value) = key_frame.Size;
}
// Success!
retval = true;
}
return retval;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Read_Line_Properties
//
WW3DErrorType
ParticleEmitterDefClass::Read_Line_Properties(ChunkLoadClass & chunk_load)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
// Is this the user chunk?
if (chunk_load.Cur_Chunk_ID () == W3D_CHUNK_EMITTER_INFO) {
// Read the chunk straight into our member structure
if (chunk_load.Read (&m_LineProperties, sizeof (m_LineProperties)) == sizeof (m_LineProperties)) {
// Success!
ret_val = WW3D_ERROR_OK;
}
}
// Return the WW3DErrorType return code
return ret_val;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Read_Rotation_Keyframes
//
WW3DErrorType
ParticleEmitterDefClass::Read_Rotation_Keyframes (ChunkLoadClass &chunk_load)
{
// Assume success
WW3DErrorType ret_val = WW3D_ERROR_OK;
// Read the header
W3dEmitterRotationHeaderStruct header;
if (chunk_load.Read(&header,sizeof(header)) != sizeof(header)) {
ret_val = WW3D_ERROR_LOAD_FAILED;
}
m_RotationKeyframes.NumKeyFrames = header.KeyframeCount;
m_RotationKeyframes.Rand = header.Random;
m_InitialOrientationRandom = header.OrientationRandom;
// Read in the first key
W3dEmitterRotationKeyframeStruct key;
if (chunk_load.Read(&key,sizeof(key)) == sizeof(key)) {
m_RotationKeyframes.Start = key.Rotation;
}
// Allocate the rotation keys
if (m_RotationKeyframes.NumKeyFrames > 0) {
m_RotationKeyframes.KeyTimes = new float[m_RotationKeyframes.NumKeyFrames];
m_RotationKeyframes.Values = new float[m_RotationKeyframes.NumKeyFrames];
}
// Read in the keys
for (unsigned int i=0; (i<header.KeyframeCount) && (ret_val == WW3D_ERROR_OK); i++) {
W3dEmitterRotationKeyframeStruct key;
if (chunk_load.Read(&key,sizeof(key)) == sizeof(key)) {
m_RotationKeyframes.KeyTimes[i] = key.Time;
m_RotationKeyframes.Values[i] = key.Rotation;
} else {
m_RotationKeyframes.KeyTimes[i] = 0.0f;
m_RotationKeyframes.Values[i] = 0.0f;
ret_val = WW3D_ERROR_LOAD_FAILED;
}
}
return ret_val;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Read_Frame_Keyframes
//
WW3DErrorType
ParticleEmitterDefClass::Read_Frame_Keyframes (ChunkLoadClass &chunk_load)
{
// Assume success
WW3DErrorType ret_val = WW3D_ERROR_OK;
// Read the header
W3dEmitterFrameHeaderStruct header;
if (chunk_load.Read(&header,sizeof(header)) != sizeof(header)) {
ret_val = WW3D_ERROR_LOAD_FAILED;
}
// Read in the first key
W3dEmitterFrameKeyframeStruct key;
if (chunk_load.Read(&key,sizeof(key)) == sizeof(key)) {
m_FrameKeyframes.Start = key.Frame;
}
// Allocate the keys
m_FrameKeyframes.NumKeyFrames = header.KeyframeCount;
m_FrameKeyframes.Rand = header.Random;
if (m_FrameKeyframes.NumKeyFrames > 0) {
m_FrameKeyframes.KeyTimes = new float[m_FrameKeyframes.NumKeyFrames];
m_FrameKeyframes.Values = new float[m_FrameKeyframes.NumKeyFrames];
}
// Read in the keys
for (unsigned int i=0; (i<header.KeyframeCount) && (ret_val == WW3D_ERROR_OK); i++) {
W3dEmitterFrameKeyframeStruct key;
if (chunk_load.Read(&key,sizeof(key)) != sizeof(key)) {
ret_val = WW3D_ERROR_LOAD_FAILED;
}
m_FrameKeyframes.KeyTimes[i] = key.Time;
m_FrameKeyframes.Values[i] = key.Frame;
}
return ret_val;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Read_Blur_Time_Keyframes
//
WW3DErrorType
ParticleEmitterDefClass::Read_Blur_Time_Keyframes (ChunkLoadClass &chunk_load)
{
// Assume success
WW3DErrorType ret_val = WW3D_ERROR_OK;
// Read the header
W3dEmitterBlurTimeHeaderStruct header;
if (chunk_load.Read(&header,sizeof(header)) != sizeof(header)) {
ret_val = WW3D_ERROR_LOAD_FAILED;
}
// Read in the first key
W3dEmitterBlurTimeKeyframeStruct key;
if (chunk_load.Read(&key,sizeof(key)) == sizeof(key)) {
m_BlurTimeKeyframes.Start = key.BlurTime;
}
// Allocate the keys
m_BlurTimeKeyframes.NumKeyFrames = header.KeyframeCount;
m_BlurTimeKeyframes.Rand = header.Random;
if (m_BlurTimeKeyframes.NumKeyFrames > 0) {
m_BlurTimeKeyframes.KeyTimes = new float[m_BlurTimeKeyframes.NumKeyFrames];
m_BlurTimeKeyframes.Values = new float[m_BlurTimeKeyframes.NumKeyFrames];
}
// Read in the keys
for (unsigned int i=0; (i<header.KeyframeCount) && (ret_val == WW3D_ERROR_OK); i++) {
W3dEmitterBlurTimeKeyframeStruct key;
if (chunk_load.Read(&key,sizeof(key)) != sizeof(key)) {
ret_val = WW3D_ERROR_LOAD_FAILED;
}
m_BlurTimeKeyframes.KeyTimes[i] = key.Time;
m_BlurTimeKeyframes.Values[i] = key.BlurTime;
}
return ret_val;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Save
//
WW3DErrorType
ParticleEmitterDefClass::Save_W3D (ChunkSaveClass &chunk_save)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
// Begin a chunk that identifies an emitter
if (chunk_save.Begin_Chunk (W3D_CHUNK_EMITTER) == TRUE) {
// Attempt to save the different sections of the emitter definition
if ((Save_Header (chunk_save) == WW3D_ERROR_OK) &&
(Save_User_Data (chunk_save) == WW3D_ERROR_OK) &&
(Save_Info (chunk_save) == WW3D_ERROR_OK) &&
(Save_InfoV2 (chunk_save) == WW3D_ERROR_OK) &&
(Save_Props (chunk_save) == WW3D_ERROR_OK) &&
(Save_Rotation_Keyframes (chunk_save) == WW3D_ERROR_OK) &&
(Save_Frame_Keyframes (chunk_save) == WW3D_ERROR_OK) &&
(Save_Blur_Time_Keyframes (chunk_save) == WW3D_ERROR_OK)
)
{
// Success!
ret_val = WW3D_ERROR_OK;
}
// Close the emitter chunk
chunk_save.End_Chunk ();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Save_Header
//
WW3DErrorType
ParticleEmitterDefClass::Save_Header (ChunkSaveClass &chunk_save)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
// Begin a chunk that identifies the emitter
if (chunk_save.Begin_Chunk (W3D_CHUNK_EMITTER_HEADER) == TRUE) {
// Fill the header structure
W3dEmitterHeaderStruct header = { 0 };
header.Version = W3D_CURRENT_EMITTER_VERSION;
::lstrcpyn (header.Name, m_pName, sizeof (header.Name));
header.Name[sizeof (header.Name) - 1] = 0;
// Write the header out to the chunk
if (chunk_save.Write (&header, sizeof (header)) == sizeof (header))
{
// Success!
ret_val = WW3D_ERROR_OK;
}
// End the header chunk
chunk_save.End_Chunk ();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Save_User_Data
//
WW3DErrorType
ParticleEmitterDefClass::Save_User_Data (ChunkSaveClass &chunk_save)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
// Begin a chunk that contains user information
if (chunk_save.Begin_Chunk (W3D_CHUNK_EMITTER_USER_DATA) == TRUE) {
DWORD string_len = m_pUserString ? (::lstrlen (m_pUserString) + 1) : 0;
// Fill the header structure
W3dEmitterUserInfoStruct user_info = { 0 };
user_info.Type = m_iUserType;
user_info.SizeofStringParam = string_len;
// Write the user information structure out to the chunk
if (chunk_save.Write (&user_info, sizeof (user_info)) == sizeof (user_info))
{
// Assume success
ret_val = WW3D_ERROR_OK;
// Do we need to write the user string to the file?
if (m_pUserString != NULL) {
// Now write the user string param to the file
if (chunk_save.Write (m_pUserString, string_len) != string_len) {
// Something went wrong
ret_val = WW3D_ERROR_SAVE_FAILED;
}
}
}
// End the user information chunk
chunk_save.End_Chunk ();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Save_Info
//
WW3DErrorType
ParticleEmitterDefClass::Save_Info (ChunkSaveClass &chunk_save)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
// Begin a chunk that identifies the generic emitter settings
if (chunk_save.Begin_Chunk (W3D_CHUNK_EMITTER_INFO) == TRUE) {
// Write the settings structure out to the chunk
if (chunk_save.Write (&m_Info, sizeof (m_Info)) == sizeof (m_Info))
{
// Success!
ret_val = WW3D_ERROR_OK;
}
// End the settings chunk
chunk_save.End_Chunk ();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Save_InfoV2
//
WW3DErrorType
ParticleEmitterDefClass::Save_InfoV2 (ChunkSaveClass &chunk_save)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
// Begin a chunk that identifies the generic emitter settings
if (chunk_save.Begin_Chunk (W3D_CHUNK_EMITTER_INFOV2) == TRUE) {
// Write the settings structure out to the chunk
if (chunk_save.Write (&m_InfoV2, sizeof (m_InfoV2)) == sizeof (m_InfoV2))
{
// Success!
ret_val = WW3D_ERROR_OK;
}
// End the settings chunk
chunk_save.End_Chunk ();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Save_Props
//
WW3DErrorType
ParticleEmitterDefClass::Save_Props (ChunkSaveClass &chunk_save)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
// Begin a chunk that identifies the generic emitter settings
if (chunk_save.Begin_Chunk (W3D_CHUNK_EMITTER_PROPS) == TRUE) {
//
// Fill in the property struct
//
W3dEmitterPropertyStruct info = { 0 };
info.ColorKeyframes = m_ColorKeyframes.NumKeyFrames + 1;
info.OpacityKeyframes = m_OpacityKeyframes.NumKeyFrames + 1;
info.SizeKeyframes = m_SizeKeyframes.NumKeyFrames + 1;
info.OpacityRandom = m_OpacityKeyframes.Rand;
info.SizeRandom = m_SizeKeyframes.Rand;
VECTOR3_TO_RGBA (m_ColorKeyframes.Rand, info.ColorRandom);
//
// Write the property structure out to the chunk
//
if (chunk_save.Write (&info, sizeof (info)) == sizeof (info)) {
//
// Save the keyframes
//
if ((Save_Color_Keyframes (chunk_save) == WW3D_ERROR_OK) &&
(Save_Opacity_Keyframes (chunk_save) == WW3D_ERROR_OK) &&
(Save_Size_Keyframes (chunk_save) == WW3D_ERROR_OK)) {
// Success!
ret_val = WW3D_ERROR_OK;
}
}
// End the settings chunk
chunk_save.End_Chunk ();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Save_Color_Keyframes
//
WW3DErrorType
ParticleEmitterDefClass::Save_Color_Keyframes (ChunkSaveClass &chunk_save)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
W3dEmitterColorKeyframeStruct info = { 0 };
info.Time = 0;
VECTOR3_TO_RGBA (m_ColorKeyframes.Start, info.Color);
//
// Write the starting color keyframe to the chunk
//
if (chunk_save.Write (&info, sizeof (info)) == sizeof (info)) {
//
// Write each of the remaining color keyframes to the chunk
//
int count = m_ColorKeyframes.NumKeyFrames;
bool success = true;
for (int index = 0; (index < count) && success; index ++) {
info.Time = m_ColorKeyframes.KeyTimes[index];
VECTOR3_TO_RGBA (m_ColorKeyframes.Values[index], info.Color);
success = (chunk_save.Write (&info, sizeof (info)) == sizeof (info));
}
ret_val = success ? WW3D_ERROR_OK : WW3D_ERROR_SAVE_FAILED;
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Save_Opacity_Keyframes
//
WW3DErrorType
ParticleEmitterDefClass::Save_Opacity_Keyframes (ChunkSaveClass &chunk_save)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
W3dEmitterOpacityKeyframeStruct info = { 0 };
info.Time = 0;
info.Opacity = m_OpacityKeyframes.Start;
//
// Write the starting keyframe to the chunk
//
if (chunk_save.Write (&info, sizeof (info)) == sizeof (info)) {
//
// Write each of the remaining keyframes to the chunk
//
int count = m_OpacityKeyframes.NumKeyFrames;
bool success = true;
for (int index = 0; (index < count) && success; index ++) {
info.Time = m_OpacityKeyframes.KeyTimes[index];
info.Opacity = m_OpacityKeyframes.Values[index];
success = (chunk_save.Write (&info, sizeof (info)) == sizeof (info));
}
ret_val = success ? WW3D_ERROR_OK : WW3D_ERROR_SAVE_FAILED;
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Save_Size_Keyframes
//
WW3DErrorType
ParticleEmitterDefClass::Save_Size_Keyframes (ChunkSaveClass &chunk_save)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
W3dEmitterSizeKeyframeStruct info = { 0 };
info.Time = 0;
info.Size = m_SizeKeyframes.Start;
//
// Write the starting keyframe to the chunk
//
if (chunk_save.Write (&info, sizeof (info)) == sizeof (info)) {
//
// Write each of the remaining keyframes to the chunk
//
int count = m_SizeKeyframes.NumKeyFrames;
bool success = true;
for (int index = 0; (index < count) && success; index ++) {
info.Time = m_SizeKeyframes.KeyTimes[index];
info.Size = m_SizeKeyframes.Values[index];
success = (chunk_save.Write (&info, sizeof (info)) == sizeof (info));
}
ret_val = success ? WW3D_ERROR_OK : WW3D_ERROR_SAVE_FAILED;
}
// Return the WW3DErrorType return code
return ret_val;
}
WW3DErrorType
ParticleEmitterDefClass::Save_Line_Properties (ChunkSaveClass &chunk_save)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
// Begin a chunk that identifies the line properties
if (chunk_save.Begin_Chunk (W3D_CHUNK_EMITTER_LINE_PROPERTIES) == TRUE) {
// Write the line properties structure out to the chunk
if (chunk_save.Write (&m_LineProperties, sizeof (m_LineProperties)) == sizeof (m_LineProperties))
{
// Success!
ret_val = WW3D_ERROR_OK;
}
// End the chunk
chunk_save.End_Chunk ();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Save_Rotation_Keyframes
// NOTE: Rotation keyframes are saved in a separate chunk unlike color,size,and
// opacity which are embedded inside the PROPS chunk.
//
WW3DErrorType
ParticleEmitterDefClass::Save_Rotation_Keyframes (ChunkSaveClass & chunk_save)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
// Begin a chunk that identifies the rotation keyframes
if (chunk_save.Begin_Chunk (W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES) == TRUE) {
// Write the header
W3dEmitterRotationHeaderStruct header;
header.KeyframeCount = m_RotationKeyframes.NumKeyFrames;
header.Random = m_RotationKeyframes.Rand;
header.OrientationRandom = m_InitialOrientationRandom;
chunk_save.Write (&header, sizeof (W3dEmitterRotationHeaderStruct));
// Write the keyframes
bool success = true;
W3dEmitterRotationKeyframeStruct key;
// Write the start keyframe
key.Time = 0;
key.Rotation = m_RotationKeyframes.Start;
chunk_save.Write (&key, sizeof (key));
// Write the remaining keyframes
for (unsigned int index = 0; (index < header.KeyframeCount) && success; index ++) {
key.Time = m_RotationKeyframes.KeyTimes[index];
key.Rotation = m_RotationKeyframes.Values[index];
success = (chunk_save.Write (&key, sizeof (key)) == sizeof (key));
}
ret_val = success ? WW3D_ERROR_OK : WW3D_ERROR_SAVE_FAILED;
// End the chunk
chunk_save.End_Chunk ();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Save_Frame_Keyframes
// NOTE: Frame keyframes are saved in a separate chunk unlike color,size,and
// opacity which are embedded inside the PROPS chunk.
//
WW3DErrorType
ParticleEmitterDefClass::Save_Frame_Keyframes (ChunkSaveClass & chunk_save)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
// Begin a chunk that identifies the rotation keyframes
if (chunk_save.Begin_Chunk (W3D_CHUNK_EMITTER_FRAME_KEYFRAMES) == TRUE) {
// Write the header
W3dEmitterFrameHeaderStruct header;
header.KeyframeCount = m_FrameKeyframes.NumKeyFrames;
header.Random = m_FrameKeyframes.Rand;
chunk_save.Write (&header, sizeof (W3dEmitterFrameHeaderStruct));
// Write the keyframes
bool success = true;
W3dEmitterFrameKeyframeStruct key;
// Write the start keyframe
key.Time = 0;
key.Frame = m_FrameKeyframes.Start;
chunk_save.Write (&key, sizeof (key));
// Write the remaining keyframes
for (unsigned int index = 0; (index < header.KeyframeCount) && success; index ++) {
key.Time = m_FrameKeyframes.KeyTimes[index];
key.Frame = m_FrameKeyframes.Values[index];
success = (chunk_save.Write (&key, sizeof (key)) == sizeof (key));
}
ret_val = success ? WW3D_ERROR_OK : WW3D_ERROR_SAVE_FAILED;
// End the chunk
chunk_save.End_Chunk ();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Save_Blur_Time_Keyframes
// NOTE: Blur Time keyframes are saved in a separate chunk unlike color,size,and
// opacity which are embedded inside the PROPS chunk.
//
WW3DErrorType
ParticleEmitterDefClass::Save_Blur_Time_Keyframes (ChunkSaveClass & chunk_save)
{
// Assume error
WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
// Begin a chunk that identifies the rotation keyframes
if (chunk_save.Begin_Chunk (W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES) == TRUE) {
// Write the header
W3dEmitterBlurTimeHeaderStruct header;
header.KeyframeCount = m_BlurTimeKeyframes.NumKeyFrames;
header.Random = m_BlurTimeKeyframes.Rand;
chunk_save.Write (&header, sizeof (W3dEmitterBlurTimeHeaderStruct));
// Write the keyframes
bool success = true;
W3dEmitterBlurTimeKeyframeStruct key;
// Write the start keyframe
key.Time = 0;
key.BlurTime = m_BlurTimeKeyframes.Start;
chunk_save.Write (&key, sizeof (key));
// Write the remaining keyframes
for (unsigned int index = 0; (index < header.KeyframeCount) && success; index ++) {
key.Time = m_BlurTimeKeyframes.KeyTimes[index];
key.BlurTime = m_BlurTimeKeyframes.Values[index];
success = (chunk_save.Write (&key, sizeof (key)) == sizeof (key));
}
ret_val = success ? WW3D_ERROR_OK : WW3D_ERROR_SAVE_FAILED;
// End the chunk
chunk_save.End_Chunk ();
}
// Return the WW3DErrorType return code
return ret_val;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Set_Color_Keyframes
//
void
ParticleEmitterDefClass::Set_Color_Keyframes (ParticlePropertyStruct<Vector3> &keyframes)
{
SAFE_DELETE_ARRAY (m_ColorKeyframes.KeyTimes);
SAFE_DELETE_ARRAY (m_ColorKeyframes.Values);
::Copy_Emitter_Property_Struct (m_ColorKeyframes, keyframes);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Set_Opacity_Keyframes
//
void
ParticleEmitterDefClass::Set_Opacity_Keyframes (ParticlePropertyStruct<float> &keyframes)
{
SAFE_DELETE_ARRAY (m_OpacityKeyframes.KeyTimes);
SAFE_DELETE_ARRAY (m_OpacityKeyframes.Values);
::Copy_Emitter_Property_Struct (m_OpacityKeyframes, keyframes);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Set_Size_Keyframes
//
void
ParticleEmitterDefClass::Set_Size_Keyframes (ParticlePropertyStruct<float> &keyframes)
{
SAFE_DELETE_ARRAY (m_SizeKeyframes.KeyTimes);
SAFE_DELETE_ARRAY (m_SizeKeyframes.Values);
::Copy_Emitter_Property_Struct (m_SizeKeyframes, keyframes);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Set_Rotation_Keyframes
//
void
ParticleEmitterDefClass::Set_Rotation_Keyframes (ParticlePropertyStruct<float> &keyframes, float orient_rnd)
{
SAFE_DELETE_ARRAY (m_RotationKeyframes.KeyTimes);
SAFE_DELETE_ARRAY (m_RotationKeyframes.Values);
::Copy_Emitter_Property_Struct (m_RotationKeyframes, keyframes);
m_InitialOrientationRandom = orient_rnd;
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Set_Frame_Keyframes
//
void
ParticleEmitterDefClass::Set_Frame_Keyframes (ParticlePropertyStruct<float> &keyframes)
{
SAFE_DELETE_ARRAY (m_FrameKeyframes.KeyTimes);
SAFE_DELETE_ARRAY (m_FrameKeyframes.Values);
::Copy_Emitter_Property_Struct (m_FrameKeyframes, keyframes);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Set_Blur_Time_Keyframes
//
void
ParticleEmitterDefClass::Set_Blur_Time_Keyframes (ParticlePropertyStruct<float> &keyframes)
{
SAFE_DELETE_ARRAY (m_BlurTimeKeyframes.KeyTimes);
SAFE_DELETE_ARRAY (m_BlurTimeKeyframes.Values);
::Copy_Emitter_Property_Struct (m_BlurTimeKeyframes, keyframes);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Get_Color_Keyframes
//
void
ParticleEmitterDefClass::Get_Color_Keyframes (ParticlePropertyStruct<Vector3> &keyframes) const
{
::Copy_Emitter_Property_Struct (keyframes, m_ColorKeyframes);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Get_Opacity_Keyframes
//
void
ParticleEmitterDefClass::Get_Opacity_Keyframes (ParticlePropertyStruct<float> &keyframes) const
{
::Copy_Emitter_Property_Struct (keyframes, m_OpacityKeyframes);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Get_Size_Keyframes
//
void
ParticleEmitterDefClass::Get_Size_Keyframes (ParticlePropertyStruct<float> &keyframes) const
{
::Copy_Emitter_Property_Struct (keyframes, m_SizeKeyframes);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Get_Rotation_Keyframes
//
void
ParticleEmitterDefClass::Get_Rotation_Keyframes (ParticlePropertyStruct<float> &keyframes) const
{
::Copy_Emitter_Property_Struct (keyframes, m_RotationKeyframes);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Get_Frame_Keyframes
//
void
ParticleEmitterDefClass::Get_Frame_Keyframes (ParticlePropertyStruct<float> &keyframes) const
{
::Copy_Emitter_Property_Struct (keyframes, m_FrameKeyframes);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Get_Blur_Time_Keyframes
//
void
ParticleEmitterDefClass::Get_Blur_Time_Keyframes (ParticlePropertyStruct<float> &blurtimeframes) const
{
::Copy_Emitter_Property_Struct (blurtimeframes, m_BlurTimeKeyframes);
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Create
//
RenderObjClass *
ParticleEmitterPrototypeClass::Create (void)
{
return ParticleEmitterClass::Create_From_Definition (*m_pDefinition);
}
///////////////////////////////////////////////////////////////////////////////////
//
// Load
//
PrototypeClass *
ParticleEmitterLoaderClass::Load_W3D (ChunkLoadClass &chunk_load)
{
// Assume failure
ParticleEmitterPrototypeClass *pprototype = NULL;
// Create a definition object
ParticleEmitterDefClass *pdefinition = new ParticleEmitterDefClass;
if (pdefinition != NULL) {
// Ask the definition object to load the emitter data
if (pdefinition->Load_W3D (chunk_load) != WW3D_ERROR_OK) {
// Error! Free the definition
delete pdefinition;
pdefinition = NULL;
} else {
// Success! Create a prototype from the definition
pprototype = new ParticleEmitterPrototypeClass (pdefinition);
}
}
// Return a pointer to the prototype
return pprototype;
}