4.10 reconstruction: BTL4OPT.EXE links clean and BOOTS to the first staged brick
The reconstructed tree now produces a runnable binary with the authentic 1995 toolchain (BC4.52 / tlink32 / DPMI32): - BTL4.CPP main TU reconstructed from the 4.11 Ghidra decomp (FUN_0040109c) + the 4.10 binary's own string pool + surviving RPL4TOOL.CPP house style; probe_main.cpp scaffold retired (BTL4.NOTES.md documents every decoded call) - L4NET.CPP staged: L4NetworkManager ctor/dtor + 10 vtable-pulled virtuals (standalone-benign ones no-op, network ones Fail loudly) + NetNub client globals (Net_Common_Ptr=NULL routes L4File to its plain-DOS path) - build410.sh: libs now built in the AUTHENTIC makefile member order (MUNGA.MAK / mungal4.mak / BT.MAK / BTL4.MAK). Order is load-bearing: tlink emits static-init records in module pull order, and alphabetical order booted into a null-vptr crash (IcomManager::ClassDerivations constructing before parent NetworkClient::ClassDerivations). Also fixed stage_link to the proven 32-bit lib set (SOSDBXC+SOSMBXC, no WATTCPLG) - BOXTREE.HPP MemoryBlock unify, BTL4GRND notify stubs, remaining engine backfills (audio/gauge/resource/stream TUs) that closed the deep ledger Smoke test (DOSBox-X + 32RTM, copy of the pod BT tree, our exe swapped in): BattleTech v4.10 BTL4Application::BTL4Application l4net.cpp(22): L4NetworkManager -- l4net.cpp not yet reconstructed Static init, main, -egg parse, BTL4.RES load (version 1.0.6 check passes), ApplicationManager and the BTL4Application ctor chain all execute real reconstructed code; boot halts at the first staged Fail() as designed. Next brick: the real l4net.cpp body. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,540 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(AUDREND_HPP)
|
||||
# include <audrend.hpp>
|
||||
# endif
|
||||
# if !defined(AUDENT_HPP)
|
||||
# include <audent.hpp>
|
||||
# endif
|
||||
# if !defined(JMOVER_HPP)
|
||||
# include <jmover.hpp>
|
||||
# endif
|
||||
# if !defined(APP_HPP)
|
||||
# include <app.hpp>
|
||||
# endif
|
||||
|
||||
//#############################################################################
|
||||
//########################### AudioRenderer #############################
|
||||
//#############################################################################
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// AudioRenderer
|
||||
//#############################################################################
|
||||
//
|
||||
AudioRenderer::AudioRenderer(RendererRate render_rate):
|
||||
Renderer(
|
||||
render_rate,
|
||||
MaxRendererComplexity,
|
||||
DefaultRendererPriority,
|
||||
AudioInterestType,
|
||||
DefaultInterestDepth,
|
||||
AudioRendererClassID
|
||||
),
|
||||
audioEventSocket(NULL, False)
|
||||
{
|
||||
audioHead = NULL;
|
||||
|
||||
#ifdef LAB_ONLY
|
||||
sourceClippedCount = 0;
|
||||
sourceStartCount = 0;
|
||||
sourceSuspendCount = 0;
|
||||
sourceResumeCount = 0;
|
||||
doubleTriggerCount = 0;
|
||||
resourceStealCount = 0;
|
||||
resourceStealPriorityCount = 0;
|
||||
resourceStealVolumeCount = 0;
|
||||
stealShortDurationCount = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// ~AudioRenderer
|
||||
//#############################################################################
|
||||
//
|
||||
AudioRenderer::~AudioRenderer()
|
||||
{
|
||||
Unregister_Object(audioHead);
|
||||
delete audioHead;
|
||||
|
||||
#ifdef LAB_ONLY
|
||||
cout << "AudioRenderer::~AudioRenderer - sourceClippedCount="
|
||||
<< sourceClippedCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - sourceStartCount="
|
||||
<< sourceStartCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - sourceSuspendCount="
|
||||
<< sourceSuspendCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - sourceResumeCount="
|
||||
<< sourceResumeCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - doubleTriggerCount="
|
||||
<< doubleTriggerCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - resourceStealCount="
|
||||
<< resourceStealCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - resourceStealPriorityCount="
|
||||
<< resourceStealPriorityCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - resourceStealVolumeCount="
|
||||
<< resourceStealVolumeCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - stealShortDurationCount="
|
||||
<< stealShortDurationCount << "\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// Initialize
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioRenderer::Initialize()
|
||||
{
|
||||
audioHead = MakeAudioHead();
|
||||
Register_Object(audioHead);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// TestInstance
|
||||
//#############################################################################
|
||||
//
|
||||
Logical
|
||||
AudioRenderer::TestInstance() const
|
||||
{
|
||||
Renderer::TestInstance();
|
||||
if (audioHead != NULL)
|
||||
{
|
||||
Check(audioHead);
|
||||
}
|
||||
Check(&audioEventSocket);
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// LinkToEntity
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioRenderer::LinkToEntity(Entity *entity)
|
||||
{
|
||||
Check(this);
|
||||
Check(entity);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Link the head to the entity
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
Check(audioHead);
|
||||
audioHead->LinkToEntity(entity);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Call inherited method
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
Renderer::LinkToEntity(entity);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// ExecuteImplementation
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioRenderer::ExecuteImplementation(
|
||||
RendererComplexity,
|
||||
RendererOrigin::InterestingEntityIterator*
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check(audioHead);
|
||||
audioHead->Execute();
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// PostAudioRequestMessage
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioRenderer::PostAudioRequestMessage(
|
||||
AudioSource *audio_source,
|
||||
AudioSource::RequestMessage *message
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check(audio_source);
|
||||
Check(message);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// If audio source is clipped and the source is transient
|
||||
// Then ignore
|
||||
// Else set priority and volume
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
AudioSourcePriority
|
||||
audio_source_priority;
|
||||
AudioControlValue
|
||||
audio_source_volume_scale;
|
||||
|
||||
if (audio_source->IsAudioSourceClipped(GetAudioHead()))
|
||||
{
|
||||
//
|
||||
// If it is a transient source then ignore request
|
||||
//
|
||||
if (audio_source->GetAudioRenderType() == TransientAudioRenderType)
|
||||
{
|
||||
#ifdef LAB_ONLY
|
||||
sourceClippedCount++;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
audio_source_priority = audio_source->GetAudioSourcePriority();
|
||||
audio_source_volume_scale = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
audio_source_priority = audio_source->GetAudioSourcePriority();
|
||||
// (task #50, AUDIO_FIDELITY F19) COLD-START PRIME: an idle source's own
|
||||
// watcher socket only executes at Start attempts, so its authored
|
||||
// AudioControlSmoothers (footstep volume: N=30/15, fill 0) warmed ONE
|
||||
// sample per attempt -- and the transient drop gate below (vol < 0.3)
|
||||
// rejected the first ~25 footfalls (~10-20 s of silent steps) before
|
||||
// the average could cross the gate. On a Start request, pump the
|
||||
// source's watchers a full smoother window so the volume chain is
|
||||
// evaluated at its True steady state; the smoother keeps its authored
|
||||
audio_source_volume_scale = audio_source->CalculateSourceVolumeScale();
|
||||
}
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// If this a transient source and volume is lower than threshold
|
||||
// Then return
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// DIAG (BT_AUDIO_NODROP): deliver low-volume transient starts anyway (at a
|
||||
// floor volume) to isolate volume-feed problems from the rest of the chain.
|
||||
if (getenv("BT_AUDIO_NODROP") &&
|
||||
message->controlID == StartAudioControlID &&
|
||||
audio_source->GetAudioRenderType() == TransientAudioRenderType &&
|
||||
audio_source_volume_scale < LowAudioVolumeThreshold)
|
||||
{
|
||||
DEBUG_STREAM << "[spatial] NODROP forcing start src=" << (void*)audio_source
|
||||
<< " vol=" << audio_source_volume_scale << "\n" << flush;
|
||||
audio_source->ReceiveControl(VolumeAudioControlID, 0.7f);
|
||||
audio_source_volume_scale = 0.7f;
|
||||
}
|
||||
if (
|
||||
message->controlID == StartAudioControlID &&
|
||||
audio_source->GetAudioRenderType() == TransientAudioRenderType &&
|
||||
audio_source_volume_scale < LowAudioVolumeThreshold
|
||||
)
|
||||
{
|
||||
#ifdef LAB_ONLY
|
||||
sourceClippedCount++;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Create audio weight based on priority and volume
|
||||
// Add audio event
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
AudioWeighting
|
||||
audio_weight(audio_source_priority, audio_source_volume_scale);
|
||||
AudioEvent
|
||||
*audio_event;
|
||||
|
||||
audio_event = new AudioEvent(audio_source, message);
|
||||
Register_Object(audio_event);
|
||||
audioEventSocket.AddValue(audio_event, audio_weight);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// ProcessAudioRequestMessage
|
||||
//#############################################################################
|
||||
//
|
||||
Logical
|
||||
AudioRenderer::ProcessAudioRequestMessage()
|
||||
{
|
||||
//
|
||||
// Process high priority, high volume event
|
||||
//
|
||||
AudioEventIterator
|
||||
iterator(&audioEventSocket);
|
||||
AudioEvent
|
||||
*audio_event;
|
||||
|
||||
Logical stuff = False;
|
||||
while ((audio_event = iterator.GetCurrent()) != NULL)
|
||||
{
|
||||
stuff = True;
|
||||
Check(audio_event);
|
||||
audio_event->Process();
|
||||
//return True;
|
||||
}
|
||||
return stuff;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// FlushAudioMessages
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioRenderer::FlushAudioMessages(AudioSource *audio_source)
|
||||
{
|
||||
Check(this);
|
||||
Check(audio_source);
|
||||
|
||||
//
|
||||
// Process matching events
|
||||
//
|
||||
AudioEventIterator
|
||||
iterator(&audioEventSocket);
|
||||
AudioEvent
|
||||
*audio_event;
|
||||
|
||||
while ((audio_event = iterator.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(audio_event);
|
||||
if (audio_event->targetReceiver.GetCurrent() == audio_source)
|
||||
{
|
||||
if (audio_event->messageToSend->controlID == StopAudioControlID)
|
||||
{
|
||||
audio_event->Process();
|
||||
}
|
||||
else
|
||||
{
|
||||
Unregister_Object(audio_event);
|
||||
delete audio_event;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// MakeAudioHead
|
||||
//#############################################################################
|
||||
//
|
||||
AudioHead*
|
||||
AudioRenderer::MakeAudioHead()
|
||||
{
|
||||
return new AudioHead;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// StartEntityEffectImplementation
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioRenderer::StartEntityEffectImplementation(
|
||||
Entity *parent_entity,
|
||||
DamageZone *damage_zone,
|
||||
ResourceDescription::ResourceID resource_ID
|
||||
)
|
||||
{
|
||||
SET_AUDIO_RENDERER();
|
||||
|
||||
Check(this);
|
||||
Check(parent_entity);
|
||||
Check(damage_zone);
|
||||
Verify(resource_ID != ResourceDescription::NullResourceID);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Get the audio resource for this effect
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
ResourceDescription *audio_resource_description;
|
||||
|
||||
Check(application);
|
||||
Check(application->GetResourceFile());
|
||||
audio_resource_description =
|
||||
application->GetResourceFile()->SearchList(
|
||||
resource_ID,
|
||||
ResourceDescription::AudioStreamListResourceType
|
||||
);
|
||||
if (audio_resource_description == NULL)
|
||||
{
|
||||
CLEAR_AUDIO_RENDERER();
|
||||
return;
|
||||
}
|
||||
Check(audio_resource_description);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Get the resource ID for the model resource for the audio effect entity
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
ResourceDescription *model_resource_description;
|
||||
|
||||
Check(application);
|
||||
Check(application->GetResourceFile());
|
||||
Check(audio_resource_description);
|
||||
model_resource_description =
|
||||
application->GetResourceFile()->SearchList(
|
||||
audio_resource_description->resourceID,
|
||||
ResourceDescription::ModelListResourceType
|
||||
);
|
||||
if (model_resource_description == NULL)
|
||||
{
|
||||
CLEAR_AUDIO_RENDERER();
|
||||
return;
|
||||
}
|
||||
Check(model_resource_description);
|
||||
model_resource_description->Lock();
|
||||
audio_resource_description->Lock();
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Get the entity segment
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
Entity *linked_entity;
|
||||
AudioRepresentation audio_representation;
|
||||
EntitySegment *parent_entity_segment;
|
||||
|
||||
linked_entity = GetLinkedEntity();
|
||||
Check(linked_entity);
|
||||
audio_representation =
|
||||
(AudioRepresentation)parent_entity->GetAudioRepresentation(
|
||||
linked_entity
|
||||
);
|
||||
|
||||
parent_entity_segment = damage_zone->GetCurrentEffectSite(
|
||||
(audio_representation == InternalAudioRepresentation) ?
|
||||
DamageZone::InternalAudioEffectSite :
|
||||
DamageZone::ExternalAudioEffectSite
|
||||
);
|
||||
Check(parent_entity_segment);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Create the audio effect entity with this resource
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
JointedMover *jointed_mover;
|
||||
|
||||
Verify(parent_entity->IsDerivedFrom(JointedMover::ClassDerivations));
|
||||
jointed_mover = Cast_Object(JointedMover*, parent_entity);
|
||||
Check(jointed_mover);
|
||||
|
||||
AudioEntity::MakeMessage
|
||||
make_message(
|
||||
model_resource_description->resourceID,
|
||||
jointed_mover,
|
||||
parent_entity_segment
|
||||
);
|
||||
#if DEBUG_LEVEL>0
|
||||
AudioEntity *audio_entity =
|
||||
#endif
|
||||
AudioEntity::Make(&make_message);
|
||||
Register_Object(audio_entity);
|
||||
|
||||
model_resource_description->Unlock();
|
||||
audio_resource_description->Unlock();
|
||||
|
||||
CLEAR_AUDIO_RENDERER();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~ AudioRenderer profile bits ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#if defined(TRACE_AUDIO_RENDERER)
|
||||
BitTrace Audio_Renderer("Audio Renderer");
|
||||
#endif
|
||||
|
||||
#if defined(TRACE_AUDIO_RENDERER_CREATE_OBJECTS)
|
||||
BitTrace Audio_Renderer_Create_Objects("Audio Renderer Create Objects");
|
||||
#endif
|
||||
|
||||
#if defined(TRACE_AUDIO_RENDERER_DESTROY_OBJECTS)
|
||||
BitTrace Audio_Renderer_Destroy_Objects("Audio Renderer Destroy Objects");
|
||||
#endif
|
||||
|
||||
#if defined(TRACE_AUDIO_RENDERER_START_HANDLER)
|
||||
BitTrace Audio_Renderer_Start_Handler("Audio Renderer Start Handler");
|
||||
#endif
|
||||
|
||||
#if defined(TRACE_AUDIO_RENDERER_STOP_HANDLER)
|
||||
BitTrace Audio_Renderer_Stop_Handler("Audio Renderer Stop Handler");
|
||||
#endif
|
||||
|
||||
#if defined(TRACE_AUDIO_RENDERER_EXECUTE)
|
||||
BitTrace Audio_Renderer_Execute("Audio Renderer Execute");
|
||||
#endif
|
||||
|
||||
//#############################################################################
|
||||
//############################## AudioEvent #############################
|
||||
//#############################################################################
|
||||
|
||||
MemoryBlock
|
||||
AudioEvent::AllocatedMemory(sizeof(Event), AUDIOEVENT_MEMORYBLOCK_ALLOCATION, AUDIOEVENT_MEMORYBLOCK_ALLOCATION, "AudioEvents");
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
AudioEvent::AudioEvent(
|
||||
AudioSource *target,
|
||||
AudioSource::RequestMessage *message
|
||||
):
|
||||
targetReceiver(this)
|
||||
{
|
||||
Check(target);
|
||||
Check(message);
|
||||
|
||||
//
|
||||
// Store the message
|
||||
//
|
||||
size_t long_size = (message->messageLength+3)>>2;
|
||||
messageToSend = (AudioSource::RequestMessage*)new long[long_size];
|
||||
Check_Pointer(messageToSend);
|
||||
Register_Pointer(messageToSend);
|
||||
|
||||
Mem_Copy(
|
||||
messageToSend,
|
||||
message,
|
||||
message->messageLength,
|
||||
long_size*sizeof(long)
|
||||
);
|
||||
|
||||
//
|
||||
// Store the target receiver
|
||||
//
|
||||
targetReceiver.Add(target);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
AudioEvent::~AudioEvent()
|
||||
{
|
||||
Unregister_Pointer(messageToSend);
|
||||
delete messageToSend;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioEvent::ReleaseLinkHandler(
|
||||
Socket*,
|
||||
Plug*
|
||||
)
|
||||
{
|
||||
Unregister_Object(this);
|
||||
delete this;
|
||||
}
|
||||
@@ -233,10 +233,10 @@ private:
|
||||
);
|
||||
~AudioEvent();
|
||||
|
||||
static MemoryBlock* GetAllocatedMemory();
|
||||
static MemoryBlock AllocatedMemory;
|
||||
|
||||
void* operator new(size_t) { return GetAllocatedMemory()->New(); }
|
||||
void operator delete(void *where) { GetAllocatedMemory()->Delete(where); }
|
||||
void* operator new(size_t) { return AllocatedMemory.New(); }
|
||||
void operator delete(void *where) { AllocatedMemory.Delete(where); }
|
||||
|
||||
void
|
||||
Process();
|
||||
|
||||
@@ -16,18 +16,16 @@ class BoundingBoxTree;
|
||||
|
||||
class BoundingBoxTreeNode SIGNATURED
|
||||
{
|
||||
public:
|
||||
static MemoryBlock
|
||||
AllocatedMemory;
|
||||
friend class BoundingBoxTree;
|
||||
|
||||
//##########################################################################
|
||||
// Memory Allocation
|
||||
//
|
||||
private:
|
||||
static MemoryBlock* GetAllocatedMemory();
|
||||
void* operator new(size_t) { return GetAllocatedMemory()->New(); }
|
||||
void operator delete(void *where) { GetAllocatedMemory()->Delete(where); }
|
||||
static MemoryBlock AllocatedMemory;
|
||||
static MemoryBlock* GetAllocatedMemory() { return &AllocatedMemory; }
|
||||
void* operator new(size_t) { return AllocatedMemory.New(); }
|
||||
void operator delete(void *where) { AllocatedMemory.Delete(where); }
|
||||
|
||||
//##########################################################################
|
||||
// Construction and Destruction
|
||||
|
||||
@@ -0,0 +1,450 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
# if !defined(CSTR_HPP)
|
||||
# include <cstr.hpp>
|
||||
# endif
|
||||
# if !defined(MEMSTRM_HPP)
|
||||
# include <memstrm.hpp>
|
||||
# endif
|
||||
|
||||
//namespace Munga
|
||||
//{
|
||||
rString StringRepresentation::operator+=(char chr)
|
||||
{
|
||||
Check(this);
|
||||
size_t len = strlen(&firstByte);
|
||||
*(&firstByte + len++) = chr;
|
||||
*(&firstByte + len) = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined(USE_SIGNATURE)
|
||||
int Is_Signature_Bad(const StringRepresentation *)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
#endif
|
||||
|
||||
MemoryStream& MemoryStream_Read(MemoryStream *stream, StringRepresentation *str)
|
||||
{
|
||||
Check(stream);
|
||||
Check(str);
|
||||
|
||||
pString ptr = *str;
|
||||
for (*stream >> ptr[(size_t)0]; ptr[(size_t)0]; ++ptr)
|
||||
*stream >> ptr[(size_t)0];
|
||||
return *stream;
|
||||
}
|
||||
|
||||
MemoryStream& MemoryStream_Write(MemoryStream *stream, const StringRepresentation &str)
|
||||
{
|
||||
Check(stream);
|
||||
Check(&str);
|
||||
|
||||
return stream->WriteBytes((const char*)str, str.GetLength() + 1);
|
||||
}
|
||||
|
||||
#define DELETE_FILL_CHAR ('0')
|
||||
|
||||
size_t CStringRepresentation::allocationIncrement = 8;
|
||||
|
||||
inline size_t CStringRepresentation::CalculateSize(size_t needed)
|
||||
{
|
||||
Verify(!Small_Enough(allocationIncrement));
|
||||
size_t x = ((needed + allocationIncrement) / allocationIncrement) * allocationIncrement;
|
||||
return x;
|
||||
}
|
||||
|
||||
CStringRepresentation::CStringRepresentation()
|
||||
{
|
||||
stringLength = 0;
|
||||
stringSize = 0;
|
||||
stringText = NULL;
|
||||
referenceCount = 0;
|
||||
}
|
||||
|
||||
CStringRepresentation::CStringRepresentation(const CStringRepresentation &str)
|
||||
{
|
||||
Check(&str);
|
||||
stringLength = str.stringLength;
|
||||
stringSize = str.stringSize;
|
||||
|
||||
if (str.stringText == NULL)
|
||||
stringText = NULL;
|
||||
else
|
||||
{
|
||||
stringText = new char[stringSize];
|
||||
Register_Pointer(stringText);
|
||||
Mem_Copy(stringText, str.stringText, stringLength + 1, stringSize);
|
||||
}
|
||||
referenceCount = 0;
|
||||
}
|
||||
|
||||
CStringRepresentation::CStringRepresentation(const char *cstr)
|
||||
{
|
||||
if ((cstr == NULL) || (cstr[0] == '\x00'))
|
||||
{
|
||||
stringLength = 0;
|
||||
stringSize = 0;
|
||||
stringText = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
stringLength = strlen(cstr);
|
||||
stringSize = CalculateSize(stringLength);
|
||||
|
||||
stringText = new char[stringSize];
|
||||
Register_Pointer(stringText);
|
||||
Mem_Copy(stringText, cstr, stringLength + 1, stringSize);
|
||||
}
|
||||
referenceCount = 0;
|
||||
}
|
||||
|
||||
CStringRepresentation::~CStringRepresentation()
|
||||
{
|
||||
if (stringText != NULL)
|
||||
{
|
||||
#if DEBUG_LEVEL>0
|
||||
memset(stringText, DELETE_FILL_CHAR, stringSize);
|
||||
#endif
|
||||
Unregister_Pointer(stringText);
|
||||
delete[] stringText;
|
||||
}
|
||||
}
|
||||
|
||||
Logical CStringRepresentation::TestInstance() const
|
||||
{
|
||||
if (stringText == NULL)
|
||||
{
|
||||
Verify(stringSize == 0);
|
||||
Verify(stringLength == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Verify(stringSize > 0);
|
||||
Verify(stringLength == strlen(stringText));
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
CStringRepresentation CStringRepresentation::operator = (const CStringRepresentation &str)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
if (this == &str)
|
||||
return *this;
|
||||
|
||||
if (stringText != NULL)
|
||||
{
|
||||
#if DEBUG_LEVEL>0
|
||||
memset(stringText, DELETE_FILL_CHAR, stringSize);
|
||||
#endif
|
||||
Unregister_Pointer(stringText);
|
||||
delete[] stringText;
|
||||
}
|
||||
|
||||
Check(&str);
|
||||
stringLength = str.stringLength;
|
||||
stringSize = str.stringSize;
|
||||
|
||||
if (stringSize == 0)
|
||||
stringText = NULL;
|
||||
else
|
||||
{
|
||||
stringText = new char[stringSize];
|
||||
Register_Pointer(stringText);
|
||||
Mem_Copy(stringText, str.stringText, stringLength + 1, stringSize);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CStringRepresentation CStringRepresentation::operator = (const char *cstr)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
if (stringText != NULL)
|
||||
{
|
||||
#if DEBUG_LEVEL>0
|
||||
memset(stringText, DELETE_FILL_CHAR, stringSize);
|
||||
#endif
|
||||
Unregister_Pointer(stringText);
|
||||
delete[] stringText;
|
||||
}
|
||||
|
||||
if ((cstr == NULL) || (cstr[0] == '\x00'))
|
||||
{
|
||||
stringLength = 0;
|
||||
stringSize = 0;
|
||||
stringText = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
stringLength = strlen(cstr);
|
||||
stringSize = CalculateSize(stringLength);
|
||||
|
||||
stringText = new char[stringSize];
|
||||
Register_Pointer(stringText);
|
||||
Mem_Copy(stringText, cstr, stringLength + 1, stringSize);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CStringRepresentation operator + (const CStringRepresentation &str1, const CStringRepresentation &str2)
|
||||
{
|
||||
Check(&str1);
|
||||
Check(&str2);
|
||||
|
||||
CStringRepresentation temp;
|
||||
|
||||
unsigned long totalLen = str1.stringLength + str2.stringLength;
|
||||
|
||||
if (totalLen == 0)
|
||||
return temp;
|
||||
|
||||
temp.stringLength = 0;
|
||||
temp.stringSize = CStringRepresentation::CalculateSize((size_t)totalLen);
|
||||
temp.stringText = new char[temp.stringSize];
|
||||
Register_Pointer(temp.stringText);
|
||||
|
||||
Verify(temp.stringSize >= 1);
|
||||
temp.stringText[0] = '\000';
|
||||
|
||||
if (str1.stringText != NULL)
|
||||
{
|
||||
Mem_Copy(temp.stringText, str1.stringText, str1.stringLength, temp.stringSize);
|
||||
temp.stringLength = str1.stringLength;
|
||||
}
|
||||
|
||||
if (str2.stringText != NULL)
|
||||
{
|
||||
Verify(temp.stringLength < temp.stringSize);
|
||||
Mem_Copy(&temp.stringText[temp.stringLength], str2.stringText, str2.stringLength + 1, temp.stringSize - temp.stringLength);
|
||||
temp.stringLength += str2.stringLength;
|
||||
}
|
||||
|
||||
Check(&temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
CStringRepresentation operator + (const CStringRepresentation &str, char ch)
|
||||
{
|
||||
Check(&str);
|
||||
|
||||
CStringRepresentation temp;
|
||||
|
||||
if (str.stringText == NULL)
|
||||
{
|
||||
temp.stringLength = 1;
|
||||
temp.stringSize = CStringRepresentation::allocationIncrement;
|
||||
temp.stringText = new char [temp.stringSize];
|
||||
Register_Pointer(temp.stringText);
|
||||
|
||||
Verify(temp.stringSize >= 2);
|
||||
temp.stringText[0] = ch;
|
||||
temp.stringText[1] = '\000';
|
||||
}
|
||||
else
|
||||
{
|
||||
Verify(str.stringLength != UINT_MAX);
|
||||
|
||||
temp.stringLength = str.stringLength + 1;
|
||||
|
||||
if (temp.stringLength == str.stringSize)
|
||||
temp.stringSize = str.stringSize + CStringRepresentation::allocationIncrement;
|
||||
else
|
||||
temp.stringSize = str.stringSize;
|
||||
|
||||
temp.stringText = new char[temp.stringSize];
|
||||
Register_Pointer(temp.stringText);
|
||||
Mem_Copy(temp.stringText, str.stringText, str.stringLength, temp.stringSize);
|
||||
|
||||
Verify(str.stringLength < temp.stringSize);
|
||||
Verify(temp.stringLength < temp.stringSize);
|
||||
temp.stringText[str.stringLength] = ch;
|
||||
temp.stringText[temp.stringLength] = '\000';
|
||||
}
|
||||
|
||||
Check(&temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
int CStringRepresentation::Compare(const CStringRepresentation &str) const
|
||||
{
|
||||
Check(this);
|
||||
Check(&str);
|
||||
|
||||
// handle special cases where one string is empty
|
||||
if (stringText == NULL)
|
||||
{
|
||||
if (str.stringText == NULL)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
if (str.stringText == NULL)
|
||||
return 1;
|
||||
|
||||
return strcmp(stringText, str.stringText);
|
||||
}
|
||||
|
||||
CStringRepresentation CStringRepresentation::GetNthToken(size_t nth_token, char *delimiters) const
|
||||
{
|
||||
Check(this);
|
||||
|
||||
//
|
||||
// Which delimters to use
|
||||
//
|
||||
char *delimter_string = " \t,";
|
||||
|
||||
if (delimiters != NULL)
|
||||
delimter_string = delimiters;
|
||||
Check_Pointer(delimter_string);
|
||||
|
||||
//
|
||||
// Make temporary
|
||||
//
|
||||
CStringRepresentation temp(*this);
|
||||
|
||||
if (temp.stringText == NULL)
|
||||
return temp;
|
||||
|
||||
//
|
||||
// Parse string with strtok
|
||||
//
|
||||
size_t i;
|
||||
char *ptr;
|
||||
|
||||
Check_Pointer(temp.stringText);
|
||||
ptr = strtok(temp.stringText, delimter_string);
|
||||
for (i = 0; i < nth_token; i++)
|
||||
if ((ptr = strtok(NULL, delimter_string)) == NULL)
|
||||
break;
|
||||
|
||||
if (ptr == NULL)
|
||||
{
|
||||
CStringRepresentation null_return;
|
||||
return null_return;
|
||||
}
|
||||
CStringRepresentation token_return(ptr);
|
||||
return token_return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void CStringRepresentation::ToUpper()
|
||||
{
|
||||
Check(this);
|
||||
if (stringText != NULL)
|
||||
strupr(stringText);
|
||||
}
|
||||
|
||||
void CStringRepresentation::ToLower()
|
||||
{
|
||||
Check(this);
|
||||
if (stringText != NULL)
|
||||
strlwr(stringText);
|
||||
}
|
||||
#endif
|
||||
|
||||
MemoryStream& MemoryStream_Read(MemoryStream *stream, CStringRepresentation *str)
|
||||
{
|
||||
Check(stream);
|
||||
Check(str);
|
||||
|
||||
size_t string_length;
|
||||
char *ptr;
|
||||
|
||||
MemoryStream_Read(stream, &string_length);
|
||||
ptr = new char[string_length + 1];
|
||||
Register_Pointer(ptr);
|
||||
stream->ReadBytes(ptr, string_length + 1);
|
||||
|
||||
*str = ptr;
|
||||
|
||||
Unregister_Pointer(ptr);
|
||||
delete[] ptr;
|
||||
|
||||
Check(str);
|
||||
return *stream;
|
||||
}
|
||||
|
||||
MemoryStream& MemoryStream_Write(MemoryStream *stream, const CStringRepresentation &str)
|
||||
{
|
||||
Check(stream);
|
||||
Check(&str);
|
||||
|
||||
MemoryStream_Write(stream, &str.stringLength);
|
||||
return stream->WriteBytes(str.stringText, str.stringLength + 1);
|
||||
}
|
||||
|
||||
void Convert_From_Ascii(const char *str, CStringRepresentation *value)
|
||||
{
|
||||
#if 0
|
||||
Check_Pointer(str);
|
||||
Check(value);
|
||||
*value = str;
|
||||
#else
|
||||
if (str == NULL)
|
||||
Fail("Convert_From_Ascii - str == NULL");
|
||||
if (value == NULL)
|
||||
Fail("Convert_From_Ascii - value == NULL");
|
||||
*value = str;
|
||||
#endif
|
||||
}
|
||||
|
||||
CString CString::operator = (const CString &str)
|
||||
{
|
||||
Check(this);
|
||||
Check(&str);
|
||||
|
||||
if (this == &str)
|
||||
return *this;
|
||||
|
||||
Check(representation);
|
||||
representation->DecrementReferenceCount();
|
||||
representation = str.representation;
|
||||
representation->IncrementReferenceCount();
|
||||
return *this;
|
||||
}
|
||||
|
||||
CString CString::operator = (const char *cstr)
|
||||
{
|
||||
Check(representation);
|
||||
representation->DecrementReferenceCount();
|
||||
representation = new CStringRepresentation(cstr);
|
||||
Register_Object(representation);
|
||||
representation->IncrementReferenceCount();
|
||||
return *this;
|
||||
}
|
||||
|
||||
MemoryStream& MemoryStream_Read(MemoryStream *stream, CString *str)
|
||||
{
|
||||
Check(str);
|
||||
Check(str->representation);
|
||||
str->representation->DecrementReferenceCount();
|
||||
str->representation = new CStringRepresentation;
|
||||
Register_Object(str->representation);
|
||||
str->representation->IncrementReferenceCount();
|
||||
Verify(str->representation->referenceCount == 1);
|
||||
return MemoryStream_Read(stream, str->representation);
|
||||
}
|
||||
|
||||
void Convert_From_Ascii(const char *str, CString *value)
|
||||
{
|
||||
Check(value);
|
||||
Check(value->representation);
|
||||
value->representation->DecrementReferenceCount();
|
||||
value->representation = new CStringRepresentation;
|
||||
Register_Object(value->representation);
|
||||
value->representation->IncrementReferenceCount();
|
||||
Verify(value->representation->referenceCount == 1);
|
||||
Convert_From_Ascii(str, value->representation);
|
||||
}
|
||||
//}
|
||||
|
||||
#if defined(TEST_CLASS)
|
||||
#include "cstr.tcp"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,625 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(EXPTBL_HPP)
|
||||
# include <exptbl.hpp>
|
||||
# endif
|
||||
# if !defined(NAMELIST_HPP)
|
||||
# include <namelist.hpp>
|
||||
# endif
|
||||
# if !defined(REGISTRY_HPP)
|
||||
# include <registry.hpp>
|
||||
# endif
|
||||
# if !defined(APP_HPP)
|
||||
# include <app.hpp>
|
||||
# endif
|
||||
# if !defined(EXPLODE_HPP)
|
||||
# include <explode.hpp>
|
||||
# endif
|
||||
# if !defined(DAMAGE_HPP)
|
||||
# include <damage.hpp>
|
||||
# endif
|
||||
# if !defined(NOTATION_HPP)
|
||||
# include <notation.hpp>
|
||||
# endif
|
||||
# if !defined(FILEUTIL_HPP)
|
||||
# include <fileutil.hpp>
|
||||
# endif
|
||||
# if !defined(RENDERER_HPP)
|
||||
# include <renderer.hpp>
|
||||
# endif
|
||||
|
||||
//##############################################################################
|
||||
//###################### Class ExplosionTableEntry ########################
|
||||
//##############################################################################
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ExplosionTableEntry::CreateExplosion(
|
||||
const EntityID &entity_hit_ID,
|
||||
const EntityID &creating_entity_ID,
|
||||
const Point3D &explode_position
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Origin explode_origin(Origin::Identity);
|
||||
explode_origin = explode_position;
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Create the explosion MakeMessage
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Explosion::MakeMessage exp_message(
|
||||
Explosion::MakeMessageID,
|
||||
sizeof(Explosion::MakeMessage),
|
||||
RegisteredClass::ExplosionClassID,
|
||||
EntityID::Null,
|
||||
explosionResourceID,
|
||||
Explosion::DefaultFlags,
|
||||
explode_origin,
|
||||
entity_hit_ID,
|
||||
creating_entity_ID
|
||||
);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Calculate actual time based on time_delay
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Time when = Now();
|
||||
when += timeDelay;
|
||||
Check(application);
|
||||
|
||||
Registry *registry;
|
||||
registry = application->GetRegistry();
|
||||
Check_Pointer(registry);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Create a MakeEntityMessage
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Registry::MakeEntityMessage *registry_message;
|
||||
registry_message = Registry::MakeEntityMessage::Make(&exp_message);
|
||||
Register_Object(registry_message);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Post entity message to the registry
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
#if 0 // ECH 1/28/96
|
||||
application->Post(
|
||||
DefaultEventPriority,
|
||||
registry,
|
||||
registry_message,
|
||||
when
|
||||
);
|
||||
#else
|
||||
application->Post(
|
||||
CreationEventPriority,
|
||||
registry,
|
||||
registry_message,
|
||||
when
|
||||
);
|
||||
#endif
|
||||
Unregister_Object(registry_message);
|
||||
delete registry_message;
|
||||
|
||||
Check_Fpu();
|
||||
}
|
||||
//##############################################################################
|
||||
// Construction/Destruction
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTableEntry::ExplosionTableEntry(MemoryStream *exp_stream)
|
||||
{
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Read in the data from the stream
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
*exp_stream >> damageLevel >> explosionResourceID >> graphicState;
|
||||
*exp_stream >> timeDelay;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTableEntry::~ExplosionTableEntry()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
// Tool Support
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
ExplosionTableEntry::CreateStreamedExplosion(
|
||||
ResourceFile *resource_file,
|
||||
CString exp_file_name,
|
||||
NotationFile *exp_file,
|
||||
CString exp_page_name,
|
||||
MemoryStream *explosion_stream
|
||||
)
|
||||
{
|
||||
Check(exp_file);
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~
|
||||
// Get the DamageLevel
|
||||
//~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Scalar damage_level;
|
||||
if (!exp_file->GetEntry(
|
||||
exp_page_name,
|
||||
"DamageLevel",
|
||||
&damage_level
|
||||
)
|
||||
)
|
||||
{
|
||||
damage_level = -1.0f;
|
||||
}
|
||||
*explosion_stream << damage_level;
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Get the Explosion Model File
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char *explosion_model_file;
|
||||
if (!exp_file->GetEntry(
|
||||
exp_page_name,
|
||||
"ExplosionModelFile",
|
||||
&explosion_model_file
|
||||
)
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM <<exp_file_name<<" : "<<exp_page_name<<" missing ExplosionModelFile!"<<endl << flush;
|
||||
return False;
|
||||
}
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Hunt for Model file in ResourceFile
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription *res;
|
||||
|
||||
res = resource_file->FindResourceDescription(
|
||||
explosion_model_file,
|
||||
ResourceDescription::ModelListResourceType
|
||||
);
|
||||
if (!res)
|
||||
{
|
||||
cout << exp_file_name << " cannot find " << explosion_model_file
|
||||
<< " in resource file!\n";
|
||||
return False;
|
||||
}
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Write out the resourceID
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
*explosion_stream << res->resourceID;
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Read in the Graphic State
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char *graphic_state_char;
|
||||
Enumeration graphic_state;
|
||||
if (exp_file->GetEntry(
|
||||
exp_page_name,
|
||||
"GraphicState",
|
||||
&graphic_state_char
|
||||
)
|
||||
)
|
||||
{
|
||||
if (!strcmp(graphic_state_char, "Destroyed"))
|
||||
{
|
||||
graphic_state = DamageZone::DestroyedGraphicState;
|
||||
}
|
||||
else if (!strcmp(graphic_state_char, "Gone"))
|
||||
{
|
||||
graphic_state = DamageZone::GoneGraphicState;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
graphic_state = DamageZone::ExistsGraphicState;
|
||||
}
|
||||
*explosion_stream << graphic_state;
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~
|
||||
// Get the TimeDelay
|
||||
//~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Scalar time_delay;
|
||||
if (!exp_file->GetEntry(
|
||||
exp_page_name,
|
||||
"TimeDelay",
|
||||
&time_delay
|
||||
)
|
||||
)
|
||||
{
|
||||
time_delay = 0.0f;
|
||||
}
|
||||
*explosion_stream << time_delay;
|
||||
return True;
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
//######################## Class ExplosionTable ###########################
|
||||
//##############################################################################
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
ExplosionTable::CrossedDamageLevelThreshold(
|
||||
Scalar old_value,
|
||||
Scalar new_value
|
||||
)
|
||||
{
|
||||
ExplosionTableIterator iterator(this);
|
||||
ExplosionTableEntry *current_exp;
|
||||
|
||||
while ((current_exp = iterator.ReadAndNext()) != NULL)
|
||||
{
|
||||
if (
|
||||
(old_value < current_exp->GetDamageLevel()) &&
|
||||
(new_value >= current_exp->GetDamageLevel())
|
||||
)
|
||||
{
|
||||
return True;
|
||||
}
|
||||
}
|
||||
return False;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTableEntry*
|
||||
ExplosionTable::SelectDamageLevelEntry(Scalar damage_level)
|
||||
{
|
||||
ExplosionTableIterator iterator(this);
|
||||
ExplosionTableEntry *current_exp;
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Choose ExplosionTableEntry by damage Level
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
while ((current_exp = iterator.ReadAndNext()) != NULL)
|
||||
{
|
||||
if (damage_level < current_exp->GetDamageLevel())
|
||||
{
|
||||
Check_Fpu();
|
||||
return current_exp;
|
||||
}
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
return NULL;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTableEntry*
|
||||
ExplosionTable::SelectGraphicStateEntry(Enumeration graphic_state)
|
||||
{
|
||||
ExplosionTableIterator iterator(this);
|
||||
ExplosionTableEntry *current_entry;
|
||||
while((current_entry = iterator.ReadAndNext() ) != NULL)
|
||||
{
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Display Explosion if an Entry Exists
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (current_entry->GetGraphicState() == graphic_state)
|
||||
{
|
||||
Check_Fpu();
|
||||
return current_entry;
|
||||
}
|
||||
}
|
||||
Check_Fpu();
|
||||
return NULL;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ExplosionTable::CreateExplosion(
|
||||
ExplosionTableEntry *explosion_entry,
|
||||
const EntityID &entity_hit_ID,
|
||||
const EntityID &creating_entity_ID,
|
||||
Point3D explode_position
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check(explosion_entry);
|
||||
explosion_entry->CreateExplosion(
|
||||
entity_hit_ID,
|
||||
creating_entity_ID,
|
||||
explode_position
|
||||
);
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
// Construction/Destruction
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTable::ExplosionTable(MemoryStream *exp_stream):
|
||||
TableOf<ExplosionTableEntry*, int>(NULL, True)
|
||||
{
|
||||
int entry_count;
|
||||
*exp_stream >> entry_count;
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Create all of the ExplosionTableEntries
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTableEntry *exp_entry;
|
||||
|
||||
for(int ii=0;ii<entry_count;++ii)
|
||||
{
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Create a new ExplosionTableEntry
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
exp_entry = new ExplosionTableEntry(exp_stream);
|
||||
Register_Object(exp_entry);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Add the entry the the ExplosionTable
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
AddValue(exp_entry, ii);
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTable::~ExplosionTable()
|
||||
{
|
||||
ExplosionTableIterator iterator(this);
|
||||
iterator.DeletePlugs();
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
// Tool Support
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
ExplosionTable::CreateStreamedExplosionTable(
|
||||
ResourceFile *resource_file,
|
||||
CString model_name,
|
||||
NotationFile *exp_file,
|
||||
CString exp_filename,
|
||||
MemoryStream *explosion_stream
|
||||
)
|
||||
{
|
||||
Check(resource_file);
|
||||
Check(exp_file);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Make a namelist of all Explosion Entries
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
NameList *exp_namelist = exp_file->MakePageList();
|
||||
Register_Object(exp_namelist);
|
||||
if (!exp_namelist->EntryCount())
|
||||
{
|
||||
DEBUG_STREAM << exp_file << " is empty or missing \n"<<endl << flush;
|
||||
Unregister_Object(exp_namelist);
|
||||
delete exp_namelist;
|
||||
return False;
|
||||
}
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Write the Number of Explosion Entries for this Entity
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
int entry_count = exp_namelist->EntryCount();
|
||||
*explosion_stream << entry_count;
|
||||
|
||||
NameList::Entry *exp_entry = exp_namelist->GetFirstEntry();
|
||||
while(exp_entry)
|
||||
{
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// While more pages Add ExplosionEntries to the stream
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTableEntry::CreateStreamedExplosion(
|
||||
resource_file,
|
||||
exp_filename,
|
||||
exp_file,
|
||||
exp_entry->GetName(),
|
||||
explosion_stream
|
||||
);
|
||||
exp_entry = exp_entry->GetNextEntry();
|
||||
}
|
||||
Unregister_Object(exp_namelist);
|
||||
delete exp_namelist;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
//##########################################################################
|
||||
//###################### EntityEffectWatcher #########################
|
||||
//##########################################################################
|
||||
|
||||
//##############################################################################
|
||||
// Construction/Destruction
|
||||
//
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
EntityEffectWatcher::EntityEffectWatcher(
|
||||
Entity *entity_watched
|
||||
)
|
||||
{
|
||||
entityWatched = entity_watched;
|
||||
entityWatched->AddEffectWatcher(this);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Init array to hold previous damageLevel values
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Verify(entityWatched->damageZoneCount > 0);
|
||||
oldDamageLevel = new Scalar[entityWatched->damageZoneCount];
|
||||
Register_Pointer(oldDamageLevel);
|
||||
for(int ii=0;ii<entityWatched->damageZoneCount;++ii)
|
||||
{
|
||||
oldDamageLevel[ii] = 0.0f;
|
||||
}
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
|
||||
EntityEffectWatcher::~EntityEffectWatcher()
|
||||
{
|
||||
Unregister_Pointer(oldDamageLevel);
|
||||
delete[] oldDamageLevel;
|
||||
}
|
||||
//##############################################################################
|
||||
// Execute
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
|
||||
void
|
||||
EntityEffectWatcher::Execute()
|
||||
{
|
||||
Check(this);
|
||||
Check(entityWatched);
|
||||
Check_Pointer(entityWatched->damageZones);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Check the flags to see if any damageZones
|
||||
// have been modified since the last Execute was called
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
DamageZone *current_zone;
|
||||
ExplosionTable *exp_table;
|
||||
ExplosionTableEntry *exp_entry(NULL);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Traverse damageZones looking for Changes
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
for (int ii=0;ii<entityWatched->damageZoneCount; ++ii)
|
||||
{
|
||||
current_zone = entityWatched->damageZones[ii];
|
||||
Check(current_zone);
|
||||
ResourceDescription::ResourceID exp_res;
|
||||
exp_table = current_zone->GetExplosionTable();
|
||||
Check(exp_table);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~
|
||||
// Check Damage Level
|
||||
//~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (current_zone->DamageLevelChanged())
|
||||
{
|
||||
exp_entry = exp_table->SelectDamageLevelEntry(current_zone->damageLevel);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// If delta was large enough signal an update
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (
|
||||
exp_table->CrossedDamageLevelThreshold(
|
||||
oldDamageLevel[ii],
|
||||
current_zone->damageLevel
|
||||
) &&
|
||||
(entityWatched->GetInstance() == Entity::MasterInstance)
|
||||
)
|
||||
{
|
||||
entityWatched->ForceUpdate(Entity::DamageZoneUpdateModelFlag);
|
||||
}
|
||||
oldDamageLevel[ii] = current_zone->damageLevel;
|
||||
}
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~
|
||||
// Check Graphic State
|
||||
//~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (current_zone->GraphicStateChanged())
|
||||
{
|
||||
exp_entry = exp_table->SelectGraphicStateEntry(
|
||||
current_zone->GetGraphicState()
|
||||
);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Always update for a graphic state change
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (entityWatched->GetInstance() == Entity::MasterInstance)
|
||||
{
|
||||
entityWatched->ForceUpdate(Entity::DamageZoneUpdateModelFlag);
|
||||
}
|
||||
}
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Notify RendererManager of Any Change
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (exp_entry)
|
||||
{
|
||||
Check(exp_entry);
|
||||
exp_res = exp_entry->GetExplosionResourceID();
|
||||
|
||||
Check(application);
|
||||
Check(application->GetRendererManager());
|
||||
application->GetRendererManager()->StartEntityEffect(
|
||||
entityWatched,
|
||||
current_zone,
|
||||
exp_res
|
||||
);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Reset the DamageZone::changedFlags if
|
||||
// I am a master and no update occurred OR
|
||||
// if I am a replicant
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (
|
||||
(
|
||||
(entityWatched->GetInstance() == Entity::MasterInstance) &&
|
||||
!entityWatched->DamageZoneUpdateModelFlagSet()
|
||||
) ||
|
||||
(
|
||||
(entityWatched->GetInstance() == Entity::ReplicantInstance)
|
||||
)
|
||||
)
|
||||
{
|
||||
current_zone->ResetChangedFlags();
|
||||
}
|
||||
}
|
||||
exp_entry = NULL;
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
// Test Support
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
EntityEffectWatcher::TestInstance() const
|
||||
{
|
||||
Check(entityWatched);
|
||||
return True;
|
||||
}
|
||||
@@ -0,0 +1,832 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
#include <dir.h>
|
||||
|
||||
#include <direct.h>
|
||||
# if !defined(FILEUTIL_HPP)
|
||||
# include <fileutil.hpp>
|
||||
# endif
|
||||
# if !defined(NOTATION_HPP)
|
||||
# include <notation.hpp>
|
||||
# endif
|
||||
|
||||
char *WorkingDirectory = NULL;
|
||||
|
||||
//#############################################################################
|
||||
|
||||
const char *White_Space = " \t\n";
|
||||
|
||||
//#############################################################################
|
||||
|
||||
char
|
||||
*SourceDirectory = NULL,
|
||||
*ConfigDirectory = NULL,
|
||||
*MaterialDirectory = NULL,
|
||||
*TextureDirectory = NULL,
|
||||
*AnimationDirectory = NULL,
|
||||
*ProductionDirectory = NULL;
|
||||
const char
|
||||
*OutputDirectory = NULL;
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
SetSourceDirectory(const char *input_file)
|
||||
{
|
||||
Check_Pointer(input_file);
|
||||
|
||||
static const char
|
||||
* const ARTTOOLS_FILENAME = ".arttoolsrc",
|
||||
* const DIRECTORIES_PAGE = "directories",
|
||||
* const CFG_DIR_ENTRY = "cfg_dir",
|
||||
* const MTL_DIR_ENTRY = "mtl_dir",
|
||||
* const TEX_DIR_ENTRY = "tex_dir",
|
||||
* const KIN_DIR_ENTRY = "kin_dir",
|
||||
* const PRD_DIR_ENTRY = "prd_dir";
|
||||
|
||||
NotationFile
|
||||
*tools_info;
|
||||
char
|
||||
*cwd;
|
||||
const char
|
||||
*cp,
|
||||
*contents;
|
||||
|
||||
//------------------------------------------------
|
||||
// parse the source directory from the input file
|
||||
//------------------------------------------------
|
||||
if ((cp = strrchr(input_file, '/')) == NULL)
|
||||
{
|
||||
//---------------------------------------------------
|
||||
// set source directory to current working directory
|
||||
//---------------------------------------------------
|
||||
cwd = getcwd(NULL, 256);
|
||||
Verify( cwd );
|
||||
SourceDirectory = new char[strlen(cwd) + 2];
|
||||
Register_Pointer(SourceDirectory);
|
||||
strcpy(SourceDirectory, cwd);
|
||||
strcat(SourceDirectory, "/");
|
||||
free(cwd);
|
||||
}
|
||||
else
|
||||
{
|
||||
//------------------------------------------------------
|
||||
// set source directory to path specified in input file
|
||||
//------------------------------------------------------
|
||||
++cp;
|
||||
SourceDirectory = new char[cp - input_file + 1];
|
||||
Register_Pointer(SourceDirectory);
|
||||
*SourceDirectory = '\0';
|
||||
strncat(SourceDirectory, input_file, cp - input_file);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// set other directories from tools config file (if present)
|
||||
//-----------------------------------------------------------
|
||||
tools_info = new NotationFile(SourceFile(ARTTOOLS_FILENAME));
|
||||
Register_Object(tools_info);
|
||||
|
||||
if (tools_info->GetEntry(DIRECTORIES_PAGE, CFG_DIR_ENTRY, &contents))
|
||||
{
|
||||
ConfigDirectory = new char[strlen(contents) + 2];
|
||||
Register_Pointer(ConfigDirectory);
|
||||
strcpy(ConfigDirectory, contents);
|
||||
cp = strchr(contents, '\0');
|
||||
if (cp > contents && *--cp != '/')
|
||||
{
|
||||
strcat(ConfigDirectory, "/");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ConfigDirectory = SourceDirectory;
|
||||
}
|
||||
|
||||
if (tools_info->GetEntry(DIRECTORIES_PAGE, MTL_DIR_ENTRY, &contents))
|
||||
{
|
||||
MaterialDirectory = new char[strlen(contents) + 2];
|
||||
Register_Pointer(MaterialDirectory);
|
||||
strcpy(MaterialDirectory, contents);
|
||||
cp = strchr(contents, '\0');
|
||||
if (cp > contents && *--cp != '/')
|
||||
{
|
||||
strcat(MaterialDirectory, "/");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MaterialDirectory = SourceDirectory;
|
||||
}
|
||||
|
||||
if (tools_info->GetEntry(DIRECTORIES_PAGE, TEX_DIR_ENTRY, &contents))
|
||||
{
|
||||
TextureDirectory = new char[strlen(contents) + 2];
|
||||
Register_Pointer(TextureDirectory);
|
||||
strcpy(TextureDirectory, contents);
|
||||
cp = strchr(contents, '\0');
|
||||
if (cp > contents && *--cp != '/')
|
||||
{
|
||||
strcat(TextureDirectory, "/");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TextureDirectory = MaterialDirectory; // this one is different!
|
||||
}
|
||||
|
||||
if (tools_info->GetEntry(DIRECTORIES_PAGE, KIN_DIR_ENTRY, &contents))
|
||||
{
|
||||
AnimationDirectory = new char[strlen(contents) + 2];
|
||||
Register_Pointer(AnimationDirectory);
|
||||
strcpy(AnimationDirectory, contents);
|
||||
cp = strchr(contents, '\0');
|
||||
if (cp > contents && *--cp != '/')
|
||||
{
|
||||
strcat(AnimationDirectory, "/");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AnimationDirectory = SourceDirectory;
|
||||
}
|
||||
|
||||
if (tools_info->GetEntry(DIRECTORIES_PAGE, PRD_DIR_ENTRY, &contents))
|
||||
{
|
||||
ProductionDirectory = new char[strlen(contents) + 2];
|
||||
Register_Pointer(ProductionDirectory);
|
||||
strcpy(ProductionDirectory, contents);
|
||||
cp = strchr(contents, '\0');
|
||||
if (cp > contents && *--cp != '/')
|
||||
{
|
||||
strcat(ProductionDirectory, "/");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ProductionDirectory = SourceDirectory;
|
||||
}
|
||||
|
||||
OutputDirectory = SourceDirectory;
|
||||
|
||||
Unregister_Object(tools_info);
|
||||
delete tools_info;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
SetOutputDirectory(const char *directory)
|
||||
{
|
||||
Check_Pointer(directory);
|
||||
|
||||
OutputDirectory = directory;
|
||||
return;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetSourceDirectory()
|
||||
{
|
||||
return SourceDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetConfigDirectory()
|
||||
{
|
||||
return ConfigDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetMaterialDirectory()
|
||||
{
|
||||
return MaterialDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetTextureDirectory()
|
||||
{
|
||||
return TextureDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetAnimationDirectory()
|
||||
{
|
||||
return AnimationDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetProductionDirectory()
|
||||
{
|
||||
return ProductionDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetOutputDirectory()
|
||||
{
|
||||
return OutputDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ClearDirectories()
|
||||
{
|
||||
//do not clear output directory
|
||||
|
||||
if (ProductionDirectory && ProductionDirectory != SourceDirectory)
|
||||
{
|
||||
Unregister_Pointer(ProductionDirectory);
|
||||
delete ProductionDirectory;
|
||||
}
|
||||
if (AnimationDirectory && AnimationDirectory != SourceDirectory)
|
||||
{
|
||||
Unregister_Pointer(AnimationDirectory);
|
||||
delete AnimationDirectory;
|
||||
}
|
||||
if (TextureDirectory && TextureDirectory != MaterialDirectory) //different!
|
||||
{
|
||||
Unregister_Pointer(TextureDirectory);
|
||||
delete TextureDirectory;
|
||||
}
|
||||
if (MaterialDirectory && MaterialDirectory != SourceDirectory)
|
||||
{
|
||||
Unregister_Pointer(MaterialDirectory);
|
||||
delete MaterialDirectory;
|
||||
}
|
||||
if (ConfigDirectory && ConfigDirectory != SourceDirectory)
|
||||
{
|
||||
Unregister_Pointer(ConfigDirectory);
|
||||
delete ConfigDirectory;
|
||||
}
|
||||
if (SourceDirectory)
|
||||
{
|
||||
Unregister_Pointer(SourceDirectory);
|
||||
delete SourceDirectory;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
DirectoryPlusFilename(
|
||||
const char *directory,
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
//do not check directory here
|
||||
Check_Pointer(filename);
|
||||
//do not check extension here
|
||||
|
||||
static char
|
||||
buffer[512];
|
||||
int
|
||||
length;
|
||||
|
||||
if (!directory) { directory = "\0"; }
|
||||
Check_Pointer(directory);
|
||||
|
||||
length = strlen(directory);
|
||||
if (extension)
|
||||
{
|
||||
Check_Pointer(extension);
|
||||
length += strlen(StripExtension(StripDirectory(filename)));
|
||||
length += *extension == '.'?0:1;
|
||||
length += strlen(extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
length += strlen(StripDirectory(filename));
|
||||
}
|
||||
|
||||
if (length >= ELEMENTS(buffer))
|
||||
{
|
||||
DEBUG_STREAM <<
|
||||
": Program Error - buffer[] too small in DirectoryPlusFilename().\n" << flush;
|
||||
Fail("Exiting");
|
||||
}
|
||||
strcpy(buffer, directory);
|
||||
if (extension)
|
||||
{
|
||||
strcat(buffer, StripExtension(StripDirectory(filename)));
|
||||
if (*extension != '.')
|
||||
{
|
||||
strcat(buffer, ".");
|
||||
}
|
||||
strcat(buffer, extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat(buffer, StripDirectory(filename));
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
SourceFile(
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
return DirectoryPlusFilename(SourceDirectory, filename, extension);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
ConfigFile(
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
return DirectoryPlusFilename(ConfigDirectory, filename, extension);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
MaterialFile(
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
return DirectoryPlusFilename(MaterialDirectory, filename, extension);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
TextureFile(
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
return DirectoryPlusFilename(TextureDirectory, filename, extension);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
AnimationFile(
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
return DirectoryPlusFilename(AnimationDirectory, filename, extension);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
OutputFile(
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
return DirectoryPlusFilename(OutputDirectory, filename, extension);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
|
||||
const char*
|
||||
StripDirectory(const char *filename)
|
||||
{
|
||||
Check_Pointer(filename);
|
||||
|
||||
if (DirectoryIsSpecified(filename))
|
||||
{
|
||||
const char
|
||||
*p;
|
||||
|
||||
//--------------------------------------
|
||||
// parse the filename from the filepath
|
||||
//--------------------------------------
|
||||
p = strchr(filename, '\0');
|
||||
Verify( p );
|
||||
while (*p != '\\' && p != filename)
|
||||
{
|
||||
--p;
|
||||
}
|
||||
if (*p == '\\')
|
||||
{
|
||||
++p;
|
||||
}
|
||||
filename = p;
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
StripExtension(const char *filename)
|
||||
{
|
||||
Check_Pointer(filename);
|
||||
|
||||
static char
|
||||
buffer[512];
|
||||
char
|
||||
*p;
|
||||
|
||||
if (strlen(filename) >= sizeof(buffer))
|
||||
{
|
||||
//DEBUG_STREAM << ProgName <<
|
||||
// ": Program Error - buffer[] too small in StripExtension()." << endl;
|
||||
DEBUG_STREAM <<
|
||||
": Program Error - buffer[] too small in StripExtension()." << endl << flush;
|
||||
|
||||
Fail("Exiting");
|
||||
}
|
||||
strcpy(buffer, filename);
|
||||
|
||||
//------------------------------------
|
||||
// remove the extension from filename
|
||||
//------------------------------------
|
||||
p = strchr(buffer, '\0');
|
||||
Verify( p );
|
||||
while (*p != '.' && p != buffer)
|
||||
{
|
||||
--p;
|
||||
}
|
||||
if (*p == '.')
|
||||
{
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
|
||||
char*
|
||||
Ind(int level)
|
||||
{
|
||||
const int buf_len = 128;
|
||||
static char buf[buf_len];
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Return string of spaces used to indent an output stream
|
||||
//---------------------------------------------------------
|
||||
buf[0] = '\0';
|
||||
if (level > 63) level = 63; // floor((buf_len - 1)/number of spaces per indent)
|
||||
for (; level > 0; --level)
|
||||
{
|
||||
strcat(buf, " ");
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical GetLine(istream &stream, char *buffer, int size_of_buffer)
|
||||
{
|
||||
static char temp_buffer[512];
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// read next line(s) from input stream automatically resolving
|
||||
// lines with a continuation character '\' at the end
|
||||
//-------------------------------------------------------------
|
||||
if (stream.getline(buffer, size_of_buffer))
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
while (True)
|
||||
{
|
||||
if ((i = strlen(buffer)) > (size_of_buffer - 2))
|
||||
{
|
||||
//DEBUG_STREAM << ProgName << ": ERROR - Input line too long." << endl << flush;
|
||||
|
||||
DEBUG_STREAM << ": ERROR - Input line too long." << endl << flush;
|
||||
break;
|
||||
}
|
||||
|
||||
p = buffer + i;
|
||||
while (p-- > buffer && isspace(*p)); // find last non-blank character
|
||||
|
||||
if (p >= buffer && *p == '\\')
|
||||
{
|
||||
if (stream.getline(temp_buffer, sizeof(temp_buffer)))
|
||||
{
|
||||
*p = ' ';
|
||||
++p;
|
||||
strncat(p, temp_buffer, size_of_buffer - (p - buffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return True;
|
||||
}
|
||||
else
|
||||
{
|
||||
*buffer = '\0';
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#if 0
|
||||
char*
|
||||
stripname(char filename[])
|
||||
{
|
||||
|
||||
// Doesn't work
|
||||
|
||||
char
|
||||
file2[200];
|
||||
char
|
||||
*filetosendback;
|
||||
|
||||
int
|
||||
wordlength,
|
||||
count,
|
||||
countbackward,
|
||||
length;
|
||||
|
||||
|
||||
length = strlen(filename);
|
||||
|
||||
|
||||
count = 0;
|
||||
countbackward = length-1;
|
||||
|
||||
while (filename[countbackward-1] != '\\')
|
||||
{
|
||||
--countbackward;
|
||||
}
|
||||
|
||||
wordlength = length - countbackward;
|
||||
|
||||
for (count = 0; count < wordlength; ++count)
|
||||
{
|
||||
file2[count] = filename[countbackward];
|
||||
++countbackward;
|
||||
}
|
||||
|
||||
file2[count] = '\0';
|
||||
|
||||
filetosendback = strdup(file2);
|
||||
|
||||
return filetosendback;
|
||||
}
|
||||
#endif
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Scalar
|
||||
D2R(float degrees)
|
||||
{
|
||||
return degrees*(3.14159259f/180.0f);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
char*
|
||||
MakeWorkingDirectory(
|
||||
const char *file
|
||||
)
|
||||
{
|
||||
char *directory;
|
||||
const char *p;
|
||||
int size;
|
||||
p = file;
|
||||
|
||||
for (int i = (strlen(file) - 1 ); i >= 0; --i)
|
||||
{
|
||||
if ( (*p == '/') || (*p == '\\') )
|
||||
{
|
||||
size = strlen(file) - i + 1;
|
||||
|
||||
directory = new char[size];
|
||||
strncpy(directory, file, size);
|
||||
|
||||
return directory;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
|
||||
//
|
||||
// Else return local directory
|
||||
//
|
||||
#define BUFFER_SIZE (256)
|
||||
char buffer[BUFFER_SIZE];
|
||||
getcwd(buffer, BUFFER_SIZE);
|
||||
|
||||
#if 0
|
||||
directory = strdup(buffer);
|
||||
strcat(directory, "\\"); // ECH 1/29/96 - This is an overwrite
|
||||
#else
|
||||
Str_Cat(buffer, "\\", BUFFER_SIZE);
|
||||
size = strlen(buffer) + 1;
|
||||
directory = new char[size];
|
||||
Str_Copy(directory, buffer, size);
|
||||
#endif
|
||||
|
||||
//
|
||||
// This is "\\" for DOS
|
||||
//
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Logical
|
||||
DirectoryIsSpecified(
|
||||
const char *file
|
||||
)
|
||||
{
|
||||
return strchr(file,'/') || strchr(file,':') || strchr(file,'\\');
|
||||
|
||||
#if 0
|
||||
const char *p;
|
||||
|
||||
p = file;
|
||||
|
||||
for (int i = 0; i < strlen(file); ++i)
|
||||
{
|
||||
if ( (*p == '/') || (*p == '\\') )
|
||||
{
|
||||
|
||||
return True;
|
||||
|
||||
}
|
||||
|
||||
++p;
|
||||
}
|
||||
return False;
|
||||
#endif
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
char*
|
||||
MakePathedFilename(
|
||||
const char *directory,
|
||||
const char *name
|
||||
)
|
||||
{
|
||||
char *filename;
|
||||
|
||||
if (DirectoryIsSpecified(name))
|
||||
{
|
||||
filename = new char[ strlen(name) + 1];
|
||||
strcpy(filename, name);
|
||||
return filename;
|
||||
}
|
||||
|
||||
if (directory == NULL)
|
||||
{
|
||||
filename = new char[strlen(name) + 1];
|
||||
strcpy(filename, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = new char[strlen(directory) + strlen(name) + 1];
|
||||
|
||||
strcpy(filename, directory);
|
||||
strcat(filename, name);
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void OpenOutput(ofstream &stream, const char *directory, const char *filename)
|
||||
{
|
||||
//do not check directory here
|
||||
Check_Pointer(filename);
|
||||
|
||||
char
|
||||
*file_to_open;
|
||||
|
||||
if (DirectoryIsSpecified(filename) || directory == NULL)
|
||||
{
|
||||
file_to_open = new char[strlen(filename) + 1];
|
||||
Register_Pointer(file_to_open);
|
||||
strcpy(file_to_open, filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_Pointer(directory);
|
||||
file_to_open = new char[strlen(directory) + strlen(filename) + 1];
|
||||
Register_Pointer(file_to_open);
|
||||
strcpy(file_to_open, directory);
|
||||
strcat(file_to_open, filename);
|
||||
}
|
||||
|
||||
stream.open(file_to_open);
|
||||
Unregister_Pointer(file_to_open);
|
||||
delete file_to_open;
|
||||
return;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
void OpenInput(ifstream &stream, char *directory, const char *filename)
|
||||
{
|
||||
char tempfile[100];
|
||||
|
||||
if (DirectoryIsSpecified(filename))
|
||||
{
|
||||
strcpy(tempfile, filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (directory != NULL)
|
||||
{
|
||||
strcpy(tempfile, directory);
|
||||
strcat(tempfile, filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(tempfile, filename);
|
||||
}
|
||||
}
|
||||
|
||||
stream.open(tempfile);
|
||||
return;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Logical
|
||||
LabOnly(
|
||||
NotationFile
|
||||
*notation_file
|
||||
)
|
||||
{
|
||||
|
||||
if (notation_file->PageExists("LAB_ONLY"))
|
||||
{
|
||||
cout << "WARNING: LAB_ONLY" << endl;
|
||||
return True;
|
||||
}
|
||||
else
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
void
|
||||
AddLabOnly(
|
||||
NotationFile
|
||||
*notation_file
|
||||
)
|
||||
{
|
||||
if (!notation_file->PageExists("LAB_ONLY"))
|
||||
{
|
||||
notation_file->AppendEntry("LAB_ONLY", NULL, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Logical
|
||||
DoesNotationFileExist(
|
||||
NotationFile
|
||||
*notation_file
|
||||
)
|
||||
{
|
||||
Check(notation_file);
|
||||
Check_Pointer(notation_file->GetFileName());
|
||||
ifstream notation_file_stream(notation_file->GetFileName());
|
||||
return (notation_file_stream) ? True : False;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
@@ -0,0 +1,827 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(GAUGE_HPP)
|
||||
# include <gauge.hpp>
|
||||
# endif
|
||||
# if !defined(GAUGREND_HPP)
|
||||
# include <gaugrend.hpp>
|
||||
# endif
|
||||
|
||||
extern void
|
||||
indent(int level); // in graph2d.cc
|
||||
|
||||
//#########################################################################
|
||||
//############################# GaugeBase #################################
|
||||
//#########################################################################
|
||||
GaugeBase::GaugeBase(
|
||||
ModeMask mode_mask,
|
||||
GaugeRenderer *new_renderer,
|
||||
unsigned int owner_ID,
|
||||
const char *identification_string
|
||||
) :
|
||||
Node(Gauge::GaugeClassID),
|
||||
alreadyActivatedFlag(False)
|
||||
{
|
||||
Check_Pointer(this);
|
||||
|
||||
modeMask = mode_mask;
|
||||
ownerID = owner_ID;
|
||||
renderer = new_renderer;
|
||||
identificationString = identification_string;
|
||||
|
||||
stayInactive = True; // used by GaugeRenderer during activation
|
||||
//---------------------------------------------------
|
||||
// If renderer exists, add to object list
|
||||
// (Not having a renderer allows for independent testing)
|
||||
//---------------------------------------------------
|
||||
if (renderer != NULL)
|
||||
{
|
||||
Check(renderer);
|
||||
renderer->Add(this);
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
GaugeBase::~GaugeBase()
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Logical
|
||||
GaugeBase::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::BecameActive()
|
||||
{
|
||||
Check(this);
|
||||
//------------------------------------------------------
|
||||
// Default method immediately inactivates the gaugeBase
|
||||
//------------------------------------------------------
|
||||
DEBUG_STREAM <<
|
||||
"BecameActive() has not been defined for '" << identificationString <<
|
||||
"'. About to call Inactivate()\n";
|
||||
Inactivate();
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::BecameInactive()
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::Inactivate()
|
||||
{
|
||||
Check(this);
|
||||
if (renderer != NULL)
|
||||
{
|
||||
Check(renderer);
|
||||
renderer->Inactivate(this);
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Logical
|
||||
GaugeBase::Update(GaugeRate /*rate_mask*/)
|
||||
{
|
||||
Check(this);
|
||||
//------------------------------------------------------
|
||||
// Default method immediately inactivates the gaugeBase
|
||||
//------------------------------------------------------
|
||||
DEBUG_STREAM <<
|
||||
"Update() has not been defined for '" << identificationString <<
|
||||
"'. About to call Inactivate()\n";
|
||||
Inactivate();
|
||||
Check_Fpu();
|
||||
return False;
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::UpdateProfile(Scalar /*frame_percentage*/)
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::ReportProfile()
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::LinkToEntity(Entity */*entity*/)
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::NotifyOfNewInterestingEntity(Entity */*entity*/)
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::NotifyOfBecomingUninterestingEntity(Entity */*entity*/)
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
GaugeBase::DiscernTier()
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//#########################################################################
|
||||
//########################## GaugeBackground ##############################
|
||||
//#########################################################################
|
||||
GaugeBackground::GaugeBackground(
|
||||
ModeMask mode_mask,
|
||||
GaugeRenderer *new_renderer,
|
||||
unsigned int owner_ID,
|
||||
const char *identification_string
|
||||
) :
|
||||
GaugeBase(mode_mask, new_renderer, owner_ID, identification_string)
|
||||
{
|
||||
Check_Pointer(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//#########################################################################
|
||||
//######################## GraphicGaugeBackground #########################
|
||||
//#########################################################################
|
||||
GraphicGaugeBackground::GraphicGaugeBackground(
|
||||
ModeMask mode_mask,
|
||||
GaugeRenderer *renderer,
|
||||
unsigned int owner_ID,
|
||||
int graphics_port_number,
|
||||
const char *identification_string
|
||||
) :
|
||||
localView(
|
||||
renderer == NULL ?
|
||||
NULL :
|
||||
renderer->GetGraphicsPort(graphics_port_number)
|
||||
),
|
||||
GaugeBackground(mode_mask, renderer, owner_ID, identification_string)
|
||||
{
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//#########################################################################
|
||||
//########################## GaugeConnection ##############################
|
||||
//#########################################################################
|
||||
|
||||
GaugeConnection::GaugeConnection(int parameter_id)
|
||||
{
|
||||
Check_Pointer(this);
|
||||
parameterID = parameter_id;
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
GaugeConnection::~GaugeConnection()
|
||||
{
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Logical
|
||||
GaugeConnection::TestInstance() const
|
||||
{
|
||||
Check_Pointer(this);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
void GaugeConnection::Update()
|
||||
{
|
||||
Fail("GaugeConnection::Update should not be called!\n");
|
||||
}
|
||||
|
||||
void
|
||||
GaugeConnection::ShowInstance(char *indent)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
cout << indent << "GaugeConnection:\n";
|
||||
|
||||
char
|
||||
temp[80];
|
||||
|
||||
Str_Copy(temp,indent, 80);
|
||||
Str_Cat(temp,"...", 80);
|
||||
cout << temp << "parameterID=" << parameterID << "\n" << flush;
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//#########################################################################
|
||||
//################################# Gauge #################################
|
||||
//#########################################################################
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// GaugeRate masks are used to spread out workload in a priority-based
|
||||
// manner. Each GaugeRate refers to the branch of a binary tree as shown:
|
||||
//
|
||||
// A = every frame
|
||||
// /--------------^--------------\ :
|
||||
// FIRST TIER: B C = 1/2
|
||||
// /------^-------\ /------^-------\ :
|
||||
// 2ND: D E F G = 1/4
|
||||
// /--^---\ /--^---\ /--^---\ /--^---\ :
|
||||
// H I J K L M N O = 1/8
|
||||
// / \ / \ / \ / \ / \ / \ / \ / \ :
|
||||
// P Q R S T U V W X Y Z Z0 Z1 Z2 Z3 Z4 = 1/16
|
||||
//
|
||||
// Each 'tier' down indicates an update rate half that of the one above it.
|
||||
//
|
||||
// Note that rates Z0..Z4 cannot be specified through the gauge renderer's
|
||||
// interpreter. They are available to automatically generated gauges, though.
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
GaugeRate
|
||||
Gauge::rateTable[31] =
|
||||
{
|
||||
gaugeRate_A, // every frame
|
||||
|
||||
gaugeRate_B, // every other frame
|
||||
gaugeRate_C,
|
||||
|
||||
gaugeRate_D, // every 4th frame
|
||||
gaugeRate_E,
|
||||
gaugeRate_F,
|
||||
gaugeRate_G,
|
||||
|
||||
gaugeRate_H, // every 8th frame
|
||||
gaugeRate_I,
|
||||
gaugeRate_J,
|
||||
gaugeRate_K,
|
||||
gaugeRate_L,
|
||||
gaugeRate_M,
|
||||
gaugeRate_N,
|
||||
gaugeRate_O,
|
||||
|
||||
gaugeRate_P, // every 16th frame
|
||||
gaugeRate_Q,
|
||||
gaugeRate_R,
|
||||
gaugeRate_S,
|
||||
gaugeRate_T,
|
||||
gaugeRate_U,
|
||||
gaugeRate_V,
|
||||
gaugeRate_W,
|
||||
gaugeRate_X,
|
||||
gaugeRate_Y,
|
||||
gaugeRate_Z,
|
||||
gaugeRate_Z0,
|
||||
gaugeRate_Z1,
|
||||
gaugeRate_Z2,
|
||||
gaugeRate_Z3,
|
||||
gaugeRate_Z4
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Gauge::NextXXXTierGaugeRate()
|
||||
// - These functions attempt to spead out workload by returning the
|
||||
// next available 'GaugeRate' in a given 'tier'.
|
||||
//
|
||||
// The higher level tiers bump the lower level tier indices to
|
||||
// attempt to avoid placing too much load on the same higher-order
|
||||
// branch of the tree.
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
static int
|
||||
first_index = -1,
|
||||
second_index = -1,
|
||||
third_index = -1,
|
||||
fourth_index = -1;
|
||||
|
||||
GaugeRate
|
||||
Gauge::NextFirstTierGaugeRate()
|
||||
{
|
||||
//----------------------------------------
|
||||
// Generate first index
|
||||
//----------------------------------------
|
||||
first_index = (++first_index) & 1;
|
||||
//----------------------------------------
|
||||
// Bump other indices to avoid same branch
|
||||
//----------------------------------------
|
||||
second_index += 2;
|
||||
third_index += 4;
|
||||
fourth_index += 8;
|
||||
//----------------------------------------
|
||||
// Return rate mask
|
||||
//----------------------------------------
|
||||
return rateTable[first_index + 1];
|
||||
}
|
||||
|
||||
GaugeRate
|
||||
Gauge::NextSecondTierGaugeRate()
|
||||
{
|
||||
//----------------------------------------
|
||||
// Generate first index
|
||||
//----------------------------------------
|
||||
second_index = (++second_index) & 3;
|
||||
//----------------------------------------
|
||||
// Bump other indices to avoid same branch
|
||||
//----------------------------------------
|
||||
third_index += 2;
|
||||
fourth_index += 4;
|
||||
//----------------------------------------
|
||||
// Return rate mask
|
||||
//----------------------------------------
|
||||
return rateTable[second_index + 3];
|
||||
}
|
||||
|
||||
GaugeRate
|
||||
Gauge::NextThirdTierGaugeRate()
|
||||
{
|
||||
//----------------------------------------
|
||||
// Generate first index
|
||||
//----------------------------------------
|
||||
third_index = (++third_index) & 7;
|
||||
//----------------------------------------
|
||||
// Bump other indices to avoid same branch
|
||||
//----------------------------------------
|
||||
fourth_index += 2;
|
||||
//----------------------------------------
|
||||
// Return rate mask
|
||||
//----------------------------------------
|
||||
return rateTable[third_index + 7];
|
||||
}
|
||||
|
||||
GaugeRate
|
||||
Gauge::NextFourthTierGaugeRate()
|
||||
{
|
||||
//----------------------------------------
|
||||
// Generate first index
|
||||
//----------------------------------------
|
||||
fourth_index = (++fourth_index) & 15;
|
||||
//----------------------------------------
|
||||
// Return rate mask
|
||||
//----------------------------------------
|
||||
return rateTable[fourth_index + 15];
|
||||
}
|
||||
|
||||
GaugeRate
|
||||
Gauge::ConvertIndexToRate(int index)
|
||||
{
|
||||
Verify(index >= 0);
|
||||
Verify(index < 32);
|
||||
|
||||
return rateTable[index];
|
||||
}
|
||||
|
||||
Gauge::Gauge(
|
||||
GaugeRate new_rate,
|
||||
ModeMask mode_mask,
|
||||
GaugeRenderer *renderer,
|
||||
unsigned int owner_ID,
|
||||
const char *identification_string
|
||||
):
|
||||
GaugeBase(mode_mask, renderer, owner_ID, identification_string),
|
||||
instanceList(this)
|
||||
{
|
||||
Check_Pointer(this);
|
||||
|
||||
rate = new_rate;
|
||||
oldRate = new_rate;
|
||||
|
||||
stayInactive = False;
|
||||
|
||||
profileFramePercentage = (Scalar) 0;
|
||||
profileMaxFramePercentage = (Scalar) 0;
|
||||
profileCycles = 0;
|
||||
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Gauge::~Gauge()
|
||||
{
|
||||
Check(this);
|
||||
RemoveAllConnections();
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Logical
|
||||
Gauge::TestInstance() const
|
||||
{
|
||||
Check(&instanceList);
|
||||
# if 0
|
||||
//--------------------------------------------------------------------
|
||||
// Check all owned GaugeConnections
|
||||
//--------------------------------------------------------------------
|
||||
ChainIteratorOf<GaugeConnection*>
|
||||
i(instanceList);
|
||||
|
||||
GaugeConnection
|
||||
*the_connection;
|
||||
|
||||
while ((the_connection=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(the_connection);
|
||||
}
|
||||
# endif
|
||||
//--------------------------------------------------------------------
|
||||
// Check the base object
|
||||
//--------------------------------------------------------------------
|
||||
return GaugeBase::TestInstance();
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::ShowInstance(char *indent)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
ChainIteratorOf<GaugeConnection*>
|
||||
i(instanceList);
|
||||
|
||||
GaugeConnection
|
||||
*the_connection;
|
||||
|
||||
cout << indent << "Gauge:\n";
|
||||
|
||||
char
|
||||
temp[80];
|
||||
|
||||
Str_Copy(temp,indent, 80);
|
||||
Str_Cat(temp,"...", 80);
|
||||
|
||||
cout << temp << "modeMask =" << modeMask << "\n";
|
||||
cout << temp << "renderer =" << renderer << "\n";
|
||||
cout << temp << "ownerID =" << ownerID << "\n";
|
||||
cout << temp << "InstanceList -\n" << flush;
|
||||
|
||||
Str_Cat(temp,"...", 80);
|
||||
|
||||
while ((the_connection=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(the_connection);
|
||||
the_connection->ShowInstance(temp);
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::AddConnection(GaugeConnection *connection)
|
||||
{
|
||||
Check(this);
|
||||
Check(connection);
|
||||
instanceList.Add(connection);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::RemoveConnection(int parameter_ID)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
ChainIteratorOf<GaugeConnection*>
|
||||
i(instanceList);
|
||||
|
||||
GaugeConnection
|
||||
*gauge_connection;
|
||||
|
||||
while ((gauge_connection=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(gauge_connection);
|
||||
if (gauge_connection->parameterID == parameter_ID)
|
||||
{
|
||||
Unregister_Object(gauge_connection);
|
||||
delete gauge_connection;
|
||||
}
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::RemoveAllConnections()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
ChainIteratorOf<GaugeConnection*>
|
||||
i(instanceList);
|
||||
|
||||
GaugeConnection
|
||||
*gauge_connection;
|
||||
|
||||
while ((gauge_connection=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(gauge_connection);
|
||||
Unregister_Object(gauge_connection);
|
||||
delete gauge_connection;
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::Disable(Logical disable_state)
|
||||
{
|
||||
Check(this);
|
||||
if (disable_state)
|
||||
{
|
||||
rate = 0;
|
||||
BecameInactive();
|
||||
}
|
||||
else
|
||||
{
|
||||
rate = oldRate;
|
||||
BecameActive();
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Logical
|
||||
Gauge::Update(GaugeRate rate_mask)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
Logical
|
||||
actually_ran = False;
|
||||
//-----------------------------------------
|
||||
// Update only if rate mask allows it
|
||||
//-----------------------------------------
|
||||
if (rate & rate_mask)
|
||||
{
|
||||
//-----------------------------------------
|
||||
// Update parameters
|
||||
//-----------------------------------------
|
||||
ChainIteratorOf<GaugeConnection*>
|
||||
i(instanceList);
|
||||
|
||||
GaugeConnection
|
||||
*gauge_connection;
|
||||
|
||||
while ((gauge_connection=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(gauge_connection);
|
||||
gauge_connection->Update();
|
||||
}
|
||||
//-----------------------------------------
|
||||
// Execute gauge code
|
||||
//-----------------------------------------
|
||||
{
|
||||
// BT DEV-GAUGES bring-up: run Execute() under SEH so a gauge whose
|
||||
// game-state binding isn't reconstructed yet is DISABLED (rate=0)
|
||||
// after its first fault instead of AV'ing every frame. Gated on
|
||||
// BT_DEV_GAUGES; the pod build calls Execute() directly.
|
||||
static int s_devGaugesUpd = -1;
|
||||
if (s_devGaugesUpd < 0)
|
||||
s_devGaugesUpd = (getenv("BT_DEV_GAUGES") != NULL ||
|
||||
getenv("L4MFDSPLIT") != NULL) ? 1 : 0;
|
||||
if (s_devGaugesUpd)
|
||||
{
|
||||
if (!GuardedExecute())
|
||||
{
|
||||
// LOUD KILL (2026-07-12): the silent version made a faulted
|
||||
// gauge simply FREEZE on screen (user-hit: a weapon panel's
|
||||
// dial + lamp died mid-session with no trace). Name the
|
||||
// casualty so the log convicts the faulting Execute.
|
||||
DEBUG_STREAM << "[gauge-fault] '"
|
||||
<< (identificationString ? identificationString : "?")
|
||||
<< "' Execute FAULTED -> gauge DISABLED (this="
|
||||
<< (void *)this << ")\n" << flush;
|
||||
Disable(True);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Execute();
|
||||
}
|
||||
}
|
||||
actually_ran = True;
|
||||
}
|
||||
Check_Fpu();
|
||||
return actually_ran;
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::Execute()
|
||||
{
|
||||
Fail("Gauge::Execute not overridden");
|
||||
}
|
||||
|
||||
//
|
||||
// GuardedExecute -- BT DEV-GAUGES bring-up. Run Execute() under a structured
|
||||
// exception handler so a gauge whose game-state data binding is not yet
|
||||
// reconstructed is skipped instead of AV'ing the whole game. (A separate
|
||||
// function because __try/__except may not share a frame with C++ objects that
|
||||
// require unwinding, which Gauge::Update does.) Returns False on fault.
|
||||
//
|
||||
Logical
|
||||
Gauge::GuardedExecute()
|
||||
{
|
||||
Execute();
|
||||
return True;
|
||||
}
|
||||
|
||||
struct TierLookup
|
||||
{
|
||||
GaugeRate rate;
|
||||
int tier;
|
||||
};
|
||||
|
||||
int
|
||||
Gauge::DiscernTier()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
TierLookup
|
||||
*tier_pointer;
|
||||
static TierLookup
|
||||
tier_lookup[] =
|
||||
{
|
||||
{gaugeRate_A, 0 },
|
||||
|
||||
{gaugeRate_B, 1 },
|
||||
{gaugeRate_C, 1 },
|
||||
|
||||
{gaugeRate_D, 2 },
|
||||
{gaugeRate_E, 2 },
|
||||
{gaugeRate_F, 2 },
|
||||
{gaugeRate_G, 2 },
|
||||
|
||||
{gaugeRate_H, 3 },
|
||||
{gaugeRate_I, 3 },
|
||||
{gaugeRate_J, 3 },
|
||||
{gaugeRate_K, 3 },
|
||||
{gaugeRate_L, 3 },
|
||||
{gaugeRate_M, 3 },
|
||||
{gaugeRate_N, 3 },
|
||||
{gaugeRate_O, 3 },
|
||||
|
||||
{gaugeRate_P, 4 },
|
||||
{gaugeRate_Q, 4 },
|
||||
{gaugeRate_R, 4 },
|
||||
{gaugeRate_S, 4 },
|
||||
{gaugeRate_T, 4 },
|
||||
{gaugeRate_U, 4 },
|
||||
{gaugeRate_V, 4 },
|
||||
{gaugeRate_W, 4 },
|
||||
{gaugeRate_X, 4 },
|
||||
{gaugeRate_Y, 4 },
|
||||
{gaugeRate_Z, 4 },
|
||||
{gaugeRate_Z0,4 },
|
||||
{gaugeRate_Z1,4 },
|
||||
{gaugeRate_Z2,4 },
|
||||
{gaugeRate_Z3,4 },
|
||||
{gaugeRate_Z4,4 },
|
||||
{0,0}
|
||||
};
|
||||
|
||||
for (tier_pointer=tier_lookup; tier_pointer->rate != 0; ++tier_pointer)
|
||||
{
|
||||
if (tier_pointer->rate == rate)
|
||||
{
|
||||
Check_Fpu();
|
||||
return tier_pointer->tier;
|
||||
}
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::UpdateProfile(Scalar frame_percentage)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
//---------------------------------------------
|
||||
// Keep worst case
|
||||
//---------------------------------------------
|
||||
if (profileMaxFramePercentage < frame_percentage)
|
||||
{
|
||||
profileMaxFramePercentage = frame_percentage;
|
||||
}
|
||||
//---------------------------------------------
|
||||
// Keep running total
|
||||
//---------------------------------------------
|
||||
profileFramePercentage += frame_percentage;
|
||||
//---------------------------------------------
|
||||
// Prevent overflow
|
||||
//---------------------------------------------
|
||||
if (++profileCycles > 16384)
|
||||
{
|
||||
profileFramePercentage /= (Scalar) 2;
|
||||
profileCycles >>= 1;
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::ReportProfile()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
int
|
||||
i;
|
||||
|
||||
DEBUG_STREAM << identificationString << flush;
|
||||
for(i=strlen(identificationString); i<32; ++i)
|
||||
{
|
||||
DEBUG_STREAM << "." << flush;
|
||||
}
|
||||
|
||||
if (profileCycles > 0)
|
||||
{
|
||||
Scalar
|
||||
average = profileFramePercentage / (Scalar)profileCycles;
|
||||
|
||||
char
|
||||
buffer[80];
|
||||
|
||||
sprintf(buffer, "%6d %6.4f %6.4f\n",
|
||||
profileCycles,
|
||||
average,
|
||||
profileMaxFramePercentage
|
||||
);
|
||||
DEBUG_STREAM << buffer << flush;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_STREAM << "never ran.\n" << flush;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Reset maximum percentage
|
||||
//----------------------------------------
|
||||
profileMaxFramePercentage = (Scalar) 0;
|
||||
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//#########################################################################
|
||||
//############################# GraphicGauge #############################
|
||||
//#########################################################################
|
||||
|
||||
GraphicGauge::GraphicGauge(
|
||||
GaugeRate new_rate,
|
||||
ModeMask mode_mask,
|
||||
GaugeRenderer *renderer,
|
||||
unsigned int owner_ID,
|
||||
int graphics_port_number,
|
||||
const char *identification_string
|
||||
) :
|
||||
Gauge(new_rate, mode_mask, renderer, owner_ID, identification_string),
|
||||
localView(
|
||||
renderer == NULL ?
|
||||
NULL :
|
||||
renderer->GetGraphicsPort(graphics_port_number)
|
||||
)
|
||||
{
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
|
||||
GraphicGauge::~GraphicGauge()
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Logical
|
||||
GraphicGauge::TestInstance() const
|
||||
{
|
||||
Check(&localView);
|
||||
Check_Fpu();
|
||||
return Gauge::TestInstance();
|
||||
}
|
||||
|
||||
void
|
||||
GraphicGauge::ShowInstance(char *indent)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
cout << indent << "GraphicGauge:\n";
|
||||
|
||||
char
|
||||
temp[80];
|
||||
|
||||
Str_Copy(temp,indent, 80);
|
||||
Str_Cat(temp,"...", 80);
|
||||
|
||||
localView.ShowInstance(temp);
|
||||
Gauge::ShowInstance(temp);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
|
||||
#if defined(TEST_CLASS)
|
||||
# include "gauge.tcp"
|
||||
#endif
|
||||
@@ -0,0 +1,744 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(GAUGMAP_HPP)
|
||||
# include <gaugmap.hpp>
|
||||
# endif
|
||||
# if !defined(POINT3D_HPP)
|
||||
# include <point3d.hpp>
|
||||
# endif
|
||||
# if !defined(ENTITY_HPP)
|
||||
# include <entity.hpp>
|
||||
# endif
|
||||
|
||||
// #define LOCAL_TEST
|
||||
|
||||
#if defined(LOCAL_TEST)
|
||||
# define Test_Tell(n) cout << n
|
||||
#else
|
||||
# define Test_Tell(n)
|
||||
#endif
|
||||
|
||||
// 'FULL_EXTENT' is a value representing the total extent
|
||||
// of the world in meters.
|
||||
#define FULL_EXTENT 32767.0
|
||||
#define HALF_EXTENT (FULL_EXTENT/2.0)
|
||||
|
||||
// 'LARGEST_RADIUS' defines a radius encompassing the largest existing entity
|
||||
#define LARGEST_RADIUS 500.0 // HACK - this is a guess
|
||||
|
||||
|
||||
//#############################################################################
|
||||
// approximateDistance
|
||||
// ...accurate to about 13%
|
||||
// Graphics Gems, p.432, "A Fast Approximation To 3D Euclidean Distance"
|
||||
//#############################################################################
|
||||
Scalar
|
||||
approximateDistance(Point3D *point1, Point3D *point2)
|
||||
{
|
||||
Check_Pointer(point1);
|
||||
Check_Pointer(point2);
|
||||
|
||||
Scalar
|
||||
max, mid, min, temp;
|
||||
//-----------------------------------------------
|
||||
// Get the three components in arbitrary order
|
||||
//-----------------------------------------------
|
||||
max = abs(point2->x - point1->x);
|
||||
mid = abs(point2->y - point1->y);
|
||||
min = abs(point2->z - point1->z);
|
||||
//-----------------------------------------------
|
||||
// Sort only the largest value to the top.
|
||||
// We don't need to completely sort the values,
|
||||
// as we weight the middle and smallest equally.
|
||||
//-----------------------------------------------
|
||||
if (max < mid)
|
||||
{
|
||||
temp=max; max=mid; mid=temp; // swap max, mid
|
||||
}
|
||||
|
||||
if (max < min)
|
||||
{
|
||||
temp=max; max=min; min=temp; // swap max, min
|
||||
}
|
||||
|
||||
//-----------------------------------------------
|
||||
// return largest + 1/4 middle + 1/4 smallest
|
||||
//-----------------------------------------------
|
||||
Check_Fpu();
|
||||
return max + ((mid+min)*.25);
|
||||
}
|
||||
|
||||
|
||||
//#############################################################################
|
||||
// GaugeEntityList
|
||||
//#############################################################################
|
||||
|
||||
//============================================================================
|
||||
// Creator
|
||||
//============================================================================
|
||||
GaugeEntityList::GaugeEntityList() :
|
||||
Node(GaugeEntityList::GaugeEntityListClassID),
|
||||
instanceList(this)
|
||||
{
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Destructor
|
||||
//============================================================================
|
||||
GaugeEntityList::~GaugeEntityList()
|
||||
{
|
||||
Check(this);
|
||||
Clear(); // is this necessary, or are nodes automatically deleted?
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// TestInstance
|
||||
//============================================================================
|
||||
Logical
|
||||
GaugeEntityList::TestInstance() const
|
||||
{
|
||||
return Node::TestInstance();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Add
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityList::Add(Entity *entity)
|
||||
{
|
||||
Check(this);
|
||||
Check(entity);
|
||||
Check(&instanceList);
|
||||
instanceList.Add(entity);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Remove
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityList::Remove(Entity *search_entity)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
Test_Tell(
|
||||
"GaugeEntityList::Remove(" << search_entity <<
|
||||
")\n"
|
||||
);
|
||||
Check(&instanceList);
|
||||
ChainIteratorOf<Entity*>
|
||||
i(instanceList);
|
||||
|
||||
Entity
|
||||
*entity;
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Search the list for the given entity
|
||||
//-----------------------------------------------------
|
||||
while((entity=i.GetCurrent()) != NULL)
|
||||
{
|
||||
Check(entity);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// If we find it, remove it and exit
|
||||
//-----------------------------------------------------
|
||||
if (entity == search_entity)
|
||||
{
|
||||
Test_Tell("Found!\n");
|
||||
i.Remove();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
i.Next();
|
||||
}
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// NumberOfItems
|
||||
//============================================================================
|
||||
int
|
||||
GaugeEntityList::NumberOfItems()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
ChainIteratorOf<Entity*>
|
||||
i(instanceList);
|
||||
|
||||
Check_Fpu();
|
||||
return i.GetSize();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Clear
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityList::Clear()
|
||||
{
|
||||
// Test_Tell("GaugeEntityList::Clear()\n");
|
||||
Check(this);
|
||||
|
||||
ChainIteratorOf<Entity*>
|
||||
i(instanceList);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Remove all objects from the list
|
||||
//-----------------------------------------------------
|
||||
while(i.GetCurrent() != NULL)
|
||||
{
|
||||
Check(i.GetCurrent());
|
||||
i.Remove();
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// CopyEntities
|
||||
//
|
||||
// This method will create a reference in the destination list to
|
||||
// all entities in the list
|
||||
//============================================================================
|
||||
int
|
||||
GaugeEntityList::CopyEntities(
|
||||
GaugeEntityList *destination,
|
||||
Derivation *derivation_type
|
||||
)
|
||||
{
|
||||
Test_Tell("GaugeEntityList::CopyEntities(" << destination << ")\n");
|
||||
Check(this);
|
||||
Check(destination);
|
||||
|
||||
ChainIteratorOf<Entity*>
|
||||
i(instanceList);
|
||||
Entity
|
||||
*entity;
|
||||
int
|
||||
count(0);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Return all items in the list
|
||||
//-----------------------------------------------------
|
||||
while ((entity=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(entity);
|
||||
//-----------------------------------------------------
|
||||
// Discard if wrong type
|
||||
//-----------------------------------------------------
|
||||
if (derivation_type != NULL)
|
||||
{
|
||||
if (! entity->IsDerivedFrom(*derivation_type))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------
|
||||
// Add to the new list
|
||||
//-----------------------------------------------------
|
||||
destination->Add(entity);
|
||||
++count;
|
||||
}
|
||||
Test_Tell("Found " << count << " items.\n");
|
||||
Check_Fpu();
|
||||
return count;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// CopyEntitiesWithinBounds
|
||||
//
|
||||
// This method will create a reference in the destination list to
|
||||
// all entities in the list that are within the given bounds (if supplied).
|
||||
//============================================================================
|
||||
int
|
||||
GaugeEntityList::CopyEntitiesWithinBounds(
|
||||
GaugeEntityList *destination,
|
||||
Scalar min_x,
|
||||
Scalar /*min_y*/,
|
||||
Scalar min_z,
|
||||
Scalar max_x,
|
||||
Scalar /*max_y*/,
|
||||
Scalar max_z,
|
||||
Derivation *derivation_type
|
||||
)
|
||||
{
|
||||
Test_Tell(
|
||||
"GaugeEntityList::CopyEntitiesWithinBounds(" << destination <<
|
||||
", " << min_x <<
|
||||
"... , " << min_z <<
|
||||
", " << max_x <<
|
||||
"... , " << max_z <<
|
||||
")\n"
|
||||
);
|
||||
Check(this);
|
||||
Check(destination);
|
||||
|
||||
ChainIteratorOf<Entity*>
|
||||
i(instanceList);
|
||||
|
||||
Entity
|
||||
*entity;
|
||||
|
||||
Point3D
|
||||
pos;
|
||||
|
||||
int
|
||||
count(0);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Check all items in the list
|
||||
//-----------------------------------------------------
|
||||
while ((entity=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(entity);
|
||||
//-----------------------------------------------------
|
||||
// Discard if wrong type
|
||||
//-----------------------------------------------------
|
||||
if (derivation_type != NULL)
|
||||
{
|
||||
if (! entity->IsDerivedFrom(*derivation_type))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------
|
||||
// Get the item's position and radius
|
||||
//-----------------------------------------------------
|
||||
pos = entity->localOrigin.linearPosition;
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Add to the new list only if inside the bounds
|
||||
//-----------------------------------------------------
|
||||
Test_Tell(
|
||||
"Testing (" << pos.x <<
|
||||
", " << pos.y <<
|
||||
", " << pos.z <<
|
||||
")\n"
|
||||
);
|
||||
//if (pos.z >= min_z)
|
||||
//{
|
||||
// if (pos.z <= max_z)
|
||||
// {
|
||||
// if (pos.x >= min_x)
|
||||
// {
|
||||
// if (pos.x <= max_x)
|
||||
{
|
||||
Test_Tell("Accepted\n");
|
||||
destination->Add(entity);
|
||||
++count;
|
||||
}
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
Test_Tell("Found " << count << " items.\n");
|
||||
Check_Fpu();
|
||||
return count;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
// GaugeEntityArray
|
||||
//#############################################################################
|
||||
|
||||
//============================================================================
|
||||
// Creator
|
||||
//============================================================================
|
||||
GaugeEntityArray::GaugeEntityArray()
|
||||
{
|
||||
minimumX= 0.0;
|
||||
minimumY= 0.0;
|
||||
minimumZ= 0.0;
|
||||
maximumX= 0.0;
|
||||
maximumY= 0.0;
|
||||
maximumZ= 0.0;
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Destructor
|
||||
//============================================================================
|
||||
GaugeEntityArray::~GaugeEntityArray()
|
||||
{
|
||||
Check(this);
|
||||
Clear();
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// TestInstance
|
||||
//============================================================================
|
||||
Logical
|
||||
GaugeEntityArray::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Add
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityArray::Add(Entity *entity)
|
||||
{
|
||||
Test_Tell(
|
||||
"GaugeEntityArray::Add(" << entity <<
|
||||
")\n"
|
||||
);
|
||||
Check(this);
|
||||
Check(entity);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Add to the proper grid list
|
||||
//-----------------------------------------------------
|
||||
Point3D
|
||||
pos(entity->localOrigin.linearPosition);
|
||||
|
||||
grid[ArrayOffset(pos.x)][ArrayOffset(pos.z)].Add(entity);
|
||||
//-----------------------------------------------------
|
||||
// Keep track of the total extents
|
||||
//-----------------------------------------------------
|
||||
if (pos.x < minimumX)
|
||||
{
|
||||
minimumX = pos.x;
|
||||
}
|
||||
if (pos.y < minimumY)
|
||||
{
|
||||
minimumY = pos.y;
|
||||
}
|
||||
if (pos.z < minimumZ)
|
||||
{
|
||||
minimumZ = pos.z;
|
||||
}
|
||||
if (pos.x > maximumX)
|
||||
{
|
||||
maximumX = pos.x;
|
||||
}
|
||||
if (pos.y > maximumY)
|
||||
{
|
||||
maximumY = pos.y;
|
||||
}
|
||||
if (pos.z > maximumZ)
|
||||
{
|
||||
maximumZ = pos.z;
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Remove
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityArray::Remove(Entity *entity)
|
||||
{
|
||||
Test_Tell(
|
||||
"GaugeEntityArray::Remove(" << entity <<
|
||||
")\n"
|
||||
);
|
||||
Check(this);
|
||||
Check(entity);
|
||||
|
||||
Point3D
|
||||
pos(entity->localOrigin.linearPosition);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Remove from the proper grid list
|
||||
//-----------------------------------------------------
|
||||
grid[ArrayOffset(pos.x)][ArrayOffset(pos.z)].Remove(entity);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Clear
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityArray::Clear()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
int
|
||||
x,
|
||||
z;
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Clear all grid lists
|
||||
//-----------------------------------------------------
|
||||
for(z=0; z<gaugeMapArraySize; ++z)
|
||||
{
|
||||
for(x=0; x<gaugeMapArraySize; ++x)
|
||||
{
|
||||
grid[x][z].Clear();
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------
|
||||
// Set the bounds to zero
|
||||
//-----------------------------------------------------
|
||||
minimumX= 0.0;
|
||||
minimumY= 0.0;
|
||||
minimumZ= 0.0;
|
||||
maximumX= 0.0;
|
||||
maximumY= 0.0;
|
||||
maximumZ= 0.0;
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// PrintStatistics
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityArray::PrintStatistics()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
int
|
||||
x,
|
||||
z,
|
||||
n,
|
||||
total(0);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Count all grid lists
|
||||
//-----------------------------------------------------
|
||||
for(z=0; z<gaugeMapArraySize; ++z)
|
||||
{
|
||||
if (z < 10)
|
||||
{
|
||||
cout << " ";
|
||||
}
|
||||
cout << z << ":";
|
||||
for(x=0; x<gaugeMapArraySize; ++x)
|
||||
{
|
||||
n = grid[x][z].NumberOfItems();
|
||||
total += n;
|
||||
if (n < 100)
|
||||
{
|
||||
cout << " ";
|
||||
if (n < 10)
|
||||
{
|
||||
cout << " ";
|
||||
}
|
||||
}
|
||||
cout << n << " ";
|
||||
}
|
||||
cout << "\n";
|
||||
}
|
||||
cout << "Total= " << total << "\n";
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// CopyEntities
|
||||
//
|
||||
// This method will create a reference in the destination list to
|
||||
// all GaugeImages in the array.
|
||||
//============================================================================
|
||||
int
|
||||
GaugeEntityArray::CopyEntities(
|
||||
GaugeEntityList *destination,
|
||||
Derivation *derivation_type
|
||||
)
|
||||
{
|
||||
Test_Tell(
|
||||
"GaugeEntityArray::CopyEntities(" << destination << ")\n");
|
||||
Check(this);
|
||||
Check(destination);
|
||||
|
||||
int
|
||||
x,
|
||||
low_x,
|
||||
high_x,
|
||||
z,
|
||||
high_z,
|
||||
count(0);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Generate the z search limits
|
||||
//-----------------------------------------------------
|
||||
z = 0;
|
||||
high_z = gaugeMapArraySize - 1;
|
||||
//-----------------------------------------------------
|
||||
// Generate the x search limits
|
||||
//-----------------------------------------------------
|
||||
low_x = 0;
|
||||
high_x = gaugeMapArraySize - 1;
|
||||
|
||||
//-------------------------------------------------------
|
||||
// Search the grid for items
|
||||
//-------------------------------------------------------
|
||||
for( ; z<high_z; ++z)
|
||||
{
|
||||
for(x=low_x; x<high_x; ++x)
|
||||
{
|
||||
Test_Tell("Searching [" << x << "][" << z << "]\n");
|
||||
count += grid[x][z].CopyEntities(destination, derivation_type);
|
||||
}
|
||||
}
|
||||
Test_Tell("Search done, total found = " << count << " items.\n");
|
||||
Check_Fpu();
|
||||
return count;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// CopyEntitiesWithinBounds
|
||||
//
|
||||
// This method will create a reference in the destination list to
|
||||
// all GaugeImages in the array that are within the given bounds.
|
||||
//============================================================================
|
||||
int
|
||||
GaugeEntityArray::CopyEntitiesWithinBounds(
|
||||
GaugeEntityList *destination,
|
||||
Scalar min_x,
|
||||
Scalar min_y,
|
||||
Scalar min_z,
|
||||
Scalar max_x,
|
||||
Scalar max_y,
|
||||
Scalar max_z,
|
||||
Derivation *derivation_type
|
||||
)
|
||||
{
|
||||
Test_Tell(
|
||||
"GaugeEntityArray::CopyEntitiesWithinBounds(" << destination <<
|
||||
", " << min_x <<
|
||||
", " << min_y <<
|
||||
", " << min_z <<
|
||||
", " << max_x <<
|
||||
", " << max_y <<
|
||||
", " << max_z <<
|
||||
")\n"
|
||||
);
|
||||
Check(this);
|
||||
Check(destination);
|
||||
|
||||
int
|
||||
x,
|
||||
low_x,
|
||||
high_x,
|
||||
z,
|
||||
high_z,
|
||||
count(0);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Generate the z search limits
|
||||
//-----------------------------------------------------
|
||||
z = ArrayOffset(min_z - LARGEST_RADIUS);
|
||||
high_z = ArrayOffset(max_z + LARGEST_RADIUS);
|
||||
|
||||
Test_Tell(
|
||||
"Initial z =" << z <<
|
||||
", high_z=" << high_z <<
|
||||
"\n"
|
||||
);
|
||||
if (z < 0)
|
||||
{
|
||||
z = 0;
|
||||
}
|
||||
else if (z >= gaugeMapArraySize)
|
||||
{
|
||||
z = gaugeMapArraySize - 1;
|
||||
}
|
||||
if (high_z < 0)
|
||||
{
|
||||
high_z = 0;
|
||||
}
|
||||
else if (high_z >= gaugeMapArraySize)
|
||||
{
|
||||
high_z = gaugeMapArraySize - 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Generate the x search limits
|
||||
//-----------------------------------------------------
|
||||
low_x = ArrayOffset(min_x - LARGEST_RADIUS);
|
||||
high_x = ArrayOffset(max_x + LARGEST_RADIUS);
|
||||
|
||||
if (low_x < 0)
|
||||
{
|
||||
low_x = 0;
|
||||
}
|
||||
else if (low_x >= gaugeMapArraySize)
|
||||
{
|
||||
low_x = gaugeMapArraySize - 1;
|
||||
}
|
||||
if (high_x < 0)
|
||||
{
|
||||
high_x = 0;
|
||||
}
|
||||
else if (high_x >= gaugeMapArraySize)
|
||||
{
|
||||
high_x = gaugeMapArraySize - 1;
|
||||
}
|
||||
|
||||
Test_Tell("Search x=(" << low_x << "..." << high_x << ")\n");
|
||||
Test_Tell("Search z=(" << z << "..." << high_z << ")\n");
|
||||
//-------------------------------------------------------
|
||||
// Search the (limited) grid for items within the bounds
|
||||
//-------------------------------------------------------
|
||||
for( ; z<high_z; ++z)
|
||||
{
|
||||
for(x=low_x; x<high_x; ++x)
|
||||
{
|
||||
Test_Tell("Searching [" << x << "][" << z << "]\n");
|
||||
count += grid[x][z].CopyEntitiesWithinBounds(
|
||||
destination,
|
||||
min_x,
|
||||
min_y,
|
||||
min_z,
|
||||
max_x,
|
||||
max_y,
|
||||
max_z,
|
||||
derivation_type
|
||||
);
|
||||
}
|
||||
}
|
||||
Test_Tell("Search done, total found = " << count << " items.\n");
|
||||
Check_Fpu();
|
||||
return count;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// GetBounds
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityArray::GetBounds(
|
||||
Scalar *min_x,
|
||||
Scalar *min_y,
|
||||
Scalar *min_z,
|
||||
Scalar *max_x,
|
||||
Scalar *max_y,
|
||||
Scalar *max_z
|
||||
)
|
||||
{
|
||||
*min_x = minimumX;
|
||||
*min_y = minimumY;
|
||||
*min_z = minimumZ;
|
||||
*max_x = maximumX;
|
||||
*max_y = maximumY;
|
||||
*max_z = maximumZ;
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// ArrayOffset - generate offset into array based on position value
|
||||
//============================================================================
|
||||
int
|
||||
GaugeEntityArray::ArrayOffset(Scalar n)
|
||||
{
|
||||
int q;
|
||||
|
||||
q = (int)(gaugeMapArraySize*(n/HALF_EXTENT)+.5)+(gaugeMapArraySize>>1);
|
||||
|
||||
if (q < 0)
|
||||
{
|
||||
q = 0;
|
||||
}
|
||||
if (q >= gaugeMapArraySize)
|
||||
{
|
||||
q = (gaugeMapArraySize-1);
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
return q;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,44 +1,440 @@
|
||||
//===========================================================================//
|
||||
// File: network.cpp //
|
||||
// Project: MUNGA Brick: Network //
|
||||
// Contents: Implementation details for network clients //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
|
||||
#include <munga.hpp>
|
||||
#pragma hdrstop
|
||||
|
||||
#if !defined(NETWORK_HPP)
|
||||
# include <network.hpp>
|
||||
#endif
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Derivation
|
||||
NetworkClient::ClassDerivations(
|
||||
Receiver::ClassDerivations,
|
||||
"NetworkClient"
|
||||
);
|
||||
|
||||
NetworkClient::SharedData
|
||||
NetworkClient::DefaultData(
|
||||
NetworkClient::ClassDerivations,
|
||||
Receiver::MessageHandlers
|
||||
);
|
||||
|
||||
Derivation
|
||||
NetworkManager::ClassDerivations(
|
||||
NetworkClient::ClassDerivations,
|
||||
"NetworkManager"
|
||||
);
|
||||
|
||||
NetworkManager::SharedData
|
||||
NetworkManager::DefaultData(
|
||||
NetworkManager::ClassDerivations,
|
||||
Receiver::MessageHandlers
|
||||
);
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(HOSTMGR_HPP)
|
||||
# include <hostmgr.hpp>
|
||||
# endif
|
||||
# if !defined(INTEREST_HPP)
|
||||
# include <interest.hpp>
|
||||
# endif
|
||||
# if !defined(ICOM_HPP)
|
||||
# include <icom.hpp>
|
||||
# endif
|
||||
# if !defined(APP_HPP)
|
||||
# include <app.hpp>
|
||||
# endif
|
||||
# if !defined(NOTATION_HPP)
|
||||
# include <notation.hpp>
|
||||
# endif
|
||||
# if !defined(NTTMGR_HPP)
|
||||
# include <nttmgr.hpp>
|
||||
# endif
|
||||
|
||||
#if defined(TRACE_ROUTE_PACKET)
|
||||
static BitTrace Route_Packet("Route Packet");
|
||||
# define SET_ROUTE_PACKET() Route_Packet.Set()
|
||||
# define CLEAR_ROUTE_PACKET() Route_Packet.Clear()
|
||||
#else
|
||||
# define SET_ROUTE_PACKET()
|
||||
# define CLEAR_ROUTE_PACKET()
|
||||
#endif
|
||||
|
||||
const NetworkAddress NullNetworkAddress = 0x00000000;// 0.0.0.0 (in TCP land);
|
||||
|
||||
//#############################################################################
|
||||
// Shared Data Support
|
||||
//
|
||||
NetworkClient::SharedData
|
||||
NetworkClient::DefaultData(
|
||||
NetworkClient::ClassDerivations,
|
||||
NetworkClient::MessageHandlers
|
||||
);
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// Code for the network client class
|
||||
//#############################################################################
|
||||
//
|
||||
Derivation
|
||||
NetworkClient::ClassDerivations(Receiver::ClassDerivations, "NetworkClient");
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Constructor for the NetworkClient
|
||||
//
|
||||
NetworkClient::NetworkClient(
|
||||
ClassID class_ID,
|
||||
SharedData &virtual_data,
|
||||
ClientID client_ID
|
||||
):
|
||||
Receiver(class_ID, virtual_data)
|
||||
{
|
||||
clientID = client_ID;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Destructor for the NetworkClient
|
||||
//
|
||||
NetworkClient::~NetworkClient()
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Destructor for the NetworkClient
|
||||
//
|
||||
Logical
|
||||
NetworkClient::TestInstance() const
|
||||
{
|
||||
return IsDerivedFrom(ClassDerivations);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Receive packet for the NetworkClient
|
||||
//
|
||||
void
|
||||
NetworkClient::ReceiveNetworkPacket(
|
||||
NetworkPacket*,
|
||||
Receiver::Message *packet_message
|
||||
)
|
||||
{
|
||||
Dispatch(packet_message);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// Code for the network manager class
|
||||
//#############################################################################
|
||||
|
||||
const Receiver::HandlerEntry
|
||||
NetworkManager::MessageHandlerEntries[]=
|
||||
{
|
||||
MESSAGE_ENTRY(NetworkManager,ReceiveEggFile)
|
||||
};
|
||||
|
||||
NetworkManager::MessageHandlerSet
|
||||
NetworkManager::MessageHandlers(ELEMENTS(NetworkManager::MessageHandlerEntries), NetworkManager::MessageHandlerEntries, NetworkClient::MessageHandlers);
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Shared Data Support
|
||||
//
|
||||
NetworkManager::SharedData
|
||||
NetworkManager::DefaultData(
|
||||
NetworkManager::ClassDerivations,
|
||||
NetworkManager::MessageHandlers
|
||||
);
|
||||
|
||||
Derivation
|
||||
NetworkManager::ClassDerivations(NetworkClient::ClassDerivations, "NetworkManager");
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Constructor for the NetworkManager
|
||||
//
|
||||
NetworkManager::NetworkManager(SharedData &shared_data):
|
||||
NetworkClient(NetworkManagerClassID, shared_data, NetworkManagerClientID)
|
||||
{
|
||||
// basic init goes here
|
||||
gameID = 0;
|
||||
eggTempBuffer = NULL;
|
||||
networkEggNotationFile = NULL;
|
||||
eggTempNext = 0;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Creates a host for us. Any derived class must deal with reading the
|
||||
// notation file to get the network nodes to connect to. This start is
|
||||
// designed for STAND-ALONE MODE ONLY and should not be inherited for use by
|
||||
//
|
||||
void
|
||||
NetworkManager::StartConnecting(Mission *)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
//
|
||||
//---------------------------------------------------------
|
||||
// Make the local host, and get the application to adopt it
|
||||
//---------------------------------------------------------
|
||||
//
|
||||
Host *local_host = new Host(1, GameMachineHostType, 1);
|
||||
Register_Object(local_host);
|
||||
|
||||
Check(application);
|
||||
Check(application->GetHostManager());
|
||||
application->GetHostManager()->AdoptLocalHost(local_host);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
// Now, since this host creator is for stand-alone mode, send the load
|
||||
// mission message to the application
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
Check(application);
|
||||
Application::Message
|
||||
load_message(
|
||||
Application::LoadMissionMessageID,
|
||||
sizeof(Application::Message)
|
||||
);
|
||||
application->Post(DefaultEventPriority, application, &load_message);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::EndMission This routine is called when a mission ends to
|
||||
// allow the network management system to do stuff (like disconnecting network
|
||||
// connections between pods and so on)
|
||||
//
|
||||
Logical
|
||||
NetworkManager::Shutdown()
|
||||
{
|
||||
//
|
||||
// If there is a notation file floating about, kill it!
|
||||
//
|
||||
if (networkEggNotationFile)
|
||||
{
|
||||
Unregister_Object(networkEggNotationFile);
|
||||
delete networkEggNotationFile;
|
||||
}
|
||||
|
||||
//
|
||||
// Deregister local host
|
||||
//
|
||||
Host *local_host;
|
||||
|
||||
local_host = application->GetHostManager()->OrphanLocalHost();
|
||||
Unregister_Object(local_host);
|
||||
delete local_host;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Destructor for the NetworkManager
|
||||
//
|
||||
NetworkManager::~NetworkManager()
|
||||
{
|
||||
// shutdown net goes here
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::ReceiveEggFileMessageHandler
|
||||
//
|
||||
void
|
||||
NetworkManager::ReceiveEggFileMessageHandler(
|
||||
ReceiveEggFileMessage* EggMessage
|
||||
)
|
||||
{
|
||||
//
|
||||
// An egg sequence number of -1 means that the egg is posted locally, and
|
||||
// should just call create mission
|
||||
//
|
||||
if (EggMessage->sequenceNumber == -1)
|
||||
{
|
||||
application->CreateMission(networkEggNotationFile);
|
||||
return;
|
||||
}
|
||||
|
||||
if (EggMessage->sequenceNumber == 0)
|
||||
{
|
||||
//
|
||||
// Make a buffer
|
||||
//
|
||||
eggTempBuffer = new char[EggMessage->notationFileLength];
|
||||
Register_Pointer(eggTempBuffer);
|
||||
eggTempNext = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Write the egg data into the buffer
|
||||
//
|
||||
memcpy(
|
||||
(eggTempBuffer+eggTempNext),
|
||||
EggMessage->notationData,
|
||||
EggMessage->thisMessageLength
|
||||
);
|
||||
eggTempNext += EggMessage->thisMessageLength;
|
||||
|
||||
//
|
||||
// If we don't have all the data, return and wait for more
|
||||
//
|
||||
if(eggTempNext < EggMessage->notationFileLength)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// We've got all the data, make the notation file
|
||||
//
|
||||
networkEggNotationFile = new NotationFile();
|
||||
Register_Object(networkEggNotationFile);
|
||||
networkEggNotationFile->ReadText(eggTempBuffer, eggTempNext);
|
||||
networkEggNotationFile->WriteFile("last.egg");
|
||||
|
||||
//
|
||||
// Now turn the notation file into a mission
|
||||
//
|
||||
application->CreateMission(networkEggNotationFile);
|
||||
|
||||
//
|
||||
// Get rid of the ram buffer now that we're done with it
|
||||
//
|
||||
Unregister_Pointer(eggTempBuffer);
|
||||
delete eggTempBuffer;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::Send Handles sending a message to a specific network address
|
||||
// which can NOT be us. Default behavior is to do nothing, as no network is
|
||||
// hooked up if we get here
|
||||
//
|
||||
void
|
||||
NetworkManager::Send(
|
||||
Message *,
|
||||
ClientID,
|
||||
HostID
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::Broadcast Handles broadcasting a message to everyone,
|
||||
// including ourselves. !!!! Reliable broadcasting is currently used,
|
||||
// implimented by sending a point-to-point message to every destination.
|
||||
//
|
||||
void
|
||||
NetworkManager::Broadcast(
|
||||
Message *message,
|
||||
ClientID client_id
|
||||
)
|
||||
{
|
||||
//
|
||||
// Send this message back to ourselves
|
||||
//
|
||||
NetworkClient *client = GetNetworkClientPointer(client_id);
|
||||
Check(client);
|
||||
client->ReceiveNetworkPacket(NULL, message);
|
||||
|
||||
//
|
||||
// Broadcast the message to everyone else on the network
|
||||
//
|
||||
ExclusiveBroadcast(message,client_id);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::ExclusiveBroadcast Broadcasts a message to everyone on the
|
||||
// network execpt us. Default behavior sends it to nobody, as there is really
|
||||
// no network
|
||||
//
|
||||
void
|
||||
NetworkManager::ExclusiveBroadcast(
|
||||
Message *,
|
||||
ClientID
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::GetNetworkClientPointer Determine who the client of a
|
||||
// message is and return a pointer to them.
|
||||
//
|
||||
NetworkClient*
|
||||
NetworkManager::GetNetworkClientPointer(ClientID client_id)
|
||||
{
|
||||
switch (client_id)
|
||||
{
|
||||
case NetworkClient::NetworkManagerClientID:
|
||||
return this;
|
||||
|
||||
case NetworkClient::EntityManagerClientID:
|
||||
Check(application);
|
||||
return application->GetEntityManager();
|
||||
|
||||
case NetworkClient::HostManagerClientID:
|
||||
Check(application);
|
||||
return application->GetHostManager();
|
||||
|
||||
case NetworkClient::InterestManagerClientID:
|
||||
Check(application);
|
||||
return application->GetInterestManager();
|
||||
|
||||
case NetworkClient::IcomManagerClientID:
|
||||
Check(application);
|
||||
return application->GetIntercomManager();
|
||||
|
||||
case NetworkClient::ApplicationClientID:
|
||||
Check(application);
|
||||
return application;
|
||||
|
||||
default:
|
||||
DEBUG_STREAM << "------UNKNOWN NETWORK CLIENT ID " << client_id << endl << flush;
|
||||
Fail("Unknown Client ID");
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::RoutePacket
|
||||
//
|
||||
Logical
|
||||
NetworkManager::RoutePacket()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
Byte
|
||||
message_buffer[NETWORKMANAGER_BUFFER_SIZE];
|
||||
NetworkPacket
|
||||
*p;
|
||||
|
||||
//
|
||||
// Return if check buffers doesn't have a packet for us
|
||||
//
|
||||
if (!CheckBuffers((NetworkPacket*)message_buffer))
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
//
|
||||
// Process and route the packet properly
|
||||
//
|
||||
p = (NetworkPacket*)message_buffer;
|
||||
|
||||
if (p->gameID == gameID)
|
||||
{
|
||||
// cout<<"++++++++client "<<p->clientID<<" gameID "<<p->gameID<<" fromHost "<<p->fromHost<<"\n";
|
||||
NetworkClient *client = GetNetworkClientPointer(p->clientID);
|
||||
|
||||
Check(client);
|
||||
SET_ROUTE_PACKET();
|
||||
client->ReceiveNetworkPacket(p, &p->messageData);
|
||||
CLEAR_ROUTE_PACKET();
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_STREAM << "+++++++++ client " << p->clientID << " gameID " << p->gameID << " fromHost " << p->fromHost << endl << flush;
|
||||
Fail("######### NOT A PACKET FOR THIS GAME!");
|
||||
}
|
||||
|
||||
RemovePacket(p);
|
||||
return True;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::ExecuteBackground Allows the network to perform tasks in
|
||||
// the applications background. The method should return True if the manager
|
||||
// is busy, False otherwise. For example, if the input and output buffers of
|
||||
// the network driver are not empty then return True, otherwise return False.
|
||||
//
|
||||
Logical
|
||||
NetworkManager::ExecuteBackground()
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::CheckBuffers Checks to see if there is a message for us
|
||||
// buffered up in the network interface card and returns a pointer to it.
|
||||
//
|
||||
Logical
|
||||
NetworkManager::CheckBuffers(NetworkPacket*)
|
||||
{
|
||||
Fail("NetworkManager::CheckBuffers - should never reach here!");
|
||||
return False;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::RemovePacket If the network implimentation requires us to
|
||||
// free up a packet buffer, this routine would do it.
|
||||
//
|
||||
void
|
||||
NetworkManager::RemovePacket(NetworkPacket*)
|
||||
{
|
||||
Fail("NetworkManager::RemovePacket - should never reach here!");
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,176 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(RAY_HPP)
|
||||
# include <ray.hpp>
|
||||
# endif
|
||||
# if !defined(PLANE_HPP)
|
||||
# include <plane.hpp>
|
||||
# endif
|
||||
# if !defined(SPHERE_HPP)
|
||||
# include <sphere.hpp>
|
||||
# endif
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void Ray::Project(Scalar length, Point3D *result)
|
||||
{
|
||||
Check(this);
|
||||
Check(result);
|
||||
|
||||
Vector3D temp;
|
||||
|
||||
temp.Multiply(direction,length);
|
||||
result->Add(origin,temp);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Scalar Ray::LengthToClosestPointTo(const Point3D &point)
|
||||
{
|
||||
Check(this);
|
||||
Check(&point);
|
||||
|
||||
Vector3D temp;
|
||||
|
||||
temp.Subtract(point,origin);
|
||||
return temp*direction;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Scalar Ray::DistanceTo(const Plane &plane, Scalar *product) const
|
||||
{
|
||||
Scalar t;
|
||||
|
||||
//
|
||||
//------------------------------------------------------------------
|
||||
// Compute the dot product of the ray and plane normal, and find the
|
||||
// distance from the origin of the ray to the plane
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
*product = plane.normal * direction;
|
||||
t = plane.DistanceTo(origin);
|
||||
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
// If the ray is not parallel to the plane, determine how far to proceed
|
||||
// along the ray until we hit the plane
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
if (!Small_Enough(*product))
|
||||
t /= -*product;
|
||||
return t;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Scalar Ray::DistanceTo(const Sphere &sphere, Scalar *penetration) const
|
||||
{
|
||||
Scalar b, c;
|
||||
Vector3D temp;
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// Set up to solve a quadratic equation for the intersection of the ray and
|
||||
// sphere. The solution is based on finding the closest point on the line
|
||||
// to the sphere, and then calculating the interval between the entry and
|
||||
// exit points of the ray
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
temp.Subtract(origin,sphere.center);
|
||||
b = 2.0f * (direction * temp);
|
||||
c = temp.LengthSquared() - sphere.radius*sphere.radius;
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Compute the squared interval to use for the solution. If it is negative,
|
||||
// then the ray misses the sphere
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
*penetration = b*b - 4.0f*c;
|
||||
if (*penetration<SMALL)
|
||||
return 0.0f;
|
||||
else
|
||||
{
|
||||
//-------------------------------------------------------------------------
|
||||
// Otherwise, find the linear distance along the line of the entry point by
|
||||
// subtracting half the interval between entry and exit points from the
|
||||
// distance to the closest point on the sphere
|
||||
//-------------------------------------------------------------------------
|
||||
*penetration = Sqrt(*penetration);
|
||||
return -0.5f*(b+*penetration);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Logical Ray::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Scalar Find_Closest_Approach(const Point3D& origin1, const Vector3D& velocity1, Point3D *result1, const Point3D& origin2, const Vector3D& velocity2, Point3D *result2, Scalar *time, Logical *constant)
|
||||
{
|
||||
Vector3D a,b;
|
||||
a.Subtract(origin1, origin2);
|
||||
b.Subtract(velocity1, velocity2);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
// If the velocities are identical, any point will do for the test, so
|
||||
// simply return the difference between the starting points
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
Scalar d = b.LengthSquared();
|
||||
if (Small_Enough(d))
|
||||
{
|
||||
*constant = True;
|
||||
d = a.Length();
|
||||
Check_Fpu();
|
||||
return d;
|
||||
}
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// The velocities are not parallel, so figure out when the closest approach
|
||||
// is via the derivative
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
*constant = False;
|
||||
*time = (a * b) / -d;
|
||||
Check_Fpu();
|
||||
|
||||
//
|
||||
//------------------------------------------------------
|
||||
// Now, plot the resultant points of both line equations
|
||||
//------------------------------------------------------
|
||||
//
|
||||
Vector3D closest;
|
||||
closest.AddScaled(a, b, *time);
|
||||
result1->AddScaled(origin1, velocity1, *time);
|
||||
result2->AddScaled(origin2, velocity2, *time);
|
||||
d = closest.Length();
|
||||
Check_Fpu();
|
||||
return d;
|
||||
}
|
||||
|
||||
#if defined(TEST_CLASS)
|
||||
# include "ray.tcp"
|
||||
#endif
|
||||
@@ -0,0 +1,916 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(RESOURCE_HPP)
|
||||
# include <resource.hpp>
|
||||
# endif
|
||||
# if !defined(RESVER_HPP)
|
||||
# include <resver.hpp>
|
||||
# endif
|
||||
|
||||
ResourceDescription::ResourceDescription(
|
||||
ResourceFile *file,
|
||||
const char* name,
|
||||
ResourceDescription::ResourceType type,
|
||||
int priority,
|
||||
LWord flags,
|
||||
const void* address,
|
||||
size_t size,
|
||||
ResourceDescription::ResourceID index
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check_Pointer(name);
|
||||
|
||||
resourceFile = file;
|
||||
resourceID = index;
|
||||
resourceType = type;
|
||||
Str_Copy(resourceName, name, sizeof(resourceName));
|
||||
for (int i = strlen(resourceName) + 1; i<sizeof(resourceName); ++i)
|
||||
{
|
||||
resourceName[i] = '\0';
|
||||
}
|
||||
|
||||
downloadPriority = priority;
|
||||
resourceFlags = flags;
|
||||
offsetInFile = 0;
|
||||
resourceSize = size;
|
||||
resourceAddress = NULL;
|
||||
lockCount = 0;
|
||||
|
||||
if (address)
|
||||
{
|
||||
Check_Pointer(address);
|
||||
resourceAddress = new char[resourceSize];
|
||||
Register_Pointer(resourceAddress);
|
||||
Mem_Copy(resourceAddress, address, resourceSize, resourceSize);
|
||||
SetLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription::~ResourceDescription()
|
||||
{
|
||||
Check(this);
|
||||
// Verify(!IsLocked());
|
||||
if (resourceAddress)
|
||||
{
|
||||
Unregister_Pointer(resourceAddress);
|
||||
delete[] resourceAddress;
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ResourceDescription::ReleaseUnlockedResource()
|
||||
{
|
||||
Check(this);
|
||||
if (!IsLocked())
|
||||
{
|
||||
if (IsLoaded())
|
||||
{
|
||||
SetNotLoaded();
|
||||
Verify(resourceAddress);
|
||||
Unregister_Pointer(resourceAddress);
|
||||
delete[] resourceAddress;
|
||||
resourceAddress = NULL;
|
||||
}
|
||||
Verify(!resourceAddress);
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ResourceDescription::LoadResource()
|
||||
{
|
||||
Check(this);
|
||||
if (!IsLoaded())
|
||||
{
|
||||
Verify(!resourceAddress);
|
||||
Check(resourceFile);
|
||||
resourceFile->LoadResource(this);
|
||||
Verify(resourceAddress);
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
ResourceDescription::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//########################## ResourceFile ###############################
|
||||
//#############################################################################
|
||||
|
||||
//#############################################################################
|
||||
// ResourceFile CONSTRUCTORS & DESTRUCTORS
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceFile::ResourceFile():
|
||||
labOnly(0),
|
||||
resourceArray(NULL),
|
||||
resourceArraySize(0),
|
||||
maxResourceID(ResourceDescription::NullResourceID),
|
||||
lastPreallocatedResourceID(ResourceDescription::NullResourceID)
|
||||
{
|
||||
versionArray[0] = RESOURCE_FORMAT_VERSION;
|
||||
versionArray[1] = 0;
|
||||
versionArray[2] = 0;
|
||||
versionArray[3] = 0;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceFile::~ResourceFile()
|
||||
{
|
||||
if (resourceArray)
|
||||
{
|
||||
for (int i=maxResourceID; i>=0; i--)
|
||||
{
|
||||
if (resourceArray[i])
|
||||
{
|
||||
Unregister_Object(resourceArray[i]);
|
||||
delete resourceArray[i];
|
||||
}
|
||||
}
|
||||
Unregister_Pointer(resourceArray);
|
||||
delete[] resourceArray;
|
||||
}
|
||||
|
||||
versionArray[0] = RESOURCE_FORMAT_VERSION;
|
||||
versionArray[1] = 0;
|
||||
versionArray[2] = 0;
|
||||
versionArray[3] = 0;
|
||||
labOnly = 0;
|
||||
resourceArraySize = 0;
|
||||
maxResourceID = ResourceDescription::NullResourceID;
|
||||
resourceArray = NULL;
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
// ResourceFile METHODS
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::AddResource(
|
||||
const char* name,
|
||||
ResourceDescription::ResourceType type,
|
||||
int priority,
|
||||
LWord load_flag,
|
||||
const void* address,
|
||||
size_t size,
|
||||
ResourceDescription::ResourceID index
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check_Pointer(name);
|
||||
|
||||
int i;
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// If we asked for the next available ID number, find out what it should be
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
if (index == ResourceDescription::NullResourceID)
|
||||
{
|
||||
index = lastPreallocatedResourceID + 1;
|
||||
if (resourceArray)
|
||||
{
|
||||
Check_Pointer(resourceArray);
|
||||
for (; index<=resourceArraySize; ++index)
|
||||
{
|
||||
if (!resourceArray[index])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------
|
||||
// Check to see if the resource index table needs to be created
|
||||
//-------------------------------------------------------------
|
||||
//
|
||||
if (!resourceArray)
|
||||
{
|
||||
resourceArraySize = index + IndexBlockSize;
|
||||
resourceArray = new ResourceDescription* [resourceArraySize];
|
||||
Register_Pointer(resourceArray);
|
||||
for (i=0; i<resourceArraySize; ++i)
|
||||
{
|
||||
resourceArray[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//-----------------------------------------------------------
|
||||
// Otherwise, check to see if we have to grow the index table
|
||||
//-----------------------------------------------------------
|
||||
//
|
||||
if (index >= resourceArraySize)
|
||||
{
|
||||
//
|
||||
//----------------------------------------
|
||||
// Allocate a new table for the main index
|
||||
//----------------------------------------
|
||||
//
|
||||
ResourceDescription **new_index =
|
||||
new ResourceDescription* [index + IndexBlockSize];
|
||||
Register_Pointer(new_index);
|
||||
|
||||
//
|
||||
//------------------------------------
|
||||
// Copy the old table into the new one
|
||||
//------------------------------------
|
||||
//
|
||||
Check_Pointer(resourceArray);
|
||||
for (i=0; i<resourceArraySize; ++i)
|
||||
{
|
||||
new_index[i] = resourceArray[i];
|
||||
}
|
||||
|
||||
//
|
||||
//---------------------
|
||||
// Delete the old table
|
||||
//---------------------
|
||||
//
|
||||
Unregister_Pointer(resourceArray);
|
||||
delete[] resourceArray;
|
||||
resourceArray = new_index;
|
||||
resourceArraySize = index + IndexBlockSize;
|
||||
|
||||
//
|
||||
//----------------------------------
|
||||
// NULL the new entries in the table
|
||||
//----------------------------------
|
||||
//
|
||||
while (i<resourceArraySize)
|
||||
{
|
||||
resourceArray[i++] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//-----------------------------------------------
|
||||
// Add the new resource in at the specified index
|
||||
//-----------------------------------------------
|
||||
//
|
||||
|
||||
Check_Pointer(resourceArray);
|
||||
Verify(!resourceArray[index]);
|
||||
if (index > maxResourceID)
|
||||
{
|
||||
maxResourceID = index;
|
||||
}
|
||||
resourceArray[index] =
|
||||
new ResourceDescription(
|
||||
this,
|
||||
name,
|
||||
type,
|
||||
priority,
|
||||
load_flag,
|
||||
address,
|
||||
size,
|
||||
index
|
||||
);
|
||||
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
// The caller of this function is responsible for registering the memory
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
Register_Object(resourceArray[index]);
|
||||
return resourceArray[index];
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::AddResourceList(
|
||||
const char* name,
|
||||
ResourceDescription::ResourceType type,
|
||||
int priority,
|
||||
LWord load_flag,
|
||||
const ResourceDescription::ResourceID* address,
|
||||
int count,
|
||||
ResourceDescription::ResourceID index
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check_Pointer(name);
|
||||
Check_Pointer(address);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------
|
||||
// prefix the directory table with the count of references
|
||||
//--------------------------------------------------------
|
||||
//
|
||||
ResourceDescription::ResourceID *table =
|
||||
new ResourceDescription::ResourceID[count+1];
|
||||
Register_Pointer(table);
|
||||
for (int i=0; i<count; ++i)
|
||||
{
|
||||
table[i+1] = address[i];
|
||||
}
|
||||
*table = count;
|
||||
|
||||
//
|
||||
//-------------------------------------------------
|
||||
// Go ahead and add the directory to the main index
|
||||
//-------------------------------------------------
|
||||
//
|
||||
ResourceDescription *directory =
|
||||
AddResource(
|
||||
name,
|
||||
type,
|
||||
priority,
|
||||
load_flag,
|
||||
table,
|
||||
(count+1) * sizeof(ResourceDescription::ResourceID),
|
||||
index
|
||||
);
|
||||
Unregister_Pointer(table);
|
||||
delete[] table;
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::AddResourceMemoryStream(
|
||||
const char* name,
|
||||
ResourceDescription::ResourceType type,
|
||||
int priority,
|
||||
LWord load_flag,
|
||||
MemoryStream* memory_stream,
|
||||
ResourceDescription::ResourceID index
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check(memory_stream);
|
||||
|
||||
size_t size = memory_stream->GetBytesUsed();
|
||||
memory_stream->Rewind();
|
||||
|
||||
return
|
||||
AddResource(
|
||||
name,
|
||||
type,
|
||||
priority,
|
||||
load_flag,
|
||||
memory_stream->GetPointer(),
|
||||
size,
|
||||
index
|
||||
);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ResourceFile::DeleteResource(ResourceDescription *resource)
|
||||
{
|
||||
Check(this);
|
||||
Check(resource);
|
||||
Check_Pointer(resourceArray);
|
||||
Verify(!resource->IsLocked());
|
||||
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// Delete pointer from resoureArray if it was there
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
if (resource->resourceID != ResourceDescription::NullResourceID )
|
||||
{
|
||||
resourceArray[resource->resourceID] = NULL;
|
||||
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// Find new maxResourceID
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
if (resource->resourceID == maxResourceID )
|
||||
{
|
||||
ResourceDescription::ResourceID i;
|
||||
for (i = maxResourceID; i>=0; i--)
|
||||
{
|
||||
if(resourceArray[i] != NULL)
|
||||
{
|
||||
Check(resourceArray[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
maxResourceID = i;
|
||||
}
|
||||
}
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// The caller of this function is responsible for unregistering the memory
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
delete resource;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::FindResourceDescription(ResourceDescription::ResourceID index)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
if (index<0 || index>maxResourceID || !resourceArray)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Check_Pointer(resourceArray);
|
||||
ResourceDescription *res = resourceArray[index];
|
||||
return res;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::FindResourceDescription(
|
||||
const char* name,
|
||||
ResourceDescription::ResourceType type,
|
||||
ResourceDescription::ResourceID after
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
ResourceDescription *desc;
|
||||
ResourceDescription::ResourceID i;
|
||||
for (i=after+1; i<=maxResourceID; ++i)
|
||||
{
|
||||
desc = FindResourceDescription(i);
|
||||
if (desc)
|
||||
{
|
||||
Check(desc);
|
||||
if (
|
||||
type == desc->resourceType &&
|
||||
(!name || !strcmp(name, desc->resourceName))
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i > maxResourceID)
|
||||
{
|
||||
desc = NULL;
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::SearchList(
|
||||
ResourceDescription::ResourceID list_id,
|
||||
ResourceDescription::ResourceType type
|
||||
)
|
||||
{
|
||||
ResourceDescription *list_res = FindResourceDescription(list_id);
|
||||
if (list_res)
|
||||
{
|
||||
Check(list_res);
|
||||
list_res->Lock();
|
||||
Verify(
|
||||
list_res->resourceType <= ResourceDescription::MaxListResourceType
|
||||
);
|
||||
ResourceDescription::ResourceID *list =
|
||||
(ResourceDescription::ResourceID*)list_res->resourceAddress;
|
||||
Check_Pointer(list);
|
||||
for (int i=1; i<=*list; ++i)
|
||||
{
|
||||
ResourceDescription *res = FindResourceDescription(list[i]);
|
||||
Check(res);
|
||||
if (res->resourceType == type)
|
||||
{
|
||||
list_res->Unlock();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
list_res->Unlock();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::SearchList(
|
||||
ResourceDescription::ResourceID list_id,
|
||||
const char* name
|
||||
)
|
||||
{
|
||||
Check_Pointer(name);
|
||||
ResourceDescription *list_res = FindResourceDescription(list_id);
|
||||
if (list_res)
|
||||
{
|
||||
Check(list_res);
|
||||
list_res->Lock();
|
||||
Verify(
|
||||
list_res->resourceType <= ResourceDescription::MaxListResourceType
|
||||
);
|
||||
ResourceDescription::ResourceID *list =
|
||||
(ResourceDescription::ResourceID*)list_res->resourceAddress;
|
||||
Check_Pointer(list);
|
||||
for (int i=1; i<=*list; ++i)
|
||||
{
|
||||
ResourceDescription *res = FindResourceDescription(list[i]);
|
||||
Check(res);
|
||||
if (!strcmp(name, res->resourceName))
|
||||
{
|
||||
list_res->Unlock();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
list_res->Unlock();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ResourceFile::ReleaseUnlockedResources()
|
||||
{
|
||||
for (ResourceDescription::ResourceID i = maxResourceID; i>=0; i--)
|
||||
{
|
||||
if(resourceArray[i] != NULL)
|
||||
{
|
||||
ResourceDescription *res = resourceArray[i];
|
||||
Check(res);
|
||||
res->ReleaseUnlockedResource();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
// ResourceFile Test Support
|
||||
//
|
||||
|
||||
Logical
|
||||
ResourceFile::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
//########################## StreamableResourceFile ######################
|
||||
//##############################################################################
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
StreamableResourceFile::StreamableResourceFile()
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
StreamableResourceFile::StreamableResourceFile(const char* file_name)
|
||||
{
|
||||
Open(file_name);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
StreamableResourceFile::StreamableResourceFile(const char* file_name, Byte version_array[3], int match_level)
|
||||
{
|
||||
Open(file_name);
|
||||
int i;
|
||||
for (i=0; i<match_level; ++i)
|
||||
if (version_array[i] != versionArray[i+1])
|
||||
break;
|
||||
|
||||
if (i < match_level)
|
||||
{
|
||||
DEBUG_STREAM << "\n\nError - Resource file " << file_name << " v" << (int)versionArray[0] << '.' << (int)versionArray[1] << '.' << (int)versionArray[2] << '.' << (int)versionArray[3] << " is obsolete!\n\n" << flush;
|
||||
Fail("Exiting");
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (release_only && labOnly)
|
||||
{
|
||||
DEBUG_STREAM << "\n\n\nERROR!\n\n"
|
||||
"This resource file was not properly released!\n\n";
|
||||
Fail("Exiting");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
StreamableResourceFile::~StreamableResourceFile()
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
int
|
||||
StreamableResourceFile::Open(const char *file_name)
|
||||
{
|
||||
Check(this);
|
||||
Str_Copy(resourceFilename, file_name, sizeof(resourceFilename));
|
||||
|
||||
diskFile.Open(resourceFilename);
|
||||
if (!diskFile.IsFileOpened())
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
//
|
||||
//-----------------------
|
||||
// Read in resource count
|
||||
//-----------------------
|
||||
//
|
||||
maxResourceID = 0;
|
||||
|
||||
diskFile.ReadBytes(&versionArray, sizeof(versionArray));
|
||||
|
||||
if (versionArray[0] != RESOURCE_FORMAT_VERSION)
|
||||
{
|
||||
DEBUG_STREAM << "\n\nError - Resource file " << file_name << " v"
|
||||
<< (int)versionArray[0] << '.' << (int)versionArray[1] << '.'
|
||||
<< (int)versionArray[2] << '.' << (int)versionArray[3]
|
||||
<< " is obsolete!\n\n" << flush;
|
||||
Fail("Exiting");
|
||||
}
|
||||
|
||||
diskFile >> labOnly >> maxResourceID;
|
||||
|
||||
//
|
||||
//------------------------------------------------------------------
|
||||
// Read in main index table first, and make room for expansion later
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
size_t *offset_table = new size_t[maxResourceID];
|
||||
Register_Pointer(offset_table);
|
||||
|
||||
diskFile.ReadBytes(offset_table, maxResourceID*sizeof(size_t));
|
||||
resourceArraySize = maxResourceID + IndexBlockSize;
|
||||
|
||||
resourceArray = new ResourceDescription*[resourceArraySize];
|
||||
Register_Pointer(resourceArray);
|
||||
int i;
|
||||
for (i=0; i<resourceArraySize; ++i)
|
||||
{
|
||||
resourceArray[i] = NULL;
|
||||
}
|
||||
--maxResourceID;
|
||||
|
||||
//
|
||||
//---------------------------------------------------------------------
|
||||
// Step through the index table, reading each description as we find it
|
||||
//---------------------------------------------------------------------
|
||||
//
|
||||
for (i=0; i<=maxResourceID; ++i)
|
||||
{
|
||||
//
|
||||
//--------------------------------------------
|
||||
// Make sure we skip empty resources correctly
|
||||
//--------------------------------------------
|
||||
//
|
||||
if (!offset_table[i])
|
||||
{
|
||||
resourceArray[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
//------------------------
|
||||
// Read in the description
|
||||
//------------------------
|
||||
//
|
||||
ResourcePhysicalFormat buffer;
|
||||
diskFile.SetPointer(offset_table[i]);
|
||||
diskFile >> buffer;
|
||||
|
||||
//
|
||||
//-------------------------------------------------
|
||||
// If the preload flag is set, read in the resource
|
||||
//-------------------------------------------------
|
||||
//
|
||||
|
||||
char *data = NULL;
|
||||
if (buffer.resourceFlags == ResourceDescription::Preload && buffer.resourceLength > 0)
|
||||
{
|
||||
data = new char[buffer.resourceLength];
|
||||
Register_Pointer(data);
|
||||
diskFile.SetPointer(buffer.resourceOffset);
|
||||
diskFile.ReadBytes(data, buffer.resourceLength);
|
||||
}
|
||||
if (buffer.resourceType > ResourceDescription::MaxListResourceType || !data)
|
||||
{
|
||||
resourceArray[i] = AddResource(
|
||||
buffer.resourceName,
|
||||
buffer.resourceType,
|
||||
buffer.downloadPriority,
|
||||
buffer.resourceFlags,
|
||||
data,
|
||||
buffer.resourceLength,
|
||||
buffer.resourceID
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceArray[i] = AddResourceList(
|
||||
buffer.resourceName,
|
||||
buffer.resourceType,
|
||||
buffer.downloadPriority,
|
||||
buffer.resourceFlags,
|
||||
(int*)data + 1,
|
||||
*(int*)data,
|
||||
buffer.resourceID
|
||||
);
|
||||
}
|
||||
resourceArray[i]->offsetInFile = buffer.resourceOffset;
|
||||
if (data)
|
||||
{
|
||||
resourceArray[i]->Lock();
|
||||
Unregister_Pointer(data);
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
|
||||
Unregister_Pointer(offset_table);
|
||||
delete[] offset_table;
|
||||
return True;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
int
|
||||
StreamableResourceFile::Save()
|
||||
{
|
||||
Check(this);
|
||||
if (!resourceArray)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
//
|
||||
//-----------------------------------------------------------------------
|
||||
// Make sure to load any unloaded resources before closing the input file
|
||||
//-----------------------------------------------------------------------
|
||||
//
|
||||
ResourceDescription *desc;
|
||||
ResourceDescription::ResourceID i;
|
||||
for (i=0; i<=maxResourceID; ++i)
|
||||
{
|
||||
desc = resourceArray[i];
|
||||
if (desc)
|
||||
{
|
||||
Check(desc);
|
||||
desc->LoadResource();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//-------------------------------------------
|
||||
// Close the current file, and open a new one
|
||||
//-------------------------------------------
|
||||
//
|
||||
if (diskFile.IsFileOpened())
|
||||
{
|
||||
diskFile.Close();
|
||||
}
|
||||
diskFile.Open(resourceFilename, True);
|
||||
Verify(diskFile.IsFileOpened());
|
||||
|
||||
//
|
||||
//-------------------------------------
|
||||
// Write out resource count and version
|
||||
//-------------------------------------
|
||||
//
|
||||
++maxResourceID;
|
||||
|
||||
diskFile.WriteBytes(&versionArray, sizeof(versionArray));
|
||||
diskFile << labOnly << maxResourceID;
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Write out main index table first. This is just filling up space, and the
|
||||
// offsets will have to be written back into this section later
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
size_t *offset_table = new size_t[maxResourceID];
|
||||
Register_Pointer(offset_table);
|
||||
diskFile.WriteBytes(offset_table, maxResourceID*sizeof(size_t));
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// Step through the index table, writing out each description as we find it
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
for (i=0; i<maxResourceID; ++i)
|
||||
{
|
||||
//
|
||||
//--------------------------------------------
|
||||
// Make sure we skip empty resources correctly
|
||||
//--------------------------------------------
|
||||
//
|
||||
desc = resourceArray[i];
|
||||
if (!desc)
|
||||
{
|
||||
offset_table[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
Check(desc);
|
||||
|
||||
//
|
||||
//-------------------
|
||||
// Write out the data
|
||||
//-------------------
|
||||
//
|
||||
ResourcePhysicalFormat buffer;
|
||||
buffer.resourceOffset = diskFile.GetIndex();
|
||||
diskFile.WriteBytes(desc->resourceAddress, desc->resourceSize);
|
||||
|
||||
//
|
||||
//--------------------------
|
||||
// Write out the description
|
||||
//--------------------------
|
||||
//
|
||||
offset_table[i] = diskFile.GetIndex();
|
||||
buffer.resourceID = desc->resourceID;
|
||||
buffer.resourceType = desc->resourceType;
|
||||
|
||||
//#if sizeof(buffer.resourceName) < sizeof(desc->resourceName)
|
||||
//# error ResourceDescription::resourceName is too big!
|
||||
//#endif
|
||||
|
||||
memcpy(
|
||||
buffer.resourceName,
|
||||
desc->resourceName,
|
||||
sizeof(desc->resourceName)
|
||||
);
|
||||
|
||||
buffer.resourceLength = desc->resourceSize;
|
||||
buffer.downloadPriority = desc->downloadPriority;
|
||||
buffer.resourceFlags =
|
||||
desc->resourceFlags & ~ResourceDescription::LoadedFlag;
|
||||
diskFile << buffer;
|
||||
}
|
||||
diskFile.SetPointer(
|
||||
sizeof(maxResourceID) + sizeof(versionArray) + sizeof(labOnly)
|
||||
);
|
||||
diskFile.WriteBytes(offset_table, maxResourceID*sizeof(long));
|
||||
Unregister_Pointer(offset_table);
|
||||
delete(offset_table);
|
||||
--maxResourceID;
|
||||
diskFile.Close();
|
||||
return True;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
int
|
||||
StreamableResourceFile::SaveAs(const char* file_name)
|
||||
{
|
||||
Str_Copy(resourceFilename, file_name, sizeof(resourceFilename));
|
||||
return Save();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
StreamableResourceFile::LoadResource(ResourceDescription *res)
|
||||
{
|
||||
ResourceFile::LoadResource(res);
|
||||
Verify(!res->resourceAddress);
|
||||
res->resourceAddress = new char[res->resourceSize];
|
||||
Register_Pointer(res->resourceAddress);
|
||||
diskFile.SetPointer(res->offsetInFile);
|
||||
diskFile.ReadBytes(res->resourceAddress, res->resourceSize);
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
// StreamableResourceFile Test Support
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
StreamableResourceFile::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
#if defined(TEST_CLASS)
|
||||
#include "resource.tcp"
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(SCNROLE_HPP)
|
||||
# include <scnrole.hpp>
|
||||
# endif
|
||||
# if !defined(APP_HPP)
|
||||
# include <app.hpp>
|
||||
# endif
|
||||
# if !defined(NOTATION_HPP)
|
||||
# include <notation.hpp>
|
||||
# endif
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ScenarioRole::ScenarioRole(const CString &role_name)
|
||||
{
|
||||
damageReceivedModifier = 0.0f;
|
||||
damageInflictedModifier = 0.0f;
|
||||
damageBias = 0.0f;
|
||||
friendlyFirePenalty = 0.0f;
|
||||
killBonus = 0.0f;
|
||||
roleName = role_name;
|
||||
returnFromDeath = 0;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ScenarioRole::ScenarioRole(const CString &role_name, const CString &model_file)
|
||||
{
|
||||
Check_Pointer(&role_name);
|
||||
Check_Pointer(&model_file);
|
||||
|
||||
roleName = role_name;
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Truncate the Role:: from roleName
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceFile
|
||||
*res = application->GetResourceFile();
|
||||
ResourceDescription
|
||||
*player_res_des;
|
||||
|
||||
player_res_des = res->FindResourceDescription(
|
||||
model_file,
|
||||
ResourceDescription::GameModelResourceType
|
||||
);
|
||||
|
||||
if (player_res_des)
|
||||
{
|
||||
player_res_des->Lock();
|
||||
ModelResource
|
||||
*player_data = (ModelResource *)player_res_des->
|
||||
resourceAddress;
|
||||
|
||||
killBonus = player_data->killBonus;
|
||||
returnFromDeath = player_data->returnFromDeath;
|
||||
damageReceivedModifier = player_data->damageReceivedModifier;
|
||||
damageInflictedModifier = player_data->damageInflictedModifier;
|
||||
damageBias = player_data->damageBias;
|
||||
friendlyFirePenalty = player_data->friendlyFirePenalty;
|
||||
player_res_des->Unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
Tell(role_name);
|
||||
Warn(" does not exists in resource! ");
|
||||
damageReceivedModifier = 0.0f;
|
||||
damageInflictedModifier = 0.0f;
|
||||
damageBias = 0.0f;
|
||||
friendlyFirePenalty = 0.0f;
|
||||
killBonus = 0.0f;
|
||||
returnFromDeath = 0;
|
||||
}
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Scalar
|
||||
ScenarioRole::CalcDamageReceivedScore(const Scalar &damage_received)
|
||||
{
|
||||
Check(this);
|
||||
// ]
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Calculate modified score for the player receiving damage
|
||||
// damageReceived * damageReceivedModifier
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Check(this);
|
||||
|
||||
Check_Fpu();
|
||||
return -(damage_received * GetDamageReceivedModifier());
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ScenarioRole::~ScenarioRole()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription::ResourceID
|
||||
ScenarioRole::CreateModelResource(
|
||||
#if DEBUG_LEVEL>0
|
||||
ResourceFile *resource_file,
|
||||
const char* model_name,
|
||||
NotationFile * model_file,
|
||||
const ResourceDirectories *directories,
|
||||
ModelResource *model
|
||||
#else
|
||||
ResourceFile *resource_file,
|
||||
const char* model_name,
|
||||
NotationFile * model_file,
|
||||
const ResourceDirectories *,
|
||||
ModelResource *model
|
||||
#endif
|
||||
)
|
||||
{
|
||||
Check(resource_file);
|
||||
Check_Pointer(model_name);
|
||||
Check_Pointer(directories);
|
||||
|
||||
//
|
||||
// If we were not provided a buffer to write the model data into, we must
|
||||
// create it ourselves. Then make sure that the model stuff is read in
|
||||
//
|
||||
ModelResource *local_model = model;
|
||||
if (!local_model)
|
||||
{
|
||||
local_model = new ModelResource;
|
||||
Register_Pointer(local_model);
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Read in the data from notation file
|
||||
//----------------------------------------
|
||||
//
|
||||
// Get PointValue assigned to this ScoreZone
|
||||
//
|
||||
|
||||
if(
|
||||
!model_file->GetEntry(
|
||||
"gamedata",
|
||||
"KillBonus",
|
||||
&local_model->killBonus
|
||||
)
|
||||
)
|
||||
{
|
||||
cerr << model_name << "Missing KillBonus" << endl;
|
||||
Dump_And_Die:
|
||||
if (!model)
|
||||
{
|
||||
Unregister_Pointer(local_model);
|
||||
delete local_model;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(
|
||||
!model_file->GetEntry(
|
||||
"gamedata",
|
||||
"DamageReceivedModifier",
|
||||
&local_model->damageReceivedModifier
|
||||
)
|
||||
)
|
||||
{
|
||||
cerr << model_name << "Missing DamageReceivedModifier" << endl;
|
||||
goto Dump_And_Die;
|
||||
}
|
||||
|
||||
if(
|
||||
!model_file->GetEntry(
|
||||
"gamedata",
|
||||
"DamageInflictedModifier",
|
||||
&local_model->damageInflictedModifier
|
||||
)
|
||||
)
|
||||
{
|
||||
cerr << model_name << "Missing DamageInflictedModifier" << endl;
|
||||
goto Dump_And_Die;
|
||||
}
|
||||
if(
|
||||
!model_file->GetEntry(
|
||||
"gamedata",
|
||||
"ReturnFromDeath",
|
||||
&local_model->returnFromDeath
|
||||
)
|
||||
)
|
||||
{
|
||||
cerr << model_name << "Missing ReturnFromDeath" << endl;
|
||||
goto Dump_And_Die;
|
||||
}
|
||||
if(
|
||||
!model_file->GetEntry(
|
||||
"gamedata",
|
||||
"DamageBias",
|
||||
&local_model->damageBias
|
||||
)
|
||||
)
|
||||
{
|
||||
cerr << model_name << "Missing DamageBias" << endl;
|
||||
goto Dump_And_Die;
|
||||
}
|
||||
|
||||
if(
|
||||
!model_file->GetEntry(
|
||||
"gamedata",
|
||||
"FriendlyFirePenalty",
|
||||
&local_model->friendlyFirePenalty
|
||||
)
|
||||
)
|
||||
{
|
||||
cerr << model_name << "Missing FriendlyFirePenalty" << endl;
|
||||
goto Dump_And_Die;
|
||||
}
|
||||
|
||||
|
||||
if (!model)
|
||||
{
|
||||
ResourceDescription *new_res =
|
||||
resource_file->AddResource(
|
||||
model_name,
|
||||
ResourceDescription::GameModelResourceType,
|
||||
1,
|
||||
ResourceDescription::Preload,
|
||||
local_model,
|
||||
sizeof(*local_model)
|
||||
);
|
||||
Unregister_Pointer(local_model);
|
||||
delete local_model;
|
||||
Check_Fpu();
|
||||
Check(new_res);
|
||||
return new_res->resourceID;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_Fpu();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
//===========================================================================//
|
||||
// File: stubs.cpp //
|
||||
// Project: MUNGA //
|
||||
// Contents: Optimized-build heap and exit stubs //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
|
||||
#include <munga.hpp>
|
||||
#pragma hdrstop
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void
|
||||
Exit(int exit_code)
|
||||
{
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
UserHeap::UserHeap(const char *, size_t)
|
||||
{
|
||||
}
|
||||
|
||||
UserHeap::~UserHeap()
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
UserHeap::Allocate(size_t size)
|
||||
{
|
||||
return new char[size];
|
||||
}
|
||||
|
||||
void
|
||||
UserHeap::Release(void *where)
|
||||
{
|
||||
delete[] (char *)where;
|
||||
}
|
||||
|
||||
void
|
||||
UserHeap::ReleaseAll()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(CONTROLS_HPP)
|
||||
# include <controls.hpp>
|
||||
# endif
|
||||
# if !defined(GAUGREND_HPP)
|
||||
# include <gaugrend.hpp>
|
||||
# endif
|
||||
|
||||
|
||||
#if defined(__BCPLUSPLUS__)
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
#if DEBUG_LEVEL>0
|
||||
int _matherr(struct exception *a)
|
||||
{
|
||||
switch (a->type)
|
||||
{
|
||||
case DOMAIN:
|
||||
DEBUG_STREAM << "Domain" << flush;
|
||||
break;
|
||||
case SING:
|
||||
DEBUG_STREAM << "Singularity" << flush;
|
||||
break;
|
||||
case UNDERFLOW:
|
||||
DEBUG_STREAM << "Underflow" << flush;
|
||||
break;
|
||||
case OVERFLOW:
|
||||
DEBUG_STREAM << "Overflow" << flush;
|
||||
break;
|
||||
case TLOSS:
|
||||
DEBUG_STREAM << "Loss of Precision" << flush;
|
||||
break;
|
||||
}
|
||||
DEBUG_STREAM << " error occurred in " << a->name << endl << flush;
|
||||
DEBUG_STREAM << "arg1 = " << a->arg1 << endl << flush;
|
||||
DEBUG_STREAM << "arg2 = " << a->arg2 << endl << flush;
|
||||
DEBUG_STREAM << "retval = " << a->retval << endl << flush << flush;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int _matherr(struct exception *)
|
||||
{
|
||||
_fpreset();
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" void _pure_error_()
|
||||
{
|
||||
Fail("Pure virtual function called");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// Fpu_Ok
|
||||
//
|
||||
// returns True if fpu has no errors, False if errors found
|
||||
//#############################################################################
|
||||
//
|
||||
int
|
||||
Fpu_Ok()
|
||||
{
|
||||
unsigned int s =
|
||||
_status87() &
|
||||
(
|
||||
SW_INVALID |
|
||||
// SW_DENORMAL |
|
||||
SW_ZERODIVIDE |
|
||||
SW_OVERFLOW
|
||||
// SW_UNDERFLOW |
|
||||
//VERIFY: SW_STACKFAULT
|
||||
);
|
||||
if (s)
|
||||
{
|
||||
DEBUG_STREAM << "ERROR: FPU status=" << flush;
|
||||
|
||||
if (s & SW_INVALID)
|
||||
{
|
||||
DEBUG_STREAM << "invalid " << flush;
|
||||
}
|
||||
if (s & SW_DENORMAL)
|
||||
{
|
||||
DEBUG_STREAM << "denormalized " << flush;
|
||||
}
|
||||
if (s & SW_ZERODIVIDE)
|
||||
{
|
||||
DEBUG_STREAM << "zeroDivide " << flush;
|
||||
}
|
||||
if (s & SW_OVERFLOW)
|
||||
{
|
||||
DEBUG_STREAM << "overflow " << flush;
|
||||
}
|
||||
if (s & SW_UNDERFLOW)
|
||||
{
|
||||
DEBUG_STREAM << "underflow " << flush;
|
||||
}
|
||||
/*if (s & SW_STACKFAULT)
|
||||
{
|
||||
DEBUG_STREAM << "stackFault" << flush;
|
||||
}*/
|
||||
DEBUG_STREAM << "\n" << flush << flush;
|
||||
return False;
|
||||
}
|
||||
else
|
||||
{
|
||||
return True;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
static Logical AlreadyFailed=False;
|
||||
|
||||
void Verify_Failed(char *Message, char *File, int Line)
|
||||
{
|
||||
if (!AlreadyFailed)
|
||||
{
|
||||
AlreadyFailed = True;
|
||||
|
||||
DEBUG_STREAM << File << "(" << Line << "): Failed " << Message << "\n" << flush;
|
||||
#if defined(USE_PROFILE_ANALYSIS)
|
||||
Analysis_Named_Status();
|
||||
#endif
|
||||
DEBUG_STREAM << "Failing to debugger\n" << flush << flush;
|
||||
SystemClock::timer.Shutdown();
|
||||
ControlsManager::Shutdown();
|
||||
GaugeRenderer::EmergencyShutdown();
|
||||
*(int*)(0xFFFFFFFF) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
Fail_To_Debugger(char *Message, char *File, int Line)
|
||||
{
|
||||
if (!AlreadyFailed)
|
||||
{
|
||||
AlreadyFailed = True;
|
||||
|
||||
DEBUG_STREAM << File << "(" << Line << "): " << Message << "\n" << flush;
|
||||
#if defined(USE_PROFILE_ANALYSIS)
|
||||
Analysis_Named_Status();
|
||||
#endif
|
||||
DEBUG_STREAM << "Failing to debugger\n" << flush << flush;
|
||||
SystemClock::timer.Shutdown();
|
||||
ControlsManager::Shutdown();
|
||||
GaugeRenderer::EmergencyShutdown();
|
||||
*(int*)(0xFFFFFFFF) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
#if defined(USE_SIGNATURE)
|
||||
Signature::Signature()
|
||||
{
|
||||
#if DEBUG_LEVEL>0
|
||||
mark = magic;
|
||||
#endif
|
||||
}
|
||||
|
||||
Signature::~Signature()
|
||||
{
|
||||
#if DEBUG_LEVEL>0
|
||||
mark = noMagic;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
Is_Signature_Bad(const volatile Signature *p)
|
||||
{
|
||||
#if DEBUG_LEVEL>0
|
||||
if (p->mark == Signature::magic)
|
||||
{
|
||||
return Signature::ok;
|
||||
}
|
||||
else if (p->mark == Signature::noMagic)
|
||||
{
|
||||
return Signature::destroyed;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Signature::corrupted;
|
||||
}
|
||||
#else
|
||||
return False;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user