//===========================================================================//
// File:	cmpnnt.cc                                                           //
// Project: MUNGA           Brick: Entity												  //
// Contents: 																					  //
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 12/14/94  ECH  Initial coding.                                            //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc.                //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "AdeptHeaders.hpp"

#include "ComponentHeaders.hpp"

//############################################################################
//############################    LFOChannel    ##############################
//############################################################################

//
// Shared Data Support
//
Channel::ClassData*
	LFOChannel::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	LFOChannel::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			LFOChannelClassID,
			"Adept::LFOChannel",
			ChannelOf<Scalar>::DefaultData,
			0,
			NULL
		);
	Register_Object(DefaultData);
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
LFOChannel::~LFOChannel()
{
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
LFOChannel*
	LFOChannel::Create(
		MemoryStream *stream,
		ComponentWeb *owning_web
	)
{
	Check_Object(stream);
	Check_Object(owning_web);
	Component *component = DoesComponentExist(stream, owning_web);
	LFOChannel *lfo;
	if (component)
	{
		lfo = Cast_Object(LFOChannel*, component);
		lfo->SkipStreamData(stream);
	}
	else
	{
		lfo = new LFOChannel(DefaultData, stream, owning_web);
		Register_Object(lfo);
	}
	return lfo;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
LFOChannel::LFOChannel(
	ClassData *class_data,
	MemoryStream *stream,
	ComponentWeb *owning_web
):
	ChannelOf<Scalar>(class_data, stream, owning_web)
{
	*stream >> waveForm;
	Verify(
		waveForm == SinusoidalWaveForm ||
		waveForm == SquareWaveForm ||
		waveForm == DescendingTriangularWaveForm ||
		waveForm == AscendingTriangularWaveForm
	);
	*stream >> minValue >> valueRange >> period >> phase;
	Verify(valueRange >= 0.0f);
	Verify(period > 0.0f);
	startTime = gos_GetElapsedTime() - phase;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	LFOChannel::SkipStreamData(MemoryStream *stream)
{
	Check_Object(this);
	Check_Object(stream);

	ChannelOf<Scalar>::SkipStreamData(stream);
	unsigned form;
	*stream >> form;
	Verify(form == waveForm);
	Scalar data;
	*stream >> data;
	Verify(data == minValue);
	*stream >> data;
	Verify(data == valueRange);
	*stream >> data;
	Verify(data == period);
	*stream >> data;
	Verify(data == phase);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	LFOChannel::Execute()
{
	Check_Object(this);

	switch (waveForm)
	{
	case SinusoidalWaveForm:
		{
			Scalar time_factor =
				static_cast<Scalar>((gos_GetElapsedTime() - startTime) / period);

			Scalar sample = (Sin(time_factor * Pi) + 1.0f) * 0.5f;
			Verify(0.0f <= sample && sample <= 1.0f);
			Verify(valueRange >= 0.0f);

			channelOutput = minValue + sample * valueRange;
			NotifyDependantsOfChange();
		}
		break;

	case SquareWaveForm:
		{
			Scalar 
				time_factor;
			Scalar
				output;
			
			time_factor =
				static_cast<Scalar>(gos_GetElapsedTime() - startTime);
			time_factor = (Scalar)fmod(time_factor, period);
			Verify(valueRange >= 0.0f);
			if (time_factor < (period * 0.5f))
			{
				output = minValue;
			}
			else
			{
				output = minValue + valueRange;
			}
			if (!Close_Enough(output, channelOutput))
			{
				channelOutput = output;
				NotifyDependantsOfChange();
			}
		}
		break;

	case DescendingTriangularWaveForm:
		{
			Scalar 
				time_factor;
			Scalar
				output;
			
			time_factor =
				static_cast<Scalar>(gos_GetElapsedTime() - startTime);
			time_factor = (Scalar)fmod(time_factor, period);
			Verify(valueRange >= 0.0f);
			output = 1.0f - (time_factor / period);
			if (!Close_Enough(output, channelOutput))
			{
				channelOutput = output;
				NotifyDependantsOfChange();
			}
		}
		break;

	case AscendingTriangularWaveForm:
		{
			Scalar 
				time_factor;
			Scalar
				output;
			
			time_factor = static_cast<Scalar>(gos_GetElapsedTime() - startTime);
			time_factor = (Scalar)fmod(time_factor, period);
			Verify(valueRange >= 0.0f);
			output = time_factor / period;
			if (!Close_Enough(output, channelOutput))
			{
				channelOutput = output;
				NotifyDependantsOfChange();
			}
		}
		break;
	}
}

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

//#############################################################################
//##########################    QuantizerChannel    ##########################
//#############################################################################

//
// Shared Data Support
//
Quantizer::ClassData*
	Quantizer::DefaultData = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Quantizer::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			QuantizerClassID,
			"Adept::Quantizer",
			ChannelOf<int>::DefaultData,
			0,
			NULL
		);
	Register_Object(DefaultData);
}

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

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Quantizer::~Quantizer()
{
	Unregister_Pointer(tableEntries);
	delete[] tableEntries;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Quantizer*
	Quantizer::Create(
		MemoryStream *stream,
		ComponentWeb *owning_web
	)
{
	Check_Object(stream);
	Check_Object(owning_web);
	Component *component = DoesComponentExist(stream, owning_web);
	Quantizer *quantizer;
	if (component)
	{
		quantizer = Cast_Object(Quantizer*, component);
		quantizer->SkipStreamData(stream);
	}
	else
	{
		quantizer = new Quantizer(DefaultData, stream, owning_web);
		Register_Object(quantizer);
	}
	return quantizer;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Quantizer::Quantizer(
	ClassData *class_data,
	MemoryStream *stream,
	ComponentWeb *owning_web
):
	ChannelOf<int>(class_data, stream, owning_web)
{
	//
	//---------------------
	// Hook up to our input
	//---------------------
	//
	ComponentID component_id;
	component_id.scriptResourceID = owning_web->GetScriptResourceID();
	*stream >> component_id.componentNumber;
	Component *component = owning_web->FindComponent(component_id);
	Check_Object(component);
	ChannelOf<Scalar>* channel = Cast_Object(ChannelOf<Scalar>*, component);
	channel->AddDependant(this);

	*stream >> tableSize;
	Verify(static_cast<unsigned>(tableSize) > 0);
	tableEntries = new Scalar[tableSize];
	Register_Pointer(tableEntries);
	for (int i=0; i<tableSize; ++i)
	{
		*stream >> tableEntries[i];
		#if defined(_ARMOR)
			if (i > 0)
			{
				Verify(tableEntries[i] > tableEntries[i-1]);
			}
		#endif
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Quantizer::SkipStreamData(MemoryStream *stream)
{
	Check_Object(this);
	Check_Object(stream);

	ChannelOf<int>::SkipStreamData(stream);
	stream->AdvancePointer(sizeof(componentID.componentNumber));
	int table_size;
	*stream >> table_size;
	Verify(table_size == tableSize);
	for (int i=0; i<tableSize; ++i)
	{
		Scalar entry;
		*stream >> entry;
		Verify(entry == tableEntries[i]);
	}
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Quantizer::ChannelChanged(Channel *channel)
{
	Check_Object(this);

	//
	//--------------------------
	// Get the new channel value
	//--------------------------
	//
	Check_Object(channel);
	ChannelOf<Scalar>* input = Cast_Object(ChannelOf<Scalar>*, channel);
	Scalar value = input->ReadChannel();

	//
	//----------------------------------------------------
	// Search the table to find the band the value fits in
	//----------------------------------------------------
	//
	Check_Pointer(tableEntries);
	for (int i=0; i<tableSize; ++i)
	{
		if (value < tableEntries[i])
		{
			break;
		}
	}

	//
	//--------------------------------------------------
	// If the band has changed, tell our downstream guys
	//--------------------------------------------------
	//
	if (i != channelOutput)
	{
		channelOutput = i;
		NotifyDependantsOfChange();
	}
}

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