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:
Cyd
2026-07-19 19:05:53 -05:00
co-authored by Claude Fable 5
parent 60d812484e
commit 5b35eb973c
35 changed files with 17798 additions and 164 deletions
File diff suppressed because it is too large Load Diff
+540
View File
@@ -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;
}
+3 -3
View File
@@ -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();
+4 -6
View File
@@ -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
+450
View File
@@ -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
+625
View File
@@ -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;
}
+832
View File
@@ -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;
}
//=============================================================================
+827
View File
@@ -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
+744
View File
@@ -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
+440 -44
View File
@@ -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
+176
View File
@@ -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
+916
View File
@@ -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
+243
View File
@@ -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;
}
}
+45
View File
@@ -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()
{
}
+204
View File
@@ -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