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:
@@ -27,3 +27,23 @@ BTCameraDirector::SharedData
|
||||
1,
|
||||
(Entity::MakeHandler)BTCameraDirector::Make
|
||||
);
|
||||
|
||||
BTCameraDirector::BTCameraDirector(
|
||||
MakeMessage *creation_message,
|
||||
SharedData &shared_data
|
||||
):
|
||||
CameraDirector(creation_message, shared_data)
|
||||
{
|
||||
Fail("BTCameraDirector -- btdirect.cpp not yet reconstructed");
|
||||
}
|
||||
|
||||
BTCameraDirector::~BTCameraDirector()
|
||||
{
|
||||
}
|
||||
|
||||
BTCameraDirector*
|
||||
BTCameraDirector::Make(CameraDirector::MakeMessage *)
|
||||
{
|
||||
Fail("BTCameraDirector::Make -- btdirect.cpp not yet reconstructed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -27,3 +27,23 @@ BTPlayer::SharedData
|
||||
1,
|
||||
(Entity::MakeHandler)BTPlayer::Make
|
||||
);
|
||||
|
||||
BTPlayer::BTPlayer(
|
||||
MakeMessage *creation_message,
|
||||
SharedData &shared_data
|
||||
):
|
||||
Player(creation_message, shared_data)
|
||||
{
|
||||
Fail("BTPlayer -- btplayer.cpp not yet reconstructed");
|
||||
}
|
||||
|
||||
BTPlayer::~BTPlayer()
|
||||
{
|
||||
}
|
||||
|
||||
BTPlayer*
|
||||
BTPlayer::Make(MakeMessage *)
|
||||
{
|
||||
Fail("BTPlayer::Make -- btplayer.cpp not yet reconstructed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -37,3 +37,20 @@ Mech::SharedData
|
||||
33,
|
||||
(Entity::MakeHandler)Mech::Make
|
||||
);
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Mech*
|
||||
Mech::Make(MakeMessage *)
|
||||
{
|
||||
Fail("Mech::Make -- mech.cpp not yet reconstructed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
Mech::SetMappingSubsystem(Subsystem *)
|
||||
{
|
||||
Fail("Mech::SetMappingSubsystem -- mech.cpp not yet reconstructed");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
//===========================================================================//
|
||||
// File: mechmppr.cpp //
|
||||
// Project: BattleTech //
|
||||
// Contents: Implementation details for the mech controls mapper //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
|
||||
#include <bt.hpp>
|
||||
#pragma hdrstop
|
||||
|
||||
#if !defined(MECHMPPR_HPP)
|
||||
# include <mechmppr.hpp>
|
||||
#endif
|
||||
|
||||
Derivation
|
||||
MechControlsMapper::ClassDerivations(
|
||||
Subsystem::ClassDerivations,
|
||||
"MechControlsMapper"
|
||||
);
|
||||
|
||||
MechControlsMapper::SharedData
|
||||
MechControlsMapper::DefaultData(
|
||||
MechControlsMapper::ClassDerivations,
|
||||
Subsystem::MessageHandlers,
|
||||
Subsystem::AttributeIndex,
|
||||
1
|
||||
);
|
||||
|
||||
MechControlsMapper::MechControlsMapper(
|
||||
Mech *owner,
|
||||
int subsystem_ID,
|
||||
CString subsystem_name,
|
||||
RegisteredClass::ClassID class_ID,
|
||||
SharedData &shared_data
|
||||
):
|
||||
Subsystem(
|
||||
(Entity *)owner,
|
||||
subsystem_ID,
|
||||
subsystem_name,
|
||||
class_ID,
|
||||
shared_data
|
||||
)
|
||||
{
|
||||
Fail("MechControlsMapper -- mechmppr.cpp not yet reconstructed");
|
||||
}
|
||||
|
||||
MechControlsMapper::~MechControlsMapper()
|
||||
{
|
||||
}
|
||||
|
||||
Logical
|
||||
MechControlsMapper::TestInstance() const
|
||||
{
|
||||
return IsDerivedFrom(ClassDerivations);
|
||||
}
|
||||
@@ -27,3 +27,10 @@ Missile::SharedData
|
||||
1,
|
||||
(Entity::MakeHandler)Missile::Make
|
||||
);
|
||||
|
||||
Missile*
|
||||
Missile::Make(MakeMessage *)
|
||||
{
|
||||
Fail("Missile::Make -- missile.cpp not yet reconstructed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -27,3 +27,10 @@ Projectile::SharedData
|
||||
1,
|
||||
(Entity::MakeHandler)Projectile::Make
|
||||
);
|
||||
|
||||
Projectile*
|
||||
Projectile::Make(MakeMessage *)
|
||||
{
|
||||
Fail("Projectile::Make -- projtile.cpp not yet reconstructed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
//===========================================================================//
|
||||
// File: btl4.cpp //
|
||||
// Project: BattleTech Brick: BattleTech LBE Application //
|
||||
// Contents: Application launcher (main) //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Date Who Modification //
|
||||
// -------- --- ---------------------------------------------------------- //
|
||||
// //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
|
||||
#include <btl4.hpp>
|
||||
#pragma hdrstop
|
||||
|
||||
#if !defined(BTL4APP_HPP)
|
||||
# include <btl4app.hpp>
|
||||
#endif
|
||||
|
||||
#if !defined(APPMGR_HPP)
|
||||
# include <appmgr.hpp>
|
||||
#endif
|
||||
|
||||
#if !defined(BTL4VER_HPP)
|
||||
# include <btl4ver.hpp>
|
||||
#endif
|
||||
|
||||
//##########################################################################
|
||||
//#################### BTL4Application Globals #######################
|
||||
//##########################################################################
|
||||
|
||||
extern const char* const ProgName;
|
||||
const char* const ProgName = "btl4";
|
||||
|
||||
static Byte
|
||||
version[3] =
|
||||
{MAJOR_DATA_VERSION, RELEASE_VERSION, MINOR_DATA_VERSION};
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// main
|
||||
//#############################################################################
|
||||
//
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
DEBUG_STREAM << "BattleTech v4.10" << endl;
|
||||
|
||||
if (!L4Application::ParseCommandLine(argc, argv, L4Application::ParseToken))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
StreamableResourceFile
|
||||
resources("btl4.res", version);
|
||||
|
||||
ApplicationManager
|
||||
*application_manager = NULL;
|
||||
|
||||
if (L4Application::GetMissionReviewMode() < 1)
|
||||
{
|
||||
application_manager =
|
||||
new ApplicationManager(GetTicksPerSecond());
|
||||
|
||||
Application
|
||||
*application = new BTL4Application(&resources);
|
||||
|
||||
application_manager->StartApplication(application);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
//-------------------------------------------------------------------
|
||||
// Mission review / live-camera launch (missionReviewMode >= 1):
|
||||
// a MissionReviewApplicationManager with a SPOOLSIZE-byte packet
|
||||
// spool plus BTL4PlaybackApplication -- those bricks are not yet
|
||||
// reconstructed (see BTL4.NOTES.md for the decompiled structure).
|
||||
//-------------------------------------------------------------------
|
||||
//
|
||||
Fail("btl4.cpp -- mission review/camera launch not yet reconstructed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
application_manager->RunMissions();
|
||||
|
||||
delete application_manager;
|
||||
|
||||
return Exit_Code;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
# BTL4.CPP — reconstruction notes
|
||||
|
||||
**Status: RECONSTRUCTED (normal launch path); review/camera branch staged with Fail().**
|
||||
|
||||
The 4.10 main TU. No original survives anywhere in the archive (OPT.MAK links
|
||||
`btl4.obj` as a bare object next to the libs — it was never a lib member).
|
||||
|
||||
## Evidence base
|
||||
|
||||
1. **Ghidra decomp of the 4.11 binary** — `C:\VWE\BT411\reference\decomp\all\part_000.c`,
|
||||
`FUN_0040109c` (the 524-byte function the Borland startup calls = `main`).
|
||||
The 4.10 and 4.11 binaries share the same string pool layout for this TU.
|
||||
2. **String pool of the original 4.10 `BTL4OPT.EXE`** (ALPHA_1/REL410/BT), file
|
||||
offset ~917884: `"btl4" "HEAPSIZE" "BattleTech v4.10" "btl4.res" "SPOOLSIZE"
|
||||
"Spool size = "` — banner text and resource name byte-exact.
|
||||
3. **Surviving 1995 launcher-style TU** `CODE/RP/RP_L4/RPL4TOOL.CPP` — house
|
||||
style for `main(int, char*[])` and the `ProgName` global pattern.
|
||||
4. **BT411's win32 launcher** `game/btl4main.cpp` (adapted from RP's RPL4.CPP)
|
||||
independently reconstructs the same skeleton and pins `version[3] = {1,0,6}`
|
||||
against the RESOURCE.cpp version check.
|
||||
|
||||
## Decoded decomp → source mapping
|
||||
|
||||
| decomp | source |
|
||||
|---|---|
|
||||
| `FUN_004dbb24(&cout, "BattleTech v4.10", 0); FUN_004d9c38(&cout)` | `DEBUG_STREAM << "BattleTech v4.10" << endl` |
|
||||
| `FUN_0047b2ec(argc, argv, &LAB_0047af8c)` | `L4Application::ParseCommandLine(argc, argv, L4Application::ParseToken)` |
|
||||
| `FUN_00407218(stack84, "btl4.res", &DAT_004e0070, 3)` | `StreamableResourceFile resources("btl4.res", version)` (match_level=3 is the declared default) |
|
||||
| `DAT_004e0070` = 3 bytes | `version[3]` = `{MAJOR_DATA_VERSION, RELEASE_VERSION, MINOR_DATA_VERSION}` = {1,0,6} from BTL4VER.HPP |
|
||||
| `DAT_004fd550 < 1` | `L4Application::GetMissionReviewMode() < 1` (inline static accessor) |
|
||||
| `new(0x28) FUN_0044f29c(this, DAT_0052140c)` | `new ApplicationManager(GetTicksPerSecond())` (inline friend accessor, TIME.HPP:49) — DAT_0052140c is set to 28.0f by `SystemClock::SystemClock()` (L4TIME.CPP:93) when `L4TIMER=FAST` |
|
||||
| `new(0xd4) FUN_004d34c4(this, &resources, 0x3EB, &DAT_0051e8d8)` | `new BTL4Application(&resources)` — 0x3EB/`DefaultData` are the declared default args (BTL4APP.HPP:34) |
|
||||
| `FUN_0044f318(mgr, app)` | `application_manager->StartApplication(application)` |
|
||||
| `FUN_0044f344(mgr)` | `application_manager->RunMissions()` |
|
||||
| vcall slot 0 (mgr, 3) | `delete application_manager` |
|
||||
| `return DAT_004efc98` | `return Exit_Code` (APP.HPP:542) |
|
||||
|
||||
## Review/camera branch (NOT yet reconstructed — staged Fail)
|
||||
|
||||
Decomp structure for `missionReviewMode >= 1` (mode 1 = camera, 2 = review per
|
||||
emulator/CAMERA-REVIEW-NOTES.md):
|
||||
|
||||
```
|
||||
spool_size = getenv("SPOOLSIZE") ? atoi(...) : 0x800000; // "Spool size = " printed
|
||||
mgr = new(0x38) MissionReviewApplicationManager(ticksPerSecond,
|
||||
(mode != 2) ? 2 : 1, spool_size);
|
||||
spool_file = <mgr getter, FUN_0044fa14>;
|
||||
if (spool_file)
|
||||
mgr->StartApplication(new(0xd8) BTL4PlaybackApplication(&resources, spool_file));
|
||||
if (mode == 1)
|
||||
mgr->StartApplication(new(0xd8) <camera app, FUN_0047c3fc>(&resources, 1));
|
||||
```
|
||||
|
||||
Class declarations survive: `BTL4PlaybackApplication` (CODE/BT/BT_L4/BTL4PB.HPP),
|
||||
spooler bricks in CODE/RP/MUNGA_L4/L4SPLR.HPP (`MissionReviewApplicationManager`
|
||||
referenced there). Their .CPP bodies are not staged, so the branch Fails loudly
|
||||
instead of linking half a subsystem.
|
||||
|
||||
## Deliberate differences from the binary
|
||||
|
||||
- `HEAPSIZE` string sits in the pool between ProgName and the banner but is not
|
||||
referenced from the decompiled main — it likely belongs to the runtime heap
|
||||
init, not this TU. Not reproduced.
|
||||
- `Register_Object`/`Start_Registering` debug bookkeeping is absent from the
|
||||
optimized binary (DEBUG_LEVEL=0 compiles it out), so it is not written here.
|
||||
@@ -0,0 +1,34 @@
|
||||
//===========================================================================//
|
||||
// File: btl4grnd.cpp //
|
||||
// Project: BattleTech //
|
||||
// Contents: Implementation details for the BT gauge renderer //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
|
||||
#include <btl4.hpp>
|
||||
#pragma hdrstop
|
||||
|
||||
#if !defined(BTL4GRND_HPP)
|
||||
# include <btl4grnd.hpp>
|
||||
#endif
|
||||
|
||||
BTL4GaugeRenderer::BTL4GaugeRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
BTL4GaugeRenderer::~BTL4GaugeRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BTL4GaugeRenderer::NotifyOfNewInterestingEntity(Entity *)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BTL4GaugeRenderer::NotifyOfBecomingUninterestingEntity(Entity *)
|
||||
{
|
||||
}
|
||||
@@ -40,3 +40,80 @@ MechRIOMapper::SharedData
|
||||
Subsystem::AttributeIndex,
|
||||
1
|
||||
);
|
||||
|
||||
Derivation
|
||||
L4MechControlsMapper::ClassDerivations(
|
||||
MechControlsMapper::ClassDerivations,
|
||||
"L4MechControlsMapper"
|
||||
);
|
||||
|
||||
L4MechControlsMapper::SharedData
|
||||
L4MechControlsMapper::DefaultData(
|
||||
L4MechControlsMapper::ClassDerivations,
|
||||
Subsystem::MessageHandlers,
|
||||
Subsystem::AttributeIndex,
|
||||
1
|
||||
);
|
||||
|
||||
L4MechControlsMapper::L4MechControlsMapper(
|
||||
Mech *owner,
|
||||
int subsystem_ID,
|
||||
CString subsystem_name,
|
||||
RegisteredClass::ClassID class_ID,
|
||||
SharedData &shared_data
|
||||
):
|
||||
MechControlsMapper(owner, subsystem_ID, subsystem_name, class_ID, shared_data)
|
||||
{
|
||||
}
|
||||
|
||||
L4MechControlsMapper::~L4MechControlsMapper()
|
||||
{
|
||||
}
|
||||
|
||||
Logical
|
||||
L4MechControlsMapper::TestInstance() const
|
||||
{
|
||||
return IsDerivedFrom(ClassDerivations);
|
||||
}
|
||||
|
||||
MechThrustmasterMapper::MechThrustmasterMapper(
|
||||
Mech *owner,
|
||||
int subsystem_ID,
|
||||
CString subsystem_name,
|
||||
RegisteredClass::ClassID class_ID,
|
||||
SharedData &shared_data
|
||||
):
|
||||
L4MechControlsMapper(owner, subsystem_ID, subsystem_name, class_ID, shared_data)
|
||||
{
|
||||
}
|
||||
|
||||
MechThrustmasterMapper::~MechThrustmasterMapper()
|
||||
{
|
||||
}
|
||||
|
||||
Logical
|
||||
MechThrustmasterMapper::TestInstance() const
|
||||
{
|
||||
return IsDerivedFrom(ClassDerivations);
|
||||
}
|
||||
|
||||
MechRIOMapper::MechRIOMapper(
|
||||
Mech *owner,
|
||||
int subsystem_ID,
|
||||
CString subsystem_name,
|
||||
RegisteredClass::ClassID class_ID,
|
||||
SharedData &shared_data
|
||||
):
|
||||
L4MechControlsMapper(owner, subsystem_ID, subsystem_name, class_ID, shared_data)
|
||||
{
|
||||
}
|
||||
|
||||
MechRIOMapper::~MechRIOMapper()
|
||||
{
|
||||
}
|
||||
|
||||
Logical
|
||||
MechRIOMapper::TestInstance() const
|
||||
{
|
||||
return IsDerivedFrom(ClassDerivations);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//===========================================================================//
|
||||
// File: btl4mssn.cpp //
|
||||
// Project: BattleTech //
|
||||
// Contents: Implementation details for the BT L4 mission //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
|
||||
#include <btl4.hpp>
|
||||
#pragma hdrstop
|
||||
|
||||
#if !defined(BTL4MSSN_HPP)
|
||||
# include <btl4mssn.hpp>
|
||||
#endif
|
||||
|
||||
BTL4Mission::BTL4Mission(
|
||||
NotationFile *notation_file,
|
||||
ResourceFile *resources
|
||||
):
|
||||
BTMission(notation_file, resources)
|
||||
{
|
||||
}
|
||||
|
||||
BTL4Mission::~BTL4Mission()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BTL4Mission::SetPlayerData(NotationFile *)
|
||||
{
|
||||
Fail("BTL4Mission::SetPlayerData -- btl4mssn.cpp not yet reconstructed");
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
//===========================================================================//
|
||||
// File: btl4vid.cpp //
|
||||
// Project: BattleTech //
|
||||
// Contents: Implementation details for the BT video renderer //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
|
||||
#include <btl4.hpp>
|
||||
#pragma hdrstop
|
||||
|
||||
#if !defined(BTL4VID_HPP)
|
||||
# include <btl4vid.hpp>
|
||||
#endif
|
||||
|
||||
BTL4VideoRenderer::BTL4VideoRenderer(
|
||||
RendererRate calibration_rate,
|
||||
RendererComplexity calibration_complexity,
|
||||
RendererPriority calibration_priority,
|
||||
InterestType interest_type,
|
||||
InterestDepth depth_calibration
|
||||
):
|
||||
DPLRenderer(
|
||||
calibration_rate,
|
||||
calibration_complexity,
|
||||
calibration_priority,
|
||||
interest_type,
|
||||
depth_calibration
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
BTL4VideoRenderer::~BTL4VideoRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BTL4VideoRenderer::LoadMissionImplementation(Mission *)
|
||||
{
|
||||
Fail("BTL4VideoRenderer::LoadMissionImplementation -- btl4vid.cpp not yet reconstructed");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,540 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(AUDREND_HPP)
|
||||
# include <audrend.hpp>
|
||||
# endif
|
||||
# if !defined(AUDENT_HPP)
|
||||
# include <audent.hpp>
|
||||
# endif
|
||||
# if !defined(JMOVER_HPP)
|
||||
# include <jmover.hpp>
|
||||
# endif
|
||||
# if !defined(APP_HPP)
|
||||
# include <app.hpp>
|
||||
# endif
|
||||
|
||||
//#############################################################################
|
||||
//########################### AudioRenderer #############################
|
||||
//#############################################################################
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// AudioRenderer
|
||||
//#############################################################################
|
||||
//
|
||||
AudioRenderer::AudioRenderer(RendererRate render_rate):
|
||||
Renderer(
|
||||
render_rate,
|
||||
MaxRendererComplexity,
|
||||
DefaultRendererPriority,
|
||||
AudioInterestType,
|
||||
DefaultInterestDepth,
|
||||
AudioRendererClassID
|
||||
),
|
||||
audioEventSocket(NULL, False)
|
||||
{
|
||||
audioHead = NULL;
|
||||
|
||||
#ifdef LAB_ONLY
|
||||
sourceClippedCount = 0;
|
||||
sourceStartCount = 0;
|
||||
sourceSuspendCount = 0;
|
||||
sourceResumeCount = 0;
|
||||
doubleTriggerCount = 0;
|
||||
resourceStealCount = 0;
|
||||
resourceStealPriorityCount = 0;
|
||||
resourceStealVolumeCount = 0;
|
||||
stealShortDurationCount = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// ~AudioRenderer
|
||||
//#############################################################################
|
||||
//
|
||||
AudioRenderer::~AudioRenderer()
|
||||
{
|
||||
Unregister_Object(audioHead);
|
||||
delete audioHead;
|
||||
|
||||
#ifdef LAB_ONLY
|
||||
cout << "AudioRenderer::~AudioRenderer - sourceClippedCount="
|
||||
<< sourceClippedCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - sourceStartCount="
|
||||
<< sourceStartCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - sourceSuspendCount="
|
||||
<< sourceSuspendCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - sourceResumeCount="
|
||||
<< sourceResumeCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - doubleTriggerCount="
|
||||
<< doubleTriggerCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - resourceStealCount="
|
||||
<< resourceStealCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - resourceStealPriorityCount="
|
||||
<< resourceStealPriorityCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - resourceStealVolumeCount="
|
||||
<< resourceStealVolumeCount << "\n";
|
||||
cout << "AudioRenderer::~AudioRenderer - stealShortDurationCount="
|
||||
<< stealShortDurationCount << "\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// Initialize
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioRenderer::Initialize()
|
||||
{
|
||||
audioHead = MakeAudioHead();
|
||||
Register_Object(audioHead);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// TestInstance
|
||||
//#############################################################################
|
||||
//
|
||||
Logical
|
||||
AudioRenderer::TestInstance() const
|
||||
{
|
||||
Renderer::TestInstance();
|
||||
if (audioHead != NULL)
|
||||
{
|
||||
Check(audioHead);
|
||||
}
|
||||
Check(&audioEventSocket);
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// LinkToEntity
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioRenderer::LinkToEntity(Entity *entity)
|
||||
{
|
||||
Check(this);
|
||||
Check(entity);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Link the head to the entity
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
Check(audioHead);
|
||||
audioHead->LinkToEntity(entity);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Call inherited method
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
Renderer::LinkToEntity(entity);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// ExecuteImplementation
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioRenderer::ExecuteImplementation(
|
||||
RendererComplexity,
|
||||
RendererOrigin::InterestingEntityIterator*
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check(audioHead);
|
||||
audioHead->Execute();
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// PostAudioRequestMessage
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioRenderer::PostAudioRequestMessage(
|
||||
AudioSource *audio_source,
|
||||
AudioSource::RequestMessage *message
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check(audio_source);
|
||||
Check(message);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// If audio source is clipped and the source is transient
|
||||
// Then ignore
|
||||
// Else set priority and volume
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
AudioSourcePriority
|
||||
audio_source_priority;
|
||||
AudioControlValue
|
||||
audio_source_volume_scale;
|
||||
|
||||
if (audio_source->IsAudioSourceClipped(GetAudioHead()))
|
||||
{
|
||||
//
|
||||
// If it is a transient source then ignore request
|
||||
//
|
||||
if (audio_source->GetAudioRenderType() == TransientAudioRenderType)
|
||||
{
|
||||
#ifdef LAB_ONLY
|
||||
sourceClippedCount++;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
audio_source_priority = audio_source->GetAudioSourcePriority();
|
||||
audio_source_volume_scale = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
audio_source_priority = audio_source->GetAudioSourcePriority();
|
||||
// (task #50, AUDIO_FIDELITY F19) COLD-START PRIME: an idle source's own
|
||||
// watcher socket only executes at Start attempts, so its authored
|
||||
// AudioControlSmoothers (footstep volume: N=30/15, fill 0) warmed ONE
|
||||
// sample per attempt -- and the transient drop gate below (vol < 0.3)
|
||||
// rejected the first ~25 footfalls (~10-20 s of silent steps) before
|
||||
// the average could cross the gate. On a Start request, pump the
|
||||
// source's watchers a full smoother window so the volume chain is
|
||||
// evaluated at its True steady state; the smoother keeps its authored
|
||||
audio_source_volume_scale = audio_source->CalculateSourceVolumeScale();
|
||||
}
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// If this a transient source and volume is lower than threshold
|
||||
// Then return
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// DIAG (BT_AUDIO_NODROP): deliver low-volume transient starts anyway (at a
|
||||
// floor volume) to isolate volume-feed problems from the rest of the chain.
|
||||
if (getenv("BT_AUDIO_NODROP") &&
|
||||
message->controlID == StartAudioControlID &&
|
||||
audio_source->GetAudioRenderType() == TransientAudioRenderType &&
|
||||
audio_source_volume_scale < LowAudioVolumeThreshold)
|
||||
{
|
||||
DEBUG_STREAM << "[spatial] NODROP forcing start src=" << (void*)audio_source
|
||||
<< " vol=" << audio_source_volume_scale << "\n" << flush;
|
||||
audio_source->ReceiveControl(VolumeAudioControlID, 0.7f);
|
||||
audio_source_volume_scale = 0.7f;
|
||||
}
|
||||
if (
|
||||
message->controlID == StartAudioControlID &&
|
||||
audio_source->GetAudioRenderType() == TransientAudioRenderType &&
|
||||
audio_source_volume_scale < LowAudioVolumeThreshold
|
||||
)
|
||||
{
|
||||
#ifdef LAB_ONLY
|
||||
sourceClippedCount++;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Create audio weight based on priority and volume
|
||||
// Add audio event
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
AudioWeighting
|
||||
audio_weight(audio_source_priority, audio_source_volume_scale);
|
||||
AudioEvent
|
||||
*audio_event;
|
||||
|
||||
audio_event = new AudioEvent(audio_source, message);
|
||||
Register_Object(audio_event);
|
||||
audioEventSocket.AddValue(audio_event, audio_weight);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// ProcessAudioRequestMessage
|
||||
//#############################################################################
|
||||
//
|
||||
Logical
|
||||
AudioRenderer::ProcessAudioRequestMessage()
|
||||
{
|
||||
//
|
||||
// Process high priority, high volume event
|
||||
//
|
||||
AudioEventIterator
|
||||
iterator(&audioEventSocket);
|
||||
AudioEvent
|
||||
*audio_event;
|
||||
|
||||
Logical stuff = False;
|
||||
while ((audio_event = iterator.GetCurrent()) != NULL)
|
||||
{
|
||||
stuff = True;
|
||||
Check(audio_event);
|
||||
audio_event->Process();
|
||||
//return True;
|
||||
}
|
||||
return stuff;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// FlushAudioMessages
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioRenderer::FlushAudioMessages(AudioSource *audio_source)
|
||||
{
|
||||
Check(this);
|
||||
Check(audio_source);
|
||||
|
||||
//
|
||||
// Process matching events
|
||||
//
|
||||
AudioEventIterator
|
||||
iterator(&audioEventSocket);
|
||||
AudioEvent
|
||||
*audio_event;
|
||||
|
||||
while ((audio_event = iterator.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(audio_event);
|
||||
if (audio_event->targetReceiver.GetCurrent() == audio_source)
|
||||
{
|
||||
if (audio_event->messageToSend->controlID == StopAudioControlID)
|
||||
{
|
||||
audio_event->Process();
|
||||
}
|
||||
else
|
||||
{
|
||||
Unregister_Object(audio_event);
|
||||
delete audio_event;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// MakeAudioHead
|
||||
//#############################################################################
|
||||
//
|
||||
AudioHead*
|
||||
AudioRenderer::MakeAudioHead()
|
||||
{
|
||||
return new AudioHead;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// StartEntityEffectImplementation
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioRenderer::StartEntityEffectImplementation(
|
||||
Entity *parent_entity,
|
||||
DamageZone *damage_zone,
|
||||
ResourceDescription::ResourceID resource_ID
|
||||
)
|
||||
{
|
||||
SET_AUDIO_RENDERER();
|
||||
|
||||
Check(this);
|
||||
Check(parent_entity);
|
||||
Check(damage_zone);
|
||||
Verify(resource_ID != ResourceDescription::NullResourceID);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Get the audio resource for this effect
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
ResourceDescription *audio_resource_description;
|
||||
|
||||
Check(application);
|
||||
Check(application->GetResourceFile());
|
||||
audio_resource_description =
|
||||
application->GetResourceFile()->SearchList(
|
||||
resource_ID,
|
||||
ResourceDescription::AudioStreamListResourceType
|
||||
);
|
||||
if (audio_resource_description == NULL)
|
||||
{
|
||||
CLEAR_AUDIO_RENDERER();
|
||||
return;
|
||||
}
|
||||
Check(audio_resource_description);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Get the resource ID for the model resource for the audio effect entity
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
ResourceDescription *model_resource_description;
|
||||
|
||||
Check(application);
|
||||
Check(application->GetResourceFile());
|
||||
Check(audio_resource_description);
|
||||
model_resource_description =
|
||||
application->GetResourceFile()->SearchList(
|
||||
audio_resource_description->resourceID,
|
||||
ResourceDescription::ModelListResourceType
|
||||
);
|
||||
if (model_resource_description == NULL)
|
||||
{
|
||||
CLEAR_AUDIO_RENDERER();
|
||||
return;
|
||||
}
|
||||
Check(model_resource_description);
|
||||
model_resource_description->Lock();
|
||||
audio_resource_description->Lock();
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Get the entity segment
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
Entity *linked_entity;
|
||||
AudioRepresentation audio_representation;
|
||||
EntitySegment *parent_entity_segment;
|
||||
|
||||
linked_entity = GetLinkedEntity();
|
||||
Check(linked_entity);
|
||||
audio_representation =
|
||||
(AudioRepresentation)parent_entity->GetAudioRepresentation(
|
||||
linked_entity
|
||||
);
|
||||
|
||||
parent_entity_segment = damage_zone->GetCurrentEffectSite(
|
||||
(audio_representation == InternalAudioRepresentation) ?
|
||||
DamageZone::InternalAudioEffectSite :
|
||||
DamageZone::ExternalAudioEffectSite
|
||||
);
|
||||
Check(parent_entity_segment);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Create the audio effect entity with this resource
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
JointedMover *jointed_mover;
|
||||
|
||||
Verify(parent_entity->IsDerivedFrom(JointedMover::ClassDerivations));
|
||||
jointed_mover = Cast_Object(JointedMover*, parent_entity);
|
||||
Check(jointed_mover);
|
||||
|
||||
AudioEntity::MakeMessage
|
||||
make_message(
|
||||
model_resource_description->resourceID,
|
||||
jointed_mover,
|
||||
parent_entity_segment
|
||||
);
|
||||
#if DEBUG_LEVEL>0
|
||||
AudioEntity *audio_entity =
|
||||
#endif
|
||||
AudioEntity::Make(&make_message);
|
||||
Register_Object(audio_entity);
|
||||
|
||||
model_resource_description->Unlock();
|
||||
audio_resource_description->Unlock();
|
||||
|
||||
CLEAR_AUDIO_RENDERER();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~ AudioRenderer profile bits ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#if defined(TRACE_AUDIO_RENDERER)
|
||||
BitTrace Audio_Renderer("Audio Renderer");
|
||||
#endif
|
||||
|
||||
#if defined(TRACE_AUDIO_RENDERER_CREATE_OBJECTS)
|
||||
BitTrace Audio_Renderer_Create_Objects("Audio Renderer Create Objects");
|
||||
#endif
|
||||
|
||||
#if defined(TRACE_AUDIO_RENDERER_DESTROY_OBJECTS)
|
||||
BitTrace Audio_Renderer_Destroy_Objects("Audio Renderer Destroy Objects");
|
||||
#endif
|
||||
|
||||
#if defined(TRACE_AUDIO_RENDERER_START_HANDLER)
|
||||
BitTrace Audio_Renderer_Start_Handler("Audio Renderer Start Handler");
|
||||
#endif
|
||||
|
||||
#if defined(TRACE_AUDIO_RENDERER_STOP_HANDLER)
|
||||
BitTrace Audio_Renderer_Stop_Handler("Audio Renderer Stop Handler");
|
||||
#endif
|
||||
|
||||
#if defined(TRACE_AUDIO_RENDERER_EXECUTE)
|
||||
BitTrace Audio_Renderer_Execute("Audio Renderer Execute");
|
||||
#endif
|
||||
|
||||
//#############################################################################
|
||||
//############################## AudioEvent #############################
|
||||
//#############################################################################
|
||||
|
||||
MemoryBlock
|
||||
AudioEvent::AllocatedMemory(sizeof(Event), AUDIOEVENT_MEMORYBLOCK_ALLOCATION, AUDIOEVENT_MEMORYBLOCK_ALLOCATION, "AudioEvents");
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
AudioEvent::AudioEvent(
|
||||
AudioSource *target,
|
||||
AudioSource::RequestMessage *message
|
||||
):
|
||||
targetReceiver(this)
|
||||
{
|
||||
Check(target);
|
||||
Check(message);
|
||||
|
||||
//
|
||||
// Store the message
|
||||
//
|
||||
size_t long_size = (message->messageLength+3)>>2;
|
||||
messageToSend = (AudioSource::RequestMessage*)new long[long_size];
|
||||
Check_Pointer(messageToSend);
|
||||
Register_Pointer(messageToSend);
|
||||
|
||||
Mem_Copy(
|
||||
messageToSend,
|
||||
message,
|
||||
message->messageLength,
|
||||
long_size*sizeof(long)
|
||||
);
|
||||
|
||||
//
|
||||
// Store the target receiver
|
||||
//
|
||||
targetReceiver.Add(target);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
AudioEvent::~AudioEvent()
|
||||
{
|
||||
Unregister_Pointer(messageToSend);
|
||||
delete messageToSend;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
AudioEvent::ReleaseLinkHandler(
|
||||
Socket*,
|
||||
Plug*
|
||||
)
|
||||
{
|
||||
Unregister_Object(this);
|
||||
delete this;
|
||||
}
|
||||
@@ -233,10 +233,10 @@ private:
|
||||
);
|
||||
~AudioEvent();
|
||||
|
||||
static MemoryBlock* GetAllocatedMemory();
|
||||
static MemoryBlock AllocatedMemory;
|
||||
|
||||
void* operator new(size_t) { return GetAllocatedMemory()->New(); }
|
||||
void operator delete(void *where) { GetAllocatedMemory()->Delete(where); }
|
||||
void* operator new(size_t) { return AllocatedMemory.New(); }
|
||||
void operator delete(void *where) { AllocatedMemory.Delete(where); }
|
||||
|
||||
void
|
||||
Process();
|
||||
|
||||
@@ -16,18 +16,16 @@ class BoundingBoxTree;
|
||||
|
||||
class BoundingBoxTreeNode SIGNATURED
|
||||
{
|
||||
public:
|
||||
static MemoryBlock
|
||||
AllocatedMemory;
|
||||
friend class BoundingBoxTree;
|
||||
|
||||
//##########################################################################
|
||||
// Memory Allocation
|
||||
//
|
||||
private:
|
||||
static MemoryBlock* GetAllocatedMemory();
|
||||
void* operator new(size_t) { return GetAllocatedMemory()->New(); }
|
||||
void operator delete(void *where) { GetAllocatedMemory()->Delete(where); }
|
||||
static MemoryBlock AllocatedMemory;
|
||||
static MemoryBlock* GetAllocatedMemory() { return &AllocatedMemory; }
|
||||
void* operator new(size_t) { return AllocatedMemory.New(); }
|
||||
void operator delete(void *where) { AllocatedMemory.Delete(where); }
|
||||
|
||||
//##########################################################################
|
||||
// Construction and Destruction
|
||||
|
||||
@@ -0,0 +1,450 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
# if !defined(CSTR_HPP)
|
||||
# include <cstr.hpp>
|
||||
# endif
|
||||
# if !defined(MEMSTRM_HPP)
|
||||
# include <memstrm.hpp>
|
||||
# endif
|
||||
|
||||
//namespace Munga
|
||||
//{
|
||||
rString StringRepresentation::operator+=(char chr)
|
||||
{
|
||||
Check(this);
|
||||
size_t len = strlen(&firstByte);
|
||||
*(&firstByte + len++) = chr;
|
||||
*(&firstByte + len) = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if defined(USE_SIGNATURE)
|
||||
int Is_Signature_Bad(const StringRepresentation *)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
#endif
|
||||
|
||||
MemoryStream& MemoryStream_Read(MemoryStream *stream, StringRepresentation *str)
|
||||
{
|
||||
Check(stream);
|
||||
Check(str);
|
||||
|
||||
pString ptr = *str;
|
||||
for (*stream >> ptr[(size_t)0]; ptr[(size_t)0]; ++ptr)
|
||||
*stream >> ptr[(size_t)0];
|
||||
return *stream;
|
||||
}
|
||||
|
||||
MemoryStream& MemoryStream_Write(MemoryStream *stream, const StringRepresentation &str)
|
||||
{
|
||||
Check(stream);
|
||||
Check(&str);
|
||||
|
||||
return stream->WriteBytes((const char*)str, str.GetLength() + 1);
|
||||
}
|
||||
|
||||
#define DELETE_FILL_CHAR ('0')
|
||||
|
||||
size_t CStringRepresentation::allocationIncrement = 8;
|
||||
|
||||
inline size_t CStringRepresentation::CalculateSize(size_t needed)
|
||||
{
|
||||
Verify(!Small_Enough(allocationIncrement));
|
||||
size_t x = ((needed + allocationIncrement) / allocationIncrement) * allocationIncrement;
|
||||
return x;
|
||||
}
|
||||
|
||||
CStringRepresentation::CStringRepresentation()
|
||||
{
|
||||
stringLength = 0;
|
||||
stringSize = 0;
|
||||
stringText = NULL;
|
||||
referenceCount = 0;
|
||||
}
|
||||
|
||||
CStringRepresentation::CStringRepresentation(const CStringRepresentation &str)
|
||||
{
|
||||
Check(&str);
|
||||
stringLength = str.stringLength;
|
||||
stringSize = str.stringSize;
|
||||
|
||||
if (str.stringText == NULL)
|
||||
stringText = NULL;
|
||||
else
|
||||
{
|
||||
stringText = new char[stringSize];
|
||||
Register_Pointer(stringText);
|
||||
Mem_Copy(stringText, str.stringText, stringLength + 1, stringSize);
|
||||
}
|
||||
referenceCount = 0;
|
||||
}
|
||||
|
||||
CStringRepresentation::CStringRepresentation(const char *cstr)
|
||||
{
|
||||
if ((cstr == NULL) || (cstr[0] == '\x00'))
|
||||
{
|
||||
stringLength = 0;
|
||||
stringSize = 0;
|
||||
stringText = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
stringLength = strlen(cstr);
|
||||
stringSize = CalculateSize(stringLength);
|
||||
|
||||
stringText = new char[stringSize];
|
||||
Register_Pointer(stringText);
|
||||
Mem_Copy(stringText, cstr, stringLength + 1, stringSize);
|
||||
}
|
||||
referenceCount = 0;
|
||||
}
|
||||
|
||||
CStringRepresentation::~CStringRepresentation()
|
||||
{
|
||||
if (stringText != NULL)
|
||||
{
|
||||
#if DEBUG_LEVEL>0
|
||||
memset(stringText, DELETE_FILL_CHAR, stringSize);
|
||||
#endif
|
||||
Unregister_Pointer(stringText);
|
||||
delete[] stringText;
|
||||
}
|
||||
}
|
||||
|
||||
Logical CStringRepresentation::TestInstance() const
|
||||
{
|
||||
if (stringText == NULL)
|
||||
{
|
||||
Verify(stringSize == 0);
|
||||
Verify(stringLength == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Verify(stringSize > 0);
|
||||
Verify(stringLength == strlen(stringText));
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
CStringRepresentation CStringRepresentation::operator = (const CStringRepresentation &str)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
if (this == &str)
|
||||
return *this;
|
||||
|
||||
if (stringText != NULL)
|
||||
{
|
||||
#if DEBUG_LEVEL>0
|
||||
memset(stringText, DELETE_FILL_CHAR, stringSize);
|
||||
#endif
|
||||
Unregister_Pointer(stringText);
|
||||
delete[] stringText;
|
||||
}
|
||||
|
||||
Check(&str);
|
||||
stringLength = str.stringLength;
|
||||
stringSize = str.stringSize;
|
||||
|
||||
if (stringSize == 0)
|
||||
stringText = NULL;
|
||||
else
|
||||
{
|
||||
stringText = new char[stringSize];
|
||||
Register_Pointer(stringText);
|
||||
Mem_Copy(stringText, str.stringText, stringLength + 1, stringSize);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CStringRepresentation CStringRepresentation::operator = (const char *cstr)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
if (stringText != NULL)
|
||||
{
|
||||
#if DEBUG_LEVEL>0
|
||||
memset(stringText, DELETE_FILL_CHAR, stringSize);
|
||||
#endif
|
||||
Unregister_Pointer(stringText);
|
||||
delete[] stringText;
|
||||
}
|
||||
|
||||
if ((cstr == NULL) || (cstr[0] == '\x00'))
|
||||
{
|
||||
stringLength = 0;
|
||||
stringSize = 0;
|
||||
stringText = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
stringLength = strlen(cstr);
|
||||
stringSize = CalculateSize(stringLength);
|
||||
|
||||
stringText = new char[stringSize];
|
||||
Register_Pointer(stringText);
|
||||
Mem_Copy(stringText, cstr, stringLength + 1, stringSize);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CStringRepresentation operator + (const CStringRepresentation &str1, const CStringRepresentation &str2)
|
||||
{
|
||||
Check(&str1);
|
||||
Check(&str2);
|
||||
|
||||
CStringRepresentation temp;
|
||||
|
||||
unsigned long totalLen = str1.stringLength + str2.stringLength;
|
||||
|
||||
if (totalLen == 0)
|
||||
return temp;
|
||||
|
||||
temp.stringLength = 0;
|
||||
temp.stringSize = CStringRepresentation::CalculateSize((size_t)totalLen);
|
||||
temp.stringText = new char[temp.stringSize];
|
||||
Register_Pointer(temp.stringText);
|
||||
|
||||
Verify(temp.stringSize >= 1);
|
||||
temp.stringText[0] = '\000';
|
||||
|
||||
if (str1.stringText != NULL)
|
||||
{
|
||||
Mem_Copy(temp.stringText, str1.stringText, str1.stringLength, temp.stringSize);
|
||||
temp.stringLength = str1.stringLength;
|
||||
}
|
||||
|
||||
if (str2.stringText != NULL)
|
||||
{
|
||||
Verify(temp.stringLength < temp.stringSize);
|
||||
Mem_Copy(&temp.stringText[temp.stringLength], str2.stringText, str2.stringLength + 1, temp.stringSize - temp.stringLength);
|
||||
temp.stringLength += str2.stringLength;
|
||||
}
|
||||
|
||||
Check(&temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
CStringRepresentation operator + (const CStringRepresentation &str, char ch)
|
||||
{
|
||||
Check(&str);
|
||||
|
||||
CStringRepresentation temp;
|
||||
|
||||
if (str.stringText == NULL)
|
||||
{
|
||||
temp.stringLength = 1;
|
||||
temp.stringSize = CStringRepresentation::allocationIncrement;
|
||||
temp.stringText = new char [temp.stringSize];
|
||||
Register_Pointer(temp.stringText);
|
||||
|
||||
Verify(temp.stringSize >= 2);
|
||||
temp.stringText[0] = ch;
|
||||
temp.stringText[1] = '\000';
|
||||
}
|
||||
else
|
||||
{
|
||||
Verify(str.stringLength != UINT_MAX);
|
||||
|
||||
temp.stringLength = str.stringLength + 1;
|
||||
|
||||
if (temp.stringLength == str.stringSize)
|
||||
temp.stringSize = str.stringSize + CStringRepresentation::allocationIncrement;
|
||||
else
|
||||
temp.stringSize = str.stringSize;
|
||||
|
||||
temp.stringText = new char[temp.stringSize];
|
||||
Register_Pointer(temp.stringText);
|
||||
Mem_Copy(temp.stringText, str.stringText, str.stringLength, temp.stringSize);
|
||||
|
||||
Verify(str.stringLength < temp.stringSize);
|
||||
Verify(temp.stringLength < temp.stringSize);
|
||||
temp.stringText[str.stringLength] = ch;
|
||||
temp.stringText[temp.stringLength] = '\000';
|
||||
}
|
||||
|
||||
Check(&temp);
|
||||
return temp;
|
||||
}
|
||||
|
||||
int CStringRepresentation::Compare(const CStringRepresentation &str) const
|
||||
{
|
||||
Check(this);
|
||||
Check(&str);
|
||||
|
||||
// handle special cases where one string is empty
|
||||
if (stringText == NULL)
|
||||
{
|
||||
if (str.stringText == NULL)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
if (str.stringText == NULL)
|
||||
return 1;
|
||||
|
||||
return strcmp(stringText, str.stringText);
|
||||
}
|
||||
|
||||
CStringRepresentation CStringRepresentation::GetNthToken(size_t nth_token, char *delimiters) const
|
||||
{
|
||||
Check(this);
|
||||
|
||||
//
|
||||
// Which delimters to use
|
||||
//
|
||||
char *delimter_string = " \t,";
|
||||
|
||||
if (delimiters != NULL)
|
||||
delimter_string = delimiters;
|
||||
Check_Pointer(delimter_string);
|
||||
|
||||
//
|
||||
// Make temporary
|
||||
//
|
||||
CStringRepresentation temp(*this);
|
||||
|
||||
if (temp.stringText == NULL)
|
||||
return temp;
|
||||
|
||||
//
|
||||
// Parse string with strtok
|
||||
//
|
||||
size_t i;
|
||||
char *ptr;
|
||||
|
||||
Check_Pointer(temp.stringText);
|
||||
ptr = strtok(temp.stringText, delimter_string);
|
||||
for (i = 0; i < nth_token; i++)
|
||||
if ((ptr = strtok(NULL, delimter_string)) == NULL)
|
||||
break;
|
||||
|
||||
if (ptr == NULL)
|
||||
{
|
||||
CStringRepresentation null_return;
|
||||
return null_return;
|
||||
}
|
||||
CStringRepresentation token_return(ptr);
|
||||
return token_return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void CStringRepresentation::ToUpper()
|
||||
{
|
||||
Check(this);
|
||||
if (stringText != NULL)
|
||||
strupr(stringText);
|
||||
}
|
||||
|
||||
void CStringRepresentation::ToLower()
|
||||
{
|
||||
Check(this);
|
||||
if (stringText != NULL)
|
||||
strlwr(stringText);
|
||||
}
|
||||
#endif
|
||||
|
||||
MemoryStream& MemoryStream_Read(MemoryStream *stream, CStringRepresentation *str)
|
||||
{
|
||||
Check(stream);
|
||||
Check(str);
|
||||
|
||||
size_t string_length;
|
||||
char *ptr;
|
||||
|
||||
MemoryStream_Read(stream, &string_length);
|
||||
ptr = new char[string_length + 1];
|
||||
Register_Pointer(ptr);
|
||||
stream->ReadBytes(ptr, string_length + 1);
|
||||
|
||||
*str = ptr;
|
||||
|
||||
Unregister_Pointer(ptr);
|
||||
delete[] ptr;
|
||||
|
||||
Check(str);
|
||||
return *stream;
|
||||
}
|
||||
|
||||
MemoryStream& MemoryStream_Write(MemoryStream *stream, const CStringRepresentation &str)
|
||||
{
|
||||
Check(stream);
|
||||
Check(&str);
|
||||
|
||||
MemoryStream_Write(stream, &str.stringLength);
|
||||
return stream->WriteBytes(str.stringText, str.stringLength + 1);
|
||||
}
|
||||
|
||||
void Convert_From_Ascii(const char *str, CStringRepresentation *value)
|
||||
{
|
||||
#if 0
|
||||
Check_Pointer(str);
|
||||
Check(value);
|
||||
*value = str;
|
||||
#else
|
||||
if (str == NULL)
|
||||
Fail("Convert_From_Ascii - str == NULL");
|
||||
if (value == NULL)
|
||||
Fail("Convert_From_Ascii - value == NULL");
|
||||
*value = str;
|
||||
#endif
|
||||
}
|
||||
|
||||
CString CString::operator = (const CString &str)
|
||||
{
|
||||
Check(this);
|
||||
Check(&str);
|
||||
|
||||
if (this == &str)
|
||||
return *this;
|
||||
|
||||
Check(representation);
|
||||
representation->DecrementReferenceCount();
|
||||
representation = str.representation;
|
||||
representation->IncrementReferenceCount();
|
||||
return *this;
|
||||
}
|
||||
|
||||
CString CString::operator = (const char *cstr)
|
||||
{
|
||||
Check(representation);
|
||||
representation->DecrementReferenceCount();
|
||||
representation = new CStringRepresentation(cstr);
|
||||
Register_Object(representation);
|
||||
representation->IncrementReferenceCount();
|
||||
return *this;
|
||||
}
|
||||
|
||||
MemoryStream& MemoryStream_Read(MemoryStream *stream, CString *str)
|
||||
{
|
||||
Check(str);
|
||||
Check(str->representation);
|
||||
str->representation->DecrementReferenceCount();
|
||||
str->representation = new CStringRepresentation;
|
||||
Register_Object(str->representation);
|
||||
str->representation->IncrementReferenceCount();
|
||||
Verify(str->representation->referenceCount == 1);
|
||||
return MemoryStream_Read(stream, str->representation);
|
||||
}
|
||||
|
||||
void Convert_From_Ascii(const char *str, CString *value)
|
||||
{
|
||||
Check(value);
|
||||
Check(value->representation);
|
||||
value->representation->DecrementReferenceCount();
|
||||
value->representation = new CStringRepresentation;
|
||||
Register_Object(value->representation);
|
||||
value->representation->IncrementReferenceCount();
|
||||
Verify(value->representation->referenceCount == 1);
|
||||
Convert_From_Ascii(str, value->representation);
|
||||
}
|
||||
//}
|
||||
|
||||
#if defined(TEST_CLASS)
|
||||
#include "cstr.tcp"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,625 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(EXPTBL_HPP)
|
||||
# include <exptbl.hpp>
|
||||
# endif
|
||||
# if !defined(NAMELIST_HPP)
|
||||
# include <namelist.hpp>
|
||||
# endif
|
||||
# if !defined(REGISTRY_HPP)
|
||||
# include <registry.hpp>
|
||||
# endif
|
||||
# if !defined(APP_HPP)
|
||||
# include <app.hpp>
|
||||
# endif
|
||||
# if !defined(EXPLODE_HPP)
|
||||
# include <explode.hpp>
|
||||
# endif
|
||||
# if !defined(DAMAGE_HPP)
|
||||
# include <damage.hpp>
|
||||
# endif
|
||||
# if !defined(NOTATION_HPP)
|
||||
# include <notation.hpp>
|
||||
# endif
|
||||
# if !defined(FILEUTIL_HPP)
|
||||
# include <fileutil.hpp>
|
||||
# endif
|
||||
# if !defined(RENDERER_HPP)
|
||||
# include <renderer.hpp>
|
||||
# endif
|
||||
|
||||
//##############################################################################
|
||||
//###################### Class ExplosionTableEntry ########################
|
||||
//##############################################################################
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ExplosionTableEntry::CreateExplosion(
|
||||
const EntityID &entity_hit_ID,
|
||||
const EntityID &creating_entity_ID,
|
||||
const Point3D &explode_position
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Origin explode_origin(Origin::Identity);
|
||||
explode_origin = explode_position;
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Create the explosion MakeMessage
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Explosion::MakeMessage exp_message(
|
||||
Explosion::MakeMessageID,
|
||||
sizeof(Explosion::MakeMessage),
|
||||
RegisteredClass::ExplosionClassID,
|
||||
EntityID::Null,
|
||||
explosionResourceID,
|
||||
Explosion::DefaultFlags,
|
||||
explode_origin,
|
||||
entity_hit_ID,
|
||||
creating_entity_ID
|
||||
);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Calculate actual time based on time_delay
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Time when = Now();
|
||||
when += timeDelay;
|
||||
Check(application);
|
||||
|
||||
Registry *registry;
|
||||
registry = application->GetRegistry();
|
||||
Check_Pointer(registry);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Create a MakeEntityMessage
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Registry::MakeEntityMessage *registry_message;
|
||||
registry_message = Registry::MakeEntityMessage::Make(&exp_message);
|
||||
Register_Object(registry_message);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Post entity message to the registry
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
#if 0 // ECH 1/28/96
|
||||
application->Post(
|
||||
DefaultEventPriority,
|
||||
registry,
|
||||
registry_message,
|
||||
when
|
||||
);
|
||||
#else
|
||||
application->Post(
|
||||
CreationEventPriority,
|
||||
registry,
|
||||
registry_message,
|
||||
when
|
||||
);
|
||||
#endif
|
||||
Unregister_Object(registry_message);
|
||||
delete registry_message;
|
||||
|
||||
Check_Fpu();
|
||||
}
|
||||
//##############################################################################
|
||||
// Construction/Destruction
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTableEntry::ExplosionTableEntry(MemoryStream *exp_stream)
|
||||
{
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Read in the data from the stream
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
*exp_stream >> damageLevel >> explosionResourceID >> graphicState;
|
||||
*exp_stream >> timeDelay;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTableEntry::~ExplosionTableEntry()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
// Tool Support
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
ExplosionTableEntry::CreateStreamedExplosion(
|
||||
ResourceFile *resource_file,
|
||||
CString exp_file_name,
|
||||
NotationFile *exp_file,
|
||||
CString exp_page_name,
|
||||
MemoryStream *explosion_stream
|
||||
)
|
||||
{
|
||||
Check(exp_file);
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~
|
||||
// Get the DamageLevel
|
||||
//~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Scalar damage_level;
|
||||
if (!exp_file->GetEntry(
|
||||
exp_page_name,
|
||||
"DamageLevel",
|
||||
&damage_level
|
||||
)
|
||||
)
|
||||
{
|
||||
damage_level = -1.0f;
|
||||
}
|
||||
*explosion_stream << damage_level;
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Get the Explosion Model File
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char *explosion_model_file;
|
||||
if (!exp_file->GetEntry(
|
||||
exp_page_name,
|
||||
"ExplosionModelFile",
|
||||
&explosion_model_file
|
||||
)
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM <<exp_file_name<<" : "<<exp_page_name<<" missing ExplosionModelFile!"<<endl << flush;
|
||||
return False;
|
||||
}
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Hunt for Model file in ResourceFile
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription *res;
|
||||
|
||||
res = resource_file->FindResourceDescription(
|
||||
explosion_model_file,
|
||||
ResourceDescription::ModelListResourceType
|
||||
);
|
||||
if (!res)
|
||||
{
|
||||
cout << exp_file_name << " cannot find " << explosion_model_file
|
||||
<< " in resource file!\n";
|
||||
return False;
|
||||
}
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Write out the resourceID
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
*explosion_stream << res->resourceID;
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Read in the Graphic State
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char *graphic_state_char;
|
||||
Enumeration graphic_state;
|
||||
if (exp_file->GetEntry(
|
||||
exp_page_name,
|
||||
"GraphicState",
|
||||
&graphic_state_char
|
||||
)
|
||||
)
|
||||
{
|
||||
if (!strcmp(graphic_state_char, "Destroyed"))
|
||||
{
|
||||
graphic_state = DamageZone::DestroyedGraphicState;
|
||||
}
|
||||
else if (!strcmp(graphic_state_char, "Gone"))
|
||||
{
|
||||
graphic_state = DamageZone::GoneGraphicState;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
graphic_state = DamageZone::ExistsGraphicState;
|
||||
}
|
||||
*explosion_stream << graphic_state;
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~
|
||||
// Get the TimeDelay
|
||||
//~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Scalar time_delay;
|
||||
if (!exp_file->GetEntry(
|
||||
exp_page_name,
|
||||
"TimeDelay",
|
||||
&time_delay
|
||||
)
|
||||
)
|
||||
{
|
||||
time_delay = 0.0f;
|
||||
}
|
||||
*explosion_stream << time_delay;
|
||||
return True;
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
//######################## Class ExplosionTable ###########################
|
||||
//##############################################################################
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
ExplosionTable::CrossedDamageLevelThreshold(
|
||||
Scalar old_value,
|
||||
Scalar new_value
|
||||
)
|
||||
{
|
||||
ExplosionTableIterator iterator(this);
|
||||
ExplosionTableEntry *current_exp;
|
||||
|
||||
while ((current_exp = iterator.ReadAndNext()) != NULL)
|
||||
{
|
||||
if (
|
||||
(old_value < current_exp->GetDamageLevel()) &&
|
||||
(new_value >= current_exp->GetDamageLevel())
|
||||
)
|
||||
{
|
||||
return True;
|
||||
}
|
||||
}
|
||||
return False;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTableEntry*
|
||||
ExplosionTable::SelectDamageLevelEntry(Scalar damage_level)
|
||||
{
|
||||
ExplosionTableIterator iterator(this);
|
||||
ExplosionTableEntry *current_exp;
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Choose ExplosionTableEntry by damage Level
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
while ((current_exp = iterator.ReadAndNext()) != NULL)
|
||||
{
|
||||
if (damage_level < current_exp->GetDamageLevel())
|
||||
{
|
||||
Check_Fpu();
|
||||
return current_exp;
|
||||
}
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
return NULL;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTableEntry*
|
||||
ExplosionTable::SelectGraphicStateEntry(Enumeration graphic_state)
|
||||
{
|
||||
ExplosionTableIterator iterator(this);
|
||||
ExplosionTableEntry *current_entry;
|
||||
while((current_entry = iterator.ReadAndNext() ) != NULL)
|
||||
{
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Display Explosion if an Entry Exists
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (current_entry->GetGraphicState() == graphic_state)
|
||||
{
|
||||
Check_Fpu();
|
||||
return current_entry;
|
||||
}
|
||||
}
|
||||
Check_Fpu();
|
||||
return NULL;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ExplosionTable::CreateExplosion(
|
||||
ExplosionTableEntry *explosion_entry,
|
||||
const EntityID &entity_hit_ID,
|
||||
const EntityID &creating_entity_ID,
|
||||
Point3D explode_position
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check(explosion_entry);
|
||||
explosion_entry->CreateExplosion(
|
||||
entity_hit_ID,
|
||||
creating_entity_ID,
|
||||
explode_position
|
||||
);
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
// Construction/Destruction
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTable::ExplosionTable(MemoryStream *exp_stream):
|
||||
TableOf<ExplosionTableEntry*, int>(NULL, True)
|
||||
{
|
||||
int entry_count;
|
||||
*exp_stream >> entry_count;
|
||||
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Create all of the ExplosionTableEntries
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTableEntry *exp_entry;
|
||||
|
||||
for(int ii=0;ii<entry_count;++ii)
|
||||
{
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Create a new ExplosionTableEntry
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
exp_entry = new ExplosionTableEntry(exp_stream);
|
||||
Register_Object(exp_entry);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Add the entry the the ExplosionTable
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
AddValue(exp_entry, ii);
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTable::~ExplosionTable()
|
||||
{
|
||||
ExplosionTableIterator iterator(this);
|
||||
iterator.DeletePlugs();
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
// Tool Support
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
ExplosionTable::CreateStreamedExplosionTable(
|
||||
ResourceFile *resource_file,
|
||||
CString model_name,
|
||||
NotationFile *exp_file,
|
||||
CString exp_filename,
|
||||
MemoryStream *explosion_stream
|
||||
)
|
||||
{
|
||||
Check(resource_file);
|
||||
Check(exp_file);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Make a namelist of all Explosion Entries
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
NameList *exp_namelist = exp_file->MakePageList();
|
||||
Register_Object(exp_namelist);
|
||||
if (!exp_namelist->EntryCount())
|
||||
{
|
||||
DEBUG_STREAM << exp_file << " is empty or missing \n"<<endl << flush;
|
||||
Unregister_Object(exp_namelist);
|
||||
delete exp_namelist;
|
||||
return False;
|
||||
}
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Write the Number of Explosion Entries for this Entity
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
int entry_count = exp_namelist->EntryCount();
|
||||
*explosion_stream << entry_count;
|
||||
|
||||
NameList::Entry *exp_entry = exp_namelist->GetFirstEntry();
|
||||
while(exp_entry)
|
||||
{
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// While more pages Add ExplosionEntries to the stream
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ExplosionTableEntry::CreateStreamedExplosion(
|
||||
resource_file,
|
||||
exp_filename,
|
||||
exp_file,
|
||||
exp_entry->GetName(),
|
||||
explosion_stream
|
||||
);
|
||||
exp_entry = exp_entry->GetNextEntry();
|
||||
}
|
||||
Unregister_Object(exp_namelist);
|
||||
delete exp_namelist;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
//##########################################################################
|
||||
//###################### EntityEffectWatcher #########################
|
||||
//##########################################################################
|
||||
|
||||
//##############################################################################
|
||||
// Construction/Destruction
|
||||
//
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
EntityEffectWatcher::EntityEffectWatcher(
|
||||
Entity *entity_watched
|
||||
)
|
||||
{
|
||||
entityWatched = entity_watched;
|
||||
entityWatched->AddEffectWatcher(this);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Init array to hold previous damageLevel values
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Verify(entityWatched->damageZoneCount > 0);
|
||||
oldDamageLevel = new Scalar[entityWatched->damageZoneCount];
|
||||
Register_Pointer(oldDamageLevel);
|
||||
for(int ii=0;ii<entityWatched->damageZoneCount;++ii)
|
||||
{
|
||||
oldDamageLevel[ii] = 0.0f;
|
||||
}
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
|
||||
EntityEffectWatcher::~EntityEffectWatcher()
|
||||
{
|
||||
Unregister_Pointer(oldDamageLevel);
|
||||
delete[] oldDamageLevel;
|
||||
}
|
||||
//##############################################################################
|
||||
// Execute
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
|
||||
void
|
||||
EntityEffectWatcher::Execute()
|
||||
{
|
||||
Check(this);
|
||||
Check(entityWatched);
|
||||
Check_Pointer(entityWatched->damageZones);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Check the flags to see if any damageZones
|
||||
// have been modified since the last Execute was called
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
DamageZone *current_zone;
|
||||
ExplosionTable *exp_table;
|
||||
ExplosionTableEntry *exp_entry(NULL);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Traverse damageZones looking for Changes
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
for (int ii=0;ii<entityWatched->damageZoneCount; ++ii)
|
||||
{
|
||||
current_zone = entityWatched->damageZones[ii];
|
||||
Check(current_zone);
|
||||
ResourceDescription::ResourceID exp_res;
|
||||
exp_table = current_zone->GetExplosionTable();
|
||||
Check(exp_table);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~
|
||||
// Check Damage Level
|
||||
//~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (current_zone->DamageLevelChanged())
|
||||
{
|
||||
exp_entry = exp_table->SelectDamageLevelEntry(current_zone->damageLevel);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// If delta was large enough signal an update
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (
|
||||
exp_table->CrossedDamageLevelThreshold(
|
||||
oldDamageLevel[ii],
|
||||
current_zone->damageLevel
|
||||
) &&
|
||||
(entityWatched->GetInstance() == Entity::MasterInstance)
|
||||
)
|
||||
{
|
||||
entityWatched->ForceUpdate(Entity::DamageZoneUpdateModelFlag);
|
||||
}
|
||||
oldDamageLevel[ii] = current_zone->damageLevel;
|
||||
}
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~
|
||||
// Check Graphic State
|
||||
//~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (current_zone->GraphicStateChanged())
|
||||
{
|
||||
exp_entry = exp_table->SelectGraphicStateEntry(
|
||||
current_zone->GetGraphicState()
|
||||
);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Always update for a graphic state change
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (entityWatched->GetInstance() == Entity::MasterInstance)
|
||||
{
|
||||
entityWatched->ForceUpdate(Entity::DamageZoneUpdateModelFlag);
|
||||
}
|
||||
}
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Notify RendererManager of Any Change
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (exp_entry)
|
||||
{
|
||||
Check(exp_entry);
|
||||
exp_res = exp_entry->GetExplosionResourceID();
|
||||
|
||||
Check(application);
|
||||
Check(application->GetRendererManager());
|
||||
application->GetRendererManager()->StartEntityEffect(
|
||||
entityWatched,
|
||||
current_zone,
|
||||
exp_res
|
||||
);
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Reset the DamageZone::changedFlags if
|
||||
// I am a master and no update occurred OR
|
||||
// if I am a replicant
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
if (
|
||||
(
|
||||
(entityWatched->GetInstance() == Entity::MasterInstance) &&
|
||||
!entityWatched->DamageZoneUpdateModelFlagSet()
|
||||
) ||
|
||||
(
|
||||
(entityWatched->GetInstance() == Entity::ReplicantInstance)
|
||||
)
|
||||
)
|
||||
{
|
||||
current_zone->ResetChangedFlags();
|
||||
}
|
||||
}
|
||||
exp_entry = NULL;
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
// Test Support
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
EntityEffectWatcher::TestInstance() const
|
||||
{
|
||||
Check(entityWatched);
|
||||
return True;
|
||||
}
|
||||
@@ -0,0 +1,832 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
#include <dir.h>
|
||||
|
||||
#include <direct.h>
|
||||
# if !defined(FILEUTIL_HPP)
|
||||
# include <fileutil.hpp>
|
||||
# endif
|
||||
# if !defined(NOTATION_HPP)
|
||||
# include <notation.hpp>
|
||||
# endif
|
||||
|
||||
char *WorkingDirectory = NULL;
|
||||
|
||||
//#############################################################################
|
||||
|
||||
const char *White_Space = " \t\n";
|
||||
|
||||
//#############################################################################
|
||||
|
||||
char
|
||||
*SourceDirectory = NULL,
|
||||
*ConfigDirectory = NULL,
|
||||
*MaterialDirectory = NULL,
|
||||
*TextureDirectory = NULL,
|
||||
*AnimationDirectory = NULL,
|
||||
*ProductionDirectory = NULL;
|
||||
const char
|
||||
*OutputDirectory = NULL;
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
SetSourceDirectory(const char *input_file)
|
||||
{
|
||||
Check_Pointer(input_file);
|
||||
|
||||
static const char
|
||||
* const ARTTOOLS_FILENAME = ".arttoolsrc",
|
||||
* const DIRECTORIES_PAGE = "directories",
|
||||
* const CFG_DIR_ENTRY = "cfg_dir",
|
||||
* const MTL_DIR_ENTRY = "mtl_dir",
|
||||
* const TEX_DIR_ENTRY = "tex_dir",
|
||||
* const KIN_DIR_ENTRY = "kin_dir",
|
||||
* const PRD_DIR_ENTRY = "prd_dir";
|
||||
|
||||
NotationFile
|
||||
*tools_info;
|
||||
char
|
||||
*cwd;
|
||||
const char
|
||||
*cp,
|
||||
*contents;
|
||||
|
||||
//------------------------------------------------
|
||||
// parse the source directory from the input file
|
||||
//------------------------------------------------
|
||||
if ((cp = strrchr(input_file, '/')) == NULL)
|
||||
{
|
||||
//---------------------------------------------------
|
||||
// set source directory to current working directory
|
||||
//---------------------------------------------------
|
||||
cwd = getcwd(NULL, 256);
|
||||
Verify( cwd );
|
||||
SourceDirectory = new char[strlen(cwd) + 2];
|
||||
Register_Pointer(SourceDirectory);
|
||||
strcpy(SourceDirectory, cwd);
|
||||
strcat(SourceDirectory, "/");
|
||||
free(cwd);
|
||||
}
|
||||
else
|
||||
{
|
||||
//------------------------------------------------------
|
||||
// set source directory to path specified in input file
|
||||
//------------------------------------------------------
|
||||
++cp;
|
||||
SourceDirectory = new char[cp - input_file + 1];
|
||||
Register_Pointer(SourceDirectory);
|
||||
*SourceDirectory = '\0';
|
||||
strncat(SourceDirectory, input_file, cp - input_file);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// set other directories from tools config file (if present)
|
||||
//-----------------------------------------------------------
|
||||
tools_info = new NotationFile(SourceFile(ARTTOOLS_FILENAME));
|
||||
Register_Object(tools_info);
|
||||
|
||||
if (tools_info->GetEntry(DIRECTORIES_PAGE, CFG_DIR_ENTRY, &contents))
|
||||
{
|
||||
ConfigDirectory = new char[strlen(contents) + 2];
|
||||
Register_Pointer(ConfigDirectory);
|
||||
strcpy(ConfigDirectory, contents);
|
||||
cp = strchr(contents, '\0');
|
||||
if (cp > contents && *--cp != '/')
|
||||
{
|
||||
strcat(ConfigDirectory, "/");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ConfigDirectory = SourceDirectory;
|
||||
}
|
||||
|
||||
if (tools_info->GetEntry(DIRECTORIES_PAGE, MTL_DIR_ENTRY, &contents))
|
||||
{
|
||||
MaterialDirectory = new char[strlen(contents) + 2];
|
||||
Register_Pointer(MaterialDirectory);
|
||||
strcpy(MaterialDirectory, contents);
|
||||
cp = strchr(contents, '\0');
|
||||
if (cp > contents && *--cp != '/')
|
||||
{
|
||||
strcat(MaterialDirectory, "/");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MaterialDirectory = SourceDirectory;
|
||||
}
|
||||
|
||||
if (tools_info->GetEntry(DIRECTORIES_PAGE, TEX_DIR_ENTRY, &contents))
|
||||
{
|
||||
TextureDirectory = new char[strlen(contents) + 2];
|
||||
Register_Pointer(TextureDirectory);
|
||||
strcpy(TextureDirectory, contents);
|
||||
cp = strchr(contents, '\0');
|
||||
if (cp > contents && *--cp != '/')
|
||||
{
|
||||
strcat(TextureDirectory, "/");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TextureDirectory = MaterialDirectory; // this one is different!
|
||||
}
|
||||
|
||||
if (tools_info->GetEntry(DIRECTORIES_PAGE, KIN_DIR_ENTRY, &contents))
|
||||
{
|
||||
AnimationDirectory = new char[strlen(contents) + 2];
|
||||
Register_Pointer(AnimationDirectory);
|
||||
strcpy(AnimationDirectory, contents);
|
||||
cp = strchr(contents, '\0');
|
||||
if (cp > contents && *--cp != '/')
|
||||
{
|
||||
strcat(AnimationDirectory, "/");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AnimationDirectory = SourceDirectory;
|
||||
}
|
||||
|
||||
if (tools_info->GetEntry(DIRECTORIES_PAGE, PRD_DIR_ENTRY, &contents))
|
||||
{
|
||||
ProductionDirectory = new char[strlen(contents) + 2];
|
||||
Register_Pointer(ProductionDirectory);
|
||||
strcpy(ProductionDirectory, contents);
|
||||
cp = strchr(contents, '\0');
|
||||
if (cp > contents && *--cp != '/')
|
||||
{
|
||||
strcat(ProductionDirectory, "/");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ProductionDirectory = SourceDirectory;
|
||||
}
|
||||
|
||||
OutputDirectory = SourceDirectory;
|
||||
|
||||
Unregister_Object(tools_info);
|
||||
delete tools_info;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
SetOutputDirectory(const char *directory)
|
||||
{
|
||||
Check_Pointer(directory);
|
||||
|
||||
OutputDirectory = directory;
|
||||
return;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetSourceDirectory()
|
||||
{
|
||||
return SourceDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetConfigDirectory()
|
||||
{
|
||||
return ConfigDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetMaterialDirectory()
|
||||
{
|
||||
return MaterialDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetTextureDirectory()
|
||||
{
|
||||
return TextureDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetAnimationDirectory()
|
||||
{
|
||||
return AnimationDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetProductionDirectory()
|
||||
{
|
||||
return ProductionDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
GetOutputDirectory()
|
||||
{
|
||||
return OutputDirectory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ClearDirectories()
|
||||
{
|
||||
//do not clear output directory
|
||||
|
||||
if (ProductionDirectory && ProductionDirectory != SourceDirectory)
|
||||
{
|
||||
Unregister_Pointer(ProductionDirectory);
|
||||
delete ProductionDirectory;
|
||||
}
|
||||
if (AnimationDirectory && AnimationDirectory != SourceDirectory)
|
||||
{
|
||||
Unregister_Pointer(AnimationDirectory);
|
||||
delete AnimationDirectory;
|
||||
}
|
||||
if (TextureDirectory && TextureDirectory != MaterialDirectory) //different!
|
||||
{
|
||||
Unregister_Pointer(TextureDirectory);
|
||||
delete TextureDirectory;
|
||||
}
|
||||
if (MaterialDirectory && MaterialDirectory != SourceDirectory)
|
||||
{
|
||||
Unregister_Pointer(MaterialDirectory);
|
||||
delete MaterialDirectory;
|
||||
}
|
||||
if (ConfigDirectory && ConfigDirectory != SourceDirectory)
|
||||
{
|
||||
Unregister_Pointer(ConfigDirectory);
|
||||
delete ConfigDirectory;
|
||||
}
|
||||
if (SourceDirectory)
|
||||
{
|
||||
Unregister_Pointer(SourceDirectory);
|
||||
delete SourceDirectory;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
DirectoryPlusFilename(
|
||||
const char *directory,
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
//do not check directory here
|
||||
Check_Pointer(filename);
|
||||
//do not check extension here
|
||||
|
||||
static char
|
||||
buffer[512];
|
||||
int
|
||||
length;
|
||||
|
||||
if (!directory) { directory = "\0"; }
|
||||
Check_Pointer(directory);
|
||||
|
||||
length = strlen(directory);
|
||||
if (extension)
|
||||
{
|
||||
Check_Pointer(extension);
|
||||
length += strlen(StripExtension(StripDirectory(filename)));
|
||||
length += *extension == '.'?0:1;
|
||||
length += strlen(extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
length += strlen(StripDirectory(filename));
|
||||
}
|
||||
|
||||
if (length >= ELEMENTS(buffer))
|
||||
{
|
||||
DEBUG_STREAM <<
|
||||
": Program Error - buffer[] too small in DirectoryPlusFilename().\n" << flush;
|
||||
Fail("Exiting");
|
||||
}
|
||||
strcpy(buffer, directory);
|
||||
if (extension)
|
||||
{
|
||||
strcat(buffer, StripExtension(StripDirectory(filename)));
|
||||
if (*extension != '.')
|
||||
{
|
||||
strcat(buffer, ".");
|
||||
}
|
||||
strcat(buffer, extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat(buffer, StripDirectory(filename));
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
SourceFile(
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
return DirectoryPlusFilename(SourceDirectory, filename, extension);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
ConfigFile(
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
return DirectoryPlusFilename(ConfigDirectory, filename, extension);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
MaterialFile(
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
return DirectoryPlusFilename(MaterialDirectory, filename, extension);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
TextureFile(
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
return DirectoryPlusFilename(TextureDirectory, filename, extension);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
AnimationFile(
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
return DirectoryPlusFilename(AnimationDirectory, filename, extension);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
OutputFile(
|
||||
const char *filename,
|
||||
const char *extension
|
||||
)
|
||||
{
|
||||
return DirectoryPlusFilename(OutputDirectory, filename, extension);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
|
||||
const char*
|
||||
StripDirectory(const char *filename)
|
||||
{
|
||||
Check_Pointer(filename);
|
||||
|
||||
if (DirectoryIsSpecified(filename))
|
||||
{
|
||||
const char
|
||||
*p;
|
||||
|
||||
//--------------------------------------
|
||||
// parse the filename from the filepath
|
||||
//--------------------------------------
|
||||
p = strchr(filename, '\0');
|
||||
Verify( p );
|
||||
while (*p != '\\' && p != filename)
|
||||
{
|
||||
--p;
|
||||
}
|
||||
if (*p == '\\')
|
||||
{
|
||||
++p;
|
||||
}
|
||||
filename = p;
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
const char*
|
||||
StripExtension(const char *filename)
|
||||
{
|
||||
Check_Pointer(filename);
|
||||
|
||||
static char
|
||||
buffer[512];
|
||||
char
|
||||
*p;
|
||||
|
||||
if (strlen(filename) >= sizeof(buffer))
|
||||
{
|
||||
//DEBUG_STREAM << ProgName <<
|
||||
// ": Program Error - buffer[] too small in StripExtension()." << endl;
|
||||
DEBUG_STREAM <<
|
||||
": Program Error - buffer[] too small in StripExtension()." << endl << flush;
|
||||
|
||||
Fail("Exiting");
|
||||
}
|
||||
strcpy(buffer, filename);
|
||||
|
||||
//------------------------------------
|
||||
// remove the extension from filename
|
||||
//------------------------------------
|
||||
p = strchr(buffer, '\0');
|
||||
Verify( p );
|
||||
while (*p != '.' && p != buffer)
|
||||
{
|
||||
--p;
|
||||
}
|
||||
if (*p == '.')
|
||||
{
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
|
||||
char*
|
||||
Ind(int level)
|
||||
{
|
||||
const int buf_len = 128;
|
||||
static char buf[buf_len];
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Return string of spaces used to indent an output stream
|
||||
//---------------------------------------------------------
|
||||
buf[0] = '\0';
|
||||
if (level > 63) level = 63; // floor((buf_len - 1)/number of spaces per indent)
|
||||
for (; level > 0; --level)
|
||||
{
|
||||
strcat(buf, " ");
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical GetLine(istream &stream, char *buffer, int size_of_buffer)
|
||||
{
|
||||
static char temp_buffer[512];
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// read next line(s) from input stream automatically resolving
|
||||
// lines with a continuation character '\' at the end
|
||||
//-------------------------------------------------------------
|
||||
if (stream.getline(buffer, size_of_buffer))
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
while (True)
|
||||
{
|
||||
if ((i = strlen(buffer)) > (size_of_buffer - 2))
|
||||
{
|
||||
//DEBUG_STREAM << ProgName << ": ERROR - Input line too long." << endl << flush;
|
||||
|
||||
DEBUG_STREAM << ": ERROR - Input line too long." << endl << flush;
|
||||
break;
|
||||
}
|
||||
|
||||
p = buffer + i;
|
||||
while (p-- > buffer && isspace(*p)); // find last non-blank character
|
||||
|
||||
if (p >= buffer && *p == '\\')
|
||||
{
|
||||
if (stream.getline(temp_buffer, sizeof(temp_buffer)))
|
||||
{
|
||||
*p = ' ';
|
||||
++p;
|
||||
strncat(p, temp_buffer, size_of_buffer - (p - buffer));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return True;
|
||||
}
|
||||
else
|
||||
{
|
||||
*buffer = '\0';
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#if 0
|
||||
char*
|
||||
stripname(char filename[])
|
||||
{
|
||||
|
||||
// Doesn't work
|
||||
|
||||
char
|
||||
file2[200];
|
||||
char
|
||||
*filetosendback;
|
||||
|
||||
int
|
||||
wordlength,
|
||||
count,
|
||||
countbackward,
|
||||
length;
|
||||
|
||||
|
||||
length = strlen(filename);
|
||||
|
||||
|
||||
count = 0;
|
||||
countbackward = length-1;
|
||||
|
||||
while (filename[countbackward-1] != '\\')
|
||||
{
|
||||
--countbackward;
|
||||
}
|
||||
|
||||
wordlength = length - countbackward;
|
||||
|
||||
for (count = 0; count < wordlength; ++count)
|
||||
{
|
||||
file2[count] = filename[countbackward];
|
||||
++countbackward;
|
||||
}
|
||||
|
||||
file2[count] = '\0';
|
||||
|
||||
filetosendback = strdup(file2);
|
||||
|
||||
return filetosendback;
|
||||
}
|
||||
#endif
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Scalar
|
||||
D2R(float degrees)
|
||||
{
|
||||
return degrees*(3.14159259f/180.0f);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
char*
|
||||
MakeWorkingDirectory(
|
||||
const char *file
|
||||
)
|
||||
{
|
||||
char *directory;
|
||||
const char *p;
|
||||
int size;
|
||||
p = file;
|
||||
|
||||
for (int i = (strlen(file) - 1 ); i >= 0; --i)
|
||||
{
|
||||
if ( (*p == '/') || (*p == '\\') )
|
||||
{
|
||||
size = strlen(file) - i + 1;
|
||||
|
||||
directory = new char[size];
|
||||
strncpy(directory, file, size);
|
||||
|
||||
return directory;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
|
||||
//
|
||||
// Else return local directory
|
||||
//
|
||||
#define BUFFER_SIZE (256)
|
||||
char buffer[BUFFER_SIZE];
|
||||
getcwd(buffer, BUFFER_SIZE);
|
||||
|
||||
#if 0
|
||||
directory = strdup(buffer);
|
||||
strcat(directory, "\\"); // ECH 1/29/96 - This is an overwrite
|
||||
#else
|
||||
Str_Cat(buffer, "\\", BUFFER_SIZE);
|
||||
size = strlen(buffer) + 1;
|
||||
directory = new char[size];
|
||||
Str_Copy(directory, buffer, size);
|
||||
#endif
|
||||
|
||||
//
|
||||
// This is "\\" for DOS
|
||||
//
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Logical
|
||||
DirectoryIsSpecified(
|
||||
const char *file
|
||||
)
|
||||
{
|
||||
return strchr(file,'/') || strchr(file,':') || strchr(file,'\\');
|
||||
|
||||
#if 0
|
||||
const char *p;
|
||||
|
||||
p = file;
|
||||
|
||||
for (int i = 0; i < strlen(file); ++i)
|
||||
{
|
||||
if ( (*p == '/') || (*p == '\\') )
|
||||
{
|
||||
|
||||
return True;
|
||||
|
||||
}
|
||||
|
||||
++p;
|
||||
}
|
||||
return False;
|
||||
#endif
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
char*
|
||||
MakePathedFilename(
|
||||
const char *directory,
|
||||
const char *name
|
||||
)
|
||||
{
|
||||
char *filename;
|
||||
|
||||
if (DirectoryIsSpecified(name))
|
||||
{
|
||||
filename = new char[ strlen(name) + 1];
|
||||
strcpy(filename, name);
|
||||
return filename;
|
||||
}
|
||||
|
||||
if (directory == NULL)
|
||||
{
|
||||
filename = new char[strlen(name) + 1];
|
||||
strcpy(filename, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = new char[strlen(directory) + strlen(name) + 1];
|
||||
|
||||
strcpy(filename, directory);
|
||||
strcat(filename, name);
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void OpenOutput(ofstream &stream, const char *directory, const char *filename)
|
||||
{
|
||||
//do not check directory here
|
||||
Check_Pointer(filename);
|
||||
|
||||
char
|
||||
*file_to_open;
|
||||
|
||||
if (DirectoryIsSpecified(filename) || directory == NULL)
|
||||
{
|
||||
file_to_open = new char[strlen(filename) + 1];
|
||||
Register_Pointer(file_to_open);
|
||||
strcpy(file_to_open, filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_Pointer(directory);
|
||||
file_to_open = new char[strlen(directory) + strlen(filename) + 1];
|
||||
Register_Pointer(file_to_open);
|
||||
strcpy(file_to_open, directory);
|
||||
strcat(file_to_open, filename);
|
||||
}
|
||||
|
||||
stream.open(file_to_open);
|
||||
Unregister_Pointer(file_to_open);
|
||||
delete file_to_open;
|
||||
return;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
void OpenInput(ifstream &stream, char *directory, const char *filename)
|
||||
{
|
||||
char tempfile[100];
|
||||
|
||||
if (DirectoryIsSpecified(filename))
|
||||
{
|
||||
strcpy(tempfile, filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (directory != NULL)
|
||||
{
|
||||
strcpy(tempfile, directory);
|
||||
strcat(tempfile, filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(tempfile, filename);
|
||||
}
|
||||
}
|
||||
|
||||
stream.open(tempfile);
|
||||
return;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Logical
|
||||
LabOnly(
|
||||
NotationFile
|
||||
*notation_file
|
||||
)
|
||||
{
|
||||
|
||||
if (notation_file->PageExists("LAB_ONLY"))
|
||||
{
|
||||
cout << "WARNING: LAB_ONLY" << endl;
|
||||
return True;
|
||||
}
|
||||
else
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
void
|
||||
AddLabOnly(
|
||||
NotationFile
|
||||
*notation_file
|
||||
)
|
||||
{
|
||||
if (!notation_file->PageExists("LAB_ONLY"))
|
||||
{
|
||||
notation_file->AppendEntry("LAB_ONLY", NULL, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Logical
|
||||
DoesNotationFileExist(
|
||||
NotationFile
|
||||
*notation_file
|
||||
)
|
||||
{
|
||||
Check(notation_file);
|
||||
Check_Pointer(notation_file->GetFileName());
|
||||
ifstream notation_file_stream(notation_file->GetFileName());
|
||||
return (notation_file_stream) ? True : False;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
@@ -0,0 +1,827 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(GAUGE_HPP)
|
||||
# include <gauge.hpp>
|
||||
# endif
|
||||
# if !defined(GAUGREND_HPP)
|
||||
# include <gaugrend.hpp>
|
||||
# endif
|
||||
|
||||
extern void
|
||||
indent(int level); // in graph2d.cc
|
||||
|
||||
//#########################################################################
|
||||
//############################# GaugeBase #################################
|
||||
//#########################################################################
|
||||
GaugeBase::GaugeBase(
|
||||
ModeMask mode_mask,
|
||||
GaugeRenderer *new_renderer,
|
||||
unsigned int owner_ID,
|
||||
const char *identification_string
|
||||
) :
|
||||
Node(Gauge::GaugeClassID),
|
||||
alreadyActivatedFlag(False)
|
||||
{
|
||||
Check_Pointer(this);
|
||||
|
||||
modeMask = mode_mask;
|
||||
ownerID = owner_ID;
|
||||
renderer = new_renderer;
|
||||
identificationString = identification_string;
|
||||
|
||||
stayInactive = True; // used by GaugeRenderer during activation
|
||||
//---------------------------------------------------
|
||||
// If renderer exists, add to object list
|
||||
// (Not having a renderer allows for independent testing)
|
||||
//---------------------------------------------------
|
||||
if (renderer != NULL)
|
||||
{
|
||||
Check(renderer);
|
||||
renderer->Add(this);
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
GaugeBase::~GaugeBase()
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Logical
|
||||
GaugeBase::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::BecameActive()
|
||||
{
|
||||
Check(this);
|
||||
//------------------------------------------------------
|
||||
// Default method immediately inactivates the gaugeBase
|
||||
//------------------------------------------------------
|
||||
DEBUG_STREAM <<
|
||||
"BecameActive() has not been defined for '" << identificationString <<
|
||||
"'. About to call Inactivate()\n";
|
||||
Inactivate();
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::BecameInactive()
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::Inactivate()
|
||||
{
|
||||
Check(this);
|
||||
if (renderer != NULL)
|
||||
{
|
||||
Check(renderer);
|
||||
renderer->Inactivate(this);
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Logical
|
||||
GaugeBase::Update(GaugeRate /*rate_mask*/)
|
||||
{
|
||||
Check(this);
|
||||
//------------------------------------------------------
|
||||
// Default method immediately inactivates the gaugeBase
|
||||
//------------------------------------------------------
|
||||
DEBUG_STREAM <<
|
||||
"Update() has not been defined for '" << identificationString <<
|
||||
"'. About to call Inactivate()\n";
|
||||
Inactivate();
|
||||
Check_Fpu();
|
||||
return False;
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::UpdateProfile(Scalar /*frame_percentage*/)
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::ReportProfile()
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::LinkToEntity(Entity */*entity*/)
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::NotifyOfNewInterestingEntity(Entity */*entity*/)
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
GaugeBase::NotifyOfBecomingUninterestingEntity(Entity */*entity*/)
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
GaugeBase::DiscernTier()
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//#########################################################################
|
||||
//########################## GaugeBackground ##############################
|
||||
//#########################################################################
|
||||
GaugeBackground::GaugeBackground(
|
||||
ModeMask mode_mask,
|
||||
GaugeRenderer *new_renderer,
|
||||
unsigned int owner_ID,
|
||||
const char *identification_string
|
||||
) :
|
||||
GaugeBase(mode_mask, new_renderer, owner_ID, identification_string)
|
||||
{
|
||||
Check_Pointer(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//#########################################################################
|
||||
//######################## GraphicGaugeBackground #########################
|
||||
//#########################################################################
|
||||
GraphicGaugeBackground::GraphicGaugeBackground(
|
||||
ModeMask mode_mask,
|
||||
GaugeRenderer *renderer,
|
||||
unsigned int owner_ID,
|
||||
int graphics_port_number,
|
||||
const char *identification_string
|
||||
) :
|
||||
localView(
|
||||
renderer == NULL ?
|
||||
NULL :
|
||||
renderer->GetGraphicsPort(graphics_port_number)
|
||||
),
|
||||
GaugeBackground(mode_mask, renderer, owner_ID, identification_string)
|
||||
{
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//#########################################################################
|
||||
//########################## GaugeConnection ##############################
|
||||
//#########################################################################
|
||||
|
||||
GaugeConnection::GaugeConnection(int parameter_id)
|
||||
{
|
||||
Check_Pointer(this);
|
||||
parameterID = parameter_id;
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
GaugeConnection::~GaugeConnection()
|
||||
{
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Logical
|
||||
GaugeConnection::TestInstance() const
|
||||
{
|
||||
Check_Pointer(this);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
void GaugeConnection::Update()
|
||||
{
|
||||
Fail("GaugeConnection::Update should not be called!\n");
|
||||
}
|
||||
|
||||
void
|
||||
GaugeConnection::ShowInstance(char *indent)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
cout << indent << "GaugeConnection:\n";
|
||||
|
||||
char
|
||||
temp[80];
|
||||
|
||||
Str_Copy(temp,indent, 80);
|
||||
Str_Cat(temp,"...", 80);
|
||||
cout << temp << "parameterID=" << parameterID << "\n" << flush;
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//#########################################################################
|
||||
//################################# Gauge #################################
|
||||
//#########################################################################
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// GaugeRate masks are used to spread out workload in a priority-based
|
||||
// manner. Each GaugeRate refers to the branch of a binary tree as shown:
|
||||
//
|
||||
// A = every frame
|
||||
// /--------------^--------------\ :
|
||||
// FIRST TIER: B C = 1/2
|
||||
// /------^-------\ /------^-------\ :
|
||||
// 2ND: D E F G = 1/4
|
||||
// /--^---\ /--^---\ /--^---\ /--^---\ :
|
||||
// H I J K L M N O = 1/8
|
||||
// / \ / \ / \ / \ / \ / \ / \ / \ :
|
||||
// P Q R S T U V W X Y Z Z0 Z1 Z2 Z3 Z4 = 1/16
|
||||
//
|
||||
// Each 'tier' down indicates an update rate half that of the one above it.
|
||||
//
|
||||
// Note that rates Z0..Z4 cannot be specified through the gauge renderer's
|
||||
// interpreter. They are available to automatically generated gauges, though.
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
GaugeRate
|
||||
Gauge::rateTable[31] =
|
||||
{
|
||||
gaugeRate_A, // every frame
|
||||
|
||||
gaugeRate_B, // every other frame
|
||||
gaugeRate_C,
|
||||
|
||||
gaugeRate_D, // every 4th frame
|
||||
gaugeRate_E,
|
||||
gaugeRate_F,
|
||||
gaugeRate_G,
|
||||
|
||||
gaugeRate_H, // every 8th frame
|
||||
gaugeRate_I,
|
||||
gaugeRate_J,
|
||||
gaugeRate_K,
|
||||
gaugeRate_L,
|
||||
gaugeRate_M,
|
||||
gaugeRate_N,
|
||||
gaugeRate_O,
|
||||
|
||||
gaugeRate_P, // every 16th frame
|
||||
gaugeRate_Q,
|
||||
gaugeRate_R,
|
||||
gaugeRate_S,
|
||||
gaugeRate_T,
|
||||
gaugeRate_U,
|
||||
gaugeRate_V,
|
||||
gaugeRate_W,
|
||||
gaugeRate_X,
|
||||
gaugeRate_Y,
|
||||
gaugeRate_Z,
|
||||
gaugeRate_Z0,
|
||||
gaugeRate_Z1,
|
||||
gaugeRate_Z2,
|
||||
gaugeRate_Z3,
|
||||
gaugeRate_Z4
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Gauge::NextXXXTierGaugeRate()
|
||||
// - These functions attempt to spead out workload by returning the
|
||||
// next available 'GaugeRate' in a given 'tier'.
|
||||
//
|
||||
// The higher level tiers bump the lower level tier indices to
|
||||
// attempt to avoid placing too much load on the same higher-order
|
||||
// branch of the tree.
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
static int
|
||||
first_index = -1,
|
||||
second_index = -1,
|
||||
third_index = -1,
|
||||
fourth_index = -1;
|
||||
|
||||
GaugeRate
|
||||
Gauge::NextFirstTierGaugeRate()
|
||||
{
|
||||
//----------------------------------------
|
||||
// Generate first index
|
||||
//----------------------------------------
|
||||
first_index = (++first_index) & 1;
|
||||
//----------------------------------------
|
||||
// Bump other indices to avoid same branch
|
||||
//----------------------------------------
|
||||
second_index += 2;
|
||||
third_index += 4;
|
||||
fourth_index += 8;
|
||||
//----------------------------------------
|
||||
// Return rate mask
|
||||
//----------------------------------------
|
||||
return rateTable[first_index + 1];
|
||||
}
|
||||
|
||||
GaugeRate
|
||||
Gauge::NextSecondTierGaugeRate()
|
||||
{
|
||||
//----------------------------------------
|
||||
// Generate first index
|
||||
//----------------------------------------
|
||||
second_index = (++second_index) & 3;
|
||||
//----------------------------------------
|
||||
// Bump other indices to avoid same branch
|
||||
//----------------------------------------
|
||||
third_index += 2;
|
||||
fourth_index += 4;
|
||||
//----------------------------------------
|
||||
// Return rate mask
|
||||
//----------------------------------------
|
||||
return rateTable[second_index + 3];
|
||||
}
|
||||
|
||||
GaugeRate
|
||||
Gauge::NextThirdTierGaugeRate()
|
||||
{
|
||||
//----------------------------------------
|
||||
// Generate first index
|
||||
//----------------------------------------
|
||||
third_index = (++third_index) & 7;
|
||||
//----------------------------------------
|
||||
// Bump other indices to avoid same branch
|
||||
//----------------------------------------
|
||||
fourth_index += 2;
|
||||
//----------------------------------------
|
||||
// Return rate mask
|
||||
//----------------------------------------
|
||||
return rateTable[third_index + 7];
|
||||
}
|
||||
|
||||
GaugeRate
|
||||
Gauge::NextFourthTierGaugeRate()
|
||||
{
|
||||
//----------------------------------------
|
||||
// Generate first index
|
||||
//----------------------------------------
|
||||
fourth_index = (++fourth_index) & 15;
|
||||
//----------------------------------------
|
||||
// Return rate mask
|
||||
//----------------------------------------
|
||||
return rateTable[fourth_index + 15];
|
||||
}
|
||||
|
||||
GaugeRate
|
||||
Gauge::ConvertIndexToRate(int index)
|
||||
{
|
||||
Verify(index >= 0);
|
||||
Verify(index < 32);
|
||||
|
||||
return rateTable[index];
|
||||
}
|
||||
|
||||
Gauge::Gauge(
|
||||
GaugeRate new_rate,
|
||||
ModeMask mode_mask,
|
||||
GaugeRenderer *renderer,
|
||||
unsigned int owner_ID,
|
||||
const char *identification_string
|
||||
):
|
||||
GaugeBase(mode_mask, renderer, owner_ID, identification_string),
|
||||
instanceList(this)
|
||||
{
|
||||
Check_Pointer(this);
|
||||
|
||||
rate = new_rate;
|
||||
oldRate = new_rate;
|
||||
|
||||
stayInactive = False;
|
||||
|
||||
profileFramePercentage = (Scalar) 0;
|
||||
profileMaxFramePercentage = (Scalar) 0;
|
||||
profileCycles = 0;
|
||||
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Gauge::~Gauge()
|
||||
{
|
||||
Check(this);
|
||||
RemoveAllConnections();
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Logical
|
||||
Gauge::TestInstance() const
|
||||
{
|
||||
Check(&instanceList);
|
||||
# if 0
|
||||
//--------------------------------------------------------------------
|
||||
// Check all owned GaugeConnections
|
||||
//--------------------------------------------------------------------
|
||||
ChainIteratorOf<GaugeConnection*>
|
||||
i(instanceList);
|
||||
|
||||
GaugeConnection
|
||||
*the_connection;
|
||||
|
||||
while ((the_connection=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(the_connection);
|
||||
}
|
||||
# endif
|
||||
//--------------------------------------------------------------------
|
||||
// Check the base object
|
||||
//--------------------------------------------------------------------
|
||||
return GaugeBase::TestInstance();
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::ShowInstance(char *indent)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
ChainIteratorOf<GaugeConnection*>
|
||||
i(instanceList);
|
||||
|
||||
GaugeConnection
|
||||
*the_connection;
|
||||
|
||||
cout << indent << "Gauge:\n";
|
||||
|
||||
char
|
||||
temp[80];
|
||||
|
||||
Str_Copy(temp,indent, 80);
|
||||
Str_Cat(temp,"...", 80);
|
||||
|
||||
cout << temp << "modeMask =" << modeMask << "\n";
|
||||
cout << temp << "renderer =" << renderer << "\n";
|
||||
cout << temp << "ownerID =" << ownerID << "\n";
|
||||
cout << temp << "InstanceList -\n" << flush;
|
||||
|
||||
Str_Cat(temp,"...", 80);
|
||||
|
||||
while ((the_connection=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(the_connection);
|
||||
the_connection->ShowInstance(temp);
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::AddConnection(GaugeConnection *connection)
|
||||
{
|
||||
Check(this);
|
||||
Check(connection);
|
||||
instanceList.Add(connection);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::RemoveConnection(int parameter_ID)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
ChainIteratorOf<GaugeConnection*>
|
||||
i(instanceList);
|
||||
|
||||
GaugeConnection
|
||||
*gauge_connection;
|
||||
|
||||
while ((gauge_connection=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(gauge_connection);
|
||||
if (gauge_connection->parameterID == parameter_ID)
|
||||
{
|
||||
Unregister_Object(gauge_connection);
|
||||
delete gauge_connection;
|
||||
}
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::RemoveAllConnections()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
ChainIteratorOf<GaugeConnection*>
|
||||
i(instanceList);
|
||||
|
||||
GaugeConnection
|
||||
*gauge_connection;
|
||||
|
||||
while ((gauge_connection=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(gauge_connection);
|
||||
Unregister_Object(gauge_connection);
|
||||
delete gauge_connection;
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::Disable(Logical disable_state)
|
||||
{
|
||||
Check(this);
|
||||
if (disable_state)
|
||||
{
|
||||
rate = 0;
|
||||
BecameInactive();
|
||||
}
|
||||
else
|
||||
{
|
||||
rate = oldRate;
|
||||
BecameActive();
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Logical
|
||||
Gauge::Update(GaugeRate rate_mask)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
Logical
|
||||
actually_ran = False;
|
||||
//-----------------------------------------
|
||||
// Update only if rate mask allows it
|
||||
//-----------------------------------------
|
||||
if (rate & rate_mask)
|
||||
{
|
||||
//-----------------------------------------
|
||||
// Update parameters
|
||||
//-----------------------------------------
|
||||
ChainIteratorOf<GaugeConnection*>
|
||||
i(instanceList);
|
||||
|
||||
GaugeConnection
|
||||
*gauge_connection;
|
||||
|
||||
while ((gauge_connection=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(gauge_connection);
|
||||
gauge_connection->Update();
|
||||
}
|
||||
//-----------------------------------------
|
||||
// Execute gauge code
|
||||
//-----------------------------------------
|
||||
{
|
||||
// BT DEV-GAUGES bring-up: run Execute() under SEH so a gauge whose
|
||||
// game-state binding isn't reconstructed yet is DISABLED (rate=0)
|
||||
// after its first fault instead of AV'ing every frame. Gated on
|
||||
// BT_DEV_GAUGES; the pod build calls Execute() directly.
|
||||
static int s_devGaugesUpd = -1;
|
||||
if (s_devGaugesUpd < 0)
|
||||
s_devGaugesUpd = (getenv("BT_DEV_GAUGES") != NULL ||
|
||||
getenv("L4MFDSPLIT") != NULL) ? 1 : 0;
|
||||
if (s_devGaugesUpd)
|
||||
{
|
||||
if (!GuardedExecute())
|
||||
{
|
||||
// LOUD KILL (2026-07-12): the silent version made a faulted
|
||||
// gauge simply FREEZE on screen (user-hit: a weapon panel's
|
||||
// dial + lamp died mid-session with no trace). Name the
|
||||
// casualty so the log convicts the faulting Execute.
|
||||
DEBUG_STREAM << "[gauge-fault] '"
|
||||
<< (identificationString ? identificationString : "?")
|
||||
<< "' Execute FAULTED -> gauge DISABLED (this="
|
||||
<< (void *)this << ")\n" << flush;
|
||||
Disable(True);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Execute();
|
||||
}
|
||||
}
|
||||
actually_ran = True;
|
||||
}
|
||||
Check_Fpu();
|
||||
return actually_ran;
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::Execute()
|
||||
{
|
||||
Fail("Gauge::Execute not overridden");
|
||||
}
|
||||
|
||||
//
|
||||
// GuardedExecute -- BT DEV-GAUGES bring-up. Run Execute() under a structured
|
||||
// exception handler so a gauge whose game-state data binding is not yet
|
||||
// reconstructed is skipped instead of AV'ing the whole game. (A separate
|
||||
// function because __try/__except may not share a frame with C++ objects that
|
||||
// require unwinding, which Gauge::Update does.) Returns False on fault.
|
||||
//
|
||||
Logical
|
||||
Gauge::GuardedExecute()
|
||||
{
|
||||
Execute();
|
||||
return True;
|
||||
}
|
||||
|
||||
struct TierLookup
|
||||
{
|
||||
GaugeRate rate;
|
||||
int tier;
|
||||
};
|
||||
|
||||
int
|
||||
Gauge::DiscernTier()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
TierLookup
|
||||
*tier_pointer;
|
||||
static TierLookup
|
||||
tier_lookup[] =
|
||||
{
|
||||
{gaugeRate_A, 0 },
|
||||
|
||||
{gaugeRate_B, 1 },
|
||||
{gaugeRate_C, 1 },
|
||||
|
||||
{gaugeRate_D, 2 },
|
||||
{gaugeRate_E, 2 },
|
||||
{gaugeRate_F, 2 },
|
||||
{gaugeRate_G, 2 },
|
||||
|
||||
{gaugeRate_H, 3 },
|
||||
{gaugeRate_I, 3 },
|
||||
{gaugeRate_J, 3 },
|
||||
{gaugeRate_K, 3 },
|
||||
{gaugeRate_L, 3 },
|
||||
{gaugeRate_M, 3 },
|
||||
{gaugeRate_N, 3 },
|
||||
{gaugeRate_O, 3 },
|
||||
|
||||
{gaugeRate_P, 4 },
|
||||
{gaugeRate_Q, 4 },
|
||||
{gaugeRate_R, 4 },
|
||||
{gaugeRate_S, 4 },
|
||||
{gaugeRate_T, 4 },
|
||||
{gaugeRate_U, 4 },
|
||||
{gaugeRate_V, 4 },
|
||||
{gaugeRate_W, 4 },
|
||||
{gaugeRate_X, 4 },
|
||||
{gaugeRate_Y, 4 },
|
||||
{gaugeRate_Z, 4 },
|
||||
{gaugeRate_Z0,4 },
|
||||
{gaugeRate_Z1,4 },
|
||||
{gaugeRate_Z2,4 },
|
||||
{gaugeRate_Z3,4 },
|
||||
{gaugeRate_Z4,4 },
|
||||
{0,0}
|
||||
};
|
||||
|
||||
for (tier_pointer=tier_lookup; tier_pointer->rate != 0; ++tier_pointer)
|
||||
{
|
||||
if (tier_pointer->rate == rate)
|
||||
{
|
||||
Check_Fpu();
|
||||
return tier_pointer->tier;
|
||||
}
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::UpdateProfile(Scalar frame_percentage)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
//---------------------------------------------
|
||||
// Keep worst case
|
||||
//---------------------------------------------
|
||||
if (profileMaxFramePercentage < frame_percentage)
|
||||
{
|
||||
profileMaxFramePercentage = frame_percentage;
|
||||
}
|
||||
//---------------------------------------------
|
||||
// Keep running total
|
||||
//---------------------------------------------
|
||||
profileFramePercentage += frame_percentage;
|
||||
//---------------------------------------------
|
||||
// Prevent overflow
|
||||
//---------------------------------------------
|
||||
if (++profileCycles > 16384)
|
||||
{
|
||||
profileFramePercentage /= (Scalar) 2;
|
||||
profileCycles >>= 1;
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
void
|
||||
Gauge::ReportProfile()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
int
|
||||
i;
|
||||
|
||||
DEBUG_STREAM << identificationString << flush;
|
||||
for(i=strlen(identificationString); i<32; ++i)
|
||||
{
|
||||
DEBUG_STREAM << "." << flush;
|
||||
}
|
||||
|
||||
if (profileCycles > 0)
|
||||
{
|
||||
Scalar
|
||||
average = profileFramePercentage / (Scalar)profileCycles;
|
||||
|
||||
char
|
||||
buffer[80];
|
||||
|
||||
sprintf(buffer, "%6d %6.4f %6.4f\n",
|
||||
profileCycles,
|
||||
average,
|
||||
profileMaxFramePercentage
|
||||
);
|
||||
DEBUG_STREAM << buffer << flush;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_STREAM << "never ran.\n" << flush;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Reset maximum percentage
|
||||
//----------------------------------------
|
||||
profileMaxFramePercentage = (Scalar) 0;
|
||||
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//#########################################################################
|
||||
//############################# GraphicGauge #############################
|
||||
//#########################################################################
|
||||
|
||||
GraphicGauge::GraphicGauge(
|
||||
GaugeRate new_rate,
|
||||
ModeMask mode_mask,
|
||||
GaugeRenderer *renderer,
|
||||
unsigned int owner_ID,
|
||||
int graphics_port_number,
|
||||
const char *identification_string
|
||||
) :
|
||||
Gauge(new_rate, mode_mask, renderer, owner_ID, identification_string),
|
||||
localView(
|
||||
renderer == NULL ?
|
||||
NULL :
|
||||
renderer->GetGraphicsPort(graphics_port_number)
|
||||
)
|
||||
{
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
|
||||
GraphicGauge::~GraphicGauge()
|
||||
{
|
||||
Check(this);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
Logical
|
||||
GraphicGauge::TestInstance() const
|
||||
{
|
||||
Check(&localView);
|
||||
Check_Fpu();
|
||||
return Gauge::TestInstance();
|
||||
}
|
||||
|
||||
void
|
||||
GraphicGauge::ShowInstance(char *indent)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
cout << indent << "GraphicGauge:\n";
|
||||
|
||||
char
|
||||
temp[80];
|
||||
|
||||
Str_Copy(temp,indent, 80);
|
||||
Str_Cat(temp,"...", 80);
|
||||
|
||||
localView.ShowInstance(temp);
|
||||
Gauge::ShowInstance(temp);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
|
||||
#if defined(TEST_CLASS)
|
||||
# include "gauge.tcp"
|
||||
#endif
|
||||
@@ -0,0 +1,744 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(GAUGMAP_HPP)
|
||||
# include <gaugmap.hpp>
|
||||
# endif
|
||||
# if !defined(POINT3D_HPP)
|
||||
# include <point3d.hpp>
|
||||
# endif
|
||||
# if !defined(ENTITY_HPP)
|
||||
# include <entity.hpp>
|
||||
# endif
|
||||
|
||||
// #define LOCAL_TEST
|
||||
|
||||
#if defined(LOCAL_TEST)
|
||||
# define Test_Tell(n) cout << n
|
||||
#else
|
||||
# define Test_Tell(n)
|
||||
#endif
|
||||
|
||||
// 'FULL_EXTENT' is a value representing the total extent
|
||||
// of the world in meters.
|
||||
#define FULL_EXTENT 32767.0
|
||||
#define HALF_EXTENT (FULL_EXTENT/2.0)
|
||||
|
||||
// 'LARGEST_RADIUS' defines a radius encompassing the largest existing entity
|
||||
#define LARGEST_RADIUS 500.0 // HACK - this is a guess
|
||||
|
||||
|
||||
//#############################################################################
|
||||
// approximateDistance
|
||||
// ...accurate to about 13%
|
||||
// Graphics Gems, p.432, "A Fast Approximation To 3D Euclidean Distance"
|
||||
//#############################################################################
|
||||
Scalar
|
||||
approximateDistance(Point3D *point1, Point3D *point2)
|
||||
{
|
||||
Check_Pointer(point1);
|
||||
Check_Pointer(point2);
|
||||
|
||||
Scalar
|
||||
max, mid, min, temp;
|
||||
//-----------------------------------------------
|
||||
// Get the three components in arbitrary order
|
||||
//-----------------------------------------------
|
||||
max = abs(point2->x - point1->x);
|
||||
mid = abs(point2->y - point1->y);
|
||||
min = abs(point2->z - point1->z);
|
||||
//-----------------------------------------------
|
||||
// Sort only the largest value to the top.
|
||||
// We don't need to completely sort the values,
|
||||
// as we weight the middle and smallest equally.
|
||||
//-----------------------------------------------
|
||||
if (max < mid)
|
||||
{
|
||||
temp=max; max=mid; mid=temp; // swap max, mid
|
||||
}
|
||||
|
||||
if (max < min)
|
||||
{
|
||||
temp=max; max=min; min=temp; // swap max, min
|
||||
}
|
||||
|
||||
//-----------------------------------------------
|
||||
// return largest + 1/4 middle + 1/4 smallest
|
||||
//-----------------------------------------------
|
||||
Check_Fpu();
|
||||
return max + ((mid+min)*.25);
|
||||
}
|
||||
|
||||
|
||||
//#############################################################################
|
||||
// GaugeEntityList
|
||||
//#############################################################################
|
||||
|
||||
//============================================================================
|
||||
// Creator
|
||||
//============================================================================
|
||||
GaugeEntityList::GaugeEntityList() :
|
||||
Node(GaugeEntityList::GaugeEntityListClassID),
|
||||
instanceList(this)
|
||||
{
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Destructor
|
||||
//============================================================================
|
||||
GaugeEntityList::~GaugeEntityList()
|
||||
{
|
||||
Check(this);
|
||||
Clear(); // is this necessary, or are nodes automatically deleted?
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// TestInstance
|
||||
//============================================================================
|
||||
Logical
|
||||
GaugeEntityList::TestInstance() const
|
||||
{
|
||||
return Node::TestInstance();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Add
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityList::Add(Entity *entity)
|
||||
{
|
||||
Check(this);
|
||||
Check(entity);
|
||||
Check(&instanceList);
|
||||
instanceList.Add(entity);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Remove
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityList::Remove(Entity *search_entity)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
Test_Tell(
|
||||
"GaugeEntityList::Remove(" << search_entity <<
|
||||
")\n"
|
||||
);
|
||||
Check(&instanceList);
|
||||
ChainIteratorOf<Entity*>
|
||||
i(instanceList);
|
||||
|
||||
Entity
|
||||
*entity;
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Search the list for the given entity
|
||||
//-----------------------------------------------------
|
||||
while((entity=i.GetCurrent()) != NULL)
|
||||
{
|
||||
Check(entity);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// If we find it, remove it and exit
|
||||
//-----------------------------------------------------
|
||||
if (entity == search_entity)
|
||||
{
|
||||
Test_Tell("Found!\n");
|
||||
i.Remove();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
i.Next();
|
||||
}
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// NumberOfItems
|
||||
//============================================================================
|
||||
int
|
||||
GaugeEntityList::NumberOfItems()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
ChainIteratorOf<Entity*>
|
||||
i(instanceList);
|
||||
|
||||
Check_Fpu();
|
||||
return i.GetSize();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Clear
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityList::Clear()
|
||||
{
|
||||
// Test_Tell("GaugeEntityList::Clear()\n");
|
||||
Check(this);
|
||||
|
||||
ChainIteratorOf<Entity*>
|
||||
i(instanceList);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Remove all objects from the list
|
||||
//-----------------------------------------------------
|
||||
while(i.GetCurrent() != NULL)
|
||||
{
|
||||
Check(i.GetCurrent());
|
||||
i.Remove();
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// CopyEntities
|
||||
//
|
||||
// This method will create a reference in the destination list to
|
||||
// all entities in the list
|
||||
//============================================================================
|
||||
int
|
||||
GaugeEntityList::CopyEntities(
|
||||
GaugeEntityList *destination,
|
||||
Derivation *derivation_type
|
||||
)
|
||||
{
|
||||
Test_Tell("GaugeEntityList::CopyEntities(" << destination << ")\n");
|
||||
Check(this);
|
||||
Check(destination);
|
||||
|
||||
ChainIteratorOf<Entity*>
|
||||
i(instanceList);
|
||||
Entity
|
||||
*entity;
|
||||
int
|
||||
count(0);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Return all items in the list
|
||||
//-----------------------------------------------------
|
||||
while ((entity=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(entity);
|
||||
//-----------------------------------------------------
|
||||
// Discard if wrong type
|
||||
//-----------------------------------------------------
|
||||
if (derivation_type != NULL)
|
||||
{
|
||||
if (! entity->IsDerivedFrom(*derivation_type))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------
|
||||
// Add to the new list
|
||||
//-----------------------------------------------------
|
||||
destination->Add(entity);
|
||||
++count;
|
||||
}
|
||||
Test_Tell("Found " << count << " items.\n");
|
||||
Check_Fpu();
|
||||
return count;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// CopyEntitiesWithinBounds
|
||||
//
|
||||
// This method will create a reference in the destination list to
|
||||
// all entities in the list that are within the given bounds (if supplied).
|
||||
//============================================================================
|
||||
int
|
||||
GaugeEntityList::CopyEntitiesWithinBounds(
|
||||
GaugeEntityList *destination,
|
||||
Scalar min_x,
|
||||
Scalar /*min_y*/,
|
||||
Scalar min_z,
|
||||
Scalar max_x,
|
||||
Scalar /*max_y*/,
|
||||
Scalar max_z,
|
||||
Derivation *derivation_type
|
||||
)
|
||||
{
|
||||
Test_Tell(
|
||||
"GaugeEntityList::CopyEntitiesWithinBounds(" << destination <<
|
||||
", " << min_x <<
|
||||
"... , " << min_z <<
|
||||
", " << max_x <<
|
||||
"... , " << max_z <<
|
||||
")\n"
|
||||
);
|
||||
Check(this);
|
||||
Check(destination);
|
||||
|
||||
ChainIteratorOf<Entity*>
|
||||
i(instanceList);
|
||||
|
||||
Entity
|
||||
*entity;
|
||||
|
||||
Point3D
|
||||
pos;
|
||||
|
||||
int
|
||||
count(0);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Check all items in the list
|
||||
//-----------------------------------------------------
|
||||
while ((entity=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(entity);
|
||||
//-----------------------------------------------------
|
||||
// Discard if wrong type
|
||||
//-----------------------------------------------------
|
||||
if (derivation_type != NULL)
|
||||
{
|
||||
if (! entity->IsDerivedFrom(*derivation_type))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------
|
||||
// Get the item's position and radius
|
||||
//-----------------------------------------------------
|
||||
pos = entity->localOrigin.linearPosition;
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Add to the new list only if inside the bounds
|
||||
//-----------------------------------------------------
|
||||
Test_Tell(
|
||||
"Testing (" << pos.x <<
|
||||
", " << pos.y <<
|
||||
", " << pos.z <<
|
||||
")\n"
|
||||
);
|
||||
//if (pos.z >= min_z)
|
||||
//{
|
||||
// if (pos.z <= max_z)
|
||||
// {
|
||||
// if (pos.x >= min_x)
|
||||
// {
|
||||
// if (pos.x <= max_x)
|
||||
{
|
||||
Test_Tell("Accepted\n");
|
||||
destination->Add(entity);
|
||||
++count;
|
||||
}
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
Test_Tell("Found " << count << " items.\n");
|
||||
Check_Fpu();
|
||||
return count;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
// GaugeEntityArray
|
||||
//#############################################################################
|
||||
|
||||
//============================================================================
|
||||
// Creator
|
||||
//============================================================================
|
||||
GaugeEntityArray::GaugeEntityArray()
|
||||
{
|
||||
minimumX= 0.0;
|
||||
minimumY= 0.0;
|
||||
minimumZ= 0.0;
|
||||
maximumX= 0.0;
|
||||
maximumY= 0.0;
|
||||
maximumZ= 0.0;
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Destructor
|
||||
//============================================================================
|
||||
GaugeEntityArray::~GaugeEntityArray()
|
||||
{
|
||||
Check(this);
|
||||
Clear();
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// TestInstance
|
||||
//============================================================================
|
||||
Logical
|
||||
GaugeEntityArray::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Add
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityArray::Add(Entity *entity)
|
||||
{
|
||||
Test_Tell(
|
||||
"GaugeEntityArray::Add(" << entity <<
|
||||
")\n"
|
||||
);
|
||||
Check(this);
|
||||
Check(entity);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Add to the proper grid list
|
||||
//-----------------------------------------------------
|
||||
Point3D
|
||||
pos(entity->localOrigin.linearPosition);
|
||||
|
||||
grid[ArrayOffset(pos.x)][ArrayOffset(pos.z)].Add(entity);
|
||||
//-----------------------------------------------------
|
||||
// Keep track of the total extents
|
||||
//-----------------------------------------------------
|
||||
if (pos.x < minimumX)
|
||||
{
|
||||
minimumX = pos.x;
|
||||
}
|
||||
if (pos.y < minimumY)
|
||||
{
|
||||
minimumY = pos.y;
|
||||
}
|
||||
if (pos.z < minimumZ)
|
||||
{
|
||||
minimumZ = pos.z;
|
||||
}
|
||||
if (pos.x > maximumX)
|
||||
{
|
||||
maximumX = pos.x;
|
||||
}
|
||||
if (pos.y > maximumY)
|
||||
{
|
||||
maximumY = pos.y;
|
||||
}
|
||||
if (pos.z > maximumZ)
|
||||
{
|
||||
maximumZ = pos.z;
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Remove
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityArray::Remove(Entity *entity)
|
||||
{
|
||||
Test_Tell(
|
||||
"GaugeEntityArray::Remove(" << entity <<
|
||||
")\n"
|
||||
);
|
||||
Check(this);
|
||||
Check(entity);
|
||||
|
||||
Point3D
|
||||
pos(entity->localOrigin.linearPosition);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Remove from the proper grid list
|
||||
//-----------------------------------------------------
|
||||
grid[ArrayOffset(pos.x)][ArrayOffset(pos.z)].Remove(entity);
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// Clear
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityArray::Clear()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
int
|
||||
x,
|
||||
z;
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Clear all grid lists
|
||||
//-----------------------------------------------------
|
||||
for(z=0; z<gaugeMapArraySize; ++z)
|
||||
{
|
||||
for(x=0; x<gaugeMapArraySize; ++x)
|
||||
{
|
||||
grid[x][z].Clear();
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------
|
||||
// Set the bounds to zero
|
||||
//-----------------------------------------------------
|
||||
minimumX= 0.0;
|
||||
minimumY= 0.0;
|
||||
minimumZ= 0.0;
|
||||
maximumX= 0.0;
|
||||
maximumY= 0.0;
|
||||
maximumZ= 0.0;
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// PrintStatistics
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityArray::PrintStatistics()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
int
|
||||
x,
|
||||
z,
|
||||
n,
|
||||
total(0);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Count all grid lists
|
||||
//-----------------------------------------------------
|
||||
for(z=0; z<gaugeMapArraySize; ++z)
|
||||
{
|
||||
if (z < 10)
|
||||
{
|
||||
cout << " ";
|
||||
}
|
||||
cout << z << ":";
|
||||
for(x=0; x<gaugeMapArraySize; ++x)
|
||||
{
|
||||
n = grid[x][z].NumberOfItems();
|
||||
total += n;
|
||||
if (n < 100)
|
||||
{
|
||||
cout << " ";
|
||||
if (n < 10)
|
||||
{
|
||||
cout << " ";
|
||||
}
|
||||
}
|
||||
cout << n << " ";
|
||||
}
|
||||
cout << "\n";
|
||||
}
|
||||
cout << "Total= " << total << "\n";
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// CopyEntities
|
||||
//
|
||||
// This method will create a reference in the destination list to
|
||||
// all GaugeImages in the array.
|
||||
//============================================================================
|
||||
int
|
||||
GaugeEntityArray::CopyEntities(
|
||||
GaugeEntityList *destination,
|
||||
Derivation *derivation_type
|
||||
)
|
||||
{
|
||||
Test_Tell(
|
||||
"GaugeEntityArray::CopyEntities(" << destination << ")\n");
|
||||
Check(this);
|
||||
Check(destination);
|
||||
|
||||
int
|
||||
x,
|
||||
low_x,
|
||||
high_x,
|
||||
z,
|
||||
high_z,
|
||||
count(0);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Generate the z search limits
|
||||
//-----------------------------------------------------
|
||||
z = 0;
|
||||
high_z = gaugeMapArraySize - 1;
|
||||
//-----------------------------------------------------
|
||||
// Generate the x search limits
|
||||
//-----------------------------------------------------
|
||||
low_x = 0;
|
||||
high_x = gaugeMapArraySize - 1;
|
||||
|
||||
//-------------------------------------------------------
|
||||
// Search the grid for items
|
||||
//-------------------------------------------------------
|
||||
for( ; z<high_z; ++z)
|
||||
{
|
||||
for(x=low_x; x<high_x; ++x)
|
||||
{
|
||||
Test_Tell("Searching [" << x << "][" << z << "]\n");
|
||||
count += grid[x][z].CopyEntities(destination, derivation_type);
|
||||
}
|
||||
}
|
||||
Test_Tell("Search done, total found = " << count << " items.\n");
|
||||
Check_Fpu();
|
||||
return count;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// CopyEntitiesWithinBounds
|
||||
//
|
||||
// This method will create a reference in the destination list to
|
||||
// all GaugeImages in the array that are within the given bounds.
|
||||
//============================================================================
|
||||
int
|
||||
GaugeEntityArray::CopyEntitiesWithinBounds(
|
||||
GaugeEntityList *destination,
|
||||
Scalar min_x,
|
||||
Scalar min_y,
|
||||
Scalar min_z,
|
||||
Scalar max_x,
|
||||
Scalar max_y,
|
||||
Scalar max_z,
|
||||
Derivation *derivation_type
|
||||
)
|
||||
{
|
||||
Test_Tell(
|
||||
"GaugeEntityArray::CopyEntitiesWithinBounds(" << destination <<
|
||||
", " << min_x <<
|
||||
", " << min_y <<
|
||||
", " << min_z <<
|
||||
", " << max_x <<
|
||||
", " << max_y <<
|
||||
", " << max_z <<
|
||||
")\n"
|
||||
);
|
||||
Check(this);
|
||||
Check(destination);
|
||||
|
||||
int
|
||||
x,
|
||||
low_x,
|
||||
high_x,
|
||||
z,
|
||||
high_z,
|
||||
count(0);
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Generate the z search limits
|
||||
//-----------------------------------------------------
|
||||
z = ArrayOffset(min_z - LARGEST_RADIUS);
|
||||
high_z = ArrayOffset(max_z + LARGEST_RADIUS);
|
||||
|
||||
Test_Tell(
|
||||
"Initial z =" << z <<
|
||||
", high_z=" << high_z <<
|
||||
"\n"
|
||||
);
|
||||
if (z < 0)
|
||||
{
|
||||
z = 0;
|
||||
}
|
||||
else if (z >= gaugeMapArraySize)
|
||||
{
|
||||
z = gaugeMapArraySize - 1;
|
||||
}
|
||||
if (high_z < 0)
|
||||
{
|
||||
high_z = 0;
|
||||
}
|
||||
else if (high_z >= gaugeMapArraySize)
|
||||
{
|
||||
high_z = gaugeMapArraySize - 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Generate the x search limits
|
||||
//-----------------------------------------------------
|
||||
low_x = ArrayOffset(min_x - LARGEST_RADIUS);
|
||||
high_x = ArrayOffset(max_x + LARGEST_RADIUS);
|
||||
|
||||
if (low_x < 0)
|
||||
{
|
||||
low_x = 0;
|
||||
}
|
||||
else if (low_x >= gaugeMapArraySize)
|
||||
{
|
||||
low_x = gaugeMapArraySize - 1;
|
||||
}
|
||||
if (high_x < 0)
|
||||
{
|
||||
high_x = 0;
|
||||
}
|
||||
else if (high_x >= gaugeMapArraySize)
|
||||
{
|
||||
high_x = gaugeMapArraySize - 1;
|
||||
}
|
||||
|
||||
Test_Tell("Search x=(" << low_x << "..." << high_x << ")\n");
|
||||
Test_Tell("Search z=(" << z << "..." << high_z << ")\n");
|
||||
//-------------------------------------------------------
|
||||
// Search the (limited) grid for items within the bounds
|
||||
//-------------------------------------------------------
|
||||
for( ; z<high_z; ++z)
|
||||
{
|
||||
for(x=low_x; x<high_x; ++x)
|
||||
{
|
||||
Test_Tell("Searching [" << x << "][" << z << "]\n");
|
||||
count += grid[x][z].CopyEntitiesWithinBounds(
|
||||
destination,
|
||||
min_x,
|
||||
min_y,
|
||||
min_z,
|
||||
max_x,
|
||||
max_y,
|
||||
max_z,
|
||||
derivation_type
|
||||
);
|
||||
}
|
||||
}
|
||||
Test_Tell("Search done, total found = " << count << " items.\n");
|
||||
Check_Fpu();
|
||||
return count;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// GetBounds
|
||||
//============================================================================
|
||||
void
|
||||
GaugeEntityArray::GetBounds(
|
||||
Scalar *min_x,
|
||||
Scalar *min_y,
|
||||
Scalar *min_z,
|
||||
Scalar *max_x,
|
||||
Scalar *max_y,
|
||||
Scalar *max_z
|
||||
)
|
||||
{
|
||||
*min_x = minimumX;
|
||||
*min_y = minimumY;
|
||||
*min_z = minimumZ;
|
||||
*max_x = maximumX;
|
||||
*max_y = maximumY;
|
||||
*max_z = maximumZ;
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
// ArrayOffset - generate offset into array based on position value
|
||||
//============================================================================
|
||||
int
|
||||
GaugeEntityArray::ArrayOffset(Scalar n)
|
||||
{
|
||||
int q;
|
||||
|
||||
q = (int)(gaugeMapArraySize*(n/HALF_EXTENT)+.5)+(gaugeMapArraySize>>1);
|
||||
|
||||
if (q < 0)
|
||||
{
|
||||
q = 0;
|
||||
}
|
||||
if (q >= gaugeMapArraySize)
|
||||
{
|
||||
q = (gaugeMapArraySize-1);
|
||||
}
|
||||
|
||||
Check_Fpu();
|
||||
return q;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,44 +1,440 @@
|
||||
//===========================================================================//
|
||||
// File: network.cpp //
|
||||
// Project: MUNGA Brick: Network //
|
||||
// Contents: Implementation details for network clients //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
|
||||
#include <munga.hpp>
|
||||
#pragma hdrstop
|
||||
|
||||
#if !defined(NETWORK_HPP)
|
||||
# include <network.hpp>
|
||||
#endif
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Derivation
|
||||
NetworkClient::ClassDerivations(
|
||||
Receiver::ClassDerivations,
|
||||
"NetworkClient"
|
||||
);
|
||||
|
||||
NetworkClient::SharedData
|
||||
NetworkClient::DefaultData(
|
||||
NetworkClient::ClassDerivations,
|
||||
Receiver::MessageHandlers
|
||||
);
|
||||
|
||||
Derivation
|
||||
NetworkManager::ClassDerivations(
|
||||
NetworkClient::ClassDerivations,
|
||||
"NetworkManager"
|
||||
);
|
||||
|
||||
NetworkManager::SharedData
|
||||
NetworkManager::DefaultData(
|
||||
NetworkManager::ClassDerivations,
|
||||
Receiver::MessageHandlers
|
||||
);
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(HOSTMGR_HPP)
|
||||
# include <hostmgr.hpp>
|
||||
# endif
|
||||
# if !defined(INTEREST_HPP)
|
||||
# include <interest.hpp>
|
||||
# endif
|
||||
# if !defined(ICOM_HPP)
|
||||
# include <icom.hpp>
|
||||
# endif
|
||||
# if !defined(APP_HPP)
|
||||
# include <app.hpp>
|
||||
# endif
|
||||
# if !defined(NOTATION_HPP)
|
||||
# include <notation.hpp>
|
||||
# endif
|
||||
# if !defined(NTTMGR_HPP)
|
||||
# include <nttmgr.hpp>
|
||||
# endif
|
||||
|
||||
#if defined(TRACE_ROUTE_PACKET)
|
||||
static BitTrace Route_Packet("Route Packet");
|
||||
# define SET_ROUTE_PACKET() Route_Packet.Set()
|
||||
# define CLEAR_ROUTE_PACKET() Route_Packet.Clear()
|
||||
#else
|
||||
# define SET_ROUTE_PACKET()
|
||||
# define CLEAR_ROUTE_PACKET()
|
||||
#endif
|
||||
|
||||
const NetworkAddress NullNetworkAddress = 0x00000000;// 0.0.0.0 (in TCP land);
|
||||
|
||||
//#############################################################################
|
||||
// Shared Data Support
|
||||
//
|
||||
NetworkClient::SharedData
|
||||
NetworkClient::DefaultData(
|
||||
NetworkClient::ClassDerivations,
|
||||
NetworkClient::MessageHandlers
|
||||
);
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// Code for the network client class
|
||||
//#############################################################################
|
||||
//
|
||||
Derivation
|
||||
NetworkClient::ClassDerivations(Receiver::ClassDerivations, "NetworkClient");
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Constructor for the NetworkClient
|
||||
//
|
||||
NetworkClient::NetworkClient(
|
||||
ClassID class_ID,
|
||||
SharedData &virtual_data,
|
||||
ClientID client_ID
|
||||
):
|
||||
Receiver(class_ID, virtual_data)
|
||||
{
|
||||
clientID = client_ID;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Destructor for the NetworkClient
|
||||
//
|
||||
NetworkClient::~NetworkClient()
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Destructor for the NetworkClient
|
||||
//
|
||||
Logical
|
||||
NetworkClient::TestInstance() const
|
||||
{
|
||||
return IsDerivedFrom(ClassDerivations);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Receive packet for the NetworkClient
|
||||
//
|
||||
void
|
||||
NetworkClient::ReceiveNetworkPacket(
|
||||
NetworkPacket*,
|
||||
Receiver::Message *packet_message
|
||||
)
|
||||
{
|
||||
Dispatch(packet_message);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// Code for the network manager class
|
||||
//#############################################################################
|
||||
|
||||
const Receiver::HandlerEntry
|
||||
NetworkManager::MessageHandlerEntries[]=
|
||||
{
|
||||
MESSAGE_ENTRY(NetworkManager,ReceiveEggFile)
|
||||
};
|
||||
|
||||
NetworkManager::MessageHandlerSet
|
||||
NetworkManager::MessageHandlers(ELEMENTS(NetworkManager::MessageHandlerEntries), NetworkManager::MessageHandlerEntries, NetworkClient::MessageHandlers);
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Shared Data Support
|
||||
//
|
||||
NetworkManager::SharedData
|
||||
NetworkManager::DefaultData(
|
||||
NetworkManager::ClassDerivations,
|
||||
NetworkManager::MessageHandlers
|
||||
);
|
||||
|
||||
Derivation
|
||||
NetworkManager::ClassDerivations(NetworkClient::ClassDerivations, "NetworkManager");
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Constructor for the NetworkManager
|
||||
//
|
||||
NetworkManager::NetworkManager(SharedData &shared_data):
|
||||
NetworkClient(NetworkManagerClassID, shared_data, NetworkManagerClientID)
|
||||
{
|
||||
// basic init goes here
|
||||
gameID = 0;
|
||||
eggTempBuffer = NULL;
|
||||
networkEggNotationFile = NULL;
|
||||
eggTempNext = 0;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Creates a host for us. Any derived class must deal with reading the
|
||||
// notation file to get the network nodes to connect to. This start is
|
||||
// designed for STAND-ALONE MODE ONLY and should not be inherited for use by
|
||||
//
|
||||
void
|
||||
NetworkManager::StartConnecting(Mission *)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
//
|
||||
//---------------------------------------------------------
|
||||
// Make the local host, and get the application to adopt it
|
||||
//---------------------------------------------------------
|
||||
//
|
||||
Host *local_host = new Host(1, GameMachineHostType, 1);
|
||||
Register_Object(local_host);
|
||||
|
||||
Check(application);
|
||||
Check(application->GetHostManager());
|
||||
application->GetHostManager()->AdoptLocalHost(local_host);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
// Now, since this host creator is for stand-alone mode, send the load
|
||||
// mission message to the application
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
Check(application);
|
||||
Application::Message
|
||||
load_message(
|
||||
Application::LoadMissionMessageID,
|
||||
sizeof(Application::Message)
|
||||
);
|
||||
application->Post(DefaultEventPriority, application, &load_message);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::EndMission This routine is called when a mission ends to
|
||||
// allow the network management system to do stuff (like disconnecting network
|
||||
// connections between pods and so on)
|
||||
//
|
||||
Logical
|
||||
NetworkManager::Shutdown()
|
||||
{
|
||||
//
|
||||
// If there is a notation file floating about, kill it!
|
||||
//
|
||||
if (networkEggNotationFile)
|
||||
{
|
||||
Unregister_Object(networkEggNotationFile);
|
||||
delete networkEggNotationFile;
|
||||
}
|
||||
|
||||
//
|
||||
// Deregister local host
|
||||
//
|
||||
Host *local_host;
|
||||
|
||||
local_host = application->GetHostManager()->OrphanLocalHost();
|
||||
Unregister_Object(local_host);
|
||||
delete local_host;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Destructor for the NetworkManager
|
||||
//
|
||||
NetworkManager::~NetworkManager()
|
||||
{
|
||||
// shutdown net goes here
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::ReceiveEggFileMessageHandler
|
||||
//
|
||||
void
|
||||
NetworkManager::ReceiveEggFileMessageHandler(
|
||||
ReceiveEggFileMessage* EggMessage
|
||||
)
|
||||
{
|
||||
//
|
||||
// An egg sequence number of -1 means that the egg is posted locally, and
|
||||
// should just call create mission
|
||||
//
|
||||
if (EggMessage->sequenceNumber == -1)
|
||||
{
|
||||
application->CreateMission(networkEggNotationFile);
|
||||
return;
|
||||
}
|
||||
|
||||
if (EggMessage->sequenceNumber == 0)
|
||||
{
|
||||
//
|
||||
// Make a buffer
|
||||
//
|
||||
eggTempBuffer = new char[EggMessage->notationFileLength];
|
||||
Register_Pointer(eggTempBuffer);
|
||||
eggTempNext = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Write the egg data into the buffer
|
||||
//
|
||||
memcpy(
|
||||
(eggTempBuffer+eggTempNext),
|
||||
EggMessage->notationData,
|
||||
EggMessage->thisMessageLength
|
||||
);
|
||||
eggTempNext += EggMessage->thisMessageLength;
|
||||
|
||||
//
|
||||
// If we don't have all the data, return and wait for more
|
||||
//
|
||||
if(eggTempNext < EggMessage->notationFileLength)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// We've got all the data, make the notation file
|
||||
//
|
||||
networkEggNotationFile = new NotationFile();
|
||||
Register_Object(networkEggNotationFile);
|
||||
networkEggNotationFile->ReadText(eggTempBuffer, eggTempNext);
|
||||
networkEggNotationFile->WriteFile("last.egg");
|
||||
|
||||
//
|
||||
// Now turn the notation file into a mission
|
||||
//
|
||||
application->CreateMission(networkEggNotationFile);
|
||||
|
||||
//
|
||||
// Get rid of the ram buffer now that we're done with it
|
||||
//
|
||||
Unregister_Pointer(eggTempBuffer);
|
||||
delete eggTempBuffer;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::Send Handles sending a message to a specific network address
|
||||
// which can NOT be us. Default behavior is to do nothing, as no network is
|
||||
// hooked up if we get here
|
||||
//
|
||||
void
|
||||
NetworkManager::Send(
|
||||
Message *,
|
||||
ClientID,
|
||||
HostID
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::Broadcast Handles broadcasting a message to everyone,
|
||||
// including ourselves. !!!! Reliable broadcasting is currently used,
|
||||
// implimented by sending a point-to-point message to every destination.
|
||||
//
|
||||
void
|
||||
NetworkManager::Broadcast(
|
||||
Message *message,
|
||||
ClientID client_id
|
||||
)
|
||||
{
|
||||
//
|
||||
// Send this message back to ourselves
|
||||
//
|
||||
NetworkClient *client = GetNetworkClientPointer(client_id);
|
||||
Check(client);
|
||||
client->ReceiveNetworkPacket(NULL, message);
|
||||
|
||||
//
|
||||
// Broadcast the message to everyone else on the network
|
||||
//
|
||||
ExclusiveBroadcast(message,client_id);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::ExclusiveBroadcast Broadcasts a message to everyone on the
|
||||
// network execpt us. Default behavior sends it to nobody, as there is really
|
||||
// no network
|
||||
//
|
||||
void
|
||||
NetworkManager::ExclusiveBroadcast(
|
||||
Message *,
|
||||
ClientID
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::GetNetworkClientPointer Determine who the client of a
|
||||
// message is and return a pointer to them.
|
||||
//
|
||||
NetworkClient*
|
||||
NetworkManager::GetNetworkClientPointer(ClientID client_id)
|
||||
{
|
||||
switch (client_id)
|
||||
{
|
||||
case NetworkClient::NetworkManagerClientID:
|
||||
return this;
|
||||
|
||||
case NetworkClient::EntityManagerClientID:
|
||||
Check(application);
|
||||
return application->GetEntityManager();
|
||||
|
||||
case NetworkClient::HostManagerClientID:
|
||||
Check(application);
|
||||
return application->GetHostManager();
|
||||
|
||||
case NetworkClient::InterestManagerClientID:
|
||||
Check(application);
|
||||
return application->GetInterestManager();
|
||||
|
||||
case NetworkClient::IcomManagerClientID:
|
||||
Check(application);
|
||||
return application->GetIntercomManager();
|
||||
|
||||
case NetworkClient::ApplicationClientID:
|
||||
Check(application);
|
||||
return application;
|
||||
|
||||
default:
|
||||
DEBUG_STREAM << "------UNKNOWN NETWORK CLIENT ID " << client_id << endl << flush;
|
||||
Fail("Unknown Client ID");
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::RoutePacket
|
||||
//
|
||||
Logical
|
||||
NetworkManager::RoutePacket()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
Byte
|
||||
message_buffer[NETWORKMANAGER_BUFFER_SIZE];
|
||||
NetworkPacket
|
||||
*p;
|
||||
|
||||
//
|
||||
// Return if check buffers doesn't have a packet for us
|
||||
//
|
||||
if (!CheckBuffers((NetworkPacket*)message_buffer))
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
//
|
||||
// Process and route the packet properly
|
||||
//
|
||||
p = (NetworkPacket*)message_buffer;
|
||||
|
||||
if (p->gameID == gameID)
|
||||
{
|
||||
// cout<<"++++++++client "<<p->clientID<<" gameID "<<p->gameID<<" fromHost "<<p->fromHost<<"\n";
|
||||
NetworkClient *client = GetNetworkClientPointer(p->clientID);
|
||||
|
||||
Check(client);
|
||||
SET_ROUTE_PACKET();
|
||||
client->ReceiveNetworkPacket(p, &p->messageData);
|
||||
CLEAR_ROUTE_PACKET();
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_STREAM << "+++++++++ client " << p->clientID << " gameID " << p->gameID << " fromHost " << p->fromHost << endl << flush;
|
||||
Fail("######### NOT A PACKET FOR THIS GAME!");
|
||||
}
|
||||
|
||||
RemovePacket(p);
|
||||
return True;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::ExecuteBackground Allows the network to perform tasks in
|
||||
// the applications background. The method should return True if the manager
|
||||
// is busy, False otherwise. For example, if the input and output buffers of
|
||||
// the network driver are not empty then return True, otherwise return False.
|
||||
//
|
||||
Logical
|
||||
NetworkManager::ExecuteBackground()
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::CheckBuffers Checks to see if there is a message for us
|
||||
// buffered up in the network interface card and returns a pointer to it.
|
||||
//
|
||||
Logical
|
||||
NetworkManager::CheckBuffers(NetworkPacket*)
|
||||
{
|
||||
Fail("NetworkManager::CheckBuffers - should never reach here!");
|
||||
return False;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// NetworkManager::RemovePacket If the network implimentation requires us to
|
||||
// free up a packet buffer, this routine would do it.
|
||||
//
|
||||
void
|
||||
NetworkManager::RemovePacket(NetworkPacket*)
|
||||
{
|
||||
Fail("NetworkManager::RemovePacket - should never reach here!");
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,176 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(RAY_HPP)
|
||||
# include <ray.hpp>
|
||||
# endif
|
||||
# if !defined(PLANE_HPP)
|
||||
# include <plane.hpp>
|
||||
# endif
|
||||
# if !defined(SPHERE_HPP)
|
||||
# include <sphere.hpp>
|
||||
# endif
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void Ray::Project(Scalar length, Point3D *result)
|
||||
{
|
||||
Check(this);
|
||||
Check(result);
|
||||
|
||||
Vector3D temp;
|
||||
|
||||
temp.Multiply(direction,length);
|
||||
result->Add(origin,temp);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Scalar Ray::LengthToClosestPointTo(const Point3D &point)
|
||||
{
|
||||
Check(this);
|
||||
Check(&point);
|
||||
|
||||
Vector3D temp;
|
||||
|
||||
temp.Subtract(point,origin);
|
||||
return temp*direction;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Scalar Ray::DistanceTo(const Plane &plane, Scalar *product) const
|
||||
{
|
||||
Scalar t;
|
||||
|
||||
//
|
||||
//------------------------------------------------------------------
|
||||
// Compute the dot product of the ray and plane normal, and find the
|
||||
// distance from the origin of the ray to the plane
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
*product = plane.normal * direction;
|
||||
t = plane.DistanceTo(origin);
|
||||
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
// If the ray is not parallel to the plane, determine how far to proceed
|
||||
// along the ray until we hit the plane
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
if (!Small_Enough(*product))
|
||||
t /= -*product;
|
||||
return t;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Scalar Ray::DistanceTo(const Sphere &sphere, Scalar *penetration) const
|
||||
{
|
||||
Scalar b, c;
|
||||
Vector3D temp;
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// Set up to solve a quadratic equation for the intersection of the ray and
|
||||
// sphere. The solution is based on finding the closest point on the line
|
||||
// to the sphere, and then calculating the interval between the entry and
|
||||
// exit points of the ray
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
temp.Subtract(origin,sphere.center);
|
||||
b = 2.0f * (direction * temp);
|
||||
c = temp.LengthSquared() - sphere.radius*sphere.radius;
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Compute the squared interval to use for the solution. If it is negative,
|
||||
// then the ray misses the sphere
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
*penetration = b*b - 4.0f*c;
|
||||
if (*penetration<SMALL)
|
||||
return 0.0f;
|
||||
else
|
||||
{
|
||||
//-------------------------------------------------------------------------
|
||||
// Otherwise, find the linear distance along the line of the entry point by
|
||||
// subtracting half the interval between entry and exit points from the
|
||||
// distance to the closest point on the sphere
|
||||
//-------------------------------------------------------------------------
|
||||
*penetration = Sqrt(*penetration);
|
||||
return -0.5f*(b+*penetration);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Logical Ray::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Scalar Find_Closest_Approach(const Point3D& origin1, const Vector3D& velocity1, Point3D *result1, const Point3D& origin2, const Vector3D& velocity2, Point3D *result2, Scalar *time, Logical *constant)
|
||||
{
|
||||
Vector3D a,b;
|
||||
a.Subtract(origin1, origin2);
|
||||
b.Subtract(velocity1, velocity2);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
// If the velocities are identical, any point will do for the test, so
|
||||
// simply return the difference between the starting points
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
Scalar d = b.LengthSquared();
|
||||
if (Small_Enough(d))
|
||||
{
|
||||
*constant = True;
|
||||
d = a.Length();
|
||||
Check_Fpu();
|
||||
return d;
|
||||
}
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// The velocities are not parallel, so figure out when the closest approach
|
||||
// is via the derivative
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
*constant = False;
|
||||
*time = (a * b) / -d;
|
||||
Check_Fpu();
|
||||
|
||||
//
|
||||
//------------------------------------------------------
|
||||
// Now, plot the resultant points of both line equations
|
||||
//------------------------------------------------------
|
||||
//
|
||||
Vector3D closest;
|
||||
closest.AddScaled(a, b, *time);
|
||||
result1->AddScaled(origin1, velocity1, *time);
|
||||
result2->AddScaled(origin2, velocity2, *time);
|
||||
d = closest.Length();
|
||||
Check_Fpu();
|
||||
return d;
|
||||
}
|
||||
|
||||
#if defined(TEST_CLASS)
|
||||
# include "ray.tcp"
|
||||
#endif
|
||||
@@ -0,0 +1,916 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(RESOURCE_HPP)
|
||||
# include <resource.hpp>
|
||||
# endif
|
||||
# if !defined(RESVER_HPP)
|
||||
# include <resver.hpp>
|
||||
# endif
|
||||
|
||||
ResourceDescription::ResourceDescription(
|
||||
ResourceFile *file,
|
||||
const char* name,
|
||||
ResourceDescription::ResourceType type,
|
||||
int priority,
|
||||
LWord flags,
|
||||
const void* address,
|
||||
size_t size,
|
||||
ResourceDescription::ResourceID index
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check_Pointer(name);
|
||||
|
||||
resourceFile = file;
|
||||
resourceID = index;
|
||||
resourceType = type;
|
||||
Str_Copy(resourceName, name, sizeof(resourceName));
|
||||
for (int i = strlen(resourceName) + 1; i<sizeof(resourceName); ++i)
|
||||
{
|
||||
resourceName[i] = '\0';
|
||||
}
|
||||
|
||||
downloadPriority = priority;
|
||||
resourceFlags = flags;
|
||||
offsetInFile = 0;
|
||||
resourceSize = size;
|
||||
resourceAddress = NULL;
|
||||
lockCount = 0;
|
||||
|
||||
if (address)
|
||||
{
|
||||
Check_Pointer(address);
|
||||
resourceAddress = new char[resourceSize];
|
||||
Register_Pointer(resourceAddress);
|
||||
Mem_Copy(resourceAddress, address, resourceSize, resourceSize);
|
||||
SetLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription::~ResourceDescription()
|
||||
{
|
||||
Check(this);
|
||||
// Verify(!IsLocked());
|
||||
if (resourceAddress)
|
||||
{
|
||||
Unregister_Pointer(resourceAddress);
|
||||
delete[] resourceAddress;
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ResourceDescription::ReleaseUnlockedResource()
|
||||
{
|
||||
Check(this);
|
||||
if (!IsLocked())
|
||||
{
|
||||
if (IsLoaded())
|
||||
{
|
||||
SetNotLoaded();
|
||||
Verify(resourceAddress);
|
||||
Unregister_Pointer(resourceAddress);
|
||||
delete[] resourceAddress;
|
||||
resourceAddress = NULL;
|
||||
}
|
||||
Verify(!resourceAddress);
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ResourceDescription::LoadResource()
|
||||
{
|
||||
Check(this);
|
||||
if (!IsLoaded())
|
||||
{
|
||||
Verify(!resourceAddress);
|
||||
Check(resourceFile);
|
||||
resourceFile->LoadResource(this);
|
||||
Verify(resourceAddress);
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
ResourceDescription::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//########################## ResourceFile ###############################
|
||||
//#############################################################################
|
||||
|
||||
//#############################################################################
|
||||
// ResourceFile CONSTRUCTORS & DESTRUCTORS
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceFile::ResourceFile():
|
||||
labOnly(0),
|
||||
resourceArray(NULL),
|
||||
resourceArraySize(0),
|
||||
maxResourceID(ResourceDescription::NullResourceID),
|
||||
lastPreallocatedResourceID(ResourceDescription::NullResourceID)
|
||||
{
|
||||
versionArray[0] = RESOURCE_FORMAT_VERSION;
|
||||
versionArray[1] = 0;
|
||||
versionArray[2] = 0;
|
||||
versionArray[3] = 0;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceFile::~ResourceFile()
|
||||
{
|
||||
if (resourceArray)
|
||||
{
|
||||
for (int i=maxResourceID; i>=0; i--)
|
||||
{
|
||||
if (resourceArray[i])
|
||||
{
|
||||
Unregister_Object(resourceArray[i]);
|
||||
delete resourceArray[i];
|
||||
}
|
||||
}
|
||||
Unregister_Pointer(resourceArray);
|
||||
delete[] resourceArray;
|
||||
}
|
||||
|
||||
versionArray[0] = RESOURCE_FORMAT_VERSION;
|
||||
versionArray[1] = 0;
|
||||
versionArray[2] = 0;
|
||||
versionArray[3] = 0;
|
||||
labOnly = 0;
|
||||
resourceArraySize = 0;
|
||||
maxResourceID = ResourceDescription::NullResourceID;
|
||||
resourceArray = NULL;
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
// ResourceFile METHODS
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::AddResource(
|
||||
const char* name,
|
||||
ResourceDescription::ResourceType type,
|
||||
int priority,
|
||||
LWord load_flag,
|
||||
const void* address,
|
||||
size_t size,
|
||||
ResourceDescription::ResourceID index
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check_Pointer(name);
|
||||
|
||||
int i;
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// If we asked for the next available ID number, find out what it should be
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
if (index == ResourceDescription::NullResourceID)
|
||||
{
|
||||
index = lastPreallocatedResourceID + 1;
|
||||
if (resourceArray)
|
||||
{
|
||||
Check_Pointer(resourceArray);
|
||||
for (; index<=resourceArraySize; ++index)
|
||||
{
|
||||
if (!resourceArray[index])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------
|
||||
// Check to see if the resource index table needs to be created
|
||||
//-------------------------------------------------------------
|
||||
//
|
||||
if (!resourceArray)
|
||||
{
|
||||
resourceArraySize = index + IndexBlockSize;
|
||||
resourceArray = new ResourceDescription* [resourceArraySize];
|
||||
Register_Pointer(resourceArray);
|
||||
for (i=0; i<resourceArraySize; ++i)
|
||||
{
|
||||
resourceArray[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//-----------------------------------------------------------
|
||||
// Otherwise, check to see if we have to grow the index table
|
||||
//-----------------------------------------------------------
|
||||
//
|
||||
if (index >= resourceArraySize)
|
||||
{
|
||||
//
|
||||
//----------------------------------------
|
||||
// Allocate a new table for the main index
|
||||
//----------------------------------------
|
||||
//
|
||||
ResourceDescription **new_index =
|
||||
new ResourceDescription* [index + IndexBlockSize];
|
||||
Register_Pointer(new_index);
|
||||
|
||||
//
|
||||
//------------------------------------
|
||||
// Copy the old table into the new one
|
||||
//------------------------------------
|
||||
//
|
||||
Check_Pointer(resourceArray);
|
||||
for (i=0; i<resourceArraySize; ++i)
|
||||
{
|
||||
new_index[i] = resourceArray[i];
|
||||
}
|
||||
|
||||
//
|
||||
//---------------------
|
||||
// Delete the old table
|
||||
//---------------------
|
||||
//
|
||||
Unregister_Pointer(resourceArray);
|
||||
delete[] resourceArray;
|
||||
resourceArray = new_index;
|
||||
resourceArraySize = index + IndexBlockSize;
|
||||
|
||||
//
|
||||
//----------------------------------
|
||||
// NULL the new entries in the table
|
||||
//----------------------------------
|
||||
//
|
||||
while (i<resourceArraySize)
|
||||
{
|
||||
resourceArray[i++] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//-----------------------------------------------
|
||||
// Add the new resource in at the specified index
|
||||
//-----------------------------------------------
|
||||
//
|
||||
|
||||
Check_Pointer(resourceArray);
|
||||
Verify(!resourceArray[index]);
|
||||
if (index > maxResourceID)
|
||||
{
|
||||
maxResourceID = index;
|
||||
}
|
||||
resourceArray[index] =
|
||||
new ResourceDescription(
|
||||
this,
|
||||
name,
|
||||
type,
|
||||
priority,
|
||||
load_flag,
|
||||
address,
|
||||
size,
|
||||
index
|
||||
);
|
||||
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
// The caller of this function is responsible for registering the memory
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
Register_Object(resourceArray[index]);
|
||||
return resourceArray[index];
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::AddResourceList(
|
||||
const char* name,
|
||||
ResourceDescription::ResourceType type,
|
||||
int priority,
|
||||
LWord load_flag,
|
||||
const ResourceDescription::ResourceID* address,
|
||||
int count,
|
||||
ResourceDescription::ResourceID index
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check_Pointer(name);
|
||||
Check_Pointer(address);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------
|
||||
// prefix the directory table with the count of references
|
||||
//--------------------------------------------------------
|
||||
//
|
||||
ResourceDescription::ResourceID *table =
|
||||
new ResourceDescription::ResourceID[count+1];
|
||||
Register_Pointer(table);
|
||||
for (int i=0; i<count; ++i)
|
||||
{
|
||||
table[i+1] = address[i];
|
||||
}
|
||||
*table = count;
|
||||
|
||||
//
|
||||
//-------------------------------------------------
|
||||
// Go ahead and add the directory to the main index
|
||||
//-------------------------------------------------
|
||||
//
|
||||
ResourceDescription *directory =
|
||||
AddResource(
|
||||
name,
|
||||
type,
|
||||
priority,
|
||||
load_flag,
|
||||
table,
|
||||
(count+1) * sizeof(ResourceDescription::ResourceID),
|
||||
index
|
||||
);
|
||||
Unregister_Pointer(table);
|
||||
delete[] table;
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::AddResourceMemoryStream(
|
||||
const char* name,
|
||||
ResourceDescription::ResourceType type,
|
||||
int priority,
|
||||
LWord load_flag,
|
||||
MemoryStream* memory_stream,
|
||||
ResourceDescription::ResourceID index
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check(memory_stream);
|
||||
|
||||
size_t size = memory_stream->GetBytesUsed();
|
||||
memory_stream->Rewind();
|
||||
|
||||
return
|
||||
AddResource(
|
||||
name,
|
||||
type,
|
||||
priority,
|
||||
load_flag,
|
||||
memory_stream->GetPointer(),
|
||||
size,
|
||||
index
|
||||
);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ResourceFile::DeleteResource(ResourceDescription *resource)
|
||||
{
|
||||
Check(this);
|
||||
Check(resource);
|
||||
Check_Pointer(resourceArray);
|
||||
Verify(!resource->IsLocked());
|
||||
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// Delete pointer from resoureArray if it was there
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
if (resource->resourceID != ResourceDescription::NullResourceID )
|
||||
{
|
||||
resourceArray[resource->resourceID] = NULL;
|
||||
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// Find new maxResourceID
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
if (resource->resourceID == maxResourceID )
|
||||
{
|
||||
ResourceDescription::ResourceID i;
|
||||
for (i = maxResourceID; i>=0; i--)
|
||||
{
|
||||
if(resourceArray[i] != NULL)
|
||||
{
|
||||
Check(resourceArray[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
maxResourceID = i;
|
||||
}
|
||||
}
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
// The caller of this function is responsible for unregistering the memory
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
delete resource;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::FindResourceDescription(ResourceDescription::ResourceID index)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
if (index<0 || index>maxResourceID || !resourceArray)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Check_Pointer(resourceArray);
|
||||
ResourceDescription *res = resourceArray[index];
|
||||
return res;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::FindResourceDescription(
|
||||
const char* name,
|
||||
ResourceDescription::ResourceType type,
|
||||
ResourceDescription::ResourceID after
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
ResourceDescription *desc;
|
||||
ResourceDescription::ResourceID i;
|
||||
for (i=after+1; i<=maxResourceID; ++i)
|
||||
{
|
||||
desc = FindResourceDescription(i);
|
||||
if (desc)
|
||||
{
|
||||
Check(desc);
|
||||
if (
|
||||
type == desc->resourceType &&
|
||||
(!name || !strcmp(name, desc->resourceName))
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i > maxResourceID)
|
||||
{
|
||||
desc = NULL;
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::SearchList(
|
||||
ResourceDescription::ResourceID list_id,
|
||||
ResourceDescription::ResourceType type
|
||||
)
|
||||
{
|
||||
ResourceDescription *list_res = FindResourceDescription(list_id);
|
||||
if (list_res)
|
||||
{
|
||||
Check(list_res);
|
||||
list_res->Lock();
|
||||
Verify(
|
||||
list_res->resourceType <= ResourceDescription::MaxListResourceType
|
||||
);
|
||||
ResourceDescription::ResourceID *list =
|
||||
(ResourceDescription::ResourceID*)list_res->resourceAddress;
|
||||
Check_Pointer(list);
|
||||
for (int i=1; i<=*list; ++i)
|
||||
{
|
||||
ResourceDescription *res = FindResourceDescription(list[i]);
|
||||
Check(res);
|
||||
if (res->resourceType == type)
|
||||
{
|
||||
list_res->Unlock();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
list_res->Unlock();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription*
|
||||
ResourceFile::SearchList(
|
||||
ResourceDescription::ResourceID list_id,
|
||||
const char* name
|
||||
)
|
||||
{
|
||||
Check_Pointer(name);
|
||||
ResourceDescription *list_res = FindResourceDescription(list_id);
|
||||
if (list_res)
|
||||
{
|
||||
Check(list_res);
|
||||
list_res->Lock();
|
||||
Verify(
|
||||
list_res->resourceType <= ResourceDescription::MaxListResourceType
|
||||
);
|
||||
ResourceDescription::ResourceID *list =
|
||||
(ResourceDescription::ResourceID*)list_res->resourceAddress;
|
||||
Check_Pointer(list);
|
||||
for (int i=1; i<=*list; ++i)
|
||||
{
|
||||
ResourceDescription *res = FindResourceDescription(list[i]);
|
||||
Check(res);
|
||||
if (!strcmp(name, res->resourceName))
|
||||
{
|
||||
list_res->Unlock();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
list_res->Unlock();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
ResourceFile::ReleaseUnlockedResources()
|
||||
{
|
||||
for (ResourceDescription::ResourceID i = maxResourceID; i>=0; i--)
|
||||
{
|
||||
if(resourceArray[i] != NULL)
|
||||
{
|
||||
ResourceDescription *res = resourceArray[i];
|
||||
Check(res);
|
||||
res->ReleaseUnlockedResource();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
// ResourceFile Test Support
|
||||
//
|
||||
|
||||
Logical
|
||||
ResourceFile::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
//########################## StreamableResourceFile ######################
|
||||
//##############################################################################
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
StreamableResourceFile::StreamableResourceFile()
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
StreamableResourceFile::StreamableResourceFile(const char* file_name)
|
||||
{
|
||||
Open(file_name);
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
StreamableResourceFile::StreamableResourceFile(const char* file_name, Byte version_array[3], int match_level)
|
||||
{
|
||||
Open(file_name);
|
||||
int i;
|
||||
for (i=0; i<match_level; ++i)
|
||||
if (version_array[i] != versionArray[i+1])
|
||||
break;
|
||||
|
||||
if (i < match_level)
|
||||
{
|
||||
DEBUG_STREAM << "\n\nError - Resource file " << file_name << " v" << (int)versionArray[0] << '.' << (int)versionArray[1] << '.' << (int)versionArray[2] << '.' << (int)versionArray[3] << " is obsolete!\n\n" << flush;
|
||||
Fail("Exiting");
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (release_only && labOnly)
|
||||
{
|
||||
DEBUG_STREAM << "\n\n\nERROR!\n\n"
|
||||
"This resource file was not properly released!\n\n";
|
||||
Fail("Exiting");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
StreamableResourceFile::~StreamableResourceFile()
|
||||
{
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
int
|
||||
StreamableResourceFile::Open(const char *file_name)
|
||||
{
|
||||
Check(this);
|
||||
Str_Copy(resourceFilename, file_name, sizeof(resourceFilename));
|
||||
|
||||
diskFile.Open(resourceFilename);
|
||||
if (!diskFile.IsFileOpened())
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
//
|
||||
//-----------------------
|
||||
// Read in resource count
|
||||
//-----------------------
|
||||
//
|
||||
maxResourceID = 0;
|
||||
|
||||
diskFile.ReadBytes(&versionArray, sizeof(versionArray));
|
||||
|
||||
if (versionArray[0] != RESOURCE_FORMAT_VERSION)
|
||||
{
|
||||
DEBUG_STREAM << "\n\nError - Resource file " << file_name << " v"
|
||||
<< (int)versionArray[0] << '.' << (int)versionArray[1] << '.'
|
||||
<< (int)versionArray[2] << '.' << (int)versionArray[3]
|
||||
<< " is obsolete!\n\n" << flush;
|
||||
Fail("Exiting");
|
||||
}
|
||||
|
||||
diskFile >> labOnly >> maxResourceID;
|
||||
|
||||
//
|
||||
//------------------------------------------------------------------
|
||||
// Read in main index table first, and make room for expansion later
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
size_t *offset_table = new size_t[maxResourceID];
|
||||
Register_Pointer(offset_table);
|
||||
|
||||
diskFile.ReadBytes(offset_table, maxResourceID*sizeof(size_t));
|
||||
resourceArraySize = maxResourceID + IndexBlockSize;
|
||||
|
||||
resourceArray = new ResourceDescription*[resourceArraySize];
|
||||
Register_Pointer(resourceArray);
|
||||
int i;
|
||||
for (i=0; i<resourceArraySize; ++i)
|
||||
{
|
||||
resourceArray[i] = NULL;
|
||||
}
|
||||
--maxResourceID;
|
||||
|
||||
//
|
||||
//---------------------------------------------------------------------
|
||||
// Step through the index table, reading each description as we find it
|
||||
//---------------------------------------------------------------------
|
||||
//
|
||||
for (i=0; i<=maxResourceID; ++i)
|
||||
{
|
||||
//
|
||||
//--------------------------------------------
|
||||
// Make sure we skip empty resources correctly
|
||||
//--------------------------------------------
|
||||
//
|
||||
if (!offset_table[i])
|
||||
{
|
||||
resourceArray[i] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
//------------------------
|
||||
// Read in the description
|
||||
//------------------------
|
||||
//
|
||||
ResourcePhysicalFormat buffer;
|
||||
diskFile.SetPointer(offset_table[i]);
|
||||
diskFile >> buffer;
|
||||
|
||||
//
|
||||
//-------------------------------------------------
|
||||
// If the preload flag is set, read in the resource
|
||||
//-------------------------------------------------
|
||||
//
|
||||
|
||||
char *data = NULL;
|
||||
if (buffer.resourceFlags == ResourceDescription::Preload && buffer.resourceLength > 0)
|
||||
{
|
||||
data = new char[buffer.resourceLength];
|
||||
Register_Pointer(data);
|
||||
diskFile.SetPointer(buffer.resourceOffset);
|
||||
diskFile.ReadBytes(data, buffer.resourceLength);
|
||||
}
|
||||
if (buffer.resourceType > ResourceDescription::MaxListResourceType || !data)
|
||||
{
|
||||
resourceArray[i] = AddResource(
|
||||
buffer.resourceName,
|
||||
buffer.resourceType,
|
||||
buffer.downloadPriority,
|
||||
buffer.resourceFlags,
|
||||
data,
|
||||
buffer.resourceLength,
|
||||
buffer.resourceID
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceArray[i] = AddResourceList(
|
||||
buffer.resourceName,
|
||||
buffer.resourceType,
|
||||
buffer.downloadPriority,
|
||||
buffer.resourceFlags,
|
||||
(int*)data + 1,
|
||||
*(int*)data,
|
||||
buffer.resourceID
|
||||
);
|
||||
}
|
||||
resourceArray[i]->offsetInFile = buffer.resourceOffset;
|
||||
if (data)
|
||||
{
|
||||
resourceArray[i]->Lock();
|
||||
Unregister_Pointer(data);
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
|
||||
Unregister_Pointer(offset_table);
|
||||
delete[] offset_table;
|
||||
return True;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
int
|
||||
StreamableResourceFile::Save()
|
||||
{
|
||||
Check(this);
|
||||
if (!resourceArray)
|
||||
{
|
||||
return False;
|
||||
}
|
||||
|
||||
//
|
||||
//-----------------------------------------------------------------------
|
||||
// Make sure to load any unloaded resources before closing the input file
|
||||
//-----------------------------------------------------------------------
|
||||
//
|
||||
ResourceDescription *desc;
|
||||
ResourceDescription::ResourceID i;
|
||||
for (i=0; i<=maxResourceID; ++i)
|
||||
{
|
||||
desc = resourceArray[i];
|
||||
if (desc)
|
||||
{
|
||||
Check(desc);
|
||||
desc->LoadResource();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//-------------------------------------------
|
||||
// Close the current file, and open a new one
|
||||
//-------------------------------------------
|
||||
//
|
||||
if (diskFile.IsFileOpened())
|
||||
{
|
||||
diskFile.Close();
|
||||
}
|
||||
diskFile.Open(resourceFilename, True);
|
||||
Verify(diskFile.IsFileOpened());
|
||||
|
||||
//
|
||||
//-------------------------------------
|
||||
// Write out resource count and version
|
||||
//-------------------------------------
|
||||
//
|
||||
++maxResourceID;
|
||||
|
||||
diskFile.WriteBytes(&versionArray, sizeof(versionArray));
|
||||
diskFile << labOnly << maxResourceID;
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Write out main index table first. This is just filling up space, and the
|
||||
// offsets will have to be written back into this section later
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
size_t *offset_table = new size_t[maxResourceID];
|
||||
Register_Pointer(offset_table);
|
||||
diskFile.WriteBytes(offset_table, maxResourceID*sizeof(size_t));
|
||||
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
// Step through the index table, writing out each description as we find it
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
for (i=0; i<maxResourceID; ++i)
|
||||
{
|
||||
//
|
||||
//--------------------------------------------
|
||||
// Make sure we skip empty resources correctly
|
||||
//--------------------------------------------
|
||||
//
|
||||
desc = resourceArray[i];
|
||||
if (!desc)
|
||||
{
|
||||
offset_table[i] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
Check(desc);
|
||||
|
||||
//
|
||||
//-------------------
|
||||
// Write out the data
|
||||
//-------------------
|
||||
//
|
||||
ResourcePhysicalFormat buffer;
|
||||
buffer.resourceOffset = diskFile.GetIndex();
|
||||
diskFile.WriteBytes(desc->resourceAddress, desc->resourceSize);
|
||||
|
||||
//
|
||||
//--------------------------
|
||||
// Write out the description
|
||||
//--------------------------
|
||||
//
|
||||
offset_table[i] = diskFile.GetIndex();
|
||||
buffer.resourceID = desc->resourceID;
|
||||
buffer.resourceType = desc->resourceType;
|
||||
|
||||
//#if sizeof(buffer.resourceName) < sizeof(desc->resourceName)
|
||||
//# error ResourceDescription::resourceName is too big!
|
||||
//#endif
|
||||
|
||||
memcpy(
|
||||
buffer.resourceName,
|
||||
desc->resourceName,
|
||||
sizeof(desc->resourceName)
|
||||
);
|
||||
|
||||
buffer.resourceLength = desc->resourceSize;
|
||||
buffer.downloadPriority = desc->downloadPriority;
|
||||
buffer.resourceFlags =
|
||||
desc->resourceFlags & ~ResourceDescription::LoadedFlag;
|
||||
diskFile << buffer;
|
||||
}
|
||||
diskFile.SetPointer(
|
||||
sizeof(maxResourceID) + sizeof(versionArray) + sizeof(labOnly)
|
||||
);
|
||||
diskFile.WriteBytes(offset_table, maxResourceID*sizeof(long));
|
||||
Unregister_Pointer(offset_table);
|
||||
delete(offset_table);
|
||||
--maxResourceID;
|
||||
diskFile.Close();
|
||||
return True;
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
int
|
||||
StreamableResourceFile::SaveAs(const char* file_name)
|
||||
{
|
||||
Str_Copy(resourceFilename, file_name, sizeof(resourceFilename));
|
||||
return Save();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
StreamableResourceFile::LoadResource(ResourceDescription *res)
|
||||
{
|
||||
ResourceFile::LoadResource(res);
|
||||
Verify(!res->resourceAddress);
|
||||
res->resourceAddress = new char[res->resourceSize];
|
||||
Register_Pointer(res->resourceAddress);
|
||||
diskFile.SetPointer(res->offsetInFile);
|
||||
diskFile.ReadBytes(res->resourceAddress, res->resourceSize);
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
// StreamableResourceFile Test Support
|
||||
//
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Logical
|
||||
StreamableResourceFile::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
#if defined(TEST_CLASS)
|
||||
#include "resource.tcp"
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(SCNROLE_HPP)
|
||||
# include <scnrole.hpp>
|
||||
# endif
|
||||
# if !defined(APP_HPP)
|
||||
# include <app.hpp>
|
||||
# endif
|
||||
# if !defined(NOTATION_HPP)
|
||||
# include <notation.hpp>
|
||||
# endif
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ScenarioRole::ScenarioRole(const CString &role_name)
|
||||
{
|
||||
damageReceivedModifier = 0.0f;
|
||||
damageInflictedModifier = 0.0f;
|
||||
damageBias = 0.0f;
|
||||
friendlyFirePenalty = 0.0f;
|
||||
killBonus = 0.0f;
|
||||
roleName = role_name;
|
||||
returnFromDeath = 0;
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ScenarioRole::ScenarioRole(const CString &role_name, const CString &model_file)
|
||||
{
|
||||
Check_Pointer(&role_name);
|
||||
Check_Pointer(&model_file);
|
||||
|
||||
roleName = role_name;
|
||||
//
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Truncate the Role:: from roleName
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceFile
|
||||
*res = application->GetResourceFile();
|
||||
ResourceDescription
|
||||
*player_res_des;
|
||||
|
||||
player_res_des = res->FindResourceDescription(
|
||||
model_file,
|
||||
ResourceDescription::GameModelResourceType
|
||||
);
|
||||
|
||||
if (player_res_des)
|
||||
{
|
||||
player_res_des->Lock();
|
||||
ModelResource
|
||||
*player_data = (ModelResource *)player_res_des->
|
||||
resourceAddress;
|
||||
|
||||
killBonus = player_data->killBonus;
|
||||
returnFromDeath = player_data->returnFromDeath;
|
||||
damageReceivedModifier = player_data->damageReceivedModifier;
|
||||
damageInflictedModifier = player_data->damageInflictedModifier;
|
||||
damageBias = player_data->damageBias;
|
||||
friendlyFirePenalty = player_data->friendlyFirePenalty;
|
||||
player_res_des->Unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
Tell(role_name);
|
||||
Warn(" does not exists in resource! ");
|
||||
damageReceivedModifier = 0.0f;
|
||||
damageInflictedModifier = 0.0f;
|
||||
damageBias = 0.0f;
|
||||
friendlyFirePenalty = 0.0f;
|
||||
killBonus = 0.0f;
|
||||
returnFromDeath = 0;
|
||||
}
|
||||
}
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Scalar
|
||||
ScenarioRole::CalcDamageReceivedScore(const Scalar &damage_received)
|
||||
{
|
||||
Check(this);
|
||||
// ]
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Calculate modified score for the player receiving damage
|
||||
// damageReceived * damageReceivedModifier
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
Check(this);
|
||||
|
||||
Check_Fpu();
|
||||
return -(damage_received * GetDamageReceivedModifier());
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ScenarioRole::~ScenarioRole()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
ResourceDescription::ResourceID
|
||||
ScenarioRole::CreateModelResource(
|
||||
#if DEBUG_LEVEL>0
|
||||
ResourceFile *resource_file,
|
||||
const char* model_name,
|
||||
NotationFile * model_file,
|
||||
const ResourceDirectories *directories,
|
||||
ModelResource *model
|
||||
#else
|
||||
ResourceFile *resource_file,
|
||||
const char* model_name,
|
||||
NotationFile * model_file,
|
||||
const ResourceDirectories *,
|
||||
ModelResource *model
|
||||
#endif
|
||||
)
|
||||
{
|
||||
Check(resource_file);
|
||||
Check_Pointer(model_name);
|
||||
Check_Pointer(directories);
|
||||
|
||||
//
|
||||
// If we were not provided a buffer to write the model data into, we must
|
||||
// create it ourselves. Then make sure that the model stuff is read in
|
||||
//
|
||||
ModelResource *local_model = model;
|
||||
if (!local_model)
|
||||
{
|
||||
local_model = new ModelResource;
|
||||
Register_Pointer(local_model);
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Read in the data from notation file
|
||||
//----------------------------------------
|
||||
//
|
||||
// Get PointValue assigned to this ScoreZone
|
||||
//
|
||||
|
||||
if(
|
||||
!model_file->GetEntry(
|
||||
"gamedata",
|
||||
"KillBonus",
|
||||
&local_model->killBonus
|
||||
)
|
||||
)
|
||||
{
|
||||
cerr << model_name << "Missing KillBonus" << endl;
|
||||
Dump_And_Die:
|
||||
if (!model)
|
||||
{
|
||||
Unregister_Pointer(local_model);
|
||||
delete local_model;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(
|
||||
!model_file->GetEntry(
|
||||
"gamedata",
|
||||
"DamageReceivedModifier",
|
||||
&local_model->damageReceivedModifier
|
||||
)
|
||||
)
|
||||
{
|
||||
cerr << model_name << "Missing DamageReceivedModifier" << endl;
|
||||
goto Dump_And_Die;
|
||||
}
|
||||
|
||||
if(
|
||||
!model_file->GetEntry(
|
||||
"gamedata",
|
||||
"DamageInflictedModifier",
|
||||
&local_model->damageInflictedModifier
|
||||
)
|
||||
)
|
||||
{
|
||||
cerr << model_name << "Missing DamageInflictedModifier" << endl;
|
||||
goto Dump_And_Die;
|
||||
}
|
||||
if(
|
||||
!model_file->GetEntry(
|
||||
"gamedata",
|
||||
"ReturnFromDeath",
|
||||
&local_model->returnFromDeath
|
||||
)
|
||||
)
|
||||
{
|
||||
cerr << model_name << "Missing ReturnFromDeath" << endl;
|
||||
goto Dump_And_Die;
|
||||
}
|
||||
if(
|
||||
!model_file->GetEntry(
|
||||
"gamedata",
|
||||
"DamageBias",
|
||||
&local_model->damageBias
|
||||
)
|
||||
)
|
||||
{
|
||||
cerr << model_name << "Missing DamageBias" << endl;
|
||||
goto Dump_And_Die;
|
||||
}
|
||||
|
||||
if(
|
||||
!model_file->GetEntry(
|
||||
"gamedata",
|
||||
"FriendlyFirePenalty",
|
||||
&local_model->friendlyFirePenalty
|
||||
)
|
||||
)
|
||||
{
|
||||
cerr << model_name << "Missing FriendlyFirePenalty" << endl;
|
||||
goto Dump_And_Die;
|
||||
}
|
||||
|
||||
|
||||
if (!model)
|
||||
{
|
||||
ResourceDescription *new_res =
|
||||
resource_file->AddResource(
|
||||
model_name,
|
||||
ResourceDescription::GameModelResourceType,
|
||||
1,
|
||||
ResourceDescription::Preload,
|
||||
local_model,
|
||||
sizeof(*local_model)
|
||||
);
|
||||
Unregister_Pointer(local_model);
|
||||
delete local_model;
|
||||
Check_Fpu();
|
||||
Check(new_res);
|
||||
return new_res->resourceID;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_Fpu();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
//===========================================================================//
|
||||
// File: stubs.cpp //
|
||||
// Project: MUNGA //
|
||||
// Contents: Optimized-build heap and exit stubs //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
|
||||
#include <munga.hpp>
|
||||
#pragma hdrstop
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void
|
||||
Exit(int exit_code)
|
||||
{
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
UserHeap::UserHeap(const char *, size_t)
|
||||
{
|
||||
}
|
||||
|
||||
UserHeap::~UserHeap()
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
UserHeap::Allocate(size_t size)
|
||||
{
|
||||
return new char[size];
|
||||
}
|
||||
|
||||
void
|
||||
UserHeap::Release(void *where)
|
||||
{
|
||||
delete[] (char *)where;
|
||||
}
|
||||
|
||||
void
|
||||
UserHeap::ReleaseAll()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
# if !defined(MUNGA_HPP)
|
||||
# include <munga.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(CONTROLS_HPP)
|
||||
# include <controls.hpp>
|
||||
# endif
|
||||
# if !defined(GAUGREND_HPP)
|
||||
# include <gaugrend.hpp>
|
||||
# endif
|
||||
|
||||
|
||||
#if defined(__BCPLUSPLUS__)
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
#if DEBUG_LEVEL>0
|
||||
int _matherr(struct exception *a)
|
||||
{
|
||||
switch (a->type)
|
||||
{
|
||||
case DOMAIN:
|
||||
DEBUG_STREAM << "Domain" << flush;
|
||||
break;
|
||||
case SING:
|
||||
DEBUG_STREAM << "Singularity" << flush;
|
||||
break;
|
||||
case UNDERFLOW:
|
||||
DEBUG_STREAM << "Underflow" << flush;
|
||||
break;
|
||||
case OVERFLOW:
|
||||
DEBUG_STREAM << "Overflow" << flush;
|
||||
break;
|
||||
case TLOSS:
|
||||
DEBUG_STREAM << "Loss of Precision" << flush;
|
||||
break;
|
||||
}
|
||||
DEBUG_STREAM << " error occurred in " << a->name << endl << flush;
|
||||
DEBUG_STREAM << "arg1 = " << a->arg1 << endl << flush;
|
||||
DEBUG_STREAM << "arg2 = " << a->arg2 << endl << flush;
|
||||
DEBUG_STREAM << "retval = " << a->retval << endl << flush << flush;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int _matherr(struct exception *)
|
||||
{
|
||||
_fpreset();
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern "C" void _pure_error_()
|
||||
{
|
||||
Fail("Pure virtual function called");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// Fpu_Ok
|
||||
//
|
||||
// returns True if fpu has no errors, False if errors found
|
||||
//#############################################################################
|
||||
//
|
||||
int
|
||||
Fpu_Ok()
|
||||
{
|
||||
unsigned int s =
|
||||
_status87() &
|
||||
(
|
||||
SW_INVALID |
|
||||
// SW_DENORMAL |
|
||||
SW_ZERODIVIDE |
|
||||
SW_OVERFLOW
|
||||
// SW_UNDERFLOW |
|
||||
//VERIFY: SW_STACKFAULT
|
||||
);
|
||||
if (s)
|
||||
{
|
||||
DEBUG_STREAM << "ERROR: FPU status=" << flush;
|
||||
|
||||
if (s & SW_INVALID)
|
||||
{
|
||||
DEBUG_STREAM << "invalid " << flush;
|
||||
}
|
||||
if (s & SW_DENORMAL)
|
||||
{
|
||||
DEBUG_STREAM << "denormalized " << flush;
|
||||
}
|
||||
if (s & SW_ZERODIVIDE)
|
||||
{
|
||||
DEBUG_STREAM << "zeroDivide " << flush;
|
||||
}
|
||||
if (s & SW_OVERFLOW)
|
||||
{
|
||||
DEBUG_STREAM << "overflow " << flush;
|
||||
}
|
||||
if (s & SW_UNDERFLOW)
|
||||
{
|
||||
DEBUG_STREAM << "underflow " << flush;
|
||||
}
|
||||
/*if (s & SW_STACKFAULT)
|
||||
{
|
||||
DEBUG_STREAM << "stackFault" << flush;
|
||||
}*/
|
||||
DEBUG_STREAM << "\n" << flush << flush;
|
||||
return False;
|
||||
}
|
||||
else
|
||||
{
|
||||
return True;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
static Logical AlreadyFailed=False;
|
||||
|
||||
void Verify_Failed(char *Message, char *File, int Line)
|
||||
{
|
||||
if (!AlreadyFailed)
|
||||
{
|
||||
AlreadyFailed = True;
|
||||
|
||||
DEBUG_STREAM << File << "(" << Line << "): Failed " << Message << "\n" << flush;
|
||||
#if defined(USE_PROFILE_ANALYSIS)
|
||||
Analysis_Named_Status();
|
||||
#endif
|
||||
DEBUG_STREAM << "Failing to debugger\n" << flush << flush;
|
||||
SystemClock::timer.Shutdown();
|
||||
ControlsManager::Shutdown();
|
||||
GaugeRenderer::EmergencyShutdown();
|
||||
*(int*)(0xFFFFFFFF) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
Fail_To_Debugger(char *Message, char *File, int Line)
|
||||
{
|
||||
if (!AlreadyFailed)
|
||||
{
|
||||
AlreadyFailed = True;
|
||||
|
||||
DEBUG_STREAM << File << "(" << Line << "): " << Message << "\n" << flush;
|
||||
#if defined(USE_PROFILE_ANALYSIS)
|
||||
Analysis_Named_Status();
|
||||
#endif
|
||||
DEBUG_STREAM << "Failing to debugger\n" << flush << flush;
|
||||
SystemClock::timer.Shutdown();
|
||||
ControlsManager::Shutdown();
|
||||
GaugeRenderer::EmergencyShutdown();
|
||||
*(int*)(0xFFFFFFFF) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
#if defined(USE_SIGNATURE)
|
||||
Signature::Signature()
|
||||
{
|
||||
#if DEBUG_LEVEL>0
|
||||
mark = magic;
|
||||
#endif
|
||||
}
|
||||
|
||||
Signature::~Signature()
|
||||
{
|
||||
#if DEBUG_LEVEL>0
|
||||
mark = noMagic;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
Is_Signature_Bad(const volatile Signature *p)
|
||||
{
|
||||
#if DEBUG_LEVEL>0
|
||||
if (p->mark == Signature::magic)
|
||||
{
|
||||
return Signature::ok;
|
||||
}
|
||||
else if (p->mark == Signature::noMagic)
|
||||
{
|
||||
return Signature::destroyed;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Signature::corrupted;
|
||||
}
|
||||
#else
|
||||
return False;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -1,73 +1,876 @@
|
||||
//===========================================================================//
|
||||
// File: l4app.cpp //
|
||||
// Project: MUNGA Brick: L4Application //
|
||||
// Contents: Implementation details for L4Application //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Date Who Modification //
|
||||
// -------- --- ---------------------------------------------------------- //
|
||||
// //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1994, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide. //
|
||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
|
||||
#include <mungal4.hpp>
|
||||
#pragma hdrstop
|
||||
|
||||
#if !defined(L4APP_HPP)
|
||||
# include <l4app.hpp>
|
||||
#endif
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
const Receiver::HandlerEntry
|
||||
L4Application::MessageHandlerEntries[]=
|
||||
{
|
||||
MESSAGE_ENTRY(L4Application, LightsOut),
|
||||
MESSAGE_ENTRY(L4Application, RunMission),
|
||||
MESSAGE_ENTRY(L4Application, StopMission),
|
||||
MESSAGE_ENTRY(L4Application, KeyCommand)
|
||||
};
|
||||
|
||||
L4Application::MessageHandlerSet
|
||||
L4Application::MessageHandlers(
|
||||
ELEMENTS(L4Application::MessageHandlerEntries),
|
||||
L4Application::MessageHandlerEntries,
|
||||
Application::MessageHandlers
|
||||
);
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Derivation
|
||||
L4Application::ClassDerivations(
|
||||
Application::ClassDerivations,
|
||||
"L4Application"
|
||||
);
|
||||
|
||||
L4Application::SharedData
|
||||
L4Application::DefaultData(
|
||||
L4Application::ClassDerivations,
|
||||
L4Application::MessageHandlers
|
||||
);
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
//#############################################################################
|
||||
//
|
||||
Logical
|
||||
L4Application::seeSolids = False;
|
||||
CString
|
||||
L4Application::eggNotationFileName;
|
||||
unsigned long
|
||||
L4Application::networkCommonFlatAddress = 0;
|
||||
int
|
||||
L4Application::missionReviewMode = 0;
|
||||
CString
|
||||
L4Application::rioPlaybackFileName;
|
||||
CString
|
||||
L4Application::rioRecordingFileName;
|
||||
# if !defined(MUNGAL4_HPP)
|
||||
# include <mungal4.hpp>
|
||||
# endif
|
||||
#pragma hdrstop
|
||||
|
||||
# if !defined(CAMSHIP_HPP)
|
||||
# include <camship.hpp>
|
||||
# endif
|
||||
# if !defined(APPMSG_HPP)
|
||||
# include <appmsg.hpp>
|
||||
# endif
|
||||
# if !defined(L4APP_HPP)
|
||||
# include <l4app.hpp>
|
||||
# endif
|
||||
# if !defined(L4CTRL_HPP)
|
||||
# include <l4ctrl.hpp>
|
||||
# endif
|
||||
# if !defined(L4ICOM_HPP)
|
||||
# include <l4icom.hpp>
|
||||
# endif
|
||||
# if !defined(L4VIDEO_HPP)
|
||||
# include <l4video.hpp>
|
||||
# endif
|
||||
# if !defined(L4AUDRND_HPP)
|
||||
# include <l4audrnd.hpp>
|
||||
# endif
|
||||
# if !defined(L4GREND_HPP)
|
||||
# include <l4grend.hpp>
|
||||
# endif
|
||||
# if !defined(L4NET_HPP)
|
||||
# include <l4net.hpp>
|
||||
# endif
|
||||
# if !defined(L4MPPR_HPP)
|
||||
# include <l4mppr.hpp>
|
||||
# endif
|
||||
# if !defined(PLAYER_HPP)
|
||||
# include <player.hpp>
|
||||
# endif
|
||||
# if !defined(MISSION_HPP)
|
||||
# include <mission.hpp>
|
||||
# endif
|
||||
|
||||
|
||||
L4Application*&
|
||||
l4_application = (L4Application*&)application;
|
||||
|
||||
const Receiver::HandlerEntry
|
||||
L4Application::MessageHandlerEntries[]=
|
||||
{
|
||||
MESSAGE_ENTRY(L4Application, RunMission),
|
||||
MESSAGE_ENTRY(L4Application, StopMission),
|
||||
MESSAGE_ENTRY(L4Application, LightsOut),
|
||||
MESSAGE_ENTRY(L4Application, KeyCommand)
|
||||
};
|
||||
|
||||
L4Application::MessageHandlerSet
|
||||
L4Application::MessageHandlers(ELEMENTS(L4Application::MessageHandlerEntries), L4Application::MessageHandlerEntries, Application::MessageHandlers);
|
||||
|
||||
//#############################################################################
|
||||
// Virtual Data support
|
||||
//
|
||||
Derivation
|
||||
L4Application::ClassDerivations(Application::ClassDerivations, "L4Application");
|
||||
|
||||
L4Application::SharedData
|
||||
L4Application::DefaultData(
|
||||
L4Application::ClassDerivations,
|
||||
L4Application::MessageHandlers
|
||||
);
|
||||
|
||||
//##########################################################################
|
||||
//################## L4Application Static Data #######################
|
||||
//##########################################################################
|
||||
|
||||
Logical L4Application::seeSolids = False;
|
||||
CString L4Application::eggNotationFileName;
|
||||
unsigned long L4Application::networkCommonFlatAddress;
|
||||
int L4Application::missionReviewMode = 0;
|
||||
CString L4Application::rioPlaybackFileName;
|
||||
CString L4Application::rioRecordingFileName;
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// ParseCommandLine
|
||||
//#############################################################################
|
||||
//
|
||||
Logical
|
||||
L4Application::ParseToken(
|
||||
int *arguement,
|
||||
int argc,
|
||||
char *argv[]
|
||||
)
|
||||
{
|
||||
Check_Pointer(argv);
|
||||
|
||||
if (!stricmp(argv[*arguement], "-egg"))
|
||||
{
|
||||
if ((*arguement+1) < argc && argv[*arguement+1][0] != '-')
|
||||
{
|
||||
eggNotationFileName = argv[++(*arguement)];
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_STREAM << "\nEgg file not specified after -egg\n" << flush << flush;
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
else if (!stricmp(argv[*arguement], "-net"))
|
||||
{
|
||||
if ((*arguement+1) < argc && argv[*arguement+1][0] != '-')
|
||||
{
|
||||
networkCommonFlatAddress = atol(argv[++(*arguement)]);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_STREAM << "\nAddress not specified after -net\n" << flush;
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
else if (!stricmp(argv[*arguement], "-r"))
|
||||
{
|
||||
if ((*arguement+1) < argc && argv[*arguement+1][0] != '-')
|
||||
{
|
||||
rioRecordingFileName = argv[++(*arguement)];
|
||||
CString playback = GetRIOPlaybackFileName();
|
||||
if (playback && strlen(playback))
|
||||
{
|
||||
DEBUG_STREAM << "\nPlayback already specified!\n" << flush;
|
||||
return False;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_STREAM << "\nRecording file not specified after -r\n" << flush;
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
else if (!stricmp(argv[*arguement], "-p"))
|
||||
{
|
||||
if ((*arguement+1) < argc && argv[*arguement+1][0] != '-')
|
||||
{
|
||||
rioPlaybackFileName = argv[++(*arguement)];
|
||||
CString recording = GetRIORecordingFileName();
|
||||
if (recording && strlen(recording))
|
||||
{
|
||||
DEBUG_STREAM << "\nRecording already specified!\n" << flush;
|
||||
return False;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_STREAM << "\nPlayback file not specified after -egg\n" << flush;
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
else if (!stricmp(argv[*arguement], "-solids"))
|
||||
{
|
||||
seeSolids = True;
|
||||
}
|
||||
|
||||
|
||||
else if (
|
||||
!stricmp(argv[*arguement], "-h") || !stricmp(argv[*arguement], "-help")
|
||||
)
|
||||
{
|
||||
DEBUG_STREAM << "\n" << argv[0] <<
|
||||
" -egg <filename> -net <memory_address> -solids -h -help\n";
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// ParseCommandLine
|
||||
//#############################################################################
|
||||
//
|
||||
Logical
|
||||
L4Application::ParseCommandLine(
|
||||
int argc,
|
||||
char *argv[],
|
||||
TokenParser parser
|
||||
)
|
||||
{
|
||||
Check_Pointer(argv);
|
||||
|
||||
//
|
||||
// Process options
|
||||
//
|
||||
seeSolids = False;
|
||||
eggNotationFileName = "";
|
||||
networkCommonFlatAddress = NULL;
|
||||
missionReviewMode = 0;
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (!stricmp(argv[i], "-mr"))
|
||||
{
|
||||
missionReviewMode = 1;
|
||||
} else if (!(*parser)(&i, argc, argv))
|
||||
{
|
||||
return False;
|
||||
}
|
||||
}
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// TestInstance
|
||||
//#############################################################################
|
||||
//
|
||||
Logical
|
||||
L4Application::TestInstance() const
|
||||
{
|
||||
if (!IsDerivedFrom(ClassDerivations))
|
||||
{
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// L4Application
|
||||
//#############################################################################
|
||||
//
|
||||
L4Application::L4Application(
|
||||
ResourceFile *resource_file,
|
||||
ApplicationID application_ID,
|
||||
ClassID class_ID,
|
||||
SharedData &shared_data
|
||||
):
|
||||
Application(resource_file, application_ID, class_ID, shared_data)
|
||||
{
|
||||
divisionParameters = getenv("DPLARG");
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// Initialize
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
L4Application::Initialize()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
InitializeTillConsole();
|
||||
|
||||
//
|
||||
// Create the console host and socket
|
||||
//
|
||||
L4NetworkManager *net_mgr = GetNetworkManager();
|
||||
net_mgr->CreateConsoleHost();
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// Initialize
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
L4Application::InitializeTillConsole()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
Application::Initialize();
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// MakeModeManager
|
||||
//#############################################################################
|
||||
//
|
||||
ModeManager*
|
||||
L4Application::MakeModeManager()
|
||||
{
|
||||
return new ModeManager((ModeMask)ModeManager::ModeAlwaysActive); // Normally called at top level!!
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// MakeNetworkManager
|
||||
//#############################################################################
|
||||
//
|
||||
NetworkManager*
|
||||
L4Application::MakeNetworkManager()
|
||||
{
|
||||
return new L4NetworkManager;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// MakeControlsManager
|
||||
//#############################################################################
|
||||
//
|
||||
ControlsManager*
|
||||
L4Application::MakeControlsManager()
|
||||
{
|
||||
LBE4ControlsManager *manager = new LBE4ControlsManager();
|
||||
Check(manager);
|
||||
manager->keyboardGroup[LBE4ControlsManager::KeyboardPC].Add(ModeManager::ModeAlwaysActive, this, KeyCommandMessageID, this);
|
||||
return manager;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// MakeIntercomManager
|
||||
//#############################################################################
|
||||
//
|
||||
IcomManager*
|
||||
L4Application::MakeIntercomManager()
|
||||
{
|
||||
L4IcomManager
|
||||
*manager = new L4IcomManager();
|
||||
Check(manager);
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// MakeVideoRenderer
|
||||
//#############################################################################
|
||||
//
|
||||
VideoRenderer*
|
||||
L4Application::MakeVideoRenderer()
|
||||
{
|
||||
if (divisionParameters)
|
||||
{
|
||||
return
|
||||
new DPLRenderer(
|
||||
DefaultRendererRate,
|
||||
MaxRendererComplexity,
|
||||
DefaultRendererPriority,
|
||||
VisualInterestType,
|
||||
1
|
||||
);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// MakeAudioRenderer
|
||||
//#############################################################################
|
||||
//
|
||||
AudioRenderer*
|
||||
L4Application::MakeAudioRenderer()
|
||||
{
|
||||
/* char *blaster1, *blaster2;
|
||||
|
||||
blaster1 = getenv(FRONT_CARD_ENV_VAR);
|
||||
blaster2 = getenv(REAR_CARD_ENV_VAR);
|
||||
|
||||
if (blaster1 != NULL && blaster2 != NULL)
|
||||
{
|
||||
return new L4AudioRenderer(DefaultRendererRate, False);
|
||||
}
|
||||
return NULL;*/
|
||||
|
||||
return new L4AudioRenderer(DefaultRendererRate, False);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// MakeGaugeRenderer
|
||||
//#############################################################################
|
||||
//
|
||||
GaugeRenderer*
|
||||
L4Application::MakeGaugeRenderer()
|
||||
{
|
||||
char *mode_string = getenv("L4GAUGE");
|
||||
if (mode_string != NULL)
|
||||
{
|
||||
return new L4GaugeRenderer;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// Terminate
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
L4Application::Terminate()
|
||||
{
|
||||
Check(this);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Turn off illumination
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
PilotIllumination(False);
|
||||
|
||||
//
|
||||
// Call inherited method
|
||||
//
|
||||
Application::Terminate();
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// ~L4Application
|
||||
//#############################################################################
|
||||
//
|
||||
L4Application::~L4Application()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// MakeAndLinkViewpointEntity
|
||||
//#############################################################################
|
||||
//
|
||||
Entity*
|
||||
L4Application::MakeAndLinkViewpointEntity(Entity::MakeMessage* message)
|
||||
{
|
||||
Check(this);
|
||||
Check(message);
|
||||
|
||||
Application::MakeAndLinkViewpointEntity(message);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Turn on lights for pilot
|
||||
// (turned off by RunMissionMessageHandler)
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
PilotIllumination(True);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Return viewpoint entity
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
return GetViewpointEntity();
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// MakeViewpointEntity
|
||||
//#############################################################################
|
||||
//
|
||||
Entity*
|
||||
L4Application::MakeViewpointEntity(Entity::MakeMessage *message)
|
||||
{
|
||||
Entity *viewing_entity;
|
||||
viewing_entity = NULL;
|
||||
switch(message->classToCreate)
|
||||
{
|
||||
case CameraShipClassID:
|
||||
viewing_entity = CameraShip::Make((CameraShip::MakeMessage*)message);
|
||||
Check(viewing_entity);
|
||||
CameraShip *viewing_camera = Cast_Object(CameraShip*, viewing_entity);
|
||||
Check(viewing_camera);
|
||||
|
||||
//
|
||||
// Create controls mapping object
|
||||
//
|
||||
CameraControlsMapper
|
||||
*camera_mapper;
|
||||
|
||||
Verify(GetControlsManager() != NULL);
|
||||
CameraControlsMapper::SubsystemResource control_subsystem_resource;
|
||||
Str_Copy(
|
||||
control_subsystem_resource.subsystemName,
|
||||
"ControlsMapper",
|
||||
sizeof(control_subsystem_resource.subsystemName)
|
||||
);
|
||||
control_subsystem_resource.classID = TrivialSubsystemClassID;
|
||||
control_subsystem_resource.subsystemModelSize =
|
||||
sizeof(control_subsystem_resource);
|
||||
|
||||
LBE4ControlsManager* controls = GetControlsManager();
|
||||
Check(controls);
|
||||
switch (controls->primaryControlType)
|
||||
{
|
||||
case LBE4ControlsManager::PrimaryThrustMaster:
|
||||
Tell("L4Application::MakeViewpointEntity, using ThrustMaster\n");
|
||||
camera_mapper =
|
||||
new CameraThrustmasterMapper(
|
||||
viewing_camera,
|
||||
CameraShip::ControlsMapperSubsystem,
|
||||
&control_subsystem_resource
|
||||
);
|
||||
Register_Object(camera_mapper);
|
||||
viewing_camera->SetMappingSubsystem(camera_mapper);
|
||||
break;
|
||||
|
||||
case LBE4ControlsManager::PrimaryRIO:
|
||||
Tell("L4Application::MakeViewpointEntity, using RIO\n");
|
||||
camera_mapper =
|
||||
new CameraRIOMapper(
|
||||
viewing_camera,
|
||||
CameraShip::ControlsMapperSubsystem,
|
||||
&control_subsystem_resource
|
||||
);
|
||||
Register_Object(camera_mapper);
|
||||
viewing_camera->SetMappingSubsystem(camera_mapper);
|
||||
break;
|
||||
default:
|
||||
Fail("L4Application::MakeViewpointEntity, *** NO MAPPER! ***\n");
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
//-------------------------------------------
|
||||
// Create gauges for this entity
|
||||
//-------------------------------------------
|
||||
//
|
||||
if (GetGaugeRenderer() != NULL)
|
||||
{
|
||||
L4GaugeRenderer *gauge_renderer = GetGaugeRenderer();
|
||||
Check(gauge_renderer);
|
||||
|
||||
gauge_renderer->ConfigureForModel(
|
||||
"Init",
|
||||
viewing_entity
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return viewing_entity;
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// RunMissionMessageHandler
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
L4Application::RunMissionMessageHandler(RunMissionMessage *message)
|
||||
{
|
||||
Check(this);
|
||||
Verify(message->messageID == RunMissionMessageID);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// If the application is already running then ignore this message
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
switch (GetApplicationState())
|
||||
{
|
||||
case RunningMission:
|
||||
break;
|
||||
|
||||
//
|
||||
//-------------------------------------
|
||||
// Start the playback if it is required
|
||||
//-------------------------------------
|
||||
//
|
||||
case LaunchingMission:
|
||||
{
|
||||
LBE4ControlsManager *controls = GetControlsManager();
|
||||
Check(controls);
|
||||
if (controls->IsRecording())
|
||||
{
|
||||
controls->StartRecording();
|
||||
}
|
||||
else if (controls->IsPlayingBack())
|
||||
{
|
||||
controls->StartPlayback();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WaitingForLaunch:
|
||||
PilotIllumination(False);
|
||||
break;
|
||||
|
||||
default:
|
||||
Fail("Application::RunMissionMessageHandler - Not ready to run!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Call previous handler
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
Application::RunMissionMessageHandler(message);
|
||||
}
|
||||
//
|
||||
//#############################################################################
|
||||
// StopMissionMessageHandler
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
L4Application::StopMissionMessageHandler(StopMissionMessage *message)
|
||||
{
|
||||
Check(this);
|
||||
Verify(message->messageID == StopMissionMessageID);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Call inherited handler
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
Application::StopMissionMessageHandler(message);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Turn on illumination
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
PilotIllumination(True);
|
||||
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Post a delayed message to ourselves to turn off the illumination
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
Receiver::Message
|
||||
lights_out_message(LightsOutMessageID, sizeof(Receiver::Message));
|
||||
|
||||
Time
|
||||
event_time;
|
||||
|
||||
event_time = Now();
|
||||
event_time += 30.0f;
|
||||
|
||||
Post(
|
||||
LowEventPriority, // priority
|
||||
this, // target
|
||||
&lights_out_message, // message
|
||||
event_time // when
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// KeyCommandMessageHandler
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
L4Application::KeyCommandMessageHandler(
|
||||
ReceiverDataMessageOf<ControlsKey> *message
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
Check(message);
|
||||
switch (message->dataContents)
|
||||
{
|
||||
//--------------------------------------------
|
||||
// FrameDump from Division card to Targa file
|
||||
//--------------------------------------------
|
||||
case PCK_ALT_F:
|
||||
{
|
||||
DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
|
||||
if (dpl_renderer)
|
||||
{
|
||||
Check(dpl_renderer);
|
||||
dpl_renderer->DPLFrameDump(True); // True indicates antialiased
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
// Report current free memory in card
|
||||
//------------------------------------
|
||||
case PCK_ALT_K:
|
||||
{
|
||||
//STUBBED: HEAP RB 1/20/07
|
||||
/*DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
|
||||
if (dpl_renderer)
|
||||
{
|
||||
Check(dpl_renderer);
|
||||
dpl_renderer->DPLReportFreeMemory(DEBUG_STREAM) << flush;
|
||||
}
|
||||
DEBUG_STREAM << UserHeap::MainStorage.GetTotalHeapLeft() << '('
|
||||
<< UserHeap::MainStorage.GetBiggestHeapLeft()
|
||||
<< " contiguous) bytes of MUNGA core left\n"
|
||||
<< UserHeap::MainStorage.GetHeapUsed() << " bytes of heap used\n";
|
||||
#if defined(USE_MEMORY_ANALYSIS)
|
||||
DEBUG_STREAM << UserHeap::MainStorage.GetLowestTotalHeapLeft()
|
||||
<< " bytes minimum available so far\n"
|
||||
<< UserHeap::MainStorage.GetMostHeapUsed()
|
||||
<< " bytes maximum used so far\n";
|
||||
#endif
|
||||
MemoryBlockBase::UsageReport();*/
|
||||
break;
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
// Report current event queue
|
||||
//------------------------------------
|
||||
case 'E':
|
||||
{
|
||||
Check(application);
|
||||
application->DumpEventQueue();
|
||||
break;
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
// Report performance statistics (Alt-?)
|
||||
//---------------------------------------
|
||||
case PCK_ALT_SLASH:
|
||||
{
|
||||
DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
|
||||
if (dpl_renderer)
|
||||
{
|
||||
Check(dpl_renderer);
|
||||
dpl_renderer->DPLReportPerfStats(DEBUG_STREAM);
|
||||
}
|
||||
break;
|
||||
}
|
||||
//--------------------------
|
||||
// Toggle Wireframe display
|
||||
//--------------------------
|
||||
case PCK_ALT_W:
|
||||
{
|
||||
DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
|
||||
if (dpl_renderer)
|
||||
{
|
||||
Check(dpl_renderer);
|
||||
dpl_renderer->DPLToggleWireframe();
|
||||
}
|
||||
break;
|
||||
}
|
||||
//--------------------------
|
||||
// Toggle "Predator-vision"
|
||||
//--------------------------
|
||||
case PCK_ALT_V:
|
||||
{
|
||||
DPLRenderer *dpl_renderer = l4_application->GetVideoRenderer();
|
||||
if (dpl_renderer)
|
||||
{
|
||||
Check(dpl_renderer);
|
||||
dpl_renderer->DPLTogglePVision();
|
||||
}
|
||||
break;
|
||||
}
|
||||
//--------------------------------------------------------------
|
||||
// Toggle transparency dither pattern between random and static
|
||||
//--------------------------------------------------------------
|
||||
case PCK_ALT_R:
|
||||
//-----------------------------
|
||||
// Report position of eyepoint
|
||||
//-----------------------------
|
||||
case PCK_ALT_P:
|
||||
DEBUG_STREAM << "Function net yet enabled.\n" << flush;
|
||||
break;
|
||||
//------------------------------
|
||||
// Pass event on to Application
|
||||
//------------------------------
|
||||
default:
|
||||
Application::KeyCommandMessageHandler(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// LightsOutMessageHandler
|
||||
//#############################################################################
|
||||
//
|
||||
#if DEBUG_LEVEL == 0
|
||||
void
|
||||
L4Application::LightsOutMessageHandler(Receiver::Message */*message*/)
|
||||
{
|
||||
#else
|
||||
void
|
||||
L4Application::LightsOutMessageHandler(Receiver::Message *message)
|
||||
{
|
||||
Check(this);
|
||||
Verify(message->messageID == LightsOutMessageID);
|
||||
#endif
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
// Turn off illumination
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
PilotIllumination(False);
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// TeslaCoil
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
L4Application::TeslaCoil(Logical light_on)
|
||||
{
|
||||
Check(controlsManager);
|
||||
|
||||
if (light_on)
|
||||
{
|
||||
((LBE4ControlsManager *) controlsManager)->SetLamp(
|
||||
LBE4ControlsManager::LampTesla1,
|
||||
RIO::solid + RIO::state1Bright + RIO::state2Bright
|
||||
);
|
||||
((LBE4ControlsManager *) controlsManager)->SetLamp(
|
||||
LBE4ControlsManager::LampTesla2,
|
||||
RIO::solid + RIO::state1Bright + RIO::state2Bright
|
||||
);
|
||||
((LBE4ControlsManager *) controlsManager)->SetLamp(
|
||||
LBE4ControlsManager::LampTesla3,
|
||||
RIO::solid + RIO::state1Bright + RIO::state2Bright
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
((LBE4ControlsManager *) controlsManager)->SetLamp(LBE4ControlsManager::LampTesla1, RIO::solid + RIO::state1Off + RIO::state2Off);
|
||||
((LBE4ControlsManager *) controlsManager)->SetLamp(LBE4ControlsManager::LampTesla2, RIO::solid + RIO::state1Off + RIO::state2Off);
|
||||
((LBE4ControlsManager *) controlsManager)->SetLamp(LBE4ControlsManager::LampTesla3, RIO::solid + RIO::state1Off + RIO::state2Off);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// PilotIllumination
|
||||
//#############################################################################
|
||||
//
|
||||
void
|
||||
L4Application::PilotIllumination(Logical light_on)
|
||||
{
|
||||
Check(controlsManager);
|
||||
|
||||
TeslaCoil(light_on);
|
||||
|
||||
if (light_on)
|
||||
{
|
||||
//--------------------------------------------
|
||||
// Turn on floor light
|
||||
//--------------------------------------------
|
||||
((LBE4ControlsManager *) controlsManager)->SetLamp(
|
||||
LBE4ControlsManager::LampFloor,
|
||||
RIO::solid + RIO::state1Bright + RIO::state2Bright
|
||||
);
|
||||
//--------------------------------------------
|
||||
// Ramp all aux screens to white
|
||||
//--------------------------------------------
|
||||
L4GaugeRenderer *gauge_renderer = GetGaugeRenderer();
|
||||
if (gauge_renderer != NULL)
|
||||
{
|
||||
Check(gauge_renderer);
|
||||
gauge_renderer->FadeToWhite(1.5);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//--------------------------------------------
|
||||
// Turn off floor light
|
||||
//--------------------------------------------
|
||||
((LBE4ControlsManager *) controlsManager)->SetLamp(
|
||||
LBE4ControlsManager::LampFloor,
|
||||
RIO::solid + RIO::state1Off + RIO::state2Off
|
||||
);
|
||||
//--------------------------------------------
|
||||
// Ramp all aux screens to normal
|
||||
//--------------------------------------------
|
||||
L4GaugeRenderer *gauge_renderer = GetGaugeRenderer();
|
||||
if (gauge_renderer != NULL)
|
||||
{
|
||||
Check(gauge_renderer);
|
||||
gauge_renderer->FadeToNormal(1.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST_CLASS
|
||||
# include "l4app.tcp"
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
//===========================================================================//
|
||||
// File: l4net.cpp //
|
||||
// Project: MUNGA Brick: L4 Network //
|
||||
// Contents: Implementation details for the L4 network manager //
|
||||
//---------------------------------------------------------------------------//
|
||||
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
|
||||
// All Rights reserved worldwide //
|
||||
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
||||
//===========================================================================//
|
||||
|
||||
#include <mungal4.hpp>
|
||||
#pragma hdrstop
|
||||
|
||||
#if !defined(L4NET_HPP)
|
||||
# include <l4net.hpp>
|
||||
#endif
|
||||
|
||||
L4NetworkManager::L4NetworkManager():
|
||||
NetworkManager(NetworkManager::DefaultData),
|
||||
messageBuffer(this)
|
||||
{
|
||||
Fail("L4NetworkManager -- l4net.cpp not yet reconstructed");
|
||||
}
|
||||
|
||||
void
|
||||
L4NetworkManager::CreateConsoleHost()
|
||||
{
|
||||
Fail("L4NetworkManager::CreateConsoleHost -- l4net.cpp not yet reconstructed");
|
||||
}
|
||||
|
||||
L4NetworkManager__MessageBuffer::L4NetworkManager__MessageBuffer(L4NetworkManager *network_manager):
|
||||
messageQueueSocket(NULL, 1)
|
||||
{
|
||||
networkManager = network_manager;
|
||||
bufferSize = 0;
|
||||
}
|
||||
|
||||
L4NetworkManager__MessageBuffer::~L4NetworkManager__MessageBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// Staged bodies: real l4net.cpp not yet reconstructed. Methods that a
|
||||
// standalone (non-networked) boot may touch are benign no-ops; methods that
|
||||
// imply real network traffic Fail loudly.
|
||||
//#############################################################################
|
||||
//
|
||||
L4NetworkManager::~L4NetworkManager()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
L4NetworkManager::Send(Message *, ClientID, HostID)
|
||||
{
|
||||
Fail("L4NetworkManager::Send -- l4net.cpp not yet reconstructed");
|
||||
}
|
||||
|
||||
void
|
||||
L4NetworkManager::ExclusiveBroadcast(Message *, ClientID)
|
||||
{
|
||||
Fail("L4NetworkManager::ExclusiveBroadcast -- l4net.cpp not yet reconstructed");
|
||||
}
|
||||
|
||||
void
|
||||
L4NetworkManager::StartConnecting(Mission *)
|
||||
{
|
||||
Fail("L4NetworkManager::StartConnecting -- l4net.cpp not yet reconstructed");
|
||||
}
|
||||
|
||||
Logical
|
||||
L4NetworkManager::Shutdown()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
Logical
|
||||
L4NetworkManager::CheckBuffers(NetworkPacket *)
|
||||
{
|
||||
Fail("L4NetworkManager::CheckBuffers -- l4net.cpp not yet reconstructed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
L4NetworkManager::RemovePacket(NetworkPacket *)
|
||||
{
|
||||
Fail("L4NetworkManager::RemovePacket -- l4net.cpp not yet reconstructed");
|
||||
}
|
||||
|
||||
Logical
|
||||
L4NetworkManager::ExecuteBackground()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
L4NetworkManager::Marker(char *)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
L4NetworkManager::Mode(NetworkMode)
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// NetNub client-side globals (real home: l4net.cpp). Net_Common_Ptr NULL =
|
||||
// no NetNub TSR loaded; L4File then takes its plain-DOS path (L4FILE.CPP:32).
|
||||
//#############################################################################
|
||||
//
|
||||
Netcom_Ptr
|
||||
Net_Common_Ptr = NULL;
|
||||
|
||||
void
|
||||
NetNub::SendCommand()
|
||||
{
|
||||
Fail("NetNub::SendCommand -- l4net.cpp not yet reconstructed");
|
||||
}
|
||||
@@ -75,7 +75,7 @@ def main():
|
||||
line = re.sub(r"(?<![:\w])GetMessageHandlers\(\)", "MessageHandlers", line)
|
||||
line = re.sub(r"(?<![:\w])GetAttributeIndex\(\)", "AttributeIndex", line)
|
||||
line = line.replace("PostQuitMessage(AbortExitCodeID);", 'Fail("Exiting");')
|
||||
for bad in ("atlbase.h", "windows.h", "winsock"):
|
||||
for bad in ("atlbase.h", "windows.h", "winsock", "windows.hpp", "<cstdlib>", "<cstring>", "<cstdio>"):
|
||||
if bad in line and "#include" in line:
|
||||
line = ""
|
||||
break
|
||||
|
||||
@@ -52,7 +52,7 @@ srcfor() { # srcfor <name.cpp> <BTdir> <RPdir> [S410dir]
|
||||
l4vidper.cpp|l4tsdpl.cpp) return;; # not in mungal4.lib
|
||||
filestub.cpp) return;; # stub.lib member (prebuilt obj)
|
||||
esac
|
||||
for d in "$2" "$4" "$3"; do # BT first, then source410, then RP
|
||||
for d in "$4" "$2" "$3"; do # source410 overrides, then BT, then RP
|
||||
[ -z "$d" ] && continue
|
||||
for f in "$d"/*.CPP "$d"/*.cpp; do
|
||||
[ -f "$f" ] || continue
|
||||
@@ -92,30 +92,50 @@ stage_bt() {
|
||||
echo "BT: $ok ok, $fail fail"
|
||||
}
|
||||
|
||||
# Authentic 1995 lib member ORDER (MUNGA.MAK / mungal4.mak / BT.MAK / BTL4.MAK).
|
||||
# Order is LOAD-BEARING: tlink emits static-init records in module pull order,
|
||||
# and base-class statics (e.g. NetworkClient::ClassDerivations, network.obj)
|
||||
# must construct before derived ones (IcomManager, icom.obj). Alphabetical
|
||||
# order boots into a null-vptr crash in Derivation::Derivation.
|
||||
ORDER_munga="heap cstr memblock memreg memstrm filestrm verify namelist notation fileutil color resource scalar rect2d random angle vector3d vector4d point3d unitvec rotation motion origin affnmtrx linmtrx matrix mtrxstk spline ray line sphere normal plane extntbox bndgbox boxtree boxlist boxsolid boxsort boxsphr boxcone boxramp boxiramp boxwedge boxdisks boxtile time vdata iterator link plug objstrm socket node slot chain sfeskt srtskt schain vchain tree table hash trace receiver event evtstat cmpnnt simulate subsystm joint network damage entity entityid nttmgr entity2 envirnmt mover segment jmover watcher host hostmgr console scnrole team exptbl caminst cammgr camship cammppr eyecandy player director dropzone explode terrain cultural doorfram door registry lattice intorgn collorgn interest collasst update reticle rndorgn renderer vidrend audio audent audtime audwgt audlvl audloc audcmp audsrc audmidi audseq audwthr audrend wrhous gaugmap gauge lamp gaugrend gaugalrm graph2d mode controls mission apptask app appmgr appmsg spooler icom maptool modtool animtool audtools tool"
|
||||
ORDER_mungal4="l4trace l4file l4time netshare l4serial l4svga16 joystick pcspak l4host l4net l4dplmem l4vidrnd l4video startdpl sosmawe l4audhdw l4audio l4audlvl l4audwtr l4audres l4audrnd l4wrhous l4vb8 l4vb16 l4gauima l4grend l4gauge l4lamp l4plasma l4ctrl l4keybd l4mouse l4rio l4mppr l4app l4splr l4icom l4vidtul l4audtul l4gautul l4ctltul"
|
||||
ORDER_bt="btmssn messmgr mechdmg dmgtable mech mech2 mech3 mech4 mechsub mechtech heat mechmppr powersub sensor gnrator gyro torso hud myomers mechweap emitter ppc projweap mislanch ammobin gauss projtile misthrst seeker missile btplayer btteam btdirect btreg btcnsl bttool"
|
||||
ORDER_btl4="btl4mode btl4rdr btl4gaug btl4gau2 btl4gau3 btl4grnd btl4galm btl4vid btl4mppr btl4arnd btl4mssn btl4app btl4pb"
|
||||
|
||||
stage_libs() {
|
||||
cd "$B/lib"
|
||||
for lib in munga mungal4 bt btl4; do
|
||||
rm -f $lib.lib
|
||||
ls "$B/obj/$lib"/*.obj >/dev/null 2>&1 || continue
|
||||
: > $lib.rsp
|
||||
for o in "$B/obj/$lib"/*.obj; do
|
||||
printf '+..\obj\%s\%s &
|
||||
' "$lib" "$(basename "$o")" >> $lib.rsp
|
||||
done
|
||||
# prebuilt-1995 fallbacks for TUs with no compiled obj
|
||||
if [ $lib = munga ] || [ $lib = mungal4 ]; then
|
||||
for o in $(find $R/MUNGA/opt $R/MUNGA_L4 -iname "*.obj" 2>/dev/null); do
|
||||
n=$(basename "${o%.*}" | tr 'A-Z' 'a-z')
|
||||
if [ ! -f "$B/obj/munga/$n.obj" ] && [ ! -f "$B/obj/mungal4/$n.obj" ]; then
|
||||
case "$lib/$o" in
|
||||
munga/*/MUNGA/*) printf '+%s &
|
||||
' "$(cygpath -w "$o" | sed 's|\|\\|g')" >> $lib.rsp;;
|
||||
mungal4/*/MUNGA_L4/*) printf '+%s &
|
||||
' "$(cygpath -w "$o" | sed 's|\|\\|g')" >> $lib.rsp;;
|
||||
esac
|
||||
eval "order=\$ORDER_$lib"
|
||||
added=" "
|
||||
# authentic makefile order first: compiled obj, else prebuilt-1995 obj
|
||||
for n in $order; do
|
||||
if [ -f "$B/obj/$lib/$n.obj" ]; then
|
||||
printf '+..\obj\%s\%s.obj &
|
||||
' "$lib" "$n" >> $lib.rsp
|
||||
added="$added$n "
|
||||
else
|
||||
pre=$(find $R/MUNGA/opt $R/MUNGA_L4 -iname "$n.obj" 2>/dev/null | head -1)
|
||||
if [ -n "$pre" ]; then
|
||||
printf '+%s &
|
||||
' "$(cygpath -w "$pre")" >> $lib.rsp
|
||||
added="$added$n "
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done
|
||||
# any extra compiled objs not in the 1995 list go last
|
||||
for o in "$B/obj/$lib"/*.obj; do
|
||||
n=$(basename "${o%.*}")
|
||||
# btl4.obj (main) is linked bare, never a lib member (BTL4.MAK:70)
|
||||
[ "$lib" = btl4 ] && [ "$n" = btl4 ] && continue
|
||||
# l4tstall = the engine TEST main -- its own exe in 1995, never a lib member
|
||||
[ "$n" = l4tstall ] && continue
|
||||
case "$added" in *" $n "*) continue;; esac
|
||||
printf '+..\obj\%s\%s.obj &
|
||||
' "$lib" "$n" >> $lib.rsp
|
||||
done
|
||||
sed -i '$ s/ &$//' $lib.rsp
|
||||
MSYS2_ARG_CONV_EXCL='*' tlib $lib.lib /P32 @$lib.rsp > $lib.tlib.log 2>&1
|
||||
echo "$lib.lib: $(grep -c '^+' $lib.rsp) members ($(ls -la $lib.lib 2>/dev/null | awk '{print $5}') bytes)"
|
||||
@@ -124,30 +144,22 @@ stage_libs() {
|
||||
|
||||
stage_link() {
|
||||
cd "$B"
|
||||
if [ ! -f obj/btl4/btl4.obj ] && [ -f probe_main.cpp ]; then
|
||||
if [ -f obj/btl4/btl4.obj ]; then
|
||||
MAIN=obj/btl4/btl4.obj
|
||||
elif [ -f probe_main.cpp ]; then
|
||||
bcc32 $FLAGS -I"$INC" -oprobe_main.obj probe_main.cpp > probe_main.log 2>&1 || { echo "probe main FAILED (probe_main.log)"; return 1; }
|
||||
MAIN=probe_main.obj
|
||||
else
|
||||
MAIN=obj/btl4/btl4.obj
|
||||
fi
|
||||
cp -f "$T/CODE/BT/32STUB.EXE" 32stub.exe 2>/dev/null
|
||||
# single-line sections; SOSDBXC+SOSMBXC = the 32-bit Borland SOS pair
|
||||
# (SOSMW* is 16-bit); WATTCPLG is the 16-bit NetNub TSR side -- excluded
|
||||
cat > link.rsp <<EOF2
|
||||
$(cygpath -w $C/C0X32.OBJ)+
|
||||
$MAIN,
|
||||
btl4opt.exe,
|
||||
btl4opt.map,
|
||||
lib/munga.lib+
|
||||
lib/mungal4.lib+
|
||||
$(cygpath -w $R/MUNGA_L4/libDPL/LIBDPL.LIB)+
|
||||
$(cygpath -w $R/MUNGA_L4/sos/SOSMWXCR.LIB)+
|
||||
$(cygpath -w $R/MUNGA_L4/NetNub/lib/WATTCPLG.LIB)+
|
||||
lib/bt.lib+
|
||||
lib/btl4.lib+
|
||||
$(cygpath -w $R/DPMI32.LIB)+
|
||||
$(cygpath -w $R/CW32.LIB)
|
||||
$(cygpath -w $C/C0X32.OBJ) $(cygpath -w "$B/$MAIN"), btl4opt.exe, btl4opt.map, lib\\munga.lib lib\\mungal4.lib $(cygpath -w $R/MUNGA_L4/libDPL/LIBDPL.LIB) $(cygpath -w $R/MUNGA_L4/sos/SOSDBXC.LIB) $(cygpath -w $R/MUNGA_L4/sos/SOSMBXC.LIB) lib\\bt.lib lib\\btl4.lib $(cygpath -w $R/DPMI32.LIB) $(cygpath -w $R/CW32.LIB)
|
||||
EOF2
|
||||
tlink32 -Tpe -ax -m -L"$(cygpath -w $TW/BORLAND/BC45/LIB)" @link.rsp > link.log 2>&1
|
||||
grep -i "undefined" link.log | sed "s/^.*Error: //" | sort -u > UNRESOLVED.txt
|
||||
echo "link exit: $? ; unresolved: $(wc -l < UNRESOLVED.txt) (build410/UNRESOLVED.txt)"
|
||||
MSYS2_ARG_CONV_EXCL='*' tlink32 -Tpe -ax -m -L"$(cygpath -w $TW/BORLAND/BC45/LIB)" @link.rsp > link.log 2>&1
|
||||
grep -i "unresolved" link.log | sed "s/^.*Error: //" | sort -u > UNRESOLVED.txt
|
||||
echo "link exit: $? ; unresolved: $(wc -l < UNRESOLVED.txt) (build410/UNRESOLVED.txt); main=$MAIN"
|
||||
ls -la btl4opt.exe 2>/dev/null
|
||||
}
|
||||
|
||||
case "${1:-all}" in
|
||||
|
||||
Reference in New Issue
Block a user