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/soundrobj.cpp

768 lines
19 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:: /Commando/Code/ww3d2/soundrobj.cpp $*
* *
* Author:: Patrick Smith *
* *
* $Modtime:: 1/16/02 10:21a $*
* *
* $Revision:: 4 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "soundrobj.h"
#include "audiblesound.h"
#include "sound3d.h"
#include "wwaudio.h"
#include "ffactory.h"
#include "wwfile.h"
#include "chunkio.h"
#include "scene.h"
//////////////////////////////////////////////////////////////////////////////////
// Global variables
//////////////////////////////////////////////////////////////////////////////////
SoundRenderObjLoaderClass _SoundRenderObjLoader;
//////////////////////////////////////////////////////////////////////////////////
//
// SoundRenderObjClass
//
//////////////////////////////////////////////////////////////////////////////////
SoundRenderObjClass::SoundRenderObjClass (void)
: Flags (FLAG_STOP_WHEN_HIDDEN),
Sound (NULL),
IsInitialized (false)
{
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// SoundRenderObjClass
//
//////////////////////////////////////////////////////////////////////////////////
SoundRenderObjClass::SoundRenderObjClass (const SoundRenderObjClass &src)
: Flags (FLAG_STOP_WHEN_HIDDEN),
Sound (NULL),
IsInitialized (false)
{
(*this) = src;
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// ~SoundRenderObjClass
//
//////////////////////////////////////////////////////////////////////////////////
SoundRenderObjClass::~SoundRenderObjClass (void)
{
//
// Remove the old sound from the world (if necessary)
//
if (Sound != NULL) {
Sound->Attach_To_Object (NULL);
Sound->Remove_From_Scene ();
REF_PTR_RELEASE (Sound);
}
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// operator=
//
//////////////////////////////////////////////////////////////////////////////////
const SoundRenderObjClass &
SoundRenderObjClass::operator= (const SoundRenderObjClass &src)
{
//
// Create a definition from the src sound object
//
AudibleSoundDefinitionClass definition;
definition.Initialize_From_Sound (src.Sound);
//
// Create the internal sound object from the definition
//
Set_Sound (&definition);
//
// Copy the other misc settings
//
Name = src.Name;
return *this;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Set_Sound
//
//////////////////////////////////////////////////////////////////////////////////
void
SoundRenderObjClass::Set_Sound (AudibleSoundDefinitionClass *definition)
{
//
// Remove the old sound from the world (if necessary)
//
if (Sound != NULL) {
Sound->Remove_From_Scene ();
REF_PTR_RELEASE (Sound);
}
//
// Create the sound object from its definition
//
if (definition != NULL) {
Sound = (AudibleSoundClass *)definition->Create ();
}
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// On_Frame_Update
//
//////////////////////////////////////////////////////////////////////////////////
void
SoundRenderObjClass::On_Frame_Update (void)
{
//
// Stop the sound from playing (if necessary)
//
if ( Sound != NULL &&
Sound->Is_In_Scene () &&
Sound->Is_Playing () == false)
{
Sound->Attach_To_Object (NULL);
Sound->Remove_From_Scene ();
}
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Set_Hidden
//
//////////////////////////////////////////////////////////////////////////////////
void
SoundRenderObjClass::Set_Hidden (int onoff)
{
int before = Is_Not_Hidden_At_All ();
RenderObjClass::Set_Hidden (onoff);
//
// If we've changed state, then update the visibility
//
if (IsInitialized == false || Is_Not_Hidden_At_All () != before) {
IsInitialized = true;
Update_On_Visibilty ();
}
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Set_Visible
//
//////////////////////////////////////////////////////////////////////////////////
void
SoundRenderObjClass::Set_Visible (int onoff)
{
int before = Is_Not_Hidden_At_All ();
RenderObjClass::Set_Visible (onoff);
//
// If we've changed state, then update the visibility
//
if (IsInitialized == false || Is_Not_Hidden_At_All () != before) {
IsInitialized = true;
Update_On_Visibilty ();
}
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Set_Animation_Hidden
//
//////////////////////////////////////////////////////////////////////////////////
void
SoundRenderObjClass::Set_Animation_Hidden (int onoff)
{
int before = Is_Not_Hidden_At_All ();
RenderObjClass::Set_Animation_Hidden (onoff);
//
// If we've changed state, then update the visibility
//
if (IsInitialized == false || Is_Not_Hidden_At_All () != before) {
IsInitialized = true;
Update_On_Visibilty ();
}
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Set_Force_Visible
//
//////////////////////////////////////////////////////////////////////////////////
void
SoundRenderObjClass::Set_Force_Visible (int onoff)
{
int before = Is_Not_Hidden_At_All ();
RenderObjClass::Set_Force_Visible (onoff);
//
// If we've changed state, then update the visibility
//
if (IsInitialized == false || Is_Not_Hidden_At_All () != before) {
IsInitialized = true;
Update_On_Visibilty ();
}
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Update_On_Visibilty
//
//////////////////////////////////////////////////////////////////////////////////
void
SoundRenderObjClass::Update_On_Visibilty (void)
{
if (Sound == NULL) {
return ;
}
//
// Ensure our transform is correct
//
Validate_Transform ();
//
// Either add the sound object to the sound scene
// or remove it from the sound scene depending
// on the visibility state of the render object.
//
if ( Is_Not_Hidden_At_All () &&
Sound->Is_In_Scene () == false &&
Peek_Scene () != NULL)
{
//
// Make sure the sound is properly attached to this render
// object and then add it to the scene
//
Sound->Attach_To_Object (this);
Sound->Add_To_Scene (true);
} else if ((Is_Not_Hidden_At_All () == false) || (Peek_Scene () == NULL)) {
//
// Remove the sound from the scene (it will stop playing)
//
if ((Flags & FLAG_STOP_WHEN_HIDDEN) != 0 || (Peek_Scene () == NULL)) {
Sound->Attach_To_Object (NULL);
Sound->Remove_From_Scene ();
}
}
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Get_Sound
//
//////////////////////////////////////////////////////////////////////////////////
AudibleSoundClass *
SoundRenderObjClass::Get_Sound (void) const
{
if (Sound != NULL) {
Sound->Add_Ref ();
}
return Sound;
}
//////////////////////////////////////////////////////////////////////////////
//
// Set_Flag
//
//////////////////////////////////////////////////////////////////////////////
void
SoundRenderObjClass::Set_Flag (uint32 flag, bool onoff)
{
Flags &= ~flag;
if (onoff) {
Flags |= flag;
}
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Notify_Added
//
//////////////////////////////////////////////////////////////////////////////////
void
SoundRenderObjClass::Notify_Added (SceneClass *scene)
{
RenderObjClass::Notify_Added (scene);
scene->Register (this, SceneClass::ON_FRAME_UPDATE);
Update_On_Visibilty ();
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Notify_Removed
//
//////////////////////////////////////////////////////////////////////////////////
void
SoundRenderObjClass::Notify_Removed (SceneClass *scene)
{
scene->Unregister (this, SceneClass::ON_FRAME_UPDATE);
RenderObjClass::Notify_Removed (scene);
Update_On_Visibilty ();
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Set_Transform
//
//////////////////////////////////////////////////////////////////////////////////
void
SoundRenderObjClass::Set_Transform (const Matrix3D &tm)
{
RenderObjClass::Set_Transform (tm);
if (IsInitialized == false) {
IsInitialized = true;
Update_On_Visibilty ();
}
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Set_Position
//
//////////////////////////////////////////////////////////////////////////////////
void
SoundRenderObjClass::Set_Position (const Vector3 &pos)
{
RenderObjClass::Set_Position (pos);
if (IsInitialized == false) {
IsInitialized = true;
Update_On_Visibilty ();
}
return ;
}
//*********************************************************************************
//
// Start of SoundRenderObjDefClass
//
//*********************************************************************************
//////////////////////////////////////////////////////////////////////////////////
//
// SoundRenderObjDefClass
//
//////////////////////////////////////////////////////////////////////////////////
SoundRenderObjDefClass::SoundRenderObjDefClass (void)
: Version (W3D_CURRENT_SOUNDROBJ_VERSION),
Flags (SoundRenderObjClass::FLAG_STOP_WHEN_HIDDEN)
{
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// SoundRenderObjDefClass
//
//////////////////////////////////////////////////////////////////////////////////
SoundRenderObjDefClass::SoundRenderObjDefClass (SoundRenderObjClass &render_obj)
: Version (W3D_CURRENT_SOUNDROBJ_VERSION),
Flags (SoundRenderObjClass::FLAG_STOP_WHEN_HIDDEN)
{
Initialize (render_obj);
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// SoundRenderObjDefClass
//
//////////////////////////////////////////////////////////////////////////////////
SoundRenderObjDefClass::SoundRenderObjDefClass (const SoundRenderObjDefClass &src)
: Version (W3D_CURRENT_SOUNDROBJ_VERSION),
Flags (SoundRenderObjClass::FLAG_STOP_WHEN_HIDDEN)
{
(*this) = src;
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// ~SoundRenderObjDefClass
//
//////////////////////////////////////////////////////////////////////////////////
SoundRenderObjDefClass::~SoundRenderObjDefClass (void)
{
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// operator=
//
//////////////////////////////////////////////////////////////////////////////////
const SoundRenderObjDefClass &
SoundRenderObjDefClass::operator= (const SoundRenderObjDefClass &src)
{
Definition = src.Definition;
Version = src.Version;
Name = src.Name;
return (*this);
}
//////////////////////////////////////////////////////////////////////////////////
//
// Create
//
//////////////////////////////////////////////////////////////////////////////////
RenderObjClass *
SoundRenderObjDefClass::Create (void)
{
//
// Allocate and initialize a new instance
//
SoundRenderObjClass *render_obj = new SoundRenderObjClass;
render_obj->Set_Name (Name);
render_obj->Set_Sound (&Definition);
render_obj->Set_Flags (Flags);
return render_obj;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Initialize
//
//////////////////////////////////////////////////////////////////////////////////
void
SoundRenderObjDefClass::Initialize (SoundRenderObjClass &render_obj)
{
//
// Copy the settings from the sound object into our definition
//
Definition.Initialize_From_Sound (render_obj.Peek_Sound ());
//
// Copy the flags from the render object
//
Flags = (SoundRenderObjClass::FLAGS)render_obj.Get_Flags ();
//
// Copy the name
//
Name = render_obj.Get_Name ();
return ;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Load
//
///////////////////////////////////////////////////////////////////////////////////
WW3DErrorType
SoundRenderObjDefClass::Load_W3D (ChunkLoadClass &cload)
{
WW3DErrorType retval = WW3D_ERROR_LOAD_FAILED;
//
// Attempt to read the different sections of the definition
//
if ((Read_Header (cload) == WW3D_ERROR_OK) &&
(Read_Definition (cload) == WW3D_ERROR_OK))
{
retval = WW3D_ERROR_OK;
}
return retval;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Save_W3D
//
//////////////////////////////////////////////////////////////////////////////////
WW3DErrorType
SoundRenderObjDefClass::Save_W3D (ChunkSaveClass &csave)
{
WW3DErrorType retval = WW3D_ERROR_SAVE_FAILED;
//
// Begin a chunk that identifies a sound render object
//
if (csave.Begin_Chunk (W3D_CHUNK_SOUNDROBJ) == TRUE) {
//
// Attempt to save the different sections of the aggregate definition
//
if ((Write_Header (csave) == WW3D_ERROR_OK) &&
(Write_Definition (csave) == WW3D_ERROR_OK))
{
retval = WW3D_ERROR_OK;
}
csave.End_Chunk ();
}
return retval;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Read_Header
//
///////////////////////////////////////////////////////////////////////////////////
WW3DErrorType
SoundRenderObjDefClass::Read_Header (ChunkLoadClass &cload)
{
WW3DErrorType retval = WW3D_ERROR_LOAD_FAILED;
//
// Is this the header chunk?
//
if (cload.Open_Chunk () &&
(cload.Cur_Chunk_ID () == W3D_CHUNK_SOUNDROBJ_HEADER))
{
//
// Read the header from the chunk
//
W3dSoundRObjHeaderStruct header = { 0 };
if (cload.Read (&header, sizeof (header)) == sizeof (header)) {
//
// Copy the names from the header structure
//
Name = header.Name;
Version = header.Version;
Flags = (SoundRenderObjClass::FLAGS)header.Flags;
retval = WW3D_ERROR_OK;
}
cload.Close_Chunk ();
}
return retval;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Read_Definition
//
///////////////////////////////////////////////////////////////////////////////////
WW3DErrorType
SoundRenderObjDefClass::Read_Definition (ChunkLoadClass &cload)
{
WW3DErrorType retval = WW3D_ERROR_LOAD_FAILED;
//
// Is this the right chunk?
//
if (cload.Open_Chunk () &&
(cload.Cur_Chunk_ID () == W3D_CHUNK_SOUNDROBJ_DEFINITION))
{
//
// Ask the definition to load its settings from the chunk
//
if (Definition.Load (cload)) {
retval = WW3D_ERROR_OK;
}
cload.Close_Chunk ();
}
return retval;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Write_Header
//
///////////////////////////////////////////////////////////////////////////////////
WW3DErrorType
SoundRenderObjDefClass::Write_Header (ChunkSaveClass &csave)
{
WW3DErrorType retval = WW3D_ERROR_SAVE_FAILED;
//
// Begin a chunk that identifies the aggregate
//
if (csave.Begin_Chunk (W3D_CHUNK_SOUNDROBJ_HEADER) == TRUE) {
//
// Fill the header structure
//
W3dSoundRObjHeaderStruct header = { 0 };
header.Version = W3D_CURRENT_AGGREGATE_VERSION;
header.Flags = Flags;
::lstrcpyn (header.Name, (const char *)Name, sizeof (header.Name));
header.Name[sizeof (header.Name) - 1] = 0;
//
// Write the header out to the chunk
//
if (csave.Write (&header, sizeof (header)) == sizeof (header)) {
retval = WW3D_ERROR_OK;
}
// End the header chunk
csave.End_Chunk ();
}
return retval;
}
///////////////////////////////////////////////////////////////////////////////////
//
// Write_Definition
//
///////////////////////////////////////////////////////////////////////////////////
WW3DErrorType
SoundRenderObjDefClass::Write_Definition (ChunkSaveClass &csave)
{
WW3DErrorType retval = WW3D_ERROR_SAVE_FAILED;
//
// Save the definition to its own chunk
//
if (csave.Begin_Chunk (W3D_CHUNK_SOUNDROBJ_DEFINITION) == TRUE) {
if (Definition.Save (csave)) {
retval = WW3D_ERROR_OK;
}
csave.End_Chunk ();
}
return retval;
}
//*********************************************************************************
//
// Start of SoundRenderObjDefClass
//
//*********************************************************************************
///////////////////////////////////////////////////////////////////////////////////
//
// Load_W3D
//
///////////////////////////////////////////////////////////////////////////////////
PrototypeClass *
SoundRenderObjLoaderClass::Load_W3D (ChunkLoadClass &cload)
{
SoundRenderObjPrototypeClass *prototype = NULL;
//
// Create a definition object
//
SoundRenderObjDefClass *definition = new SoundRenderObjDefClass;
if (definition != NULL) {
//
// Ask the definition object to load the sound data
//
if (definition->Load_W3D (cload) == WW3D_ERROR_OK) {
//
// Success! Create a prototype from the definition
//
prototype = new SoundRenderObjPrototypeClass (definition);
}
REF_PTR_RELEASE (definition);
}
return prototype;
}