//===========================================================================//
// File:	AudioRenderer.cpp                                                //
// Project: MUNGA           Brick: Video Renderer 	                         //
// Contents: Abstracted Base Video Renderer								     //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 03/04/97  JTR  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1997, Virtual World Entertainment, Inc.                     //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "AdeptHeaders.hpp"
#include "SpatializedChannel.hpp"
#include "SpatializedCommand.hpp"
#include "AudioRenderer.hpp"
#include "Interface.hpp"

//##########################################################################
//############################    SpatializedChannel    ##########################
//##########################################################################

SpatializedChannel::ClassData* SpatializedChannel::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void SpatializedChannel::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			SpatializedChannelClassID,
			"Adept::SpatializedChannel",
			BaseClass::DefaultData
		);
	Register_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void SpatializedChannel::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void SpatializedChannel::TestInstance() const
{
	Verify(IsDerivedFrom(DefaultData));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SpatializedChannel::SpatializedChannel(ClassData *class_data, int channel, int type):
	AudioChannel(class_data, channel, type, SpatializedProperties)
{
	Check_Object(this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SpatializedChannel::~SpatializedChannel()
{
	Check_Object(this);
	Stop();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void SpatializedChannel::Activate(AudioCommand *command)
{
	Check_Object(this);
	Verify(m_sample->m_3D);

	//
	//------------------------------
	// Set the position and velocity
	//------------------------------
	//
	SetPosition(Cast_Object(SpatializedCommand*, command)->GetPosition());
	SetBearing();
	BaseClass::Activate(command);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void SpatializedChannel::Execute(Stuff::Time till)
{
	Check_Object(this);
	Verify(m_playMode != gosAudio_Stop);
	Verify(m_sample->m_3D);
	AUDIO_RENDER("Execute::SpatializedChannel");

	//
	//-----------------------------------------
	// If we have stopped, deactivate the sound
	//-----------------------------------------
	//
	gosAudio_PlayMode play_mode = gosAudio_GetChannelPlayMode(m_channel);
	switch (play_mode)
	{
	case gosAudio_Pause:
		return;

	case gosAudio_Stop:
		if (m_playMode == gosAudio_Loop)
		{
			gosAudio_SetChannelPlayMode(m_channel, m_playMode);
			goto Still_Playing;
		}
		Deactivate();
		break;

	//
	//----------------------------------------------
	// Otherwise, compute our new bearing to the ear
	//----------------------------------------------
	//
	default:
		Verify(m_playMode == play_mode);
Still_Playing:
		SetBearing();
		SpatializedCommand *command = Cast_Object(SpatializedCommand*, m_command);
		if (m_bearing.range<command->m_nearClip || m_bearing.range>command->m_farClip)
			Stop();
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void SpatializedChannel::SetBearing()
{
	Check_Object(this);

	LinearMatrix4D ear_to_world = AudioRenderer::Instance->GetInterface()->GetLocalToWorld();
	Point3D ear_in_world(ear_to_world);
	Vector3D ear_to_command;
	ear_to_command.Subtract(m_position, ear_in_world);
	m_bearing = ear_to_command;
}
